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
This commit is contained in:
parent
522e6c1167
commit
91487faa20
@ -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'])
|
||||
|
@ -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,
|
||||
|
28
scale/cfg.tenants.yaml
Normal file
28
scale/cfg.tenants.yaml
Normal file
@ -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
|
@ -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"
|
||||
|
@ -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):
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -48,6 +48,7 @@ class ConfigController(object):
|
||||
# 'testing_rc': '<STRING>', 'passwd_testing': '<STRING>'},
|
||||
# 'kb_cfg': {<USER_OVERRIDED_CONFIGS>},
|
||||
# 'topo_cfg': {<TOPOLOGY_CONFIGS>}
|
||||
# 'tenants_cfg': {<TENANT_AND_USER_LISTS_FOR_REUSING>}
|
||||
# }
|
||||
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)
|
||||
|
@ -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:
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user