Exemple #1
0
    def run(self):
        """
        The runner for KloudBuster Tests
        """
        vm_creation_concurrency = self.client_cfg.vm_creation_concurrency
        try:
            tenant_quota = self.calc_tenant_quota()
            self.kloud.create_resources(tenant_quota['server'])
            self.testing_kloud.create_resources(tenant_quota['client'])

            # Start the runner and ready for the incoming redis messages
            client_list = self.testing_kloud.get_all_instances()
            server_list = self.kloud.get_all_instances()

            # Setting up the KloudBuster Proxy node
            self.kb_proxy = client_list[-1]
            client_list.pop()

            self.kb_proxy.vm_name = 'KB-PROXY'
            self.kb_proxy.user_data['role'] = 'KB-PROXY'
            self.kb_proxy.boot_info['flavor_type'] = 'kb.proxy' if \
                not self.tenants_list['client'] else self.testing_kloud.flavor_to_use
            if self.topology:
                proxy_hyper = self.topology.clients_rack.split()[0]
                self.kb_proxy.boot_info['avail_zone'] =\
                    "%s:%s" % (self.testing_kloud.placement_az, proxy_hyper)\
                    if self.testing_kloud.placement_az else "nova:%s" % (proxy_hyper)

            self.kb_proxy.boot_info['user_data'] = str(self.kb_proxy.user_data)
            self.testing_kloud.create_vm(self.kb_proxy)

            self.kb_runner = KBRunner(client_list, self.client_cfg,
                                      kb_vm_agent.get_image_version(),
                                      self.single_cloud)
            self.kb_runner.setup_redis(self.kb_proxy.fip_ip)

            if self.single_cloud:
                # Find the shared network if the cloud used to testing is same
                # Attach the router in tested kloud to the shared network
                shared_net = self.testing_kloud.get_first_network()
                self.kloud.attach_to_shared_net(shared_net)

            # Create VMs in both tested and testing kloud concurrently
            self.client_vm_create_thread = threading.Thread(target=self.testing_kloud.create_vms,
                                                            args=[vm_creation_concurrency])
            self.server_vm_create_thread = threading.Thread(target=self.kloud.create_vms,
                                                            args=[vm_creation_concurrency])
            self.client_vm_create_thread.daemon = True
            self.server_vm_create_thread.daemon = True
            if self.single_cloud:
                self.gen_user_data("Server")
                self.server_vm_create_thread.start()
                self.server_vm_create_thread.join()
                self.gen_user_data("Client")
                self.client_vm_create_thread.start()
                self.client_vm_create_thread.join()
            else:
                self.gen_user_data("Server")
                self.gen_user_data("Client")
                self.server_vm_create_thread.start()
                self.client_vm_create_thread.start()
                self.server_vm_create_thread.join()
                self.client_vm_create_thread.join()

            # Function that print all the provisioning info
            self.print_provision_info()

            # Run the runner to perform benchmarkings
            self.kb_runner.run()
            self.final_result = self.kb_runner.tool_result
            self.final_result['total_server_vms'] = len(server_list)
            self.final_result['total_client_vms'] = len(client_list)
            # self.final_result['host_stats'] = self.kb_runner.host_stats
            LOG.info(self.final_result)
        except KeyboardInterrupt:
            traceback.format_exc()
        except (ClientException, Exception):
            traceback.print_exc()

        # Cleanup: start with tested side first
        # then testing side last (order is important because of the shared network)
        if self.server_cfg['cleanup_resources']:
            try:
                self.kloud.delete_resources()
            except Exception:
                traceback.print_exc()
                KBResLogger.dump_and_save('svr', self.kloud.res_logger.resource_list)
        if self.client_cfg['cleanup_resources']:
            try:
                self.testing_kloud.delete_resources()
            except Exception:
                traceback.print_exc()
                KBResLogger.dump_and_save('clt', self.testing_kloud.res_logger.resource_list)
