diff options
Diffstat (limited to 'functest/opnfv_tests/openstack')
32 files changed, 1111 insertions, 657 deletions
diff --git a/functest/opnfv_tests/openstack/api/connection_check.py b/functest/opnfv_tests/openstack/api/connection_check.py index 48d06211b..eaf9767c0 100644 --- a/functest/opnfv_tests/openstack/api/connection_check.py +++ b/functest/opnfv_tests/openstack/api/connection_check.py @@ -16,15 +16,27 @@ import os_client_config import shade from xtesting.core import testcase +from functest.utils import env +from functest.utils import functest_utils + class ConnectionCheck(testcase.TestCase): """Perform simplest queries""" __logger = logging.getLogger(__name__) + func_list = [ + "get_network_extensions", "list_aggregates", "list_domains", + "list_endpoints", "list_floating_ip_pools", "list_floating_ips", + "list_hypervisors", "list_keypairs", "list_networks", "list_ports", + "list_role_assignments", "list_roles", "list_routers", "list_servers", + "list_subnets"] + def __init__(self, **kwargs): if "case_name" not in kwargs: kwargs["case_name"] = 'connection_check' - super(ConnectionCheck, self).__init__(**kwargs) + super().__init__(**kwargs) + self.output_log_name = 'functest.log' + self.output_debug_log_name = 'functest.debug.log' try: cloud_config = os_client_config.get_config() self.cloud = shade.OpenStackCloud(cloud_config=cloud_config) @@ -38,19 +50,20 @@ class ConnectionCheck(testcase.TestCase): try: assert self.cloud self.start_time = time.time() - for func in ["get_network_extensions", - "list_aggregates", "list_domains", "list_endpoints", - "list_floating_ip_pools", "list_floating_ips", - "list_hypervisors", "list_keypairs", "list_networks", - "list_ports", "list_role_assignments", "list_roles", - "list_routers", "list_servers", "list_services", - "list_subnets"]: + self.__logger.debug( + "list_services: %s", functest_utils.list_services(self.cloud)) + if env.get('NO_TENANT_NETWORK').lower() == 'true': + self.func_list.remove("list_floating_ip_pools") + self.func_list.remove("list_floating_ips") + self.func_list.remove("list_routers") + for func in self.func_list: self.__logger.debug( "%s: %s", func, getattr(self.cloud, func)()) data = self.cloud._network_client.get("/service-providers.json") self.__logger.debug( "list_service_providers: %s", self.cloud._get_and_munchify('service_providers', data)) + functest_utils.get_openstack_version(self.cloud) self.result = 100 status = testcase.TestCase.EX_OK except Exception: # pylint: disable=broad-except diff --git a/functest/opnfv_tests/openstack/barbican/barbican.py b/functest/opnfv_tests/openstack/barbican/barbican.py index b9488c2b6..706304bbf 100644 --- a/functest/opnfv_tests/openstack/barbican/barbican.py +++ b/functest/opnfv_tests/openstack/barbican/barbican.py @@ -9,8 +9,6 @@ # pylint: disable=missing-docstring -import logging - from six.moves import configparser from functest.opnfv_tests.openstack.tempest import tempest @@ -18,10 +16,8 @@ from functest.opnfv_tests.openstack.tempest import tempest class Barbican(tempest.TempestCommon): - __logger = logging.getLogger(__name__) - def configure(self, **kwargs): - super(Barbican, self).configure(**kwargs) + super().configure(**kwargs) rconfig = configparser.RawConfigParser() rconfig.read(self.conf_file) if not rconfig.has_section('auth'): @@ -36,6 +32,6 @@ class Barbican(tempest.TempestCommon): if not rconfig.has_section('image-feature-enabled'): rconfig.add_section('image-feature-enabled') rconfig.set('image-feature-enabled', 'api_v1', False) - with open(self.conf_file, 'wb') as config_file: + with open(self.conf_file, 'w', encoding='utf-8') as config_file: rconfig.write(config_file) self.backup_tempest_config(self.conf_file, self.res_dir) diff --git a/functest/opnfv_tests/openstack/cinder/cinder_test.py b/functest/opnfv_tests/openstack/cinder/cinder_test.py index bbed9a64f..7d8c0a0bd 100644 --- a/functest/opnfv_tests/openstack/cinder/cinder_test.py +++ b/functest/opnfv_tests/openstack/cinder/cinder_test.py @@ -35,7 +35,7 @@ class CinderCheck(singlevm.SingleVm2): """Initialize testcase.""" if "case_name" not in kwargs: kwargs["case_name"] = "cinder_test" - super(CinderCheck, self).__init__(**kwargs) + super().__init__(**kwargs) self.logger = logging.getLogger(__name__) self.vm2 = None self.fip2 = None @@ -52,14 +52,14 @@ class CinderCheck(singlevm.SingleVm2): return self._write_data() or self._read_data() def prepare(self): - super(CinderCheck, self).prepare() + super().prepare() self.vm2 = self.boot_vm( - '{}-vm2_{}'.format(self.case_name, self.guid), + f'{self.case_name}-vm2_{self.guid}', key_name=self.keypair.id, security_groups=[self.sec.id]) (self.fip2, self.ssh2) = self.connect(self.vm2) self.volume = self.cloud.create_volume( - name='{}-volume_{}'.format(self.case_name, self.guid), size='2', + name=f'{self.case_name}-volume_{self.guid}', size='2', timeout=self.volume_timeout, wait=True) def _write_data(self): @@ -76,9 +76,11 @@ class CinderCheck(singlevm.SingleVm2): return testcase.TestCase.EX_RUN_ERROR self.logger.debug("ssh: %s", self.ssh) (_, stdout, stderr) = self.ssh.exec_command( - "sh ~/write_data.sh {}".format(env.get('VOLUME_DEVICE_NAME'))) - self.logger.debug("volume_write stdout: %s", stdout.read()) - self.logger.debug("volume_write stderr: %s", stderr.read()) + f"sh ~/write_data.sh {env.get('VOLUME_DEVICE_NAME')}") + self.logger.debug( + "volume_write stdout: %s", stdout.read().decode("utf-8")) + self.logger.debug( + "volume_write stderr: %s", stderr.read().decode("utf-8")) # Detach volume from VM 1 self.logger.info("Detach volume from VM 1") self.cloud.detach_volume( @@ -102,9 +104,11 @@ class CinderCheck(singlevm.SingleVm2): return testcase.TestCase.EX_RUN_ERROR self.logger.debug("ssh: %s", self.ssh2) (_, stdout, stderr) = self.ssh2.exec_command( - "sh ~/read_data.sh {}".format(env.get('VOLUME_DEVICE_NAME'))) - self.logger.debug("read volume stdout: %s", stdout.read()) - self.logger.debug("read volume stderr: %s", stderr.read()) + f"sh ~/read_data.sh {env.get('VOLUME_DEVICE_NAME')}") + self.logger.debug( + "read volume stdout: %s", stdout.read().decode("utf-8")) + self.logger.debug( + "read volume stderr: %s", stderr.read().decode("utf-8")) self.logger.info("Detach volume from VM 2") self.cloud.detach_volume( self.vm2, self.volume, timeout=self.volume_timeout) @@ -120,4 +124,4 @@ class CinderCheck(singlevm.SingleVm2): self.cloud.delete_floating_ip(self.fip2.id) if self.volume: self.cloud.delete_volume(self.volume.id) - super(CinderCheck, self).clean() + super().clean() diff --git a/functest/opnfv_tests/openstack/cinder/write_data.sh b/functest/opnfv_tests/openstack/cinder/write_data.sh index 6689309b9..16845ba31 100644 --- a/functest/opnfv_tests/openstack/cinder/write_data.sh +++ b/functest/opnfv_tests/openstack/cinder/write_data.sh @@ -15,7 +15,7 @@ echo "VOL_DEV_NAME: $VOL_DEV_NAME" echo "$(lsblk -l -o NAME)" if [ ! -z $(lsblk -l -o NAME | grep $VOL_DEV_NAME) ]; then - sudo /usr/sbin/mkfs.ext4 -F /dev/$VOL_DEV_NAME + sudo mkfs.ext4 -F /dev/$VOL_DEV_NAME sudo mount /dev/$VOL_DEV_NAME $DEST sudo touch $DEST/new_data if [ -f $DEST/new_data ]; then diff --git a/functest/opnfv_tests/openstack/patrole/patrole.py b/functest/opnfv_tests/openstack/patrole/patrole.py index 45378b6cd..88c42f269 100644 --- a/functest/opnfv_tests/openstack/patrole/patrole.py +++ b/functest/opnfv_tests/openstack/patrole/patrole.py @@ -9,8 +9,6 @@ # pylint: disable=missing-docstring -import logging - from six.moves import configparser from functest.opnfv_tests.openstack.tempest import tempest @@ -18,23 +16,13 @@ from functest.opnfv_tests.openstack.tempest import tempest class Patrole(tempest.TempestCommon): - __logger = logging.getLogger(__name__) - def configure(self, **kwargs): - super(Patrole, self).configure(**kwargs) + super().configure(**kwargs) rconfig = configparser.RawConfigParser() rconfig.read(self.conf_file) - rconfig.add_section('rbac') - rconfig.set('rbac', 'enable_rbac', True) - rconfig.set('rbac', 'rbac_test_role', kwargs.get('role', 'admin')) - with open(self.conf_file, 'wb') as config_file: + if not rconfig.has_section('rbac'): + rconfig.add_section('rbac') + rconfig.set('rbac', 'rbac_test_roles', kwargs.get('roles', 'admin')) + with open(self.conf_file, 'w', encoding='utf-8') as config_file: rconfig.write(config_file) self.backup_tempest_config(self.conf_file, self.res_dir) - - def run(self, **kwargs): - for exclude in kwargs.get('excludes', []): - kwargs['mode'] = "{}(?!.*{})".format( - kwargs.get('mode', ''), exclude) - kwargs['mode'] = '{}(?=patrole_tempest_plugin.tests.api.({}))'.format( - kwargs['mode'], '|'.join(kwargs.get('includes', []))) - return super(Patrole, self).run(**kwargs) diff --git a/functest/opnfv_tests/openstack/rally/blacklist.yaml b/functest/opnfv_tests/openstack/rally/blacklist.yaml index 4c85088a8..e16b83ba6 100644 --- a/functest/opnfv_tests/openstack/rally/blacklist.yaml +++ b/functest/opnfv_tests/openstack/rally/blacklist.yaml @@ -1,17 +1,14 @@ --- scenario: - - - scenarios: - - '^os-' # all scenarios - tests: - # Following test occasionally fails due to race condition issue on - # quota manipulation in nova. - # Ref: https://bugs.launchpad.net/nova/+bug/1552622 - - 'Quotas.nova_update_and_delete' functionality: - functions: + - block_migration + tests: + - NovaServers.boot_server_from_volume_and_live_migrate + - + functions: - no_migration tests: - NovaServers.boot_and_live_migrate_server @@ -23,3 +20,21 @@ functionality: - no_net_trunk_service tests: - '^NeutronTrunk' + - + functions: + - no_floating_ip + tests: + - HeatStacks.create_and_delete_stack + - NovaServers.boot_and_associate_floating_ip + - NovaServers.boot_server_and_list_interfaces + - NovaServers.boot_server_associate_and_dissociate_floating_ip + - NeutronNetworks.create_and_delete_floating_ips + - NeutronNetworks.create_and_list_floating_ips + - NeutronNetworks.associate_and_dissociate_floating_ips + - VMTasks.dd_load_test + - NeutronNetworks.create_and_delete_routers + - NeutronNetworks.create_and_list_routers + - NeutronNetworks.create_and_show_routers + - NeutronNetworks.create_and_update_routers + - NeutronNetworks.set_and_clear_router_gateway + - Quotas.neutron_update diff --git a/functest/opnfv_tests/openstack/rally/rally.py b/functest/opnfv_tests/openstack/rally/rally.py index 1f56e168c..3d897e25d 100644 --- a/functest/opnfv_tests/openstack/rally/rally.py +++ b/functest/opnfv_tests/openstack/rally/rally.py @@ -25,6 +25,7 @@ import time import pkg_resources import prettytable from ruamel.yaml import YAML +import six from six.moves import configparser from xtesting.core import testcase import yaml @@ -32,6 +33,7 @@ import yaml from functest.core import singlevm from functest.utils import config from functest.utils import env +from functest.utils import functest_utils LOGGER = logging.getLogger(__name__) @@ -40,36 +42,39 @@ class RallyBase(singlevm.VmReady2): """Base class form Rally testcases implementation.""" # pylint: disable=too-many-instance-attributes, too-many-public-methods - TESTS = ['authenticate', 'glance', 'cinder', 'gnocchi', 'heat', - 'keystone', 'neutron', 'nova', 'quotas'] + stests = ['authenticate', 'glance', 'cinder', 'gnocchi', 'heat', + 'keystone', 'neutron', 'nova', 'quotas', 'swift', 'barbican', + 'vm'] - RALLY_CONF_PATH = "/etc/rally/rally.conf" - RALLY_AARCH64_PATCH_PATH = pkg_resources.resource_filename( + rally_conf_path = "/etc/rally/rally.conf" + rally_aar4_patch_path = pkg_resources.resource_filename( 'functest', 'ci/rally_aarch64_patch.conf') - RALLY_DIR = pkg_resources.resource_filename( + rally_dir = pkg_resources.resource_filename( 'functest', 'opnfv_tests/openstack/rally') - RALLY_SCENARIO_DIR = pkg_resources.resource_filename( + rally_scenario_dir = pkg_resources.resource_filename( 'functest', 'opnfv_tests/openstack/rally/scenario') - TEMPLATE_DIR = pkg_resources.resource_filename( + template_dir = pkg_resources.resource_filename( 'functest', 'opnfv_tests/openstack/rally/scenario/templates') - SUPPORT_DIR = pkg_resources.resource_filename( + support_dir = pkg_resources.resource_filename( 'functest', 'opnfv_tests/openstack/rally/scenario/support') - USERS_AMOUNT = 2 - TENANTS_AMOUNT = 3 - ITERATIONS_AMOUNT = 10 - CONCURRENCY = 4 - VOLUME_VERSION = 3 - VOLUME_SERVICE_TYPE = "volumev3" - BLACKLIST_FILE = os.path.join(RALLY_DIR, "blacklist.yaml") - TASK_DIR = os.path.join(getattr(config.CONF, 'dir_rally_data'), 'task') - TEMP_DIR = os.path.join(TASK_DIR, 'var') + users_amount = 2 + tenants_amount = 3 + iterations_amount = 10 + concurrency = 4 + volume_version = 3 + volume_service_type = "volumev3" + blacklist_file = os.path.join(rally_dir, "blacklist.yaml") + task_dir = os.path.join(getattr(config.CONF, 'dir_rally_data'), 'task') + temp_dir = os.path.join(task_dir, 'var') visibility = 'public' shared_network = True + task_timeout = 3600 + username = 'cirros' def __init__(self, **kwargs): """Initialize RallyBase object.""" - super(RallyBase, self).__init__(**kwargs) + super().__init__(**kwargs) assert self.orig_cloud assert self.project if self.orig_cloud.get_role("admin"): @@ -91,7 +96,6 @@ class RallyBase(singlevm.VmReady2): self.smoke = None self.start_time = None self.result = None - self.details = None self.compute_cnt = 0 self.flavor_alt = None self.tests = [] @@ -107,16 +111,18 @@ class RallyBase(singlevm.VmReady2): task_args['flavor_alt_name'] = str(self.flavor_alt.name) task_args['glance_image_location'] = str(self.filename) task_args['glance_image_format'] = str(self.image_format) - task_args['tmpl_dir'] = str(self.TEMPLATE_DIR) - task_args['sup_dir'] = str(self.SUPPORT_DIR) - task_args['users_amount'] = self.USERS_AMOUNT - task_args['tenants_amount'] = self.TENANTS_AMOUNT + task_args['tmpl_dir'] = str(self.template_dir) + task_args['sup_dir'] = str(self.support_dir) + task_args['users_amount'] = self.users_amount + task_args['tenants_amount'] = self.tenants_amount task_args['use_existing_users'] = False - task_args['iterations'] = self.ITERATIONS_AMOUNT - task_args['concurrency'] = self.CONCURRENCY + task_args['iterations'] = self.iterations_amount + task_args['concurrency'] = self.concurrency task_args['smoke'] = self.smoke - task_args['volume_version'] = self.VOLUME_VERSION - task_args['volume_service_type'] = self.VOLUME_SERVICE_TYPE + task_args['volume_version'] = self.volume_version + task_args['volume_service_type'] = self.volume_service_type + task_args['block_migration'] = env.get("BLOCK_MIGRATION").lower() + task_args['username'] = self.username if self.ext_net: task_args['floating_network'] = str(self.ext_net.name) @@ -126,14 +132,21 @@ class RallyBase(singlevm.VmReady2): if self.network: task_args['netid'] = str(self.network.id) else: - task_args['netid'] = '' + LOGGER.warning( + 'No tenant network created. ' + 'Trying EXTERNAL_NETWORK as a fallback') + if env.get("EXTERNAL_NETWORK"): + network = self.cloud.get_network(env.get("EXTERNAL_NETWORK")) + task_args['netid'] = str(network.id) if network else '' + else: + task_args['netid'] = '' return task_args def _prepare_test_list(self, test_name): """Build the list of test cases to be executed.""" - test_yaml_file_name = 'opnfv-{}.yaml'.format(test_name) - scenario_file_name = os.path.join(self.RALLY_SCENARIO_DIR, + test_yaml_file_name = f'opnfv-{test_name}.yaml' + scenario_file_name = os.path.join(self.rally_scenario_dir, test_yaml_file_name) if not os.path.exists(scenario_file_name): @@ -141,14 +154,14 @@ class RallyBase(singlevm.VmReady2): test_yaml_file_name) if not os.path.exists(scenario_file_name): - raise Exception("The scenario '%s' does not exist." - % scenario_file_name) + raise Exception( + f"The scenario '{scenario_file_name}' does not exist.") LOGGER.debug('Scenario fetched from : %s', scenario_file_name) - test_file_name = os.path.join(self.TEMP_DIR, test_yaml_file_name) + test_file_name = os.path.join(self.temp_dir, test_yaml_file_name) - if not os.path.exists(self.TEMP_DIR): - os.makedirs(self.TEMP_DIR) + if not os.path.exists(self.temp_dir): + os.makedirs(self.temp_dir) self.apply_blacklist(scenario_file_name, test_file_name) return test_file_name @@ -161,14 +174,15 @@ class RallyBase(singlevm.VmReady2): cmd = ("rally deployment list | awk '/" + getattr(config.CONF, 'rally_deployment_name') + "/ {print $2}'") - proc = subprocess.Popen(cmd, shell=True, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) - deployment_uuid = proc.stdout.readline().rstrip() - return deployment_uuid + with subprocess.Popen( + cmd, shell=True, stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) as proc: + deployment_uuid = proc.stdout.readline().rstrip() + return deployment_uuid.decode("utf-8") @staticmethod def create_rally_deployment(environ=None): + # pylint: disable=unexpected-keyword-arg """Create new rally deployment""" # set the architecture to default pod_arch = env.get("POD_ARCH") @@ -176,10 +190,12 @@ class RallyBase(singlevm.VmReady2): if pod_arch and pod_arch in arch_filter: LOGGER.info("Apply aarch64 specific to rally config...") - with open(RallyBase.RALLY_AARCH64_PATCH_PATH, "r") as pfile: + with open( + RallyBase.rally_aar4_patch_path, "r", + encoding='utf-8') as pfile: rally_patch_conf = pfile.read() - for line in fileinput.input(RallyBase.RALLY_CONF_PATH): + for line in fileinput.input(RallyBase.rally_conf_path): print(line, end=' ') if "cirros|testvm" in line: print(rally_patch_conf) @@ -190,18 +206,18 @@ class RallyBase(singlevm.VmReady2): '--deployment', str(getattr(config.CONF, 'rally_deployment_name'))] output = subprocess.check_output(cmd) - LOGGER.info("%s\n%s", " ".join(cmd), output) + LOGGER.info("%s\n%s", " ".join(cmd), output.decode("utf-8")) except subprocess.CalledProcessError: pass cmd = ['rally', 'deployment', 'create', '--fromenv', '--name', str(getattr(config.CONF, 'rally_deployment_name'))] output = subprocess.check_output(cmd, env=environ) - LOGGER.info("%s\n%s", " ".join(cmd), output) + LOGGER.info("%s\n%s", " ".join(cmd), output.decode("utf-8")) cmd = ['rally', 'deployment', 'check'] output = subprocess.check_output(cmd) - LOGGER.info("%s\n%s", " ".join(cmd), output) + LOGGER.info("%s\n%s", " ".join(cmd), output.decode("utf-8")) return RallyBase.get_verifier_deployment_id() @staticmethod @@ -214,7 +230,7 @@ class RallyBase(singlevm.VmReady2): rconfig.add_section('openstack') rconfig.set( 'openstack', 'keystone_default_role', env.get("NEW_USER_ROLE")) - with open(rally_conf, 'wb') as config_file: + with open(rally_conf, 'w', encoding='utf-8') as config_file: rconfig.write(config_file) @staticmethod @@ -225,24 +241,21 @@ class RallyBase(singlevm.VmReady2): rconfig.read(rally_conf) if rconfig.has_option('openstack', 'keystone_default_role'): rconfig.remove_option('openstack', 'keystone_default_role') - with open(rally_conf, 'wb') as config_file: + with open(rally_conf, 'w', encoding='utf-8') as config_file: rconfig.write(config_file) @staticmethod - def get_task_id(cmd_raw): + def get_task_id(tag): """ Get task id from command rally result. - :param cmd_raw: + :param tag: :return: task_id as string """ - taskid_re = re.compile('^Task +(.*): started$') - for line in cmd_raw.splitlines(True): - line = line.strip() - match = taskid_re.match(line) - if match: - return match.group(1) - return None + cmd = ["rally", "task", "list", "--tag", tag, "--uuids-only"] + output = subprocess.check_output(cmd).decode("utf-8").rstrip() + LOGGER.info("%s: %s", " ".join(cmd), output) + return output @staticmethod def task_succeed(json_raw): @@ -280,7 +293,9 @@ class RallyBase(singlevm.VmReady2): """Exclude scenario.""" black_tests = [] try: - with open(RallyBase.BLACKLIST_FILE, 'r') as black_list_file: + with open( + RallyBase.blacklist_file, 'r', + encoding='utf-8') as black_list_file: black_list_yaml = yaml.safe_load(black_list_file) deploy_scenario = env.get('DEPLOY_SCENARIO') @@ -324,13 +339,19 @@ class RallyBase(singlevm.VmReady2): func_list = [] try: - with open(RallyBase.BLACKLIST_FILE, 'r') as black_list_file: + with open( + RallyBase.blacklist_file, 'r', + encoding='utf-8') as black_list_file: black_list_yaml = yaml.safe_load(black_list_file) + if env.get('BLOCK_MIGRATION').lower() == 'true': + func_list.append("block_migration") if not self._migration_supported(): func_list.append("no_migration") if not self._network_trunk_supported(): func_list.append("no_net_trunk_service") + if not self.ext_net: + func_list.append("no_floating_ip") if 'functionality' in black_list_yaml.keys(): for item in black_list_yaml['functionality']: @@ -347,31 +368,25 @@ class RallyBase(singlevm.VmReady2): def apply_blacklist(self, case_file_name, result_file_name): """Apply blacklist.""" LOGGER.debug("Applying blacklist...") - cases_file = open(case_file_name, 'r') - result_file = open(result_file_name, 'w') - - black_tests = list(set(self.excl_func() + - self.excl_scenario())) - - if black_tests: - LOGGER.debug("Blacklisted tests: %s", str(black_tests)) - - include = True - for cases_line in cases_file: - if include: - for black_tests_line in black_tests: - if re.search(black_tests_line, - cases_line.strip().rstrip(':')): - include = False - break + with open(case_file_name, 'r', encoding='utf-8') as cases_file, open( + result_file_name, 'w', encoding='utf-8') as result_file: + black_tests = list(set(self.excl_func() + self.excl_scenario())) + if black_tests: + LOGGER.debug("Blacklisted tests: %s", str(black_tests)) + + include = True + for cases_line in cases_file: + if include: + for black_tests_line in black_tests: + if re.search(black_tests_line, + cases_line.strip().rstrip(':')): + include = False + break + else: + result_file.write(str(cases_line)) else: - result_file.write(str(cases_line)) - else: - if cases_line.isspace(): - include = True - - cases_file.close() - result_file.close() + if cases_line.isspace(): + include = True @staticmethod def file_is_empty(file_name): @@ -396,18 +411,19 @@ class RallyBase(singlevm.VmReady2): cmd = (["rally", "task", "detailed", "--uuid", task_id]) LOGGER.debug('running command: %s', cmd) output = subprocess.check_output(cmd, stderr=subprocess.STDOUT) - LOGGER.info("%s\n%s", " ".join(cmd), output) + LOGGER.info("%s\n%s", " ".join(cmd), output.decode("utf-8")) # save report as JSON - report_json_name = '{}.json'.format(test_name) + report_json_name = f'{test_name}.json' report_json_dir = os.path.join(self.results_dir, report_json_name) cmd = (["rally", "task", "report", "--json", "--uuid", task_id, "--out", report_json_dir]) LOGGER.debug('running command: %s', cmd) output = subprocess.check_output(cmd, stderr=subprocess.STDOUT) - LOGGER.info("%s\n%s", " ".join(cmd), output) + LOGGER.info("%s\n%s", " ".join(cmd), output.decode("utf-8")) - json_results = open(report_json_dir).read() + with open(report_json_dir, encoding='utf-8') as json_file: + json_results = json_file.read() self._append_summary(json_results, test_name) # parse JSON operation result @@ -420,19 +436,22 @@ class RallyBase(singlevm.VmReady2): """Run a task.""" LOGGER.info('Starting test scenario "%s" ...', test_name) LOGGER.debug('running command: %s', self.run_cmd) - proc = subprocess.Popen(self.run_cmd, stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) - output = proc.communicate()[0] - - task_id = self.get_task_id(output) + if six.PY3: + subprocess.call( + self.run_cmd, timeout=self.task_timeout, + stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + else: + with open(os.devnull, 'wb') as devnull: + subprocess.call(self.run_cmd, stdout=devnull, stderr=devnull) + task_id = self.get_task_id(test_name) LOGGER.debug('task_id : %s', task_id) - if task_id is None: + if not task_id: LOGGER.error("Failed to retrieve task_id") - LOGGER.error("Result:\n%s", output) raise Exception("Failed to retrieve task id") self._save_results(test_name, task_id) def _append_summary(self, json_raw, test_name): + # pylint: disable=too-many-locals """Update statistics summary info.""" nb_tests = 0 nb_success = 0 @@ -475,39 +494,37 @@ class RallyBase(singlevm.VmReady2): """Prepare resources needed by test scenarios.""" assert self.cloud LOGGER.debug('Validating run tests...') - for test in kwargs.get('tests', self.TESTS): - if test in self.TESTS: + for test in kwargs.get('tests', self.stests): + if test in self.stests: self.tests.append(test) else: - raise Exception("Test name '%s' is invalid" % test) + raise Exception(f"Test name '{test}' is invalid") - if not os.path.exists(self.TASK_DIR): - os.makedirs(self.TASK_DIR) + if not os.path.exists(self.task_dir): + os.makedirs(self.task_dir) - task = os.path.join(self.RALLY_DIR, 'task.yaml') + task = os.path.join(self.rally_dir, 'task.yaml') if not os.path.exists(task): LOGGER.error("Task file '%s' does not exist.", task) - raise Exception("Task file '{}' does not exist.". - format(task)) - self.task_file = os.path.join(self.TASK_DIR, 'task.yaml') + raise Exception(f"Task file '{task}' does not exist.") + self.task_file = os.path.join(self.task_dir, 'task.yaml') shutil.copyfile(task, self.task_file) - task_macro = os.path.join(self.RALLY_DIR, 'macro') + task_macro = os.path.join(self.rally_dir, 'macro') if not os.path.exists(task_macro): LOGGER.error("Task macro dir '%s' does not exist.", task_macro) - raise Exception("Task macro dir '{}' does not exist.". - format(task_macro)) - macro_dir = os.path.join(self.TASK_DIR, 'macro') + raise Exception(f"Task macro dir '{task_macro}' does not exist.") + macro_dir = os.path.join(self.task_dir, 'macro') if os.path.exists(macro_dir): shutil.rmtree(macro_dir) shutil.copytree(task_macro, macro_dir) self.update_keystone_default_role() - self.compute_cnt = len(self.cloud.list_hypervisors()) + self.compute_cnt = self.count_hypervisors() self.network_extensions = self.cloud.get_network_extensions() self.flavor_alt = self.create_flavor_alt() self.services = [service.name for service in - self.cloud.list_services()] + functest_utils.list_services(self.cloud)] LOGGER.debug("flavor: %s", self.flavor_alt) @@ -517,7 +534,8 @@ class RallyBase(singlevm.VmReady2): if self.file_is_empty(file_name): LOGGER.info('No tests for scenario "%s"', test_name) return False - self.run_cmd = (["rally", "task", "start", "--abort-on-sla-failure", + self.run_cmd = (["rally", "task", "start", "--tag", test_name, + "--abort-on-sla-failure", "--task", self.task_file, "--task-args", str(self.build_task_args(test_name))]) return True @@ -556,7 +574,7 @@ class RallyBase(singlevm.VmReady2): success_avg = 100 * item['nb_success'] / item['nb_tests'] except ZeroDivisionError: success_avg = 0 - success_str = str("{:0.2f}".format(success_avg)) + '%' + success_str = f"{success_avg:0.2f}%" duration_str = time.strftime("%H:%M:%S", time.gmtime(item['overall_duration'])) res_table.add_row([item['test_name'], duration_str, @@ -574,7 +592,7 @@ class RallyBase(singlevm.VmReady2): self.result = 100 * total_nb_success / total_nb_tests except ZeroDivisionError: self.result = 100 - success_rate = "{:0.2f}".format(self.result) + success_rate = f"{self.result:0.2f}" success_rate_str = str(success_rate) + '%' res_table.add_row(["", "", "", ""]) res_table.add_row(["TOTAL:", total_duration_str, total_nb_tests, @@ -584,10 +602,10 @@ class RallyBase(singlevm.VmReady2): LOGGER.info("Rally '%s' success_rate is %s%% in %s/%s modules", self.case_name, success_rate, nb_modules, len(self.summary)) - payload.append({'summary': {'duration': total_duration, - 'nb tests': total_nb_tests, - 'nb success': success_rate}}) - self.details = payload + self.details['summary'] = {'duration': total_duration, + 'nb tests': total_nb_tests, + 'nb success': success_rate} + self.details["modules"] = payload @staticmethod def export_task(file_name, export_type="html"): @@ -605,7 +623,7 @@ class RallyBase(singlevm.VmReady2): "--to", file_name] LOGGER.debug('running command: %s', cmd) output = subprocess.check_output(cmd, stderr=subprocess.STDOUT) - LOGGER.info("%s\n%s", " ".join(cmd), output) + LOGGER.info("%s\n%s", " ".join(cmd), output.decode("utf-8")) @staticmethod def verify_report(file_name, uuid, export_type="html"): @@ -621,14 +639,15 @@ class RallyBase(singlevm.VmReady2): "--uuid", uuid, "--to", file_name] LOGGER.debug('running command: %s', cmd) output = subprocess.check_output(cmd, stderr=subprocess.STDOUT) - LOGGER.info("%s\n%s", " ".join(cmd), output) + LOGGER.info("%s\n%s", " ".join(cmd), output.decode("utf-8")) def clean(self): """Cleanup of OpenStack resources. Should be called on completion.""" self.clean_rally_conf() + self.clean_rally_logs() if self.flavor_alt: self.orig_cloud.delete_flavor(self.flavor_alt.id) - super(RallyBase, self).clean() + super().clean() def is_successful(self): """The overall result of the test.""" @@ -636,37 +655,57 @@ class RallyBase(singlevm.VmReady2): if item['task_status'] is False: return testcase.TestCase.EX_TESTCASE_FAILED - return super(RallyBase, self).is_successful() + return super().is_successful() + + @staticmethod + def update_rally_logs(res_dir, rally_conf='/etc/rally/rally.conf'): + """Print rally logs in res dir""" + if not os.path.exists(res_dir): + os.makedirs(res_dir) + rconfig = configparser.RawConfigParser() + rconfig.read(rally_conf) + rconfig.set('DEFAULT', 'debug', True) + rconfig.set('DEFAULT', 'use_stderr', False) + rconfig.set('DEFAULT', 'log-file', 'rally.log') + rconfig.set('DEFAULT', 'log_dir', res_dir) + with open(rally_conf, 'w', encoding='utf-8') as config_file: + rconfig.write(config_file) + + @staticmethod + def clean_rally_logs(rally_conf='/etc/rally/rally.conf'): + """Clean Rally config""" + rconfig = configparser.RawConfigParser() + rconfig.read(rally_conf) + if rconfig.has_option('DEFAULT', 'use_stderr'): + rconfig.remove_option('DEFAULT', 'use_stderr') + if rconfig.has_option('DEFAULT', 'debug'): + rconfig.remove_option('DEFAULT', 'debug') + if rconfig.has_option('DEFAULT', 'log-file'): + rconfig.remove_option('DEFAULT', 'log-file') + if rconfig.has_option('DEFAULT', 'log_dir'): + rconfig.remove_option('DEFAULT', 'log_dir') + with open(rally_conf, 'w', encoding='utf-8') as config_file: + rconfig.write(config_file) def run(self, **kwargs): """Run testcase.""" self.start_time = time.time() try: - assert super(RallyBase, self).run( + assert super().run( **kwargs) == testcase.TestCase.EX_OK - environ = dict( - os.environ, - OS_USERNAME=self.project.user.name, - OS_PROJECT_NAME=self.project.project.name, - OS_PROJECT_ID=self.project.project.id, - OS_PASSWORD=self.project.password) - try: - del environ['OS_TENANT_NAME'] - del environ['OS_TENANT_ID'] - except Exception: # pylint: disable=broad-except - pass - self.create_rally_deployment(environ=environ) + self.update_rally_logs(self.res_dir) + self.create_rally_deployment(environ=self.project.get_environ()) self.prepare_run(**kwargs) self.run_tests(**kwargs) self._generate_report() self.export_task( - "{}/{}.html".format(self.results_dir, self.case_name)) + f"{self.results_dir}/{self.case_name}.html") self.export_task( - "{}/{}.xml".format(self.results_dir, self.case_name), + f"{self.results_dir}/{self.case_name}.xml", export_type="junit-xml") res = testcase.TestCase.EX_OK - except Exception as exc: # pylint: disable=broad-except - LOGGER.error('Error with run: %s', exc) + except Exception: # pylint: disable=broad-except + LOGGER.exception('Error with run:') self.result = 0 res = testcase.TestCase.EX_RUN_ERROR self.stop_time = time.time() @@ -680,47 +719,50 @@ class RallySanity(RallyBase): """Initialize RallySanity object.""" if "case_name" not in kwargs: kwargs["case_name"] = "rally_sanity" - super(RallySanity, self).__init__(**kwargs) + super().__init__(**kwargs) self.smoke = True - self.scenario_dir = os.path.join(self.RALLY_SCENARIO_DIR, 'sanity') + self.scenario_dir = os.path.join(self.rally_scenario_dir, 'sanity') class RallyFull(RallyBase): """Rally full testcase implementation.""" + task_timeout = 7200 + def __init__(self, **kwargs): """Initialize RallyFull object.""" if "case_name" not in kwargs: kwargs["case_name"] = "rally_full" - super(RallyFull, self).__init__(**kwargs) + super().__init__(**kwargs) self.smoke = False - self.scenario_dir = os.path.join(self.RALLY_SCENARIO_DIR, 'full') + self.scenario_dir = os.path.join(self.rally_scenario_dir, 'full') class RallyJobs(RallyBase): """Rally OpenStack CI testcase implementation.""" - TESTS = ["neutron"] + stests = ["neutron"] + task_timeout = 7200 def __init__(self, **kwargs): """Initialize RallyJobs object.""" if "case_name" not in kwargs: kwargs["case_name"] = "rally_jobs" - super(RallyJobs, self).__init__(**kwargs) - self.task_file = os.path.join(self.RALLY_DIR, 'rally_jobs.yaml') + super().__init__(**kwargs) + self.task_file = os.path.join(self.rally_dir, 'rally_jobs.yaml') self.task_yaml = None def prepare_run(self, **kwargs): """Create resources needed by test scenarios.""" - super(RallyJobs, self).prepare_run(**kwargs) - with open(os.path.join(self.RALLY_DIR, - 'rally_jobs.yaml'), 'r') as task_file: + super().prepare_run(**kwargs) + with open( + os.path.join(self.rally_dir, 'rally_jobs.yaml'), + 'r', encoding='utf-8') as task_file: self.task_yaml = yaml.safe_load(task_file) for task in self.task_yaml: if task not in self.tests: - raise Exception("Test '%s' not in '%s'" % - (task, self.tests)) + raise Exception(f"Test '{task}' not in '{self.tests}'") def apply_blacklist(self, case_file_name, result_file_name): # pylint: disable=too-many-branches @@ -732,7 +774,7 @@ class RallyJobs(RallyBase): LOGGER.debug("Blacklisted tests: %s", str(black_tests)) template = YAML(typ='jinja2') - with open(case_file_name, 'r') as fname: + with open(case_file_name, 'r', encoding='utf-8') as fname: cases = template.load(fname) if cases.get("version", 1) == 1: # scenarios in dictionary @@ -741,28 +783,28 @@ class RallyJobs(RallyBase): cases.pop(name) else: # workloads in subtasks - for sind, subtask in enumerate(cases.get('subtasks', [])): - idx = [] - for wind, workload in enumerate(subtask.get('workloads', [])): + for sind, subtask in reversed(list( + enumerate(cases.get('subtasks', [])))): + for wind, workload in reversed(list( + enumerate(subtask.get('workloads', [])))): scenario = workload.get('scenario', {}) for name in scenario.keys(): if self.in_iterable_re(name, black_tests): - idx.append(wind) + cases['subtasks'][sind]['workloads'].pop(wind) break - for wind in reversed(idx): - cases['subtasks'][sind]['workloads'].pop(wind) + if 'workloads' in cases['subtasks'][sind]: + if not cases['subtasks'][sind]['workloads']: + cases['subtasks'].pop(sind) # scenarios in subtasks - idx = [] - for sind, subtask in enumerate(cases.get('subtasks', [])): + for sind, subtask in reversed(list( + enumerate(cases.get('subtasks', [])))): scenario = subtask.get('scenario', {}) for name in scenario.keys(): if self.in_iterable_re(name, black_tests): - idx.append(sind) + cases['subtasks'].pop(sind) break - for sind in reversed(idx): - cases['subtasks'].pop(sind) - with open(result_file_name, 'w') as fname: + with open(result_file_name, 'w', encoding='utf-8') as fname: template.dump(cases, fname) def build_task_args(self, test_name): @@ -772,42 +814,25 @@ class RallyJobs(RallyBase): task_args['floating_network'] = str(self.ext_net.name) else: task_args['floating_network'] = '' + task_args['image_name'] = str(self.image.name) + task_args['flavor_name'] = str(self.flavor.name) return task_args - @staticmethod - def _remove_plugins_extra(): - inst_dir = getattr(config.CONF, 'dir_rally_inst') - try: - shutil.rmtree(os.path.join(inst_dir, 'plugins')) - shutil.rmtree(os.path.join(inst_dir, 'extra')) - except Exception: # pylint: disable=broad-except - pass - def prepare_task(self, test_name): """Prepare resources for test run.""" - self._remove_plugins_extra() jobs_dir = os.path.join( getattr(config.CONF, 'dir_rally_data'), test_name, 'rally-jobs') - inst_dir = getattr(config.CONF, 'dir_rally_inst') - shutil.copytree(os.path.join(jobs_dir, 'plugins'), - os.path.join(inst_dir, 'plugins')) - shutil.copytree(os.path.join(jobs_dir, 'extra'), - os.path.join(inst_dir, 'extra')) - task_name = self.task_yaml.get(test_name).get("task") task = os.path.join(jobs_dir, task_name) if not os.path.exists(task): - raise Exception("The scenario '%s' does not exist." % task) + raise Exception(f"The scenario '{task}' does not exist.") LOGGER.debug('Scenario fetched from : %s', task) - if not os.path.exists(self.TEMP_DIR): - os.makedirs(self.TEMP_DIR) - task_file_name = os.path.join(self.TEMP_DIR, task_name) + if not os.path.exists(self.temp_dir): + os.makedirs(self.temp_dir) + task_file_name = os.path.join(self.temp_dir, task_name) self.apply_blacklist(task, task_file_name) - self.run_cmd = (["rally", "task", "start", "--task", task_file_name, + self.run_cmd = (["rally", "task", "start", "--tag", test_name, + "--task", task_file_name, "--task-args", str(self.build_task_args(test_name))]) return True - - def clean(self): - self._remove_plugins_extra() - super(RallyJobs, self).clean() diff --git a/functest/opnfv_tests/openstack/rally/scenario/full/opnfv-cinder.yaml b/functest/opnfv_tests/openstack/rally/scenario/full/opnfv-cinder.yaml index 4b3c22ebd..7abeeac68 100644 --- a/functest/opnfv_tests/openstack/rally/scenario/full/opnfv-cinder.yaml +++ b/functest/opnfv_tests/openstack/rally/scenario/full/opnfv-cinder.yaml @@ -348,20 +348,6 @@ sla: {{ no_failures_sla() }} - CinderVolumeTypes.create_and_update_volume_type: - - - args: - description: "test" - update_description: "test update" - context: - {{ user_context(tenants_amount, users_amount, use_existing_users) }} - api_versions: - {{ volume_service(version=volume_version, service_type=volume_service_type) }} - runner: - {{ constant_runner(concurrency=concurrency, times=iterations, is_smoke=smoke) }} - sla: - {{ no_failures_sla() }} - CinderVolumeTypes.create_volume_type_and_encryption_type: - args: @@ -378,16 +364,3 @@ {{ constant_runner(concurrency=concurrency, times=iterations, is_smoke=smoke) }} sla: {{ no_failures_sla() }} - - CinderVolumeTypes.create_volume_type_add_and_list_type_access: - - - args: - description: "rally tests creating types" - context: - {{ user_context(tenants_amount, users_amount, use_existing_users) }} - api_versions: - {{ volume_service(version=volume_version, service_type=volume_service_type) }} - runner: - {{ constant_runner(concurrency=concurrency, times=iterations, is_smoke=smoke) }} - sla: - {{ no_failures_sla() }} diff --git a/functest/opnfv_tests/openstack/rally/scenario/full/opnfv-glance.yaml b/functest/opnfv_tests/openstack/rally/scenario/full/opnfv-glance.yaml index dfc1fc156..993b83ff7 100644 --- a/functest/opnfv_tests/openstack/rally/scenario/full/opnfv-glance.yaml +++ b/functest/opnfv_tests/openstack/rally/scenario/full/opnfv-glance.yaml @@ -36,8 +36,9 @@ flavor: name: {{ flavor_name }} number_instances: 2 - nics: - - net-id: {{ netid }} + boot_server_kwargs: + nics: + - net-id: {{ netid }} context: {{ user_context(tenants_amount, users_amount, use_existing_users) }} quotas: diff --git a/functest/opnfv_tests/openstack/rally/scenario/full/opnfv-neutron.yaml b/functest/opnfv_tests/openstack/rally/scenario/full/opnfv-neutron.yaml index b8b1b9b6b..b2248d499 100644 --- a/functest/opnfv_tests/openstack/rally/scenario/full/opnfv-neutron.yaml +++ b/functest/opnfv_tests/openstack/rally/scenario/full/opnfv-neutron.yaml @@ -150,8 +150,6 @@ subnets_per_network: 1 context: {% call user_context(tenants_amount, users_amount, use_existing_users) %} - network: - router: {} quotas: neutron: network: -1 diff --git a/functest/opnfv_tests/openstack/rally/scenario/full/opnfv-nova.yaml b/functest/opnfv_tests/openstack/rally/scenario/full/opnfv-nova.yaml index 0f4e7b26e..210591f9b 100644 --- a/functest/opnfv_tests/openstack/rally/scenario/full/opnfv-nova.yaml +++ b/functest/opnfv_tests/openstack/rally/scenario/full/opnfv-nova.yaml @@ -39,9 +39,6 @@ - net-id: {{ netid }} context: {% call user_context(tenants_amount, users_amount, use_existing_users) %} - network: - networks_per_tenant: 1 - start_cidr: "100.1.0.0/25" quotas: {{ unlimited_neutron() }} {{ unlimited_nova() }} @@ -59,9 +56,6 @@ - net-id: {{ netid }} context: {% call user_context(tenants_amount, users_amount, use_existing_users) %} - network: - networks_per_tenant: 1 - start_cidr: "100.1.0.0/25" quotas: {{ unlimited_neutron() }} {{ unlimited_nova() }} @@ -80,9 +74,6 @@ - net-id: {{ netid }} context: {% call user_context(tenants_amount, users_amount, use_existing_users) %} - network: - networks_per_tenant: 1 - start_cidr: "100.1.0.0/25" quotas: {{ unlimited_neutron() }} {{ unlimited_nova() }} @@ -104,9 +95,6 @@ - net-id: {{ netid }} context: {% call user_context(tenants_amount, users_amount, use_existing_users) %} - network: - networks_per_tenant: 1 - start_cidr: "100.1.0.0/25" quotas: {{ unlimited_neutron() }} {{ unlimited_nova() }} @@ -124,9 +112,6 @@ - net-id: {{ netid }} context: {% call user_context(tenants_amount, users_amount, use_existing_users) %} - network: - networks_per_tenant: 1 - start_cidr: "100.1.0.0/25" quotas: {{ unlimited_neutron() }} {{ unlimited_nova() }} @@ -202,7 +187,7 @@ NovaServers.boot_and_live_migrate_server: - args: {{ vm_params(image_name, flavor_name) }} - block_migration: false + block_migration: {{ block_migration }} nics: - net-id: {{ netid }} context: @@ -216,8 +201,8 @@ - args: {{ vm_params(image_name, flavor_name) }} - size: 10 - block_migration: false + size: 1 + block_migration: {{ block_migration }} boot_server_kwargs: nics: - net-id: {{ netid }} @@ -233,7 +218,7 @@ NovaServers.boot_server_from_volume_and_live_migrate: - args: {{ vm_params(image_name, flavor_name) }} - block_migration: false + block_migration: {{ block_migration }} volume_size: 1 force_delete: false nics: @@ -251,14 +236,11 @@ - args: {{ vm_params(image_name, flavor_name) }} - server_kwargs: + boot_server_kwargs: nics: - net-id: {{ netid }} context: {% call user_context(tenants_amount, users_amount, use_existing_users) %} - network: - networks_per_tenant: 1 - start_cidr: "100.1.0.0/25" quotas: {{ unlimited_neutron() }} {{ unlimited_nova(keypairs=true) }} @@ -277,9 +259,6 @@ - net-id: {{ netid }} context: {% call user_context(tenants_amount, users_amount, use_existing_users) %} - network: - networks_per_tenant: 1 - start_cidr: "100.1.0.0/25" quotas: {{ unlimited_volumes() }} {{ unlimited_neutron() }} @@ -301,9 +280,6 @@ - net-id: {{ netid }} context: {% call user_context(tenants_amount, users_amount, use_existing_users) %} - network: - networks_per_tenant: 1 - start_cidr: "100.1.0.0/25" quotas: {{ unlimited_neutron() }} {{ unlimited_nova() }} @@ -395,8 +371,7 @@ - args: {{ vm_params(image_name, flavor_name) }} - create_floating_ip_args: - ext_network: {{ floating_network }} + floating_network: {{ floating_network }} nics: - net-id: {{ netid }} context: @@ -412,8 +387,7 @@ - args: {{ vm_params(image_name, flavor_name) }} - create_floating_ip_args: - ext_network: {{ floating_network }} + floating_network: {{ floating_network }} nics: - net-id: {{ netid }} context: diff --git a/functest/opnfv_tests/openstack/rally/scenario/opnfv-barbican.yaml b/functest/opnfv_tests/openstack/rally/scenario/opnfv-barbican.yaml new file mode 100644 index 000000000..9dd9ca271 --- /dev/null +++ b/functest/opnfv_tests/openstack/rally/scenario/opnfv-barbican.yaml @@ -0,0 +1,98 @@ + BarbicanContainers.create_and_add: + - + runner: + {{ constant_runner(concurrency=concurrency, times=iterations, is_smoke=smoke) }} + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + sla: + {{ no_failures_sla() }} + + BarbicanContainers.create_certificate_and_delete: + - + runner: + {{ constant_runner(concurrency=concurrency, times=iterations, is_smoke=smoke) }} + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + sla: + {{ no_failures_sla() }} + + BarbicanContainers.create_and_delete: + - + runner: + {{ constant_runner(concurrency=concurrency, times=iterations, is_smoke=smoke) }} + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + sla: + {{ no_failures_sla() }} + + BarbicanContainers.create_rsa_and_delete: + - + runner: + {{ constant_runner(concurrency=concurrency, times=iterations, is_smoke=smoke) }} + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + sla: + {{ no_failures_sla() }} + + BarbicanSecrets.create_and_delete: + - + runner: + {{ constant_runner(concurrency=concurrency, times=iterations, is_smoke=smoke) }} + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + sla: + {{ no_failures_sla() }} + + BarbicanSecrets.create_and_get: + - + runner: + {{ constant_runner(concurrency=concurrency, times=iterations, is_smoke=smoke) }} + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + sla: + {{ no_failures_sla() }} + + BarbicanSecrets.create_and_list: + - + runner: + {{ constant_runner(concurrency=concurrency, times=iterations, is_smoke=smoke) }} + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + sla: + {{ no_failures_sla() }} + + BarbicanSecrets.create: + - + runner: + {{ constant_runner(concurrency=concurrency, times=iterations, is_smoke=smoke) }} + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + sla: + {{ no_failures_sla() }} + + BarbicanSecrets.get: + - + runner: + {{ constant_runner(concurrency=concurrency, times=iterations, is_smoke=smoke) }} + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + sla: + {{ no_failures_sla() }} + + BarbicanContainers.list: + - + runner: + {{ constant_runner(concurrency=concurrency, times=iterations, is_smoke=smoke) }} + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + sla: + {{ no_failures_sla() }} + + BarbicanSecrets.list: + - + runner: + {{ constant_runner(concurrency=concurrency, times=iterations, is_smoke=smoke) }} + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + sla: + {{ no_failures_sla() }} diff --git a/functest/opnfv_tests/openstack/rally/scenario/opnfv-quotas.yaml b/functest/opnfv_tests/openstack/rally/scenario/opnfv-quotas.yaml index 3f0cf0840..dcb007c50 100644 --- a/functest/opnfv_tests/openstack/rally/scenario/opnfv-quotas.yaml +++ b/functest/opnfv_tests/openstack/rally/scenario/opnfv-quotas.yaml @@ -35,17 +35,6 @@ sla: {{ no_failures_sla() }} - Quotas.nova_update_and_delete: - - - args: - max_quota: 1024 - context: - {{ user_context(tenants_amount, users_amount, use_existing_users) }} - runner: - {{ constant_runner(concurrency=concurrency, times=iterations, is_smoke=smoke) }} - sla: - {{ no_failures_sla() }} - Quotas.nova_update: - args: diff --git a/functest/opnfv_tests/openstack/rally/scenario/opnfv-swift.yaml b/functest/opnfv_tests/openstack/rally/scenario/opnfv-swift.yaml new file mode 100644 index 000000000..66d7cd24d --- /dev/null +++ b/functest/opnfv_tests/openstack/rally/scenario/opnfv-swift.yaml @@ -0,0 +1,71 @@ + SwiftObjects.create_container_and_object_then_list_objects: + - + args: + objects_per_container: 2 + object_size: 5120 + runner: + {{ constant_runner(concurrency=1, times=iterations, is_smoke=smoke) }} + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + roles: + - "admin" + sla: + {{ no_failures_sla() }} + + SwiftObjects.list_objects_in_containers: + - + runner: + {{ constant_runner(concurrency=1, times=iterations, is_smoke=smoke) }} + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + roles: + - "admin" + swift_objects: + containers_per_tenant: 1 + objects_per_container: 10 + object_size: 1024 + sla: + {{ no_failures_sla() }} + + SwiftObjects.create_container_and_object_then_download_object: + - + args: + objects_per_container: 5 + object_size: 1024 + runner: + {{ constant_runner(concurrency=1, times=iterations, is_smoke=smoke) }} + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + roles: + - "admin" + sla: + {{ no_failures_sla() }} + + SwiftObjects.create_container_and_object_then_delete_all: + - + args: + objects_per_container: 5 + object_size: 102400 + runner: + {{ constant_runner(concurrency=1, times=iterations, is_smoke=smoke) }} + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + roles: + - "admin" + sla: + {{ no_failures_sla() }} + + SwiftObjects.list_and_download_objects_in_containers: + - + runner: + {{ constant_runner(concurrency=1, times=iterations, is_smoke=smoke) }} + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + roles: + - "admin" + swift_objects: + containers_per_tenant: 1 + objects_per_container: 5 + object_size: 10240 + sla: + {{ no_failures_sla() }} diff --git a/functest/opnfv_tests/openstack/rally/scenario/opnfv-vm.yaml b/functest/opnfv_tests/openstack/rally/scenario/opnfv-vm.yaml new file mode 100644 index 000000000..3aa8ac8e5 --- /dev/null +++ b/functest/opnfv_tests/openstack/rally/scenario/opnfv-vm.yaml @@ -0,0 +1,19 @@ + VMTasks.dd_load_test: + - + args: + flavor: + name: {{ flavor_name }} + image: + name: {{ image_name }} + nics: + - net-id: {{ netid }} + floating_network: {{ floating_network }} + force_delete: false + username: {{ username }} + runner: + {{ constant_runner(concurrency=1, times=iterations, is_smoke=smoke) }} + context: + {{ user_context(tenants_amount, users_amount, use_existing_users) }} + network: {} + sla: + {{ no_failures_sla() }} diff --git a/functest/opnfv_tests/openstack/rally/scenario/sanity/opnfv-glance.yaml b/functest/opnfv_tests/openstack/rally/scenario/sanity/opnfv-glance.yaml index 1b61762f9..279e81439 100644 --- a/functest/opnfv_tests/openstack/rally/scenario/sanity/opnfv-glance.yaml +++ b/functest/opnfv_tests/openstack/rally/scenario/sanity/opnfv-glance.yaml @@ -36,8 +36,9 @@ flavor: name: {{ flavor_name }} number_instances: 2 - nics: - - net-id: {{ netid }} + boot_server_kwargs: + nics: + - net-id: {{ netid }} context: {{ user_context(tenants_amount, users_amount, use_existing_users) }} quotas: diff --git a/functest/opnfv_tests/openstack/rally/scenario/sanity/opnfv-nova.yaml b/functest/opnfv_tests/openstack/rally/scenario/sanity/opnfv-nova.yaml index b92494a43..1fbfccb5a 100644 --- a/functest/opnfv_tests/openstack/rally/scenario/sanity/opnfv-nova.yaml +++ b/functest/opnfv_tests/openstack/rally/scenario/sanity/opnfv-nova.yaml @@ -1,7 +1,7 @@ NovaServers.boot_and_live_migrate_server: - args: {{ vm_params(image_name, flavor_name) }} - block_migration: false + block_migration: {{ block_migration }} nics: - net-id: {{ netid }} context: @@ -15,8 +15,8 @@ - args: {{ vm_params(image_name, flavor_name) }} - size: 10 - block_migration: false + size: 1 + block_migration: {{ block_migration }} boot_server_kwargs: nics: - net-id: {{ netid }} @@ -32,7 +32,7 @@ NovaServers.boot_server_from_volume_and_live_migrate: - args: {{ vm_params(image_name, flavor_name) }} - block_migration: false + block_migration: {{ block_migration }} volume_size: 1 force_delete: false nics: @@ -50,14 +50,11 @@ - args: {{ vm_params(image_name, flavor_name) }} - server_kwargs: + boot_server_kwargs: nics: - net-id: {{ netid }} context: {% call user_context(tenants_amount, users_amount, use_existing_users) %} - network: - networks_per_tenant: 1 - start_cidr: "100.1.0.0/25" quotas: {{ unlimited_neutron() }} {{ unlimited_nova(keypairs=true) }} @@ -76,9 +73,6 @@ - net-id: {{ netid }} context: {% call user_context(tenants_amount, users_amount, use_existing_users) %} - network: - networks_per_tenant: 1 - start_cidr: "100.1.0.0/25" quotas: {{ unlimited_volumes() }} {{ unlimited_neutron() }} @@ -100,9 +94,6 @@ - net-id: {{ netid }} context: {% call user_context(tenants_amount, users_amount, use_existing_users) %} - network: - networks_per_tenant: 1 - start_cidr: "100.1.0.0/25" quotas: {{ unlimited_neutron() }} {{ unlimited_nova() }} @@ -128,7 +119,8 @@ - args: {{ vm_params(image_name, flavor_name) }} - auto_assign_nic: true + nics: + - net-id: {{ netid }} context: {% call user_context(tenants_amount, users_amount, use_existing_users) %} network: {} @@ -142,8 +134,7 @@ - args: {{ vm_params(image_name, flavor_name) }} - create_floating_ip_args: - ext_network: {{ floating_network }} + floating_network: {{ floating_network }} nics: - net-id: {{ netid }} context: diff --git a/functest/opnfv_tests/openstack/rally/scenario/templates/server_with_ports.yaml.template b/functest/opnfv_tests/openstack/rally/scenario/templates/server_with_ports.yaml.template index 35b107838..75afb2dbe 100644 --- a/functest/opnfv_tests/openstack/rally/scenario/templates/server_with_ports.yaml.template +++ b/functest/opnfv_tests/openstack/rally/scenario/templates/server_with_ports.yaml.template @@ -7,7 +7,7 @@ parameters: default: public image: type: string - default: cirros-0.4.0-x86_64-uec + default: cirros-0.6.1-x86_64-uec flavor: type: string default: m1.tiny diff --git a/functest/opnfv_tests/openstack/rally/scenario/templates/server_with_volume.yaml.template b/functest/opnfv_tests/openstack/rally/scenario/templates/server_with_volume.yaml.template index 5c9a86b79..9a0f1aa72 100644 --- a/functest/opnfv_tests/openstack/rally/scenario/templates/server_with_volume.yaml.template +++ b/functest/opnfv_tests/openstack/rally/scenario/templates/server_with_volume.yaml.template @@ -4,7 +4,7 @@ parameters: # set all correct defaults for parameters before launch test image: type: string - default: cirros-0.4.0-x86_64-uec + default: cirros-0.5.1-x86_64-uec flavor: type: string default: m1.tiny diff --git a/functest/opnfv_tests/openstack/rally/task.yaml b/functest/opnfv_tests/openstack/rally/task.yaml index 181fdb42e..649c04557 100644 --- a/functest/opnfv_tests/openstack/rally/task.yaml +++ b/functest/opnfv_tests/openstack/rally/task.yaml @@ -42,3 +42,15 @@ {% if "heat" in service_list %} {%- include "var/opnfv-heat.yaml"-%} {% endif %} + +{% if "swift" in service_list %} +{%- include "var/opnfv-swift.yaml"-%} +{% endif %} + +{% if "barbican" in service_list %} +{%- include "var/opnfv-barbican.yaml"-%} +{% endif %} + +{% if "vm" in service_list %} +{%- include "var/opnfv-vm.yaml"-%} +{% endif %} diff --git a/functest/opnfv_tests/openstack/refstack/refstack.py b/functest/opnfv_tests/openstack/refstack/refstack.py index c709e5626..87932020b 100644 --- a/functest/opnfv_tests/openstack/refstack/refstack.py +++ b/functest/opnfv_tests/openstack/refstack/refstack.py @@ -24,20 +24,16 @@ class Refstack(tempest.TempestCommon): __logger = logging.getLogger(__name__) - defcorelist = os.path.join( - getattr(config.CONF, 'dir_refstack_data'), 'defcore.txt') - - def _extract_refstack_data(self): + def _extract_refstack_data(self, refstack_list): yaml_data = "" - with open(self.defcorelist) as def_file: + with open(refstack_list, encoding='utf-8') as def_file: for line in def_file: try: grp = re.search(r'^([^\[]*)(\[.*\])\n*$', line) - yaml_data = "{}\n{}: {}".format( - yaml_data, grp.group(1), grp.group(2)) + yaml_data = f"{yaml_data}\n{grp.group(1)}: {grp.group(2)}" except Exception: # pylint: disable=broad-except self.__logger.warning("Cannot parse %s", line) - return yaml.load(yaml_data) + return yaml.full_load(yaml_data) def _extract_tempest_data(self): olddir = os.getcwd() @@ -48,25 +44,27 @@ class Refstack(tempest.TempestCommon): except subprocess.CalledProcessError as cpe: self.__logger.error( "Exception when listing tempest tests: %s\n%s", - cpe.cmd, cpe.output) + cpe.cmd, cpe.output.decode("utf-8")) raise finally: os.chdir(olddir) yaml_data2 = "" for line in output.splitlines(): try: - grp = re.search(r'^([^\[]*)(\[.*\])\n*$', line) - yaml_data2 = "{}\n{}: {}".format( - yaml_data2, grp.group(1), grp.group(2)) + grp = re.search(r'^([^\[]*)(\[.*\])\n*$', line.decode("utf-8")) + yaml_data2 = f"{yaml_data2}\n{grp.group(1)}: {grp.group(2)}" except Exception: # pylint: disable=broad-except self.__logger.warning("Cannot parse %s. skipping it", line) - return yaml.load(yaml_data2) + return yaml.full_load(yaml_data2) def generate_test_list(self, **kwargs): + refstack_list = os.path.join( + getattr(config.CONF, 'dir_refstack_data'), + f"{kwargs.get('target', 'compute')}.txt") self.backup_tempest_config(self.conf_file, '/etc') - refstack_data = self._extract_refstack_data() + refstack_data = self._extract_refstack_data(refstack_list) tempest_data = self._extract_tempest_data() - with open(self.list, 'w') as ref_file: + with open(self.list, 'w', encoding='utf-8') as ref_file: for key in refstack_data.keys(): try: for data in tempest_data[key]: @@ -75,9 +73,9 @@ class Refstack(tempest.TempestCommon): else: self.__logger.info("%s: ids differ. skipping it", key) continue - ref_file.write("{}{}\n".format( - key, str(tempest_data[key]).replace( - "'", "").replace(", ", ","))) + value = str(tempest_data[key]).replace( + "'", "").replace(", ", ",") + ref_file.write(f"{key}{value}\n") except Exception: # pylint: disable=broad-except self.__logger.info("%s: not found. skipping it", key) continue diff --git a/functest/opnfv_tests/openstack/shaker/shaker.py b/functest/opnfv_tests/openstack/shaker/shaker.py index 995a10b18..275cc3077 100644 --- a/functest/opnfv_tests/openstack/shaker/shaker.py +++ b/functest/opnfv_tests/openstack/shaker/shaker.py @@ -19,6 +19,7 @@ and list of tests to execute. import logging import os +import json import scp from functest.core import singlevm @@ -31,28 +32,32 @@ class Shaker(singlevm.SingleVm2): __logger = logging.getLogger(__name__) - filename = '/home/opnfv/functest/images/shaker-image.qcow2' + filename = '/home/opnfv/functest/images/shaker-image-1.3.4+stretch.qcow2' flavor_ram = 512 flavor_vcpus = 1 flavor_disk = 3 - username = 'ubuntu' + username = 'debian' port = 9000 ssh_connect_loops = 12 create_server_timeout = 300 + check_console_loop = 12 shaker_timeout = '3600' + quota_instances = -1 + quota_cores = -1 + check_console_loop = 12 def __init__(self, **kwargs): - super(Shaker, self).__init__(**kwargs) + super().__init__(**kwargs) self.role = None def check_requirements(self): - if len(self.orig_cloud.list_hypervisors()) < 2: + if self.count_hypervisors() < 2: self.__logger.warning("Shaker requires at least 2 hypervisors") self.is_skipped = True self.project.clean() def prepare(self): - super(Shaker, self).prepare() + super().prepare() self.cloud.create_security_group_rule( self.sec.id, port_range_min=self.port, port_range_max=self.port, protocol='tcp', direction='ingress') @@ -82,39 +87,41 @@ class Shaker(singlevm.SingleVm2): "heat_stack_owner", user=self.project.user.id, project=self.project.project.id, domain=self.project.domain.id) + self.orig_cloud.set_compute_quotas( + self.project.project.name, + instances=self.quota_instances, + cores=self.quota_cores) scpc = scp.SCPClient(self.ssh.get_transport()) scpc.put('/home/opnfv/functest/conf/env_file', remote_path='~/') if os.environ.get('OS_CACERT'): scpc.put(os.environ.get('OS_CACERT'), remote_path='~/os_cacert') + opt = 'export OS_CACERT=~/os_cacert && ' if os.environ.get( + 'OS_CACERT') else '' (_, stdout, stderr) = self.ssh.exec_command( 'source ~/env_file && ' 'export OS_INTERFACE=public && ' - 'export OS_AUTH_URL={} && ' - 'export OS_USERNAME={} && ' - 'export OS_PROJECT_NAME={} && ' - 'export OS_PROJECT_ID={} && ' + f'export OS_AUTH_URL={endpoint} && ' + f'export OS_USERNAME={self.project.user.name} && ' + f'export OS_PROJECT_NAME={self.project.project.name} && ' + f'export OS_PROJECT_ID={self.project.project.id} && ' 'unset OS_TENANT_NAME && ' 'unset OS_TENANT_ID && ' 'unset OS_ENDPOINT_TYPE && ' - 'export OS_PASSWORD={} && ' - '{}' + f'export OS_PASSWORD="{self.project.password}" && ' + f'{opt}' 'env && ' - 'timeout {} shaker --image-name {} --flavor-name {} ' - '--server-endpoint {}:9000 --external-net {} --dns-nameservers {} ' + f'timeout {self.shaker_timeout} shaker --debug ' + f'--image-name {self.image.name} --flavor-name {self.flavor.name} ' + f'--server-endpoint {self.fip.floating_ip_address}:9000 ' + f'--external-net {self.ext_net.id} ' + f"--dns-nameservers {env.get('NAMESERVER')} " '--scenario openstack/full_l2,' 'openstack/full_l3_east_west,' 'openstack/full_l3_north_south,' 'openstack/perf_l3_north_south ' - '--report report.html --output report.json'.format( - endpoint, self.project.user.name, self.project.project.name, - self.project.project.id, self.project.password, - 'export OS_CACERT=~/os_cacert && ' if os.environ.get( - 'OS_CACERT') else '', - self.shaker_timeout, self.image.name, self.flavor.name, - self.fip.floating_ip_address, self.ext_net.id, - env.get('NAMESERVER'))) - self.__logger.info("output:\n%s", stdout.read()) - self.__logger.info("error:\n%s", stderr.read()) + '--report report.html --output report.json') + self.__logger.info("output:\n%s", stdout.read().decode("utf-8")) + self.__logger.info("error:\n%s", stderr.read().decode("utf-8")) if not os.path.exists(self.res_dir): os.makedirs(self.res_dir) try: @@ -123,9 +130,18 @@ class Shaker(singlevm.SingleVm2): except scp.SCPException: self.__logger.exception("cannot get report files") return 1 + with open( + os.path.join(self.res_dir, 'report.json'), + encoding='utf-8') as json_file: + data = json.load(json_file) + for value in data["records"].values(): + if value["status"] != "ok": + self.__logger.error( + "%s failed\n%s", value["scenario"], value["stderr"]) + return 1 return stdout.channel.recv_exit_status() def clean(self): - super(Shaker, self).clean() + super().clean() if self.role: self.orig_cloud.delete_role(self.role.id) diff --git a/functest/opnfv_tests/openstack/tempest/custom_tests/blacklist.yaml b/functest/opnfv_tests/openstack/tempest/custom_tests/blacklist.yaml index 8d7d6eca9..43a77fa3c 100644 --- a/functest/opnfv_tests/openstack/tempest/custom_tests/blacklist.yaml +++ b/functest/opnfv_tests/openstack/tempest/custom_tests/blacklist.yaml @@ -4,10 +4,16 @@ - os-ovn-nofeature-ha - os-ovn-nofeature-noha tests: - - neutron_tempest_plugin.api.admin.test_agent_management - neutron_tempest_plugin.api.admin.test_dhcp_agent_scheduler - - patrole_tempest_plugin.tests.api.network.test_agents_rbac + - neutron_tempest_plugin.api.admin.test_ports.PortTestCasesResourceRequest.test_port_resource_request + - neutron_tempest_plugin.api.admin.test_ports.PortTestCasesResourceRequest.test_port_resource_request_empty + - neutron_tempest_plugin.api.admin.test_ports.PortTestCasesResourceRequest.test_port_resource_request_inherited_policy + - neutron_tempest_plugin.api.admin.test_ports.PortTestCasesResourceRequest.test_port_resource_request_no_provider_net_conflict + - neutron_tempest_plugin.api.test_ports.PortsTestJSON.test_create_update_port_with_dns_name + - patrole_tempest_plugin.tests.api.network.test_availability_zones_rbac.AvailabilityZoneExtRbacTest.test_list_availability_zone_rbac + - patrole_tempest_plugin.tests.api.network.test_agents_rbac.DHCPAgentSchedulersRbacTest.test_add_dhcp_agent_to_network + - patrole_tempest_plugin.tests.api.network.test_agents_rbac.DHCPAgentSchedulersRbacTest.test_delete_network_from_dhcp_agent + - patrole_tempest_plugin.tests.api.network.test_agents_rbac.DHCPAgentSchedulersRbacTest.test_list_networks_hosted_by_one_dhcp_agent - patrole_tempest_plugin.tests.api.network.test_networks_rbac.NetworksRbacTest.test_create_network_provider_network_type - patrole_tempest_plugin.tests.api.network.test_networks_rbac.NetworksRbacTest.test_create_network_provider_segmentation_id - - tempest.api.network.admin.test_agent_management - tempest.api.network.admin.test_dhcp_agent_scheduler diff --git a/functest/opnfv_tests/openstack/tempest/custom_tests/public_blacklist.yaml b/functest/opnfv_tests/openstack/tempest/custom_tests/public_blacklist.yaml new file mode 100644 index 000000000..e53b577b2 --- /dev/null +++ b/functest/opnfv_tests/openstack/tempest/custom_tests/public_blacklist.yaml @@ -0,0 +1,15 @@ +--- +- + scenarios: + - os-* + tests: + - neutron_tempest_plugin.api.admin.test_floating_ips_admin_actions.FloatingIPAdminTestJSON.test_associate_floating_ip_with_port_from_another_project + - neutron_tempest_plugin.api.admin.test_quotas.QuotasTest.test_detail_quotas + - neutron_tempest_plugin.api.admin.test_quotas.QuotasTest.test_quotas + - neutron_tempest_plugin.api.admin.test_quotas_negative.QuotasAdminNegativeTestJSON.test_create_floatingip_when_quotas_is_full + - neutron_tempest_plugin.api.admin.test_quotas_negative.QuotasAdminNegativeTestJSON.test_create_network_when_quotas_is_full + - neutron_tempest_plugin.api.admin.test_quotas_negative.QuotasAdminNegativeTestJSON.test_create_port_when_quotas_is_full + - neutron_tempest_plugin.api.admin.test_quotas_negative.QuotasAdminNegativeTestJSON.test_create_router_when_quotas_is_full + - neutron_tempest_plugin.api.admin.test_quotas_negative.QuotasAdminNegativeTestJSON.test_create_security_group_rule_when_quotas_is_full + - neutron_tempest_plugin.api.admin.test_quotas_negative.QuotasAdminNegativeTestJSON.test_create_security_group_when_quotas_is_full + - neutron_tempest_plugin.api.admin.test_quotas_negative.QuotasAdminNegativeTestJSON.test_create_subnet_when_quotas_is_full diff --git a/functest/opnfv_tests/openstack/tempest/custom_tests/tempest_conf.yaml b/functest/opnfv_tests/openstack/tempest/custom_tests/tempest_conf.yaml index ee3087dc3..0ee4ab613 100644 --- a/functest/opnfv_tests/openstack/tempest/custom_tests/tempest_conf.yaml +++ b/functest/opnfv_tests/openstack/tempest/custom_tests/tempest_conf.yaml @@ -1,21 +1,104 @@ --- compute: + min_microversion: '2.44' max_microversion: latest compute-feature-enabled: - shelve: false - vnc_console: false + attach_encrypted_volume: false + block_migration_for_live_migration: false + block_migrate_cinder_iscsi: false + change_password: false + cold_migration: true + config_drive: true + console_output: true + disk_config: true + enable_instance_password: true + hostname_fqdn_sanitization: true + interface_attach: true + live_migration: true + live_migrate_back_and_forth: false + metadata_service: true + pause: true + personality: false + rdp_console: false + rescue: true + resize: true + scheduler_available_filters: "AvailabilityZoneFilter,ComputeFilter,\ + ComputeCapabilitiesFilter,ImagePropertiesFilter,ServerGroupAntiAffinityFilter,\ + ServerGroupAffinityFilter,SameHostFilter,DifferentHostFilter" + serial_console: false + shelve: true + snapshot: true + spice_console: false + suspend: true + swap_volume: false + vnc_console: true + volume_backed_live_migration: false + volume_multiattach: false identity: + auth_version: v3 user_unique_last_password_count: 2 user_lockout_duration: 10 user_lockout_failure_attempts: 2 identity-feature-enabled: + trust: true api_v2: false api_v2_admin: false security_compliance: true + federation: false + external_idp: false + project_tags: true + application_credentials: true + access_rules: true image-feature-enabled: api_v2: true api_v1: false + import_image: false +network-feature-enabled: + port_admin_state_change: true + port_security: true +placement: + max_microversion: latest +validation: + image_ssh_user: cirros + ssh_timeout: 196 + ip_version_for_ssh: 4 + run_validation: true volume: - storage_protocol: iSCSI + max_microversion: latest + storage_protocol: ceph + manage_volume_ref: source-name,volume-%s + manage_snapshot_ref: source-name,snapshot-%s volume-feature-enabled: - backup: false + multi_backend: false + backup: true + snapshot: true + clone: true + manage_snapshot: true + manage_volume: true + extend_attached_volume: true + extend_attached_encrypted_volume: false + consistency_group: false + volume_revert: true +load_balancer: + test_with_ipv6: false +neutron_plugin_options: + agent_availability_zone: nova + available_type_drivers: flat,geneve,vlan,gre,local,vxlan + provider_vlans: public, + create_shared_resources: true +object-storage-feature-enabled: + discoverable_apis: "account_quotas,formpost,bulk_upload,bulk_delete,\ + tempurl,crossdomain,container_quotas,staticweb,account_quotas,slo" + object_versioning: true + discoverability: true + tempurl_digest_hashlib: sha1 +heat_plugin: + skip_functional_test_list: EncryptionVolTypeTest + skip_scenario_test_list: "AodhAlarmTest,SoftwareConfigIntegrationTest,\ + VolumeBackupRestoreIntegrationTest,CfnInitIntegrationTest,\ + LoadBalancerTest" + auth_version: 3 +heat_features_enabled: + multi_cloud: false +rbac: + enable_rbac: true diff --git a/functest/opnfv_tests/openstack/tempest/custom_tests/tempest_conf_ovn.yaml b/functest/opnfv_tests/openstack/tempest/custom_tests/tempest_conf_ovn.yaml new file mode 100644 index 000000000..6b09d8e5a --- /dev/null +++ b/functest/opnfv_tests/openstack/tempest/custom_tests/tempest_conf_ovn.yaml @@ -0,0 +1,104 @@ +--- +compute: + min_microversion: '2.44' + max_microversion: latest +compute-feature-enabled: + attach_encrypted_volume: false + block_migration_for_live_migration: false + block_migrate_cinder_iscsi: false + change_password: false + cold_migration: true + config_drive: true + console_output: true + disk_config: true + enable_instance_password: true + hostname_fqdn_sanitization: true + interface_attach: true + live_migration: true + live_migrate_back_and_forth: false + metadata_service: true + pause: true + personality: false + rdp_console: false + rescue: true + resize: true + scheduler_available_filters: "AvailabilityZoneFilter,ComputeFilter,\ + ComputeCapabilitiesFilter,ImagePropertiesFilter,ServerGroupAntiAffinityFilter,\ + ServerGroupAffinityFilter,SameHostFilter,DifferentHostFilter" + serial_console: false + shelve: true + snapshot: true + spice_console: false + suspend: true + swap_volume: false + vnc_console: true + volume_backed_live_migration: false + volume_multiattach: false +identity: + auth_version: v3 + user_unique_last_password_count: 2 + user_lockout_duration: 10 + user_lockout_failure_attempts: 2 +identity-feature-enabled: + trust: true + api_v2: false + api_v2_admin: false + security_compliance: true + federation: false + external_idp: false + project_tags: true + application_credentials: true + access_rules: true +image-feature-enabled: + api_v2: true + api_v1: false + import_image: false +network-feature-enabled: + port_admin_state_change: true + port_security: true +placement: + max_microversion: latest +validation: + image_ssh_user: cirros + ssh_timeout: 196 + ip_version_for_ssh: 4 + run_validation: true +volume: + max_microversion: latest + storage_protocol: ceph + manage_volume_ref: source-name,volume-%s + manage_snapshot_ref: source-name,snapshot-%s +volume-feature-enabled: + multi_backend: false + backup: true + snapshot: true + clone: true + manage_snapshot: true + manage_volume: true + extend_attached_volume: true + extend_attached_encrypted_volume: false + consistency_group: false + volume_revert: true +load_balancer: + test_with_ipv6: false +neutron_plugin_options: + agent_availability_zone: nova + available_type_drivers: flat,geneve,vlan,local + provider_vlans: public, + create_shared_resources: true +object-storage-feature-enabled: + discoverable_apis: "account_quotas,formpost,bulk_upload,bulk_delete,\ + tempurl,crossdomain,container_quotas,staticweb,account_quotas,slo" + object_versioning: true + discoverability: true + tempurl_digest_hashlib: sha1 +heat_plugin: + skip_functional_test_list: EncryptionVolTypeTest + skip_scenario_test_list: "AodhAlarmTest,SoftwareConfigIntegrationTest,\ + VolumeBackupRestoreIntegrationTest,CfnInitIntegrationTest,\ + LoadBalancerTest" + auth_version: 3 +heat_features_enabled: + multi_cloud: false +rbac: + enable_rbac: true diff --git a/functest/opnfv_tests/openstack/tempest/tempest.py b/functest/opnfv_tests/openstack/tempest/tempest.py index 894b6e2b3..7233ffd60 100644 --- a/functest/opnfv_tests/openstack/tempest/tempest.py +++ b/functest/opnfv_tests/openstack/tempest/tempest.py @@ -39,22 +39,25 @@ class TempestCommon(singlevm.VmReady2): """TempestCommon testcases implementation class.""" visibility = 'public' - filename_alt = '/home/opnfv/functest/images/cirros-0.4.0-x86_64-disk.img' + filename_alt = '/home/opnfv/functest/images/cirros-0.6.1-x86_64-disk.img' shared_network = True - TEMPEST_CONF_YAML = pkg_resources.resource_filename( + tempest_conf_yaml = pkg_resources.resource_filename( 'functest', 'opnfv_tests/openstack/tempest/custom_tests/tempest_conf.yaml') - TEMPEST_CUSTOM = pkg_resources.resource_filename( + tempest_custom = pkg_resources.resource_filename( 'functest', 'opnfv_tests/openstack/tempest/custom_tests/test_list.txt') - TEMPEST_BLACKLIST = pkg_resources.resource_filename( + tempest_blacklist = pkg_resources.resource_filename( 'functest', 'opnfv_tests/openstack/tempest/custom_tests/blacklist.yaml') + tempest_public_blacklist = pkg_resources.resource_filename( + 'functest', + 'opnfv_tests/openstack/tempest/custom_tests/public_blacklist.yaml') def __init__(self, **kwargs): if "case_name" not in kwargs: kwargs["case_name"] = 'tempest' - super(TempestCommon, self).__init__(**kwargs) + super().__init__(**kwargs) assert self.orig_cloud assert self.cloud assert self.project @@ -95,6 +98,7 @@ class TempestCommon(singlevm.VmReady2): except Exception: # pylint: disable=broad-except pass self.deny_skipping = kwargs.get("deny_skipping", False) + self.tests_count = kwargs.get("tests_count", 0) def check_services(self): """Check the mandatory services.""" @@ -124,7 +128,7 @@ class TempestCommon(singlevm.VmReady2): @staticmethod def read_file(filename): """Read file and return content as a stripped list.""" - with open(filename) as src: + with open(filename, encoding='utf-8') as src: return [line.strip() for line in src.readlines()] @staticmethod @@ -138,22 +142,22 @@ class TempestCommon(singlevm.VmReady2): } cmd = ["rally", "verify", "show", "--uuid", verif_id] LOGGER.info("Showing result for a verification: '%s'.", cmd) - proc = subprocess.Popen(cmd, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) - for line in proc.stdout: - LOGGER.info(line.rstrip()) - new_line = line.replace(' ', '').split('|') - if 'Tests' in new_line: - break - if 'Testscount' in new_line: - result['num_tests'] = int(new_line[2]) - elif 'Success' in new_line: - result['num_success'] = int(new_line[2]) - elif 'Skipped' in new_line: - result['num_skipped'] = int(new_line[2]) - elif 'Failures' in new_line: - result['num_failures'] = int(new_line[2]) + with subprocess.Popen( + cmd, stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) as proc: + for line in proc.stdout: + LOGGER.info(line.decode("utf-8").rstrip()) + new_line = line.decode("utf-8").replace(' ', '').split('|') + if 'Tests' in new_line: + break + if 'Testscount' in new_line: + result['num_tests'] = int(new_line[2]) + elif 'Success' in new_line: + result['num_success'] = int(new_line[2]) + elif 'Skipped' in new_line: + result['num_skipped'] = int(new_line[2]) + elif 'Failures' in new_line: + result['num_failures'] = int(new_line[2]) return result @staticmethod @@ -175,7 +179,7 @@ class TempestCommon(singlevm.VmReady2): '--force'] try: output = subprocess.check_output(cmd) - LOGGER.info("%s\n%s", " ".join(cmd), output) + LOGGER.info("%s\n%s", " ".join(cmd), output.decode("utf-8")) except subprocess.CalledProcessError: pass @@ -184,7 +188,7 @@ class TempestCommon(singlevm.VmReady2): '--name', str(getattr(config.CONF, 'tempest_verifier_name')), '--type', 'tempest', '--system-wide'] output = subprocess.check_output(cmd) - LOGGER.info("%s\n%s", " ".join(cmd), output) + LOGGER.info("%s\n%s", " ".join(cmd), output.decode("utf-8")) return TempestCommon.get_verifier_id() @staticmethod @@ -195,11 +199,11 @@ class TempestCommon(singlevm.VmReady2): cmd = ("rally verify list-verifiers | awk '/" + getattr(config.CONF, 'tempest_verifier_name') + "/ {print $2}'") - proc = subprocess.Popen(cmd, shell=True, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) - verifier_uuid = proc.stdout.readline().rstrip() - return verifier_uuid + with subprocess.Popen( + cmd, shell=True, stdout=subprocess.PIPE, + stderr=subprocess.DEVNULL) as proc: + verifier_uuid = proc.stdout.readline().rstrip() + return verifier_uuid.decode("utf-8") @staticmethod def get_verifier_repo_dir(verifier_id): @@ -208,7 +212,7 @@ class TempestCommon(singlevm.VmReady2): """ return os.path.join(getattr(config.CONF, 'dir_rally_inst'), 'verification', - 'verifier-{}'.format(verifier_id), + f'verifier-{verifier_id}', 'repo') @staticmethod @@ -218,13 +222,13 @@ class TempestCommon(singlevm.VmReady2): """ return os.path.join(getattr(config.CONF, 'dir_rally_inst'), 'verification', - 'verifier-{}'.format(verifier_id), - 'for-deployment-{}'.format(deployment_id)) + f'verifier-{verifier_id}', + f'for-deployment-{deployment_id}') @staticmethod def update_tempest_conf_file(conf_file, rconfig): """Update defined paramters into tempest config file""" - with open(TempestCommon.TEMPEST_CONF_YAML) as yfile: + with open(TempestCommon.tempest_conf_yaml, encoding='utf-8') as yfile: conf_yaml = yaml.safe_load(yfile) if conf_yaml: sections = rconfig.sections() @@ -235,7 +239,7 @@ class TempestCommon(singlevm.VmReady2): for key, value in sub_conf.items(): rconfig.set(section, key, value) - with open(conf_file, 'wb') as config_file: + with open(conf_file, 'w', encoding='utf-8') as config_file: rconfig.write(config_file) @staticmethod @@ -244,8 +248,8 @@ class TempestCommon(singlevm.VmReady2): compute_cnt=1, image_alt_id=None, flavor_alt_id=None, admin_role_name='admin', cidr='192.168.120.0/24', domain_id='default'): - # pylint: disable=too-many-branches,too-many-arguments, - # too-many-statements + # pylint: disable=too-many-branches,too-many-arguments + # pylint: disable=too-many-statements,too-many-locals """ Add/update needed parameters into tempest.conf file """ @@ -266,27 +270,8 @@ class TempestCommon(singlevm.VmReady2): # enable multinode tests rconfig.set('compute', 'min_compute_nodes', compute_cnt) rconfig.set('compute-feature-enabled', 'live_migration', True) - filters = ['RetryFilter', 'AvailabilityZoneFilter', 'ComputeFilter', - 'ComputeCapabilitiesFilter', 'ImagePropertiesFilter', - 'ServerGroupAntiAffinityFilter', - 'ServerGroupAffinityFilter'] - rconfig.set( - 'compute-feature-enabled', 'scheduler_available_filters', - functest_utils.convert_list_to_ini(filters)) if os.environ.get('OS_REGION_NAME'): rconfig.set('identity', 'region', os.environ.get('OS_REGION_NAME')) - if env.get("NEW_USER_ROLE").lower() != "member": - rconfig.set( - 'auth', 'tempest_roles', - functest_utils.convert_list_to_ini([env.get("NEW_USER_ROLE")])) - if not json.loads(env.get("USE_DYNAMIC_CREDENTIALS").lower()): - rconfig.set('auth', 'use_dynamic_credentials', False) - account_file = os.path.join( - getattr(config.CONF, 'dir_functest_data'), 'accounts.yaml') - assert os.path.exists( - account_file), "{} doesn't exist".format(account_file) - rconfig.set('auth', 'test_accounts_file', account_file) - rconfig.set('identity', 'auth_version', 'v3') rconfig.set('identity', 'admin_role', admin_role_name) rconfig.set('identity', 'default_domain_id', domain_id) if not rconfig.has_section('network'): @@ -320,7 +305,7 @@ class TempestCommon(singlevm.VmReady2): cmd = ['rally', 'verify', 'configure-verifier', '--reconfigure', '--id', str(getattr(config.CONF, 'tempest_verifier_name'))] output = subprocess.check_output(cmd) - LOGGER.info("%s\n%s", " ".join(cmd), output) + LOGGER.info("%s\n%s", " ".join(cmd), output.decode("utf-8")) LOGGER.debug("Looking for tempest.conf file...") tempest_conf_file = os.path.join(deployment_dir, "tempest.conf") @@ -335,55 +320,53 @@ class TempestCommon(singlevm.VmReady2): LOGGER.debug("Generating test case list...") self.backup_tempest_config(self.conf_file, '/etc') if kwargs.get('mode') == 'custom': - if os.path.isfile(self.TEMPEST_CUSTOM): + if os.path.isfile(self.tempest_custom): shutil.copyfile( - self.TEMPEST_CUSTOM, self.list) + self.tempest_custom, self.list) else: - raise Exception("Tempest test list file %s NOT found." - % self.TEMPEST_CUSTOM) + raise Exception( + f"Tempest test list file {self.tempest_custom} NOT found.") else: testr_mode = kwargs.get( 'mode', r'^tempest\.(api|scenario).*\[.*\bsmoke\b.*\]$') - cmd = "(cd {0}; stestr list '{1}' >{2} 2>/dev/null)".format( - self.verifier_repo_dir, testr_mode, self.list) + cmd = (f"(cd {self.verifier_repo_dir}; " + f"stestr list '{testr_mode}' > {self.list} 2>/dev/null)") output = subprocess.check_output(cmd, shell=True) - LOGGER.info("%s\n%s", cmd, output) + LOGGER.info("%s\n%s", cmd, output.decode("utf-8")) os.remove('/etc/tempest.conf') - def apply_tempest_blacklist(self): + def apply_tempest_blacklist(self, black_list): """Exclude blacklisted test cases.""" LOGGER.debug("Applying tempest blacklist...") if os.path.exists(self.raw_list): os.remove(self.raw_list) os.rename(self.list, self.raw_list) cases_file = self.read_file(self.raw_list) - result_file = open(self.list, 'w') - black_tests = [] - try: - deploy_scenario = env.get('DEPLOY_SCENARIO') - if bool(deploy_scenario): - # if DEPLOY_SCENARIO is set we read the file - black_list_file = open(self.TEMPEST_BLACKLIST) - black_list_yaml = yaml.safe_load(black_list_file) - black_list_file.close() - for item in black_list_yaml: - scenarios = item['scenarios'] - if deploy_scenario in scenarios: - tests = item['tests'] - for test in tests: - black_tests.append(test) - break - except Exception: # pylint: disable=broad-except + with open(self.list, 'w', encoding='utf-8') as result_file: black_tests = [] - LOGGER.debug("Tempest blacklist file does not exist.") + try: + deploy_scenario = env.get('DEPLOY_SCENARIO') + if bool(deploy_scenario): + # if DEPLOY_SCENARIO is set we read the file + with open(black_list, encoding='utf-8') as black_list_file: + black_list_yaml = yaml.safe_load(black_list_file) + black_list_file.close() + for item in black_list_yaml: + scenarios = item['scenarios'] + in_it = rally.RallyBase.in_iterable_re + if in_it(deploy_scenario, scenarios): + tests = item['tests'] + black_tests.extend(tests) + except Exception: # pylint: disable=broad-except + black_tests = [] + LOGGER.debug("Tempest blacklist file does not exist.") - for cases_line in cases_file: - for black_tests_line in black_tests: - if black_tests_line in cases_line: - break - else: - result_file.write(str(cases_line) + '\n') - result_file.close() + for cases_line in cases_file: + for black_tests_line in black_tests: + if re.search(black_tests_line, cases_line): + break + else: + result_file.write(str(cases_line) + '\n') def run_verifier_tests(self, **kwargs): """Execute tempest test cases.""" @@ -392,33 +375,31 @@ class TempestCommon(singlevm.VmReady2): cmd.extend(kwargs.get('option', [])) LOGGER.info("Starting Tempest test suite: '%s'.", cmd) - f_stdout = open( - os.path.join(self.res_dir, "tempest.log"), 'w+') - - proc = subprocess.Popen( - cmd, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - bufsize=1) - - with proc.stdout: - for line in iter(proc.stdout.readline, b''): - if re.search(r"\} tempest\.", line): - LOGGER.info(line.rstrip()) - elif re.search(r'(?=\(UUID=(.*)\))', line): - self.verification_id = re.search( - r'(?=\(UUID=(.*)\))', line).group(1) - f_stdout.write(line) - proc.wait() - f_stdout.close() + with open( + os.path.join(self.res_dir, "tempest.log"), 'w+', + encoding='utf-8') as f_stdout: + with subprocess.Popen( + cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, + bufsize=1) as proc: + with proc.stdout: + for line in iter(proc.stdout.readline, b''): + if re.search(r"\} tempest\.", line.decode("utf-8")): + LOGGER.info(line.rstrip()) + elif re.search(r'(?=\(UUID=(.*)\))', + line.decode("utf-8")): + self.verification_id = re.search( + r'(?=\(UUID=(.*)\))', + line.decode("utf-8")).group(1) + f_stdout.write(line.decode("utf-8")) + proc.wait() if self.verification_id is None: raise Exception('Verification UUID not found') LOGGER.info('Verification UUID: %s', self.verification_id) shutil.copy( - "{}/tempest.log".format(self.deployment_dir), - "{}/tempest.debug.log".format(self.res_dir)) + f"{self.deployment_dir}/tempest.log", + f"{self.res_dir}/tempest.debug.log") def parse_verifier_result(self): """Parse and save test results.""" @@ -435,8 +416,8 @@ class TempestCommon(singlevm.VmReady2): LOGGER.error("No test has been executed") return - with open(os.path.join(self.res_dir, - "rally.log"), 'r') as logfile: + with open(os.path.join(self.res_dir, "rally.log"), + 'r', encoding='utf-8') as logfile: output = logfile.read() success_testcases = [] @@ -471,9 +452,8 @@ class TempestCommon(singlevm.VmReady2): rconfig.read(rally_conf) if not rconfig.has_section('openstack'): rconfig.add_section('openstack') - rconfig.set('openstack', 'img_name_regex', '^{}$'.format( - self.image.name)) - with open(rally_conf, 'wb') as config_file: + rconfig.set('openstack', 'img_name_regex', f'^{self.image.name}$') + with open(rally_conf, 'w', encoding='utf-8') as config_file: rconfig.write(config_file) def update_default_role(self, rally_conf='/etc/rally/rally.conf'): @@ -486,20 +466,7 @@ class TempestCommon(singlevm.VmReady2): if not rconfig.has_section('openstack'): rconfig.add_section('openstack') rconfig.set('openstack', 'swift_operator_role', role.name) - with open(rally_conf, 'wb') as config_file: - rconfig.write(config_file) - - def update_rally_logs(self, rally_conf='/etc/rally/rally.conf'): - """Print rally logs in res dir""" - if not os.path.exists(self.res_dir): - os.makedirs(self.res_dir) - rconfig = configparser.RawConfigParser() - rconfig.read(rally_conf) - rconfig.set('DEFAULT', 'debug', True) - rconfig.set('DEFAULT', 'use_stderr', False) - rconfig.set('DEFAULT', 'log-file', 'rally.log') - rconfig.set('DEFAULT', 'log_dir', self.res_dir) - with open(rally_conf, 'wb') as config_file: + with open(rally_conf, 'w', encoding='utf-8') as config_file: rconfig.write(config_file) @staticmethod @@ -511,26 +478,51 @@ class TempestCommon(singlevm.VmReady2): rconfig.remove_option('openstack', 'img_name_regex') if rconfig.has_option('openstack', 'swift_operator_role'): rconfig.remove_option('openstack', 'swift_operator_role') - if rconfig.has_option('DEFAULT', 'use_stderr'): - rconfig.remove_option('DEFAULT', 'use_stderr') - if rconfig.has_option('DEFAULT', 'debug'): - rconfig.remove_option('DEFAULT', 'debug') - if rconfig.has_option('DEFAULT', 'log-file'): - rconfig.remove_option('DEFAULT', 'log-file') - if rconfig.has_option('DEFAULT', 'log_dir'): - rconfig.remove_option('DEFAULT', 'log_dir') - with open(rally_conf, 'wb') as config_file: + with open(rally_conf, 'w', encoding='utf-8') as config_file: + rconfig.write(config_file) + + def update_auth_section(self): + """Update auth section in tempest.conf""" + rconfig = configparser.RawConfigParser() + rconfig.read(self.conf_file) + if not rconfig.has_section("auth"): + rconfig.add_section("auth") + if env.get("NEW_USER_ROLE").lower() != "member": + tempest_roles = [] + if rconfig.has_option("auth", "tempest_roles"): + tempest_roles = functest_utils.convert_ini_to_list( + rconfig.get("auth", "tempest_roles")) + rconfig.set( + 'auth', 'tempest_roles', + functest_utils.convert_list_to_ini( + [env.get("NEW_USER_ROLE")] + tempest_roles)) + if not json.loads(env.get("USE_DYNAMIC_CREDENTIALS").lower()): + rconfig.set('auth', 'use_dynamic_credentials', False) + account_file = os.path.join( + getattr(config.CONF, 'dir_functest_data'), 'accounts.yaml') + assert os.path.exists( + account_file), f"{account_file} doesn't exist" + rconfig.set('auth', 'test_accounts_file', account_file) + if env.get('NO_TENANT_NETWORK').lower() == 'true': + rconfig.set('auth', 'create_isolated_networks', False) + with open(self.conf_file, 'w', encoding='utf-8') as config_file: rconfig.write(config_file) def update_network_section(self): """Update network section in tempest.conf""" rconfig = configparser.RawConfigParser() rconfig.read(self.conf_file) - if not rconfig.has_section('network'): - rconfig.add_section('network') - rconfig.set('network', 'public_network_id', self.ext_net.id) - rconfig.set('network', 'floating_network_name', self.ext_net.name) - with open(self.conf_file, 'wb') as config_file: + if self.ext_net: + if not rconfig.has_section('network'): + rconfig.add_section('network') + rconfig.set('network', 'public_network_id', self.ext_net.id) + rconfig.set('network', 'floating_network_name', self.ext_net.name) + rconfig.set('network-feature-enabled', 'floating_ips', True) + else: + if not rconfig.has_section('network-feature-enabled'): + rconfig.add_section('network-feature-enabled') + rconfig.set('network-feature-enabled', 'floating_ips', False) + with open(self.conf_file, 'w', encoding='utf-8') as config_file: rconfig.write(config_file) def update_compute_section(self): @@ -539,8 +531,25 @@ class TempestCommon(singlevm.VmReady2): rconfig.read(self.conf_file) if not rconfig.has_section('compute'): rconfig.add_section('compute') - rconfig.set('compute', 'fixed_network_name', self.network.name) - with open(self.conf_file, 'wb') as config_file: + rconfig.set( + 'compute', 'fixed_network_name', + self.network.name if self.network else env.get("EXTERNAL_NETWORK")) + with open(self.conf_file, 'w', encoding='utf-8') as config_file: + rconfig.write(config_file) + + def update_validation_section(self): + """Update validation section in tempest.conf""" + rconfig = configparser.RawConfigParser() + rconfig.read(self.conf_file) + if not rconfig.has_section('validation'): + rconfig.add_section('validation') + rconfig.set( + 'validation', 'connect_method', + 'floating' if self.ext_net else 'fixed') + rconfig.set( + 'validation', 'network_for_ssh', + self.network.name if self.network else env.get("EXTERNAL_NETWORK")) + with open(self.conf_file, 'w', encoding='utf-8') as config_file: rconfig.write(config_file) def update_scenario_section(self): @@ -548,13 +557,12 @@ class TempestCommon(singlevm.VmReady2): rconfig = configparser.RawConfigParser() rconfig.read(self.conf_file) filename = getattr( - config.CONF, '{}_image'.format(self.case_name), self.filename) + config.CONF, f'{self.case_name}_image', self.filename) if not rconfig.has_section('scenario'): rconfig.add_section('scenario') - rconfig.set('scenario', 'img_file', os.path.basename(filename)) - rconfig.set('scenario', 'img_dir', os.path.dirname(filename)) + rconfig.set('scenario', 'img_file', filename) rconfig.set('scenario', 'img_disk_format', getattr( - config.CONF, '{}_image_format'.format(self.case_name), + config.CONF, f'{self.case_name}_image_format', self.image_format)) extra_properties = self.extra_properties.copy() if env.get('IMAGE_PROPERTIES'): @@ -562,12 +570,24 @@ class TempestCommon(singlevm.VmReady2): functest_utils.convert_ini_to_dict( env.get('IMAGE_PROPERTIES'))) extra_properties.update( - getattr(config.CONF, '{}_extra_properties'.format( - self.case_name), {})) + getattr(config.CONF, f'{self.case_name}_extra_properties', {})) rconfig.set( 'scenario', 'img_properties', functest_utils.convert_dict_to_ini(extra_properties)) - with open(self.conf_file, 'wb') as config_file: + with open(self.conf_file, 'w', encoding='utf-8') as config_file: + rconfig.write(config_file) + + def update_dashboard_section(self): + """Update dashboard section in tempest.conf""" + rconfig = configparser.RawConfigParser() + rconfig.read(self.conf_file) + if env.get('DASHBOARD_URL'): + if not rconfig.has_section('dashboard'): + rconfig.add_section('dashboard') + rconfig.set('dashboard', 'dashboard_url', env.get('DASHBOARD_URL')) + else: + rconfig.set('service_available', 'horizon', False) + with open(self.conf_file, 'w', encoding='utf-8') as config_file: rconfig.write(config_file) def configure(self, **kwargs): # pylint: disable=unused-argument @@ -577,19 +597,8 @@ class TempestCommon(singlevm.VmReady2): """ if not os.path.exists(self.res_dir): os.makedirs(self.res_dir) - environ = dict( - os.environ, - OS_USERNAME=self.project.user.name, - OS_PROJECT_NAME=self.project.project.name, - OS_PROJECT_ID=self.project.project.id, - OS_PASSWORD=self.project.password) - try: - del environ['OS_TENANT_NAME'] - del environ['OS_TENANT_ID'] - except Exception: # pylint: disable=broad-except - pass self.deployment_id = rally.RallyBase.create_rally_deployment( - environ=environ) + environ=self.project.get_environ()) if not self.deployment_id: raise Exception("Deployment create failed") self.verifier_id = self.create_verifier() @@ -600,8 +609,8 @@ class TempestCommon(singlevm.VmReady2): self.deployment_dir = self.get_verifier_deployment_dir( self.verifier_id, self.deployment_id) - compute_cnt = len(self.orig_cloud.list_hypervisors()) - + compute_cnt = self.count_hypervisors() if self.count_hypervisors( + ) <= 10 else 10 self.image_alt = self.publish_image_alt() self.flavor_alt = self.create_flavor_alt() LOGGER.debug("flavor: %s", self.flavor_alt) @@ -618,25 +627,31 @@ class TempestCommon(singlevm.VmReady2): flavor_alt_id=self.flavor_alt.id, admin_role_name=self.role_name, cidr=self.cidr, domain_id=self.project.domain.id) + self.update_auth_section() self.update_network_section() self.update_compute_section() + self.update_validation_section() self.update_scenario_section() + self.update_dashboard_section() self.backup_tempest_config(self.conf_file, self.res_dir) def run(self, **kwargs): self.start_time = time.time() try: - assert super(TempestCommon, self).run( + assert super().run( **kwargs) == testcase.TestCase.EX_OK if not os.path.exists(self.res_dir): os.makedirs(self.res_dir) self.update_rally_regex() self.update_default_role() - self.update_rally_logs() + rally.RallyBase.update_rally_logs(self.res_dir) shutil.copy("/etc/rally/rally.conf", self.res_dir) self.configure(**kwargs) self.generate_test_list(**kwargs) - self.apply_tempest_blacklist() + self.apply_tempest_blacklist(TempestCommon.tempest_blacklist) + if env.get('PUBLIC_ENDPOINT_ONLY').lower() == 'true': + self.apply_tempest_blacklist( + TempestCommon.tempest_public_blacklist) self.run_verifier_tests(**kwargs) self.parse_verifier_result() rally.RallyBase.verify_report( @@ -658,15 +673,102 @@ class TempestCommon(singlevm.VmReady2): Cleanup all OpenStack objects. Should be called on completion. """ self.clean_rally_conf() + rally.RallyBase.clean_rally_logs() if self.image_alt: self.cloud.delete_image(self.image_alt) if self.flavor_alt: self.orig_cloud.delete_flavor(self.flavor_alt.id) - super(TempestCommon, self).clean() + super().clean() def is_successful(self): """The overall result of the test.""" skips = self.details.get("skipped_number", 0) if skips > 0 and self.deny_skipping: return testcase.TestCase.EX_TESTCASE_FAILED - return super(TempestCommon, self).is_successful() + if self.tests_count and ( + self.details.get("tests_number", 0) != self.tests_count): + return testcase.TestCase.EX_TESTCASE_FAILED + return super().is_successful() + + +class TempestHeat(TempestCommon): + """Tempest Heat testcase implementation class.""" + + filename_alt = ('/home/opnfv/functest/images/' + 'Fedora-Cloud-Base-30-1.2.x86_64.qcow2') + flavor_alt_ram = 512 + flavor_alt_vcpus = 1 + flavor_alt_disk = 4 + + def __init__(self, **kwargs): + super().__init__(**kwargs) + self.user2 = self.orig_cloud.create_user( + name=f'{self.case_name}-user2_{self.project.guid}', + password=self.project.password, + domain_id=self.project.domain.id) + self.orig_cloud.grant_role( + self.role_name, user=self.user2.id, + project=self.project.project.id, domain=self.project.domain.id) + if not self.orig_cloud.get_role("heat_stack_owner"): + self.role = self.orig_cloud.create_role("heat_stack_owner") + self.orig_cloud.grant_role( + "heat_stack_owner", user=self.user2.id, + project=self.project.project.id, + domain=self.project.domain.id) + + def configure(self, **kwargs): + assert self.user2 + super().configure(**kwargs) + rconfig = configparser.RawConfigParser() + rconfig.read(self.conf_file) + if not rconfig.has_section('heat_plugin'): + rconfig.add_section('heat_plugin') + # It fails if region and domain ids are unset + rconfig.set( + 'heat_plugin', 'region', + os.environ.get('OS_REGION_NAME', 'RegionOne')) + rconfig.set('heat_plugin', 'auth_url', os.environ["OS_AUTH_URL"]) + rconfig.set('heat_plugin', 'project_domain_id', self.project.domain.id) + rconfig.set('heat_plugin', 'user_domain_id', self.project.domain.id) + rconfig.set( + 'heat_plugin', 'project_domain_name', self.project.domain.name) + rconfig.set( + 'heat_plugin', 'user_domain_name', self.project.domain.name) + rconfig.set('heat_plugin', 'username', self.user2.name) + rconfig.set('heat_plugin', 'password', self.project.password) + rconfig.set('heat_plugin', 'project_name', self.project.project.name) + rconfig.set('heat_plugin', 'admin_username', self.project.user.name) + rconfig.set('heat_plugin', 'admin_password', self.project.password) + rconfig.set( + 'heat_plugin', 'admin_project_name', self.project.project.name) + rconfig.set('heat_plugin', 'image_ref', self.image_alt.id) + rconfig.set('heat_plugin', 'instance_type', self.flavor_alt.id) + rconfig.set('heat_plugin', 'minimal_image_ref', self.image.id) + rconfig.set('heat_plugin', 'minimal_instance_type', self.flavor.id) + if self.ext_net: + rconfig.set( + 'heat_plugin', 'floating_network_name', self.ext_net.name) + if self.network: + rconfig.set('heat_plugin', 'fixed_network_name', self.network.name) + rconfig.set('heat_plugin', 'fixed_subnet_name', self.subnet.name) + rconfig.set('heat_plugin', 'network_for_ssh', self.network.name) + else: + LOGGER.warning( + 'No tenant network created. ' + 'Trying EXTERNAL_NETWORK as a fallback') + rconfig.set( + 'heat_plugin', 'fixed_network_name', + env.get("EXTERNAL_NETWORK")) + rconfig.set( + 'heat_plugin', 'network_for_ssh', env.get("EXTERNAL_NETWORK")) + with open(self.conf_file, 'w', encoding='utf-8') as config_file: + rconfig.write(config_file) + self.backup_tempest_config(self.conf_file, self.res_dir) + + def clean(self): + """ + Cleanup all OpenStack objects. Should be called on completion. + """ + super().clean() + if self.user2: + self.orig_cloud.delete_user(self.user2.id) diff --git a/functest/opnfv_tests/openstack/vgpu/__init__.py b/functest/opnfv_tests/openstack/vgpu/__init__.py deleted file mode 100644 index e69de29bb..000000000 --- a/functest/opnfv_tests/openstack/vgpu/__init__.py +++ /dev/null diff --git a/functest/opnfv_tests/openstack/vgpu/vgpu.py b/functest/opnfv_tests/openstack/vgpu/vgpu.py deleted file mode 100644 index c8180a45c..000000000 --- a/functest/opnfv_tests/openstack/vgpu/vgpu.py +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env python - -# Copyright (c) 2018 Kontron and others. -# -# All rights reserved. This program and the accompanying materials -# are made available under the terms of the Apache License, Version 2.0 -# which accompanies this distribution, and is available at -# http://www.apache.org/licenses/LICENSE-2.0 - -"""vGPU testcase implementation.""" - -from __future__ import division - -import logging - -from functest.core import singlevm - - -class VGPU(singlevm.SingleVm2): - """OpenStack vGPU Test Case.""" - - __logger = logging.getLogger(__name__) - - filename = ('/home/opnfv/functest/images/' - 'ubuntu-16.04-server-cloudimg-amd64-disk1.img') - flavor_ram = 4096 - flavor_vcpus = 2 - flavor_disk = 40 - flavor_extra_specs = {'resources:VGPU': '1'} - username = 'ubuntu' - ssh_connect_loops = 12 - create_server_timeout = 300 - - def __init__(self, **kwargs): - """Initialize vGPU testcase object.""" - if "case_name" not in kwargs: - kwargs["case_name"] = "vgpu" - super(VGPU, self).__init__(**kwargs) - - def execute(self): - """ - Test if the vGPU exist. - """ - (_, stdout, stderr) = self.ssh.exec_command('lspci') - lspci_output = stdout.read() - self.__logger.debug("output:\n%s", stdout.read()) - self.__logger.debug("error:\n%s", stderr.read()) - if ('VGA compatible controller: Intel' in lspci_output or - 'VGA compatible controller: Nvidia' in lspci_output): - self.__logger.info("The VM have a vGPU") - return 0 - self.__logger.error("The VM haven't any vGPU") - return 1 diff --git a/functest/opnfv_tests/openstack/vmtp/vmtp.py b/functest/opnfv_tests/openstack/vmtp/vmtp.py index 3462ec063..9833cc72a 100644 --- a/functest/opnfv_tests/openstack/vmtp/vmtp.py +++ b/functest/opnfv_tests/openstack/vmtp/vmtp.py @@ -33,6 +33,7 @@ from xtesting.core import testcase from functest.core import singlevm from functest.utils import env +from functest.utils import functest_utils class Vmtp(singlevm.VmReady2): @@ -50,17 +51,18 @@ class Vmtp(singlevm.VmReady2): flavor_vcpus = 1 flavor_disk = 0 create_server_timeout = 300 + ssh_retry_timeout = 240 def __init__(self, **kwargs): if "case_name" not in kwargs: kwargs["case_name"] = 'vmtp' - super(Vmtp, self).__init__(**kwargs) - self.config = "{}/vmtp.conf".format(self.res_dir) + super().__init__(**kwargs) + self.config = f"{self.res_dir}/vmtp.conf" (_, self.privkey_filename) = tempfile.mkstemp() (_, self.pubkey_filename) = tempfile.mkstemp() def check_requirements(self): - if len(self.orig_cloud.list_hypervisors()) < 2: + if self.count_hypervisors() < 2: self.__logger.warning("Vmtp requires at least 2 hypervisors") self.is_skipped = True self.project.clean() @@ -75,7 +77,7 @@ class Vmtp(singlevm.VmReady2): assert self.cloud assert self.ext_net self.router = self.cloud.create_router( - name='{}-router_{}'.format(self.case_name, self.guid), + name=f'{self.case_name}-router_{self.guid}', ext_gateway_net_id=self.ext_net.id) self.__logger.debug("router: %s", self.router) @@ -85,13 +87,13 @@ class Vmtp(singlevm.VmReady2): Raises: Exception on error """ assert self.cloud - name = "vmtp_{}".format(self.guid) + name = f"vmtp_{self.guid}" self.__logger.info("Creating keypair with name: '%s'", name) keypair = self.cloud.create_keypair(name) self.__logger.debug("keypair: %s", keypair) - with open(self.privkey_filename, 'w') as key_file: + with open(self.privkey_filename, 'w', encoding='utf-8') as key_file: key_file.write(keypair.private_key) - with open(self.pubkey_filename, 'w') as key_file: + with open(self.pubkey_filename, 'w', encoding='utf-8') as key_file: key_file.write(keypair.public_key) self.cloud.delete_keypair(keypair.id) @@ -104,27 +106,28 @@ class Vmtp(singlevm.VmReady2): if not os.path.exists(self.res_dir): os.makedirs(self.res_dir) cmd = ['vmtp', '-sc'] - output = subprocess.check_output(cmd) + output = subprocess.check_output(cmd).decode("utf-8") self.__logger.info("%s\n%s", " ".join(cmd), output) - with open(self.config, "w+") as conf: - vmtp_conf = yaml.load(output) + with open(self.config, "w+", encoding='utf-8') as conf: + vmtp_conf = yaml.full_load(output) vmtp_conf["private_key_file"] = self.privkey_filename vmtp_conf["public_key_file"] = self.pubkey_filename vmtp_conf["image_name"] = str(self.image.name) vmtp_conf["router_name"] = str(self.router.name) vmtp_conf["flavor_type"] = str(self.flavor.name) vmtp_conf["internal_network_name"] = [ - "pns-internal-net_{}".format(self.guid), - "pns-internal-net2_{}".format(self.guid)] - vmtp_conf["vm_name_client"] = "TestClient_{}".format(self.guid) - vmtp_conf["vm_name_server"] = "TestServer_{}".format(self.guid) - vmtp_conf["security_group_name"] = "pns-security{}".format( - self.guid) + f"pns-internal-net_{self.guid}", + f"pns-internal-net2_{self.guid}"] + vmtp_conf["vm_name_client"] = f"TestClient_{self.guid}" + vmtp_conf["vm_name_server"] = f"TestServer_{self.guid}" + vmtp_conf["security_group_name"] = f"pns-security{self.guid}" vmtp_conf["dns_nameservers"] = [env.get('NAMESERVER')] vmtp_conf["generic_retry_count"] = self.create_server_timeout // 2 + vmtp_conf["ssh_retry_count"] = self.ssh_retry_timeout // 2 conf.write(yaml.dump(vmtp_conf)) def run_vmtp(self): + # pylint: disable=unexpected-keyword-arg """Run Vmtp and generate charts Raises: Exception on error @@ -135,24 +138,34 @@ class Vmtp(singlevm.VmReady2): OS_USERNAME=self.project.user.name, OS_PROJECT_NAME=self.project.project.name, OS_PROJECT_ID=self.project.project.id, + OS_PROJECT_DOMAIN_NAME=self.project.domain.name, + OS_USER_DOMAIN_NAME=self.project.domain.name, OS_PASSWORD=self.project.password) if not new_env["OS_AUTH_URL"].endswith(('v3', 'v3/')): - new_env["OS_AUTH_URL"] = "{}/v3".format(new_env["OS_AUTH_URL"]) + new_env["OS_AUTH_URL"] = f'{new_env["OS_AUTH_URL"]}/v3' try: del new_env['OS_TENANT_NAME'] del new_env['OS_TENANT_ID'] except Exception: # pylint: disable=broad-except pass - cmd = ['vmtp', '-d', '--json', '{}/vmtp.json'.format(self.res_dir), + cmd = ['vmtp', '-d', '--json', f'{self.res_dir}/vmtp.json', '-c', self.config] + if env.get("VMTP_HYPERVISORS"): + hypervisors = functest_utils.convert_ini_to_list( + env.get("VMTP_HYPERVISORS")) + for hypervisor in hypervisors: + cmd.extend(["--hypervisor", hypervisor]) + self.__logger.debug("cmd: %s", cmd) output = subprocess.check_output( - cmd, stderr=subprocess.STDOUT, env=new_env) + cmd, stderr=subprocess.STDOUT, env=new_env).decode("utf-8") self.__logger.info("%s\n%s", " ".join(cmd), output) - cmd = ['vmtp_genchart', '-c', '{}/vmtp.html'.format(self.res_dir), - '{}/vmtp.json'.format(self.res_dir)] - output = subprocess.check_output(cmd, stderr=subprocess.STDOUT) + cmd = ['vmtp_genchart', '-c', f'{self.res_dir}/vmtp.html', + f'{self.res_dir}/vmtp.json'] + output = subprocess.check_output( + cmd, stderr=subprocess.STDOUT).decode("utf-8") self.__logger.info("%s\n%s", " ".join(cmd), output) - with open('{}/vmtp.json'.format(self.res_dir), 'r') as res_file: + with open(f'{self.res_dir}/vmtp.json', 'r', + encoding='utf-8') as res_file: self.details = json.load(res_file) def run(self, **kwargs): @@ -160,7 +173,7 @@ class Vmtp(singlevm.VmReady2): status = testcase.TestCase.EX_RUN_ERROR try: assert self.cloud - assert super(Vmtp, self).run(**kwargs) == self.EX_OK + assert super().run(**kwargs) == self.EX_OK status = testcase.TestCase.EX_RUN_ERROR if self.orig_cloud.get_role("admin"): role_name = "admin" @@ -179,7 +192,8 @@ class Vmtp(singlevm.VmReady2): status = testcase.TestCase.EX_OK except subprocess.CalledProcessError as cpe: self.__logger.error( - "Exception when calling %s\n%s", cpe.cmd, cpe.output) + "Exception when calling %s\n%s", cpe.cmd, + cpe.output.decode("utf-8")) self.result = 0 except Exception: # pylint: disable=broad-except self.__logger.exception("Cannot run vmtp") @@ -190,10 +204,10 @@ class Vmtp(singlevm.VmReady2): def clean(self): try: assert self.cloud - super(Vmtp, self).clean() + super().clean() os.remove(self.privkey_filename) os.remove(self.pubkey_filename) - self.cloud.delete_network("pns-internal-net_{}".format(self.guid)) - self.cloud.delete_network("pns-internal-net2_{}".format(self.guid)) + self.cloud.delete_network(f"pns-internal-net_{self.guid}") + self.cloud.delete_network(f"pns-internal-net2_{self.guid}") except Exception: # pylint: disable=broad-except pass diff --git a/functest/opnfv_tests/openstack/vping/vping_ssh.py b/functest/opnfv_tests/openstack/vping/vping_ssh.py index 6420013a0..ad64348c4 100644 --- a/functest/opnfv_tests/openstack/vping/vping_ssh.py +++ b/functest/opnfv_tests/openstack/vping/vping_ssh.py @@ -29,13 +29,13 @@ class VPingSSH(singlevm.SingleVm2): """Initialize testcase.""" if "case_name" not in kwargs: kwargs["case_name"] = "vping_ssh" - super(VPingSSH, self).__init__(**kwargs) + super().__init__(**kwargs) self.vm2 = None def prepare(self): - super(VPingSSH, self).prepare() + super().prepare() self.vm2 = self.boot_vm( - '{}-vm2_{}'.format(self.case_name, self.guid), + f'{self.case_name}-vm2_{self.guid}', security_groups=[self.sec.id]) def execute(self): @@ -44,12 +44,13 @@ class VPingSSH(singlevm.SingleVm2): Returns: ping exit codes """ assert self.ssh - (_, stdout, stderr) = self.ssh.exec_command( - 'ping -c 1 {}'.format( - self.vm2.private_v4 or self.vm2.addresses[ - self.network.name][0].addr)) - self.__logger.info("output:\n%s", stdout.read()) - self.__logger.info("error:\n%s", stderr.read()) + if not self.check_regex_in_console(self.vm2.name): + return 1 + ip4 = self.vm2.private_v4 or self.vm2.addresses[ + self.network.name][0].addr + (_, stdout, stderr) = self.ssh.exec_command(f'ping -c 1 {ip4}') + self.__logger.info("output:\n%s", stdout.read().decode("utf-8")) + self.__logger.info("error:\n%s", stderr.read().decode("utf-8")) return stdout.channel.recv_exit_status() def clean(self): @@ -58,4 +59,4 @@ class VPingSSH(singlevm.SingleVm2): self.cloud.delete_server( self.vm2, wait=True, timeout=getattr(config.CONF, 'vping_vm_delete_timeout')) - super(VPingSSH, self).clean() + super().clean() diff --git a/functest/opnfv_tests/openstack/vping/vping_userdata.py b/functest/opnfv_tests/openstack/vping/vping_userdata.py index a58184c59..8a8f26f37 100644 --- a/functest/opnfv_tests/openstack/vping/vping_userdata.py +++ b/functest/opnfv_tests/openstack/vping/vping_userdata.py @@ -26,7 +26,7 @@ class VPingUserdata(singlevm.VmReady2): def __init__(self, **kwargs): if "case_name" not in kwargs: kwargs["case_name"] = "vping_userdata" - super(VPingUserdata, self).__init__(**kwargs) + super().__init__(**kwargs) self.logger = logging.getLogger(__name__) self.vm1 = None self.vm2 = None @@ -39,12 +39,12 @@ class VPingUserdata(singlevm.VmReady2): """ try: assert self.cloud - assert super(VPingUserdata, self).run( + assert super().run( **kwargs) == testcase.TestCase.EX_OK self.result = 0 self.vm1 = self.boot_vm() self.vm2 = self.boot_vm( - '{}-vm2_{}'.format(self.case_name, self.guid), + f'{self.case_name}-vm2_{self.guid}', userdata=self._get_userdata()) result = self._do_vping() @@ -79,16 +79,16 @@ class VPingUserdata(singlevm.VmReady2): self.logger.info("vPing detected!") exit_code = testcase.TestCase.EX_OK break - elif "failed to read iid from metadata" in p_console or tries > 5: + if "failed to read iid from metadata" in p_console or tries > 5: self.logger.info("Failed to read iid from metadata") break - elif sec == getattr(config.CONF, 'vping_ping_timeout'): + if sec == getattr(config.CONF, 'vping_ping_timeout'): self.logger.info("Timeout reached.") break - elif sec % 10 == 0: + if sec % 10 == 0: if "request failed" in p_console: self.logger.debug( - "It seems userdata is not supported in nova boot. " + + "It seems userdata is not supported in nova boot. " "Waiting a bit...") tries += 1 else: @@ -104,13 +104,15 @@ class VPingUserdata(singlevm.VmReady2): """ Returns the post VM creation script to be added into the VM's userdata :param test_ip: the IP value to substitute into the script - :return: the bash script contents + :return: the shell script contents """ + ip4 = self.vm1.private_v4 or self.vm1.addresses[ + self.network.name][0].addr if self.vm1.private_v4 or self.vm1.addresses[ self.network.name][0].addr: return ("#!/bin/sh\n\n" "while true; do\n" - " ping -c 1 %s 2>&1 >/dev/null\n" + f" ping -c 1 {ip4} 2>&1 >/dev/null\n" " RES=$?\n" " if [ \"Z$RES\" = \"Z0\" ] ; then\n" " echo 'vPing OK'\n" @@ -119,9 +121,7 @@ class VPingUserdata(singlevm.VmReady2): " echo 'vPing KO'\n" " fi\n" " sleep 1\n" - "done\n" % str( - self.vm1.private_v4 or self.vm1.addresses[ - self.network.name][0].addr)) + "done\n") return None def clean(self): @@ -134,4 +134,4 @@ class VPingUserdata(singlevm.VmReady2): self.cloud.delete_server( self.vm2, wait=True, timeout=getattr(config.CONF, 'vping_vm_delete_timeout')) - super(VPingUserdata, self).clean() + super().clean() |