From 91487faa20528a94b9c9766955bccc3802cf3ef4 Mon Sep 17 00:00:00 2001 From: Yichen Wang Date: Thu, 16 Jul 2015 16:32:21 -0700 Subject: [PATCH] Add support for resuing tenants/users 1. Add support for resuing tenants/users; 2. Add the version checks; 3. KNOWN ISSUE: Single cloud mode is not supported under reusing mode. (WIP on the solution) Change-Id: I0607312d341e53df4ad6d869ac4265f074c23cf5 --- scale/base_compute.py | 5 +- scale/base_network.py | 2 +- scale/cfg.tenants.yaml | 28 ++++ scale/cfg.topo.yaml | 1 + .../kloudbuster/static/kb_test/kb_vm_agent.py | 18 ++- scale/kb_config.py | 20 ++- scale/kb_runner.py | 18 ++- .../kb_server/kb_server/controllers/config.py | 10 +- scale/kloudbuster.py | 120 ++++++++++++------ scale/tenant.py | 55 +++++--- scale/users.py | 46 ++++--- 11 files changed, 231 insertions(+), 92 deletions(-) create mode 100644 scale/cfg.tenants.yaml diff --git a/scale/base_compute.py b/scale/base_compute.py index b39f324..fa6ddb8 100644 --- a/scale/base_compute.py +++ b/scale/base_compute.py @@ -79,7 +79,10 @@ class BaseCompute(object): instance = self.novaclient.servers.get(instance.id) if instance.status == 'ACTIVE': self.instance = instance - self.host = instance.__dict__['OS-EXT-SRV-ATTR:hypervisor_hostname'] + if 'OS-EXT-SRV-ATTR:hypervisor_hostname' in instance.__dict__: + self.host = instance.__dict__['OS-EXT-SRV-ATTR:hypervisor_hostname'] + else: + self.host = "Unknown" return instance if instance.status == 'ERROR': LOG.error('Instance creation error:' + instance.fault['message']) diff --git a/scale/base_network.py b/scale/base_network.py index 4365ee3..4f3ab3a 100644 --- a/scale/base_network.py +++ b/scale/base_network.py @@ -158,7 +158,7 @@ class BaseNetwork(object): """ Create a network with 1 subnet inside it """ - subnet_name = "kloudbuster_subnet_" + network_name + subnet_name = "KB_subnet_" + network_name body = { 'network': { 'name': network_name, diff --git a/scale/cfg.tenants.yaml b/scale/cfg.tenants.yaml new file mode 100644 index 0000000..78fdd40 --- /dev/null +++ b/scale/cfg.tenants.yaml @@ -0,0 +1,28 @@ +# KloudBuster tenant and users files +# Usage: Pass to KloudBuster using "-l" +# +# This file contains the a list of tenants and users that will be reused by +# KloudBuster instead of creating them. This is useful when running +# KloudBuster on clouds without admin permissions. +# +# Settings in this file has higher priority than user configs. It determines +# the final count of tenants and useres that KloudBuster will use. + + +# Sections for listing the tenant and user lists for server cloud. +# Note: For now we only support 1 user per tenant +server: + - name: ts_1 + user: + - username: tsu_1 + password: tsu_1 + - name: ts_2 + user: + - username: tsu_2 + password: tsu_2 + +client: + - name: tc_1 + user: + - username: tcu_1 + password: tcu_1 diff --git a/scale/cfg.topo.yaml b/scale/cfg.topo.yaml index 73c6876..2274fe7 100644 --- a/scale/cfg.topo.yaml +++ b/scale/cfg.topo.yaml @@ -1,4 +1,5 @@ # Compute host topology file for running KloudBuster +# Usage: Pass to KloudBuster using -t # The compute host name must be exactly the same as shown from NOVA: # i.e. "nova hypervisor-list" diff --git a/scale/dib/elements/kloudbuster/static/kb_test/kb_vm_agent.py b/scale/dib/elements/kloudbuster/static/kb_test/kb_vm_agent.py index f666c57..114f67c 100644 --- a/scale/dib/elements/kloudbuster/static/kb_test/kb_vm_agent.py +++ b/scale/dib/elements/kloudbuster/static/kb_test/kb_vm_agent.py @@ -13,7 +13,6 @@ # under the License. # -import socket import subprocess import sys import threading @@ -21,6 +20,16 @@ import time import redis +# Define the version of the KloudBuster agent. +# +# When VM is up running, the agent will send the READY message to the +# KloudBuster main program, along with its version. The main program +# will check the version to see whether the image meets the minimum +# requirements to run, and stopped with an error if not. +# +# Note: All majors are compatible regardless of minor. +__version__ = '1.0' + class KB_Instance(object): # Check whether the HTTP Service is up running @@ -96,10 +105,7 @@ class KB_VM_Agent(object): self.pubsub = self.redis_obj.pubsub(ignore_subscribe_messages=True) self.hello_thread = None self.stop_hello = threading.Event() - # Assumption: - # Here we assume the vm_name is the same as the host name (lower case), - # which is true if the VM is spawned by Kloud Buster. - self.vm_name = socket.gethostname().lower() + self.vm_name = user_data['vm_name'] self.orches_chan_name = "kloudbuster_orches" self.report_chan_name = "kloudbuster_report" self.last_cmd = None @@ -125,7 +131,7 @@ class KB_VM_Agent(object): def send_hello(self): # Sending "hello" message to master node every 2 seconds while not self.stop_hello.is_set(): - self.report('READY', None, None) + self.report('READY', None, __version__) time.sleep(2) def exec_command(self, cmd): diff --git a/scale/kb_config.py b/scale/kb_config.py index a5e91db..81543f3 100644 --- a/scale/kb_config.py +++ b/scale/kb_config.py @@ -24,6 +24,9 @@ import credentials CONF = cfg.CONF LOG = logging.getLogger(__name__) +class KBConfigParseException(Exception): + pass + # Some hardcoded client side options we do not want users to change hardcoded_client_cfg = { # Number of tenants to be created on the cloud @@ -74,6 +77,7 @@ class KBConfig(object): self.server_cfg = None self.client_cfg = None self.topo_cfg = None + self.tenants_list = None def update_configs(self): # Initialize the key pair name @@ -109,12 +113,14 @@ class KBConfig(object): self.get_credentials() self.get_configs() self.get_topo_cfg() + self.get_tenants_list() self.update_configs() def init_with_rest_api(self, **kwargs): self.cred_tested = kwargs['cred_tested'] self.cred_testing = kwargs['cred_testing'] self.topo_cfg = kwargs['topo_cfg'] + self.tenants_list = kwargs['tenants_list'] self.update_configs() def get_total_vm_count(self, config): @@ -125,11 +131,11 @@ class KBConfig(object): def get_credentials(self): # Retrieve the credentials self.cred_tested = credentials.Credentials(openrc_file=CONF.tested_rc, - pwd=CONF.passwd_tested, + pwd=CONF.tested_passwd, no_env=CONF.no_env) if CONF.testing_rc and CONF.testing_rc != CONF.tested_rc: self.cred_testing = credentials.Credentials(openrc_file=CONF.testing_rc, - pwd=CONF.passwd_testing, + pwd=CONF.testing_passwd, no_env=CONF.no_env) else: # Use the same openrc file for both cases @@ -143,3 +149,13 @@ class KBConfig(object): def get_topo_cfg(self): if CONF.topology: self.topo_cfg = configure.Configuration.from_file(CONF.topology).configure() + + def get_tenants_list(self): + if CONF.tenants_list: + self.tenants_list = configure.Configuration.from_file(CONF.tenants_list).configure() + try: + self.config_scale['number_tenants'] = len(self.tenants_list['server']) + self.config_scale['users_per_tenant'] = len(self.tenants_list['server'][0]['user']) + except Exception as e: + LOG.error('Cannot parse the count of tenant/user from the config file.') + raise KBConfigParseException(e.message) diff --git a/scale/kb_runner.py b/scale/kb_runner.py index 5cf0dff..09248ad 100644 --- a/scale/kb_runner.py +++ b/scale/kb_runner.py @@ -12,6 +12,7 @@ # License for the specific language governing permissions and limitations # under the License. +from distutils.version import LooseVersion import time import log as logging @@ -39,13 +40,15 @@ class KBRunner(object): Control the testing VMs on the testing cloud """ - def __init__(self, client_list, config, single_cloud=True): - self.client_dict = dict(zip([x.vm_name.lower() for x in client_list], client_list)) + def __init__(self, client_list, config, required_agent_version, single_cloud=True): + self.client_dict = dict(zip([x.vm_name for x in client_list], client_list)) self.config = config self.single_cloud = single_cloud self.result = {} self.host_stats = {} self.tool_result = {} + self.required_agent_version = str(required_agent_version) + self.agent_version = None # Redis self.redis_obj = None @@ -129,6 +132,7 @@ class KBRunner(object): clist[vm_name].up_flag = True clist.pop(vm_name) cnt_succ = cnt_succ + 1 + self.agent_version = payload['data'] elif cmd == 'REPORT': sample_count = sample_count + 1 # Parse the results from HTTP Tools @@ -212,7 +216,13 @@ class KBRunner(object): try: LOG.info("Waiting for agents on VMs to come up...") self.wait_for_vm_up() - + if not self.agent_version: + self.agent_version = "0.0" + if (LooseVersion(self.agent_version) < LooseVersion(self.required_agent_version)): + LOG.error("The VM image you are running is too old (%s), the minimum version " + "required is %s.x. Please build the image from latest repository." % + (self.agent_version, self.required_agent_version)) + return if self.single_cloud: LOG.info("Setting up static route to reach tested cloud...") self.setup_static_route() @@ -224,7 +234,7 @@ class KBRunner(object): print "Press enter to start running benchmarking tools..." raw_input() - LOG.info("Starting HTTP Benchmarking...") + LOG.info("Running HTTP Benchmarking...") self.run_http_test() # Call the method in corresponding tools to consolidate results diff --git a/scale/kb_server/kb_server/controllers/config.py b/scale/kb_server/kb_server/controllers/config.py index f0f8332..336a533 100644 --- a/scale/kb_server/kb_server/controllers/config.py +++ b/scale/kb_server/kb_server/controllers/config.py @@ -48,6 +48,7 @@ class ConfigController(object): # 'testing_rc': '', 'passwd_testing': ''}, # 'kb_cfg': {}, # 'topo_cfg': {} + # 'tenants_cfg': {} # } user_config = eval(args) @@ -80,6 +81,12 @@ class ConfigController(object): topo_cfg = Configuration.from_string(user_config['topo_cfg']).configure() else: topo_cfg = None + + # Parsing tenants configs from application input + if 'tenants_list' in user_config: + tenants_list = Configuration.from_string(user_config['tenants_list']).configure() + else: + tenants_list = None except Exception as e: response.status = 403 response.text = "Error while parsing configurations: %s" % e.message @@ -87,7 +94,8 @@ class ConfigController(object): self.kb_config.init_with_rest_api(cred_tested=cred_tested, cred_testing=cred_testing, - topo_cfg=topo_cfg) + topo_cfg=topo_cfg, + tenants_list=tenants_list) return str(self.kb_config.config_scale) @expose(generic=True) diff --git a/scale/kloudbuster.py b/scale/kloudbuster.py index 5c7ff8c..d06809f 100644 --- a/scale/kloudbuster.py +++ b/scale/kloudbuster.py @@ -37,6 +37,9 @@ import sshutils CONF = cfg.CONF LOG = logging.getLogger(__name__) +__version__ = '1.0.0' +KB_IMAGE_MAJOR_VERSION = 1 + class KBVMCreationException(Exception): pass @@ -62,6 +65,10 @@ def check_and_upload_images(cred, cred_testing, server_img_name, client_img_name if img['name'] == img_name_dict[kloud]: img_found = True break + if img.visibility != 'public' and CONF.tenants_list: + LOG.error("Image must be public when running in reusing mode.") + sys.exit(1) + if not img_found: # Trying upload images LOG.info("Image is not found in %s, trying to upload..." % (kloud)) @@ -72,17 +79,19 @@ def check_and_upload_images(cred, cred_testing, server_img_name, client_img_name with open('dib/kloudbuster.qcow2') as fimage: image = glance_client.images.create(name=img_name_dict[kloud], disk_format="qcow2", - container_format="bare") + container_format="bare", + visibility='public') glance_client.images.upload(image['id'], fimage) return True class Kloud(object): - def __init__(self, scale_cfg, admin_creds, testing_side=False): + def __init__(self, scale_cfg, admin_creds, reusing_tenants, testing_side=False): self.cred = admin_creds self.tenant_list = [] self.testing_side = testing_side self.scale_cfg = scale_cfg + self.reusing_tenants = reusing_tenants self.keystone, self.auth_url = create_keystone_client(self.cred) if testing_side: self.prefix = 'KBc' @@ -102,21 +111,32 @@ class Kloud(object): LOG.info('%s Availability Zone: %s' % (self.name, self.placement_az)) def create_resources(self, tenant_quota): - for tenant_count in xrange(self.scale_cfg['number_tenants']): - tenant_name = self.prefix + "-T" + str(tenant_count) - new_tenant = tenant.Tenant(tenant_name, self, tenant_quota) - self.tenant_list.append(new_tenant) - new_tenant.create_resources() - - # Create flavors for servers, clients, and kb-proxy nodes - nova_client = self.tenant_list[0].user_list[0].nova_client - flavor_manager = base_compute.Flavor(nova_client) - flavor_dict = self.scale_cfg.flavor - if self.testing_side: - flavor_manager.create_flavor('kb.client', override=True, **flavor_dict) - flavor_manager.create_flavor('kb.proxy', override=True, ram=2048, vcpus=1, disk=20) + if self.reusing_tenants: + for tenant_info in self.reusing_tenants: + tenant_name = tenant_info['name'] + user_list = tenant_info['user'] + tenant_instance = tenant.Tenant(tenant_name, self, tenant_quota, + reusing_users=user_list) + self.tenant_list.append(tenant_instance) else: - flavor_manager.create_flavor('kb.server', override=True, **flavor_dict) + for tenant_count in xrange(self.scale_cfg['number_tenants']): + tenant_name = self.prefix + "-T" + str(tenant_count) + tenant_instance = tenant.Tenant(tenant_name, self, tenant_quota) + self.tenant_list.append(tenant_instance) + + for tenant_instance in self.tenant_list: + tenant_instance.create_resources() + + if not self.reusing_tenants: + # Create flavors for servers, clients, and kb-proxy nodes + nova_client = self.tenant_list[0].user_list[0].nova_client + flavor_manager = base_compute.Flavor(nova_client) + flavor_dict = self.scale_cfg.flavor + if self.testing_side: + flavor_manager.create_flavor('kb.client', override=True, **flavor_dict) + flavor_manager.create_flavor('kb.proxy', override=True, ram=2048, vcpus=1, disk=20) + else: + flavor_manager.create_flavor('kb.server', override=True, **flavor_dict) def delete_resources(self): # Deleting flavors created by KloudBuster @@ -126,12 +146,13 @@ class Kloud(object): # NOVA Client is not yet initialized, so skip cleaning up... return - flavor_manager = base_compute.Flavor(nova_client) - if self.testing_side: - flavor_manager.delete_flavor('kb.client') - flavor_manager.delete_flavor('kb.proxy') - else: - flavor_manager.delete_flavor('kb.server') + if not self.reusing_tenants: + flavor_manager = base_compute.Flavor(nova_client) + if self.testing_side: + flavor_manager.delete_flavor('kb.client') + flavor_manager.delete_flavor('kb.proxy') + else: + flavor_manager.delete_flavor('kb.server') for tnt in self.tenant_list: tnt.delete_resources() @@ -205,22 +226,30 @@ class KloudBuster(object): 4. Networks per router 5. Instances per network """ - def __init__(self, server_cred, client_cred, server_cfg, client_cfg, topology): + def __init__(self, server_cred, client_cred, server_cfg, client_cfg, topology, tenants_list): # List of tenant objects to keep track of all tenants - self.tenant_list = [] - self.tenant = None - self.tenant_list_testing = [] - self.tenant_testing = None self.server_cfg = server_cfg self.client_cfg = client_cfg - self.topology = topology + if topology and tenants_list: + self.topology = None + LOG.warn("REUSING MODE: Topology configs will be ignored.") + else: + self.topology = topology + if tenants_list: + self.tenants_list = tenants_list + LOG.warn("REUSING MODE: The quota will not adjust automatically.") + LOG.warn("REUSING MODE: The flavor configs will be ignored, and m1.small is used.") + else: + self.tenants_list = {'server': None, 'client': None} # TODO(check on same auth_url instead) if server_cred == client_cred: self.single_cloud = True else: self.single_cloud = False - self.kloud = Kloud(server_cfg, server_cred) - self.testing_kloud = Kloud(client_cfg, client_cred, testing_side=True) + self.kloud = Kloud(server_cfg, server_cred, self.tenants_list['server']) + self.testing_kloud = Kloud(client_cfg, client_cred, + self.tenants_list['client'], + testing_side=True) self.kb_proxy = None self.final_result = None self.server_vm_create_thread = None @@ -256,8 +285,8 @@ class KloudBuster(object): KBScheduler.setup_vm_placement(role, svr_list, self.topology, self.kloud.placement_az, "Round-robin") for ins in svr_list: - ins.user_data['role'] = "Server" - ins.boot_info['flavor_type'] = "kb.server" + ins.user_data['role'] = 'Server' + ins.boot_info['flavor_type'] = 'm1.small' if self.tenants_list else 'kb.server' ins.boot_info['user_data'] = str(ins.user_data) elif role == "Client": client_list = self.testing_kloud.get_all_instances() @@ -266,14 +295,15 @@ class KloudBuster(object): KBScheduler.setup_vm_placement(role, client_list, self.topology, self.testing_kloud.placement_az, "Round-robin") for idx, ins in enumerate(client_list): - ins.user_data['role'] = "Client" + ins.user_data['role'] = 'Client' + ins.user_data['vm_name'] = ins.vm_name ins.user_data['redis_server'] = self.kb_proxy.fixed_ip ins.user_data['redis_server_port'] = 6379 ins.user_data['target_subnet_ip'] = svr_list[idx].subnet_ip ins.user_data['target_shared_interface_ip'] = svr_list[idx].shared_interface_ip ins.user_data['http_tool'] = ins.config['http_tool'] ins.user_data['http_tool_configs'] = ins.config['http_tool_configs'] - ins.boot_info['flavor_type'] = "kb.client" + ins.boot_info['flavor_type'] = 'm1.small' if self.tenants_list else 'kb.client' ins.boot_info['user_data'] = str(ins.user_data) def run(self): @@ -297,16 +327,18 @@ class KloudBuster(object): self.kb_proxy = client_list[-1] client_list.pop() - self.kb_proxy.vm_name = "KB-PROXY" + self.kb_proxy.vm_name = 'KB-PROXY' self.kb_proxy.user_data['role'] = 'KB-PROXY' - self.kb_proxy.boot_info['flavor_type'] = 'kb.proxy' + self.kb_proxy.boot_info['flavor_type'] = 'm1.small' if self.tenants_list else 'kb.proxy' if self.testing_kloud.placement_az: self.kb_proxy.boot_info['avail_zone'] = "%s:%s" %\ (self.testing_kloud.placement_az, self.topology.clients_rack.split()[0]) self.kb_proxy.boot_info['user_data'] = str(self.kb_proxy.user_data) self.testing_kloud.create_vm(self.kb_proxy) - kbrunner = KBRunner(client_list, self.client_cfg, self.single_cloud) + kbrunner = KBRunner(client_list, self.client_cfg, + KB_IMAGE_MAJOR_VERSION, + self.single_cloud) kbrunner.setup_redis(self.kb_proxy.fip_ip) if self.single_cloud: @@ -499,18 +531,24 @@ if __name__ == '__main__': short="t", default=None, help="Topology files for compute hosts"), + cfg.StrOpt("tenants-list", + short="l", + default=None, + help="Existing tenant and user lists for reusing"), cfg.StrOpt("tested-rc", default=None, help="Tested cloud openrc credentials file"), cfg.StrOpt("testing-rc", default=None, help="Testing cloud openrc credentials file"), - cfg.StrOpt("passwd_tested", + cfg.StrOpt("tested-passwd", default=None, + secret=True, help="Tested cloud password"), - cfg.StrOpt("passwd_testing", + cfg.StrOpt("testing-passwd", default=None, - help="OpenStack password testing cloud"), + secret=True, + help="Testing cloud password"), cfg.StrOpt("json", default=None, help='store results in JSON format file'), @@ -540,7 +578,7 @@ if __name__ == '__main__': kloudbuster = KloudBuster( kb_config.cred_tested, kb_config.cred_testing, kb_config.server_cfg, kb_config.client_cfg, - kb_config.topo_cfg) + kb_config.topo_cfg, kb_config.tenants_list) kloudbuster.run() if CONF.json: diff --git a/scale/tenant.py b/scale/tenant.py index cea948a..f24c5f6 100644 --- a/scale/tenant.py +++ b/scale/tenant.py @@ -26,7 +26,7 @@ class Tenant(object): 2. Uses the User class to perform all user resource creation and deletion """ - def __init__(self, tenant_name, kloud, tenant_quota): + def __init__(self, tenant_name, kloud, tenant_quota, reusing_users=None): """ Holds the tenant name tenant id and keystone client @@ -39,32 +39,42 @@ class Tenant(object): self.tenant_object = self._get_tenant() self.tenant_id = self.tenant_object.id self.tenant_quota = tenant_quota + self.reusing_users = reusing_users # Contains a list of user instance objects self.user_list = [] def _get_tenant(self): + if self.kloud.reusing_tenants: + LOG.info("Using tenant: " + self.tenant_name) + tenant_list = self.kloud.keystone.tenants.list() + for tenant in tenant_list: + if tenant.name == self.tenant_name: + return tenant + raise Exception("Tenant not found") + ''' Create or reuse a tenant object of a given name ''' try: LOG.info("Creating tenant: " + self.tenant_name) - self.tenant_object = \ + tenant_object = \ self.kloud.keystone.tenants.create(tenant_name=self.tenant_name, description="KloudBuster tenant", enabled=True) + return tenant_object except keystone_exception.Conflict as exc: # ost likely the entry already exists: # Conflict: Conflict occurred attempting to store project - Duplicate Entry (HTTP 409) if exc.http_status != 409: raise exc LOG.info("Tenant %s already present, reusing it" % self.tenant_name) + # It is a hassle to find a tenant by name as the only way seems to retrieve + # the list of all tenants which can be very large + tenant_list = self.kloud.keystone.tenants.list() + for tenant in tenant_list: + if tenant.name == self.tenant_name: + return tenant - # It is a hassle to find a tenant by name as the only way seems to retrieve - # the list of all tenants which can be very large - tenant_list = self.kloud.keystone.tenants.list() - for tenant in tenant_list: - if tenant.name == self.tenant_name: - return tenant # Should never come here raise Exception("Tenant not found") @@ -73,16 +83,22 @@ class Tenant(object): Creates all the entities associated with a user offloads tasks to user class """ + if self.reusing_users: + for user_info in self.reusing_users: + user_name = user_info['username'] + password = user_info['password'] + user_instance = users.User(user_name, password, self, None) + self.user_list.append(user_instance) + else: + # Loop over the required number of users and create resources + for user_count in xrange(self.kloud.scale_cfg['users_per_tenant']): + user_name = self.tenant_name + "-U" + str(user_count) + user_instance = users.User(user_name, user_name, self, + self.kloud.scale_cfg['keystone_admin_role']) + # Global list with all user instances + self.user_list.append(user_instance) - # Loop over the required number of users and create resources - for user_count in xrange(self.kloud.scale_cfg['users_per_tenant']): - user_name = self.tenant_name + "-U" + str(user_count) - user_instance = users.User(user_name, - self, - self.kloud.scale_cfg['keystone_admin_role']) - # Global list with all user instances - self.user_list.append(user_instance) - + for user_instance in self.user_list: # Now create the user resources like routers which inturn trigger network and # vm creation user_instance.create_resources() @@ -110,5 +126,6 @@ class Tenant(object): for user in self.user_list: user.delete_resources() - # Delete the tenant (self) - self.kloud.keystone.tenants.delete(self.tenant_id) + if not self.reusing_users: + # Delete the tenant (self) + self.kloud.keystone.tenants.delete(self.tenant_id) diff --git a/scale/users.py b/scale/users.py index fa6c013..bee90f1 100644 --- a/scale/users.py +++ b/scale/users.py @@ -29,7 +29,7 @@ class User(object): Creates and deletes N routers based on num of routers """ - def __init__(self, user_name, tenant, user_role): + def __init__(self, user_name, password, tenant, user_role): """ Store all resources 1. Keystone client object @@ -38,14 +38,14 @@ class User(object): 4. router list """ self.user_name = user_name + self.password = password self.tenant = tenant - self.user_id = None self.router_list = [] # Store the nova, neutron and cinder client self.nova_client = None self.neutron_client = None self.cinder_client = None - self.admin_user = self._get_user() + self.user = self._get_user() # Each user is associated to 1 key pair at most self.key_pair = None self.key_name = None @@ -53,25 +53,35 @@ class User(object): # Create the user within the given tenant associate # admin role with user. We need admin role for user # since we perform VM placement in future - - current_role = None - for role in self.tenant.kloud.keystone.roles.list(): - if role.name == user_role: - current_role = role - break - self.tenant.kloud.keystone.roles.add_user_role(self.admin_user, - current_role, - tenant.tenant_id) - self.user_id = self.admin_user.id + # + # If running on top of existing tenants/users, skip + # the step for admin role association. + if not self.tenant.kloud.reusing_tenants: + current_role = None + for role in self.tenant.kloud.keystone.roles.list(): + if role.name == user_role: + current_role = role + break + self.tenant.kloud.keystone.roles.add_user_role(self.user, + current_role, + tenant.tenant_id) def _create_user(self): LOG.info("Creating user: " + self.user_name) return self.tenant.kloud.keystone.users.create(name=self.user_name, - password=self.user_name, + password=self.password, email="kloudbuster@localhost", tenant_id=self.tenant.tenant_id) def _get_user(self): + if self.tenant.reusing_users: + LOG.info("Using user: " + self.user_name) + users_list = self.tenant.kloud.keystone.users.list() + for user in users_list: + if user.name == self.user_name: + return user + raise Exception('Cannot find stale user:' + self.user_name) + ''' Create a new user or reuse if it already exists (on a different tenant) delete the user and create a new one @@ -112,8 +122,9 @@ class User(object): for router in self.router_list: router.delete_router() - # Finally delete the user - self.tenant.kloud.keystone.users.delete(self.user_id) + if not self.tenant.reusing_users: + # Finally delete the user + self.tenant.kloud.keystone.users.delete(self.user.id) def update_tenant_quota(self, tenant_quota): nova_quota = base_compute.NovaQuota(self.nova_client, self.tenant.tenant_id) @@ -152,7 +163,8 @@ class User(object): self.nova_client = Client(**creden_nova) self.cinder_client = cinderclient.Client(**creden_nova) - self.update_tenant_quota(self.tenant.tenant_quota) + if not self.tenant.kloud.reusing_tenants: + self.update_tenant_quota(self.tenant.tenant_quota) config_scale = self.tenant.kloud.scale_cfg