Exemple #2
0
class KloudBuster(object):
    """
    Creates resources on the cloud for loading up the cloud
    1. Tenants
    2. Users per tenant
    3. Routers per user
    4. Networks per router
    5. Instances per network
    """
    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.server_cred = server_cred
        self.client_cred = client_cred
        self.server_cfg = server_cfg
        self.client_cfg = client_cfg
        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 = {}
            self.tenants_list['server'] =\
                [{'name': tenants_list['tenant_name'], 'user': tenants_list['server_user']}]
            self.tenants_list['client'] =\
                [{'name': tenants_list['tenant_name'], 'user': [tenants_list['client_user']]}]
            LOG.warn("REUSING MODE: The quotas will not be adjusted automatically.")
            LOG.warn("REUSING MODE: The flavor configs will be ignored.")
        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.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
        self.client_vm_create_thread = None
        self.kb_runner = None
        self.fp_logfile = None

    def check_and_upload_images(self):
        keystone_list = [create_keystone_client(self.server_cred)[0],
                         create_keystone_client(self.client_cred)[0]]
        keystone_dict = dict(zip(['Server kloud', 'Client kloud'], keystone_list))

        img_name_dict = dict(zip(['Server kloud', 'Client kloud'],
                                 [self.server_cfg.image_name, self.client_cfg.image_name]))

        for kloud, keystone in keystone_dict.items():
            glance_endpoint = keystone.service_catalog.url_for(
                service_type='image', endpoint_type='publicURL')
            glance_client = glanceclient.Client(glance_endpoint, token=keystone.auth_token)
            try:
                # Search for the image
                glance_client.images.list(filters={'name': img_name_dict[kloud]}).next()
                return True
            except StopIteration:
                pass

            # Trying to upload images
            kb_image_name = 'dib/' + kb_vm_agent.get_image_name() + '.qcow2'
            if not os.path.exists(kb_image_name):
                LOG.error("VM Image not in Glance and could not find " + kb_image_name +
                          " to upload, please refer to dib/README.rst for how to build"
                          " image for KloudBuster.")
                return False
            LOG.info("Image is not found in %s, uploading %s..." % (kloud, kb_image_name))
            with open(kb_image_name) as fimage:
                try:
                    image = glance_client.images.create(name=img_name_dict[kloud],
                                                        disk_format="qcow2",
                                                        container_format="bare",
                                                        visibility='public')
                    glance_client.images.upload(image['id'], fimage)
                except glance_exception.HTTPForbidden:
                    LOG.error("Cannot upload image without admin access. Please make sure the "
                              "image is uploaded and is either public or owned by you.")
                    return False
            return True

    def print_provision_info(self):
        """
        Function that iterates and prints all VM info
        for tested and testing cloud
        """
        table = [["VM Name", "Host", "Internal IP", "Floating IP", "Subnet", "Shared Interface IP"]]
        client_list = self.kloud.get_all_instances()
        for instance in client_list:
            row = [instance.vm_name, instance.host, instance.fixed_ip,
                   instance.fip_ip, instance.subnet_ip, instance.shared_interface_ip]
            table.append(row)
        LOG.info('Provision Details (Tested Kloud)\n' +
                 tabulate(table, headers="firstrow", tablefmt="psql"))

        table = [["VM Name", "Host", "Internal IP", "Floating IP", "Subnet"]]
        client_list = self.testing_kloud.get_all_instances(include_kb_proxy=True)
        for instance in client_list:
            row = [instance.vm_name, instance.host, instance.fixed_ip,
                   instance.fip_ip, instance.subnet_ip]
            table.append(row)
        LOG.info('Provision Details (Testing Kloud)\n' +
                 tabulate(table, headers="firstrow", tablefmt="psql"))

    def gen_user_data(self, role):
        LOG.info("Preparing metadata for VMs... (%s)" % role)
        if role == "Server":
            svr_list = self.kloud.get_all_instances()
            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' if \
                    not self.tenants_list['server'] else self.kloud.flavor_to_use
                ins.boot_info['user_data'] = str(ins.user_data)
        elif role == "Client":
            client_list = self.testing_kloud.get_all_instances()
            svr_list = self.kloud.get_all_instances()
            KBScheduler.setup_vm_mappings(client_list, svr_list, "1:1")
            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['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' if \
                    not self.tenants_list['client'] else self.testing_kloud.flavor_to_use
                ins.boot_info['user_data'] = str(ins.user_data)

    def run(self):
        """
        The runner for KloudBuster Tests
        """
        vm_creation_concurrency = self.client_cfg.vm_creation_concurrency
        try:
            tenant_quota = self.calc_tenant_quota()
            self.kloud.create_resources(tenant_quota['server'])
            self.testing_kloud.create_resources(tenant_quota['client'])

            # Start the runner and ready for the incoming redis messages
            client_list = self.testing_kloud.get_all_instances()
            server_list = self.kloud.get_all_instances()

            # Setting up the KloudBuster Proxy node
            self.kb_proxy = client_list[-1]
            client_list.pop()

            self.kb_proxy.vm_name = 'KB-PROXY'
            self.kb_proxy.user_data['role'] = 'KB-PROXY'
            self.kb_proxy.boot_info['flavor_type'] = 'kb.proxy' if \
                not self.tenants_list['client'] else self.testing_kloud.flavor_to_use
            if self.topology:
                proxy_hyper = self.topology.clients_rack.split()[0]
                self.kb_proxy.boot_info['avail_zone'] =\
                    "%s:%s" % (self.testing_kloud.placement_az, proxy_hyper)\
                    if self.testing_kloud.placement_az else "nova:%s" % (proxy_hyper)

            self.kb_proxy.boot_info['user_data'] = str(self.kb_proxy.user_data)
            self.testing_kloud.create_vm(self.kb_proxy)

            self.kb_runner = KBRunner(client_list, self.client_cfg,
                                      kb_vm_agent.get_image_version(),
                                      self.single_cloud)
            self.kb_runner.setup_redis(self.kb_proxy.fip_ip)

            if self.single_cloud:
                # Find the shared network if the cloud used to testing is same
                # Attach the router in tested kloud to the shared network
                shared_net = self.testing_kloud.get_first_network()
                self.kloud.attach_to_shared_net(shared_net)

            # Create VMs in both tested and testing kloud concurrently
            self.client_vm_create_thread = threading.Thread(target=self.testing_kloud.create_vms,
                                                            args=[vm_creation_concurrency])
            self.server_vm_create_thread = threading.Thread(target=self.kloud.create_vms,
                                                            args=[vm_creation_concurrency])
            self.client_vm_create_thread.daemon = True
            self.server_vm_create_thread.daemon = True
            if self.single_cloud:
                self.gen_user_data("Server")
                self.server_vm_create_thread.start()
                self.server_vm_create_thread.join()
                self.gen_user_data("Client")
                self.client_vm_create_thread.start()
                self.client_vm_create_thread.join()
            else:
                self.gen_user_data("Server")
                self.gen_user_data("Client")
                self.server_vm_create_thread.start()
                self.client_vm_create_thread.start()
                self.server_vm_create_thread.join()
                self.client_vm_create_thread.join()

            # Function that print all the provisioning info
            self.print_provision_info()

            # Run the runner to perform benchmarkings
            self.kb_runner.run()
            self.final_result = self.kb_runner.tool_result
            self.final_result['total_server_vms'] = len(server_list)
            self.final_result['total_client_vms'] = len(client_list)
            # self.final_result['host_stats'] = self.kb_runner.host_stats
            LOG.info(self.final_result)
        except KeyboardInterrupt:
            traceback.format_exc()
        except (ClientException, Exception):
            traceback.print_exc()

        # Cleanup: start with tested side first
        # then testing side last (order is important because of the shared network)
        if self.server_cfg['cleanup_resources']:
            try:
                self.kloud.delete_resources()
            except Exception:
                traceback.print_exc()
                KBResLogger.dump_and_save('svr', self.kloud.res_logger.resource_list)
        if self.client_cfg['cleanup_resources']:
            try:
                self.testing_kloud.delete_resources()
            except Exception:
                traceback.print_exc()
                KBResLogger.dump_and_save('clt', self.testing_kloud.res_logger.resource_list)

    def dump_logs(self, offset=0):
        if not self.fp_logfile:
            self.fp_logfile = open(CONF.log_file)

        self.fp_logfile.seek(offset)
        return self.fp_logfile.read()

    def dispose(self):
        self.fp_logfile.close()
        logging.delete_logfile('kloudbuster')

    def get_tenant_vm_count(self, config):
        return (config['users_per_tenant'] * config['routers_per_user'] *
                config['networks_per_router'] * config['vms_per_network'])

    def calc_neutron_quota(self):
        total_vm = self.get_tenant_vm_count(self.server_cfg)

        server_quota = {}
        server_quota['network'] = self.server_cfg['routers_per_user'] *\
            self.server_cfg['networks_per_router']
        server_quota['subnet'] = server_quota['network']
        server_quota['router'] = self.server_cfg['routers_per_user']
        if (self.server_cfg['use_floatingip']):
            # (1) Each VM has one floating IP
            # (2) Each Router has one external IP
            server_quota['floatingip'] = total_vm + server_quota['router']
            # (1) Each VM Floating IP takes up 1 port, total of $total_vm port(s)
            # (2) Each VM Fixed IP takes up 1 port, total of $total_vm port(s)
            # (3) Each Network has one router_interface (gateway), and one DHCP agent, total of
            #     server_quota['network'] * 2 port(s)
            # (4) Each Router has one external IP, takes up 1 port, total of
            #     server_quota['router'] port(s)
            server_quota['port'] = 2 * total_vm + 2 * server_quota['network'] +\
                server_quota['router']
        else:
            server_quota['floatingip'] = server_quota['router']
            server_quota['port'] = total_vm + 2 * server_quota['network'] + server_quota['router']
        server_quota['security_group'] = server_quota['network'] + 1
        server_quota['security_group_rule'] = server_quota['security_group'] * 10

        client_quota = {}
        total_vm = total_vm * self.server_cfg['number_tenants']
        client_quota['network'] = 1
        client_quota['subnet'] = 1
        client_quota['router'] = 1
        if (self.client_cfg['use_floatingip']):
            # (1) Each VM has one floating IP
            # (2) Each Router has one external IP, total of 1 router
            # (3) KB-Proxy node has one floating IP
            client_quota['floatingip'] = total_vm + 1 + 1
            # (1) Each VM Floating IP takes up 1 port, total of $total_vm port(s)
            # (2) Each VM Fixed IP takes up 1 port, total of $total_vm port(s)
            # (3) Each Network has one router_interface (gateway), and one DHCP agent, total of
            #     client_quota['network'] * 2 port(s)
            # (4) KB-Proxy node takes up 2 ports, one for fixed IP, one for floating IP
            # (5) Each Router has one external IP, takes up 1 port, total of 1 router/port
            client_quota['port'] = 2 * total_vm + 2 * client_quota['network'] + 2 + 1
        else:
            client_quota['floatingip'] = 1 + 1
            client_quota['port'] = total_vm + 2 * client_quota['network'] + 2 + 1
        if self.single_cloud:
            # Under single-cloud mode, the shared network is attached to every router in server
            # cloud, and each one takes up 1 port on client side.
            client_quota['port'] = client_quota['port'] + server_quota['router']
        client_quota['security_group'] = client_quota['network'] + 1
        client_quota['security_group_rule'] = client_quota['security_group'] * 10

        return [server_quota, client_quota]

    def calc_nova_quota(self):
        total_vm = self.get_tenant_vm_count(self.server_cfg)
        server_quota = {}
        server_quota['instances'] = total_vm
        server_quota['cores'] = total_vm * self.server_cfg['flavor']['vcpus']
        server_quota['ram'] = total_vm * self.server_cfg['flavor']['ram']

        client_quota = {}
        total_vm = total_vm * self.server_cfg['number_tenants']
        client_quota['instances'] = total_vm + 1
        client_quota['cores'] = total_vm * self.client_cfg['flavor']['vcpus'] + 1
        client_quota['ram'] = total_vm * self.client_cfg['flavor']['ram'] + 2048

        return [server_quota, client_quota]

    def calc_cinder_quota(self):
        total_vm = self.get_tenant_vm_count(self.server_cfg)
        server_quota = {}
        server_quota['gigabytes'] = total_vm * self.server_cfg['flavor']['disk']

        client_quota = {}
        total_vm = total_vm * self.server_cfg['number_tenants']
        client_quota['gigabytes'] = total_vm * self.client_cfg['flavor']['disk'] + 20

        return [server_quota, client_quota]

    def calc_tenant_quota(self):
        quota_dict = {'server': {}, 'client': {}}
        nova_quota = self.calc_nova_quota()
        neutron_quota = self.calc_neutron_quota()
        cinder_quota = self.calc_cinder_quota()
        for idx, val in enumerate(['server', 'client']):
            quota_dict[val]['nova'] = nova_quota[idx]
            quota_dict[val]['neutron'] = neutron_quota[idx]
            quota_dict[val]['cinder'] = cinder_quota[idx]

        return quota_dict