diff --git a/unit_tests/charm_tests/test_tempest.py b/unit_tests/charm_tests/test_tempest.py index 3c4c161..ac6962e 100644 --- a/unit_tests/charm_tests/test_tempest.py +++ b/unit_tests/charm_tests/test_tempest.py @@ -15,25 +15,22 @@ import mock import unittest -import zaza.openstack.charm_tests.tempest.setup as tempest_setup +import zaza.openstack.charm_tests.tempest.utils as tempest_utils -class TestTempestSetup(unittest.TestCase): - """Test class to encapsulate testing Mysql test utils.""" - - def setUp(self): - super(TestTempestSetup, self).setUp() +class TestTempestUtils(unittest.TestCase): + """Test class to encapsulate testing Tempest test utils.""" def test_add_environment_var_config_with_missing_variable(self): ctxt = {} with self.assertRaises(Exception) as context: - tempest_setup.add_environment_var_config(ctxt, ['swift']) + tempest_utils._add_environment_var_config(ctxt, ['swift']) self.assertEqual( ('Environment variables [TEST_SWIFT_IP] must all be ' 'set to run this test'), str(context.exception)) - @mock.patch.object(tempest_setup.deployment_env, 'get_deployment_context') + @mock.patch.object(tempest_utils.deployment_env, 'get_deployment_context') def test_add_environment_var_config_with_all_variables( self, get_deployment_context): @@ -45,10 +42,10 @@ class TestTempestSetup(unittest.TestCase): 'TEST_NAME_SERVER': 'test', 'TEST_CIDR_PRIV': 'test', } - tempest_setup.add_environment_var_config(ctxt, ['neutron']) + tempest_utils._add_environment_var_config(ctxt, ['neutron']) self.assertEqual(ctxt['test_gateway'], 'test') - @mock.patch.object(tempest_setup.deployment_env, 'get_deployment_context') + @mock.patch.object(tempest_utils.deployment_env, 'get_deployment_context') def test_add_environment_var_config_with_some_variables( self, get_deployment_context): @@ -59,7 +56,7 @@ class TestTempestSetup(unittest.TestCase): 'TEST_CIDR_PRIV': 'test', } with self.assertRaises(Exception) as context: - tempest_setup.add_environment_var_config(ctxt, ['neutron']) + tempest_utils._add_environment_var_config(ctxt, ['neutron']) self.assertEqual( ('Environment variables [TEST_CIDR_EXT, TEST_FIP_RANGE] must ' 'all be set to run this test'), diff --git a/zaza/openstack/charm_tests/tempest/setup.py b/zaza/openstack/charm_tests/tempest/setup.py index 7ae0ba3..627290c 100644 --- a/zaza/openstack/charm_tests/tempest/setup.py +++ b/zaza/openstack/charm_tests/tempest/setup.py @@ -14,315 +14,9 @@ """Code for configuring and initializing tempest.""" -import jinja2 -import urllib.parse -import os -import subprocess +import logging -import zaza.utilities.deployment_env as deployment_env -import zaza.openstack.utilities.juju as juju_utils -import zaza.openstack.utilities.openstack as openstack_utils import zaza.openstack.charm_tests.tempest.utils as tempest_utils -import zaza.openstack.charm_tests.glance.setup as glance_setup - -SETUP_ENV_VARS = { - 'neutron': ['TEST_GATEWAY', 'TEST_CIDR_EXT', 'TEST_FIP_RANGE', - 'TEST_NAME_SERVER', 'TEST_CIDR_PRIV'], - 'swift': ['TEST_SWIFT_IP'], -} - -IGNORABLE_VARS = ['TEST_CIDR_PRIV'] - -TEMPEST_FLAVOR_NAME = 'm1.tempest' -TEMPEST_ALT_FLAVOR_NAME = 'm2.tempest' -TEMPEST_SVC_LIST = ['ceilometer', 'cinder', 'glance', 'heat', 'horizon', - 'ironic', 'neutron', 'nova', 'octavia', 'sahara', 'swift', - 'trove', 'zaqar'] - - -def add_application_ips(ctxt): - """Add application access IPs to context. - - :param ctxt: Context dictionary - :type ctxt: dict - :returns: None - :rtype: None - """ - ctxt['keystone'] = juju_utils.get_application_ip('keystone') - ctxt['dashboard'] = juju_utils.get_application_ip('openstack-dashboard') - ctxt['ncc'] = juju_utils.get_application_ip('nova-cloud-controller') - - -def add_nova_config(ctxt, keystone_session): - """Add nova config to context. - - :param ctxt: Context dictionary - :type ctxt: dict - :param keystone_session: keystoneauth1.session.Session object - :type: keystoneauth1.session.Session - :returns: None - :rtype: None - """ - nova_client = openstack_utils.get_nova_session_client( - keystone_session) - for flavor in nova_client.flavors.list(): - if flavor.name == TEMPEST_FLAVOR_NAME: - ctxt['flavor_ref'] = flavor.id - if flavor.name == TEMPEST_ALT_FLAVOR_NAME: - ctxt['flavor_ref_alt'] = flavor.id - - -def add_neutron_config(ctxt, keystone_session): - """Add neutron config to context. - - :param ctxt: Context dictionary - :type ctxt: dict - :param keystone_session: keystoneauth1.session.Session object - :type: keystoneauth1.session.Session - :returns: None - :rtype: None - """ - current_release = openstack_utils.get_os_release() - focal_ussuri = openstack_utils.get_os_release('focal_ussuri') - neutron_client = openstack_utils.get_neutron_session_client( - keystone_session) - net = neutron_client.find_resource("network", "ext_net") - ctxt['ext_net'] = net['id'] - router = neutron_client.find_resource("router", "provider-router") - ctxt['provider_router_id'] = router['id'] - # For focal+ with OVN, we use the same settings as upstream gate. - # This is because the l3_agent_scheduler extension is only - # applicable for OVN when conventional layer-3 agent enabled: - # https://docs.openstack.org/networking-ovn/2.0.1/features.html - # This enables test_list_show_extensions to run successfully. - if current_release >= focal_ussuri: - extensions = ('address-scope,agent,allowed-address-pairs,' - 'auto-allocated-topology,availability_zone,' - 'binding,default-subnetpools,external-net,' - 'extra_dhcp_opt,multi-provider,net-mtu,' - 'network_availability_zone,network-ip-availability,' - 'port-security,provider,quotas,rbac-address-scope,' - 'rbac-policies,standard-attr-revisions,security-group,' - 'standard-attr-description,subnet_allocation,' - 'standard-attr-tag,standard-attr-timestamp,trunk,' - 'quota_details,router,extraroute,ext-gw-mode,' - 'fip-port-details,pagination,sorting,project-id,' - 'dns-integration,qos') - ctxt['neutron_api_extensions'] = extensions - else: - ctxt['neutron_api_extensions'] = 'all' - - -def add_glance_config(ctxt, keystone_session): - """Add glance config to context. - - :param ctxt: Context dictionary - :type ctxt: dict - :param keystone_session: keystoneauth1.session.Session object - :type: keystoneauth1.session.Session - :returns: None - :rtype: None - """ - glance_client = openstack_utils.get_glance_session_client( - keystone_session) - image = openstack_utils.get_images_by_name( - glance_client, glance_setup.CIRROS_IMAGE_NAME) - image_alt = openstack_utils.get_images_by_name( - glance_client, glance_setup.CIRROS_ALT_IMAGE_NAME) - if image: - ctxt['image_id'] = image[0].id - if image_alt: - ctxt['image_alt_id'] = image_alt[0].id - - -def add_cinder_config(ctxt, keystone_session): - """Add cinder config to context. - - :param ctxt: Context dictionary - :type ctxt: dict - :param keystone_session: keystoneauth1.session.Session object - :type: keystoneauth1.session.Session - :returns: None - :rtype: None - """ - volume_types = ['volumev2', 'volumev3'] - keystone_client = openstack_utils.get_keystone_session_client( - keystone_session) - for volume_type in volume_types: - service = keystone_client.services.list(type=volume_type) - if service: - ctxt['catalog_type'] = volume_type - break - - -def add_keystone_config(ctxt, keystone_session): - """Add keystone config to context. - - :param ctxt: Context dictionary - :type ctxt: dict - :param keystone_session: keystoneauth1.session.Session object - :type: keystoneauth1.session.Session - :returns: None - :rtype: None - """ - keystone_client = openstack_utils.get_keystone_session_client( - keystone_session) - domain = keystone_client.domains.find(name="admin_domain") - ctxt['default_domain_id'] = domain.id - - -def add_octavia_config(ctxt): - """Add octavia config to context. - - :param ctxt: Context dictionary - :type ctxt: dict - :returns: None - :rtype: None - :raises: subprocess.CalledProcessError - """ - subprocess.check_call([ - 'curl', - "{}:80/swift/v1/fixtures/test_server.bin".format( - ctxt['test_swift_ip']), - '-o', "{}/test_server.bin".format(ctxt['workspace_path']) - ]) - subprocess.check_call([ - 'chmod', '+x', - "{}/test_server.bin".format(ctxt['workspace_path']) - ]) - - -def get_service_list(keystone_session): - """Retrieve list of services from keystone. - - :param keystone_session: keystoneauth1.session.Session object - :type: keystoneauth1.session.Session - :returns: None - :rtype: None - """ - keystone_client = openstack_utils.get_keystone_session_client( - keystone_session) - return [s.name for s in keystone_client.services.list() if s.enabled] - - -def add_environment_var_config(ctxt, services): - """Add environment variable config to context. - - :param ctxt: Context dictionary - :type ctxt: dict - :returns: None - :rtype: None - """ - deploy_env = deployment_env.get_deployment_context() - missing_vars = [] - for svc, env_vars in SETUP_ENV_VARS.items(): - if svc in services: - for var in env_vars: - value = deploy_env.get(var) - if value: - ctxt[var.lower()] = value - else: - if var not in IGNORABLE_VARS: - missing_vars.append(var) - if missing_vars: - raise ValueError( - ("Environment variables [{}] must all be set to run this" - " test").format(', '.join(missing_vars))) - - -def add_auth_config(ctxt): - """Add authorization config to context. - - :param ctxt: Context dictionary - :type ctxt: dict - :returns: None - :rtype: None - """ - overcloud_auth = openstack_utils.get_overcloud_auth() - ctxt['proto'] = urllib.parse.urlparse(overcloud_auth['OS_AUTH_URL']).scheme - ctxt['admin_username'] = overcloud_auth['OS_USERNAME'] - ctxt['admin_password'] = overcloud_auth['OS_PASSWORD'] - if overcloud_auth['API_VERSION'] == 3: - ctxt['admin_project_name'] = overcloud_auth['OS_PROJECT_NAME'] - ctxt['admin_domain_name'] = overcloud_auth['OS_DOMAIN_NAME'] - ctxt['default_credentials_domain_name'] = ( - overcloud_auth['OS_PROJECT_DOMAIN_NAME']) - - -def get_tempest_context(workspace_path): - """Generate the tempest config context. - - :returns: Context dictionary - :rtype: dict - """ - keystone_session = openstack_utils.get_overcloud_keystone_session() - ctxt = {} - ctxt['workspace_path'] = workspace_path - ctxt_funcs = { - 'nova': add_nova_config, - 'neutron': add_neutron_config, - 'glance': add_glance_config, - 'cinder': add_cinder_config, - 'keystone': add_keystone_config} - ctxt['enabled_services'] = get_service_list(keystone_session) - if set(['cinderv2', 'cinderv3']) \ - .intersection(set(ctxt['enabled_services'])): - ctxt['enabled_services'].append('cinder') - ctxt['disabled_services'] = list( - set(TEMPEST_SVC_LIST) - set(ctxt['enabled_services'])) - add_application_ips(ctxt) - for svc_name, ctxt_func in ctxt_funcs.items(): - if svc_name in ctxt['enabled_services']: - ctxt_func(ctxt, keystone_session) - add_environment_var_config(ctxt, ctxt['enabled_services']) - add_auth_config(ctxt) - if 'octavia' in ctxt['enabled_services']: - add_octavia_config(ctxt) - return ctxt - - -def render_tempest_config(target_file, ctxt, template_name): - """Render tempest config for specified config file and template. - - :param target_file: Name of file to render config to - :type target_file: str - :param ctxt: Context dictionary - :type ctxt: dict - :param template_name: Name of template file - :type template_name: str - :returns: None - :rtype: None - """ - jenv = jinja2.Environment(loader=jinja2.PackageLoader( - 'zaza.openstack', - 'charm_tests/tempest/templates')) - template = jenv.get_template(template_name) - with open(target_file, 'w') as f: - f.write(template.render(ctxt)) - - -def setup_tempest(tempest_template, accounts_template): - """Initialize tempest and render tempest config. - - :param tempest_template: tempest.conf template - :type tempest_template: module - :param accounts_template: accounts.yaml template - :type accounts_template: module - :returns: None - :rtype: None - """ - workspace_name, workspace_path = tempest_utils.get_workspace() - tempest_utils.destroy_workspace(workspace_name, workspace_path) - tempest_utils.init_workspace(workspace_path) - context = get_tempest_context(workspace_path) - render_tempest_config( - os.path.join(workspace_path, 'etc/tempest.conf'), - context, - tempest_template) - render_tempest_config( - os.path.join(workspace_path, 'etc/accounts.yaml'), - context, - accounts_template) def render_tempest_config_keystone_v2(): @@ -331,7 +25,11 @@ def render_tempest_config_keystone_v2(): :returns: None :rtype: None """ - setup_tempest('tempest_v2.j2', 'accounts.j2') + logging.warning( + 'The render_tempest_config_keystone_v2 config step is deprecated. ' + 'This is now directly done by the TempestTestWithKeystoneV2 test ' + 'class.') + tempest_utils.render_tempest_config_keystone_v2() def render_tempest_config_keystone_v3(): @@ -340,4 +38,8 @@ def render_tempest_config_keystone_v3(): :returns: None :rtype: None """ - setup_tempest('tempest_v3.j2', 'accounts.j2') + logging.warning( + 'The render_tempest_config_keystone_v3 config step is deprecated. ' + 'This is now directly done by the TempestTestWithKeystoneV3 test ' + 'class.') + tempest_utils.render_tempest_config_keystone_v3() diff --git a/zaza/openstack/charm_tests/tempest/tests.py b/zaza/openstack/charm_tests/tempest/tests.py index 5c83ec0..b7fc859 100644 --- a/zaza/openstack/charm_tests/tempest/tests.py +++ b/zaza/openstack/charm_tests/tempest/tests.py @@ -14,6 +14,7 @@ """Code for running tempest tests.""" +import logging import os import subprocess @@ -24,8 +25,8 @@ import zaza.openstack.charm_tests.tempest.utils as tempest_utils import tempfile -class TempestTest(): - """Tempest test class.""" +class TempestTestBase(): + """Tempest test base class.""" test_runner = zaza.charm_lifecycle.test.DIRECT @@ -89,3 +90,54 @@ class TempestTest(): if not keep_workspace or keep_workspace is not True: tempest_utils.destroy_workspace(workspace_name, workspace_path) return result + + +class TempestTestWithKeystoneV2(TempestTestBase): + """Tempest test class to validate an OpenStack setup with Keystone V2.""" + + def run(self): + """Run tempest tests as specified in tests/tests.yaml. + + See TempestTestBase.run() for the available test options. + + :returns: Status of tempest run + :rtype: bool + """ + tempest_utils.render_tempest_config_keystone_v2() + return super().run() + + +class TempestTestWithKeystoneV3(TempestTestBase): + """Tempest test class to validate an OpenStack setup with Keystone V2.""" + + def run(self): + """Run tempest tests as specified in tests/tests.yaml. + + See TempestTestBase.run() for the available test options. + + :returns: Status of tempest run + :rtype: bool + """ + tempest_utils.render_tempest_config_keystone_v3() + return super().run() + + +class TempestTest(TempestTestBase): + """Tempest test class. + + Requires running one of the render_tempest_config_keystone_v? Zaza + configuration steps before. + """ + + def run(self): + """Run tempest tests as specified in tests/tests.yaml. + + See TempestTestBase.run() for the available test options. + + :returns: Status of tempest run + :rtype: bool + """ + logging.warning( + 'The TempestTest test class is deprecated. Please use one of the ' + 'TempestTestWithKeystoneV? test classes instead.') + return super().run() diff --git a/zaza/openstack/charm_tests/tempest/utils.py b/zaza/openstack/charm_tests/tempest/utils.py index 52ae126..28ad65e 100644 --- a/zaza/openstack/charm_tests/tempest/utils.py +++ b/zaza/openstack/charm_tests/tempest/utils.py @@ -14,12 +14,50 @@ """Utility code for working with tempest workspaces.""" +import jinja2 import os from pathlib import Path import shutil import subprocess +import urllib.parse import zaza.model as model +import zaza.utilities.deployment_env as deployment_env +import zaza.openstack.utilities.juju as juju_utils +import zaza.openstack.utilities.openstack as openstack_utils +import zaza.openstack.charm_tests.glance.setup as glance_setup + +SETUP_ENV_VARS = { + 'neutron': ['TEST_GATEWAY', 'TEST_CIDR_EXT', 'TEST_FIP_RANGE', + 'TEST_NAME_SERVER', 'TEST_CIDR_PRIV'], + 'swift': ['TEST_SWIFT_IP'], +} + +IGNORABLE_VARS = ['TEST_CIDR_PRIV'] + +TEMPEST_FLAVOR_NAME = 'm1.tempest' +TEMPEST_ALT_FLAVOR_NAME = 'm2.tempest' +TEMPEST_SVC_LIST = ['ceilometer', 'cinder', 'glance', 'heat', 'horizon', + 'ironic', 'neutron', 'nova', 'octavia', 'sahara', 'swift', + 'trove', 'zaqar'] + + +def render_tempest_config_keystone_v2(): + """Render tempest config for Keystone V2 API. + + :returns: None + :rtype: None + """ + _setup_tempest('tempest_v2.j2', 'accounts.j2') + + +def render_tempest_config_keystone_v3(): + """Render tempest config for Keystone V3 API. + + :returns: None + :rtype: None + """ + _setup_tempest('tempest_v3.j2', 'accounts.j2') def get_workspace(): @@ -53,7 +91,7 @@ def destroy_workspace(workspace_name, workspace_path): shutil.rmtree(workspace_path) -def init_workspace(workspace_path): +def _init_workspace(workspace_path): """Initialize tempest workspace. :param workspace_path: directory path where workspace is stored @@ -65,3 +103,288 @@ def init_workspace(workspace_path): subprocess.check_call(['tempest', 'init', workspace_path]) except subprocess.CalledProcessError: pass + + +def _setup_tempest(tempest_template, accounts_template): + """Initialize tempest and render tempest config. + + :param tempest_template: tempest.conf template + :type tempest_template: module + :param accounts_template: accounts.yaml template + :type accounts_template: module + :returns: None + :rtype: None + """ + workspace_name, workspace_path = get_workspace() + destroy_workspace(workspace_name, workspace_path) + _init_workspace(workspace_path) + context = _get_tempest_context(workspace_path) + _render_tempest_config( + os.path.join(workspace_path, 'etc/tempest.conf'), + context, + tempest_template) + _render_tempest_config( + os.path.join(workspace_path, 'etc/accounts.yaml'), + context, + accounts_template) + + +def _get_tempest_context(workspace_path): + """Generate the tempest config context. + + :returns: Context dictionary + :rtype: dict + """ + keystone_session = openstack_utils.get_overcloud_keystone_session() + ctxt = {} + ctxt['workspace_path'] = workspace_path + ctxt_funcs = { + 'nova': _add_nova_config, + 'neutron': _add_neutron_config, + 'glance': _add_glance_config, + 'cinder': _add_cinder_config, + 'keystone': _add_keystone_config} + ctxt['enabled_services'] = _get_service_list(keystone_session) + if set(['cinderv2', 'cinderv3']) \ + .intersection(set(ctxt['enabled_services'])): + ctxt['enabled_services'].append('cinder') + ctxt['disabled_services'] = list( + set(TEMPEST_SVC_LIST) - set(ctxt['enabled_services'])) + _add_application_ips(ctxt) + for svc_name, ctxt_func in ctxt_funcs.items(): + if svc_name in ctxt['enabled_services']: + ctxt_func(ctxt, keystone_session) + _add_environment_var_config(ctxt, ctxt['enabled_services']) + _add_auth_config(ctxt) + if 'octavia' in ctxt['enabled_services']: + _add_octavia_config(ctxt) + return ctxt + + +def _render_tempest_config(target_file, ctxt, template_name): + """Render tempest config for specified config file and template. + + :param target_file: Name of file to render config to + :type target_file: str + :param ctxt: Context dictionary + :type ctxt: dict + :param template_name: Name of template file + :type template_name: str + :returns: None + :rtype: None + """ + jenv = jinja2.Environment(loader=jinja2.PackageLoader( + 'zaza.openstack', + 'charm_tests/tempest/templates')) + template = jenv.get_template(template_name) + with open(target_file, 'w') as f: + f.write(template.render(ctxt)) + + +def _add_application_ips(ctxt): + """Add application access IPs to context. + + :param ctxt: Context dictionary + :type ctxt: dict + :returns: None + :rtype: None + """ + ctxt['keystone'] = juju_utils.get_application_ip('keystone') + ctxt['dashboard'] = juju_utils.get_application_ip('openstack-dashboard') + ctxt['ncc'] = juju_utils.get_application_ip('nova-cloud-controller') + + +def _add_nova_config(ctxt, keystone_session): + """Add nova config to context. + + :param ctxt: Context dictionary + :type ctxt: dict + :param keystone_session: keystoneauth1.session.Session object + :type: keystoneauth1.session.Session + :returns: None + :rtype: None + """ + nova_client = openstack_utils.get_nova_session_client( + keystone_session) + for flavor in nova_client.flavors.list(): + if flavor.name == TEMPEST_FLAVOR_NAME: + ctxt['flavor_ref'] = flavor.id + if flavor.name == TEMPEST_ALT_FLAVOR_NAME: + ctxt['flavor_ref_alt'] = flavor.id + + +def _add_neutron_config(ctxt, keystone_session): + """Add neutron config to context. + + :param ctxt: Context dictionary + :type ctxt: dict + :param keystone_session: keystoneauth1.session.Session object + :type: keystoneauth1.session.Session + :returns: None + :rtype: None + """ + current_release = openstack_utils.get_os_release() + focal_ussuri = openstack_utils.get_os_release('focal_ussuri') + neutron_client = openstack_utils.get_neutron_session_client( + keystone_session) + net = neutron_client.find_resource("network", "ext_net") + ctxt['ext_net'] = net['id'] + router = neutron_client.find_resource("router", "provider-router") + ctxt['provider_router_id'] = router['id'] + # For focal+ with OVN, we use the same settings as upstream gate. + # This is because the l3_agent_scheduler extension is only + # applicable for OVN when conventional layer-3 agent enabled: + # https://docs.openstack.org/networking-ovn/2.0.1/features.html + # This enables test_list_show_extensions to run successfully. + if current_release >= focal_ussuri: + extensions = ('address-scope,agent,allowed-address-pairs,' + 'auto-allocated-topology,availability_zone,' + 'binding,default-subnetpools,external-net,' + 'extra_dhcp_opt,multi-provider,net-mtu,' + 'network_availability_zone,network-ip-availability,' + 'port-security,provider,quotas,rbac-address-scope,' + 'rbac-policies,standard-attr-revisions,security-group,' + 'standard-attr-description,subnet_allocation,' + 'standard-attr-tag,standard-attr-timestamp,trunk,' + 'quota_details,router,extraroute,ext-gw-mode,' + 'fip-port-details,pagination,sorting,project-id,' + 'dns-integration,qos') + ctxt['neutron_api_extensions'] = extensions + else: + ctxt['neutron_api_extensions'] = 'all' + + +def _add_glance_config(ctxt, keystone_session): + """Add glance config to context. + + :param ctxt: Context dictionary + :type ctxt: dict + :param keystone_session: keystoneauth1.session.Session object + :type: keystoneauth1.session.Session + :returns: None + :rtype: None + """ + glance_client = openstack_utils.get_glance_session_client( + keystone_session) + image = openstack_utils.get_images_by_name( + glance_client, glance_setup.CIRROS_IMAGE_NAME) + image_alt = openstack_utils.get_images_by_name( + glance_client, glance_setup.CIRROS_ALT_IMAGE_NAME) + if image: + ctxt['image_id'] = image[0].id + if image_alt: + ctxt['image_alt_id'] = image_alt[0].id + + +def _add_cinder_config(ctxt, keystone_session): + """Add cinder config to context. + + :param ctxt: Context dictionary + :type ctxt: dict + :param keystone_session: keystoneauth1.session.Session object + :type: keystoneauth1.session.Session + :returns: None + :rtype: None + """ + volume_types = ['volumev2', 'volumev3'] + keystone_client = openstack_utils.get_keystone_session_client( + keystone_session) + for volume_type in volume_types: + service = keystone_client.services.list(type=volume_type) + if service: + ctxt['catalog_type'] = volume_type + break + + +def _add_keystone_config(ctxt, keystone_session): + """Add keystone config to context. + + :param ctxt: Context dictionary + :type ctxt: dict + :param keystone_session: keystoneauth1.session.Session object + :type: keystoneauth1.session.Session + :returns: None + :rtype: None + """ + keystone_client = openstack_utils.get_keystone_session_client( + keystone_session) + domain = keystone_client.domains.find(name="admin_domain") + ctxt['default_domain_id'] = domain.id + + +def _add_octavia_config(ctxt): + """Add octavia config to context. + + :param ctxt: Context dictionary + :type ctxt: dict + :returns: None + :rtype: None + :raises: subprocess.CalledProcessError + """ + subprocess.check_call([ + 'curl', + "{}:80/swift/v1/fixtures/test_server.bin".format( + ctxt['test_swift_ip']), + '-o', "{}/test_server.bin".format(ctxt['workspace_path']) + ]) + subprocess.check_call([ + 'chmod', '+x', + "{}/test_server.bin".format(ctxt['workspace_path']) + ]) + + +def _add_environment_var_config(ctxt, services): + """Add environment variable config to context. + + :param ctxt: Context dictionary + :type ctxt: dict + :returns: None + :rtype: None + """ + deploy_env = deployment_env.get_deployment_context() + missing_vars = [] + for svc, env_vars in SETUP_ENV_VARS.items(): + if svc in services: + for var in env_vars: + value = deploy_env.get(var) + if value: + ctxt[var.lower()] = value + else: + if var not in IGNORABLE_VARS: + missing_vars.append(var) + if missing_vars: + raise ValueError( + ("Environment variables [{}] must all be set to run this" + " test").format(', '.join(missing_vars))) + + +def _add_auth_config(ctxt): + """Add authorization config to context. + + :param ctxt: Context dictionary + :type ctxt: dict + :returns: None + :rtype: None + """ + overcloud_auth = openstack_utils.get_overcloud_auth() + ctxt['proto'] = urllib.parse.urlparse(overcloud_auth['OS_AUTH_URL']).scheme + ctxt['admin_username'] = overcloud_auth['OS_USERNAME'] + ctxt['admin_password'] = overcloud_auth['OS_PASSWORD'] + if overcloud_auth['API_VERSION'] == 3: + ctxt['admin_project_name'] = overcloud_auth['OS_PROJECT_NAME'] + ctxt['admin_domain_name'] = overcloud_auth['OS_DOMAIN_NAME'] + ctxt['default_credentials_domain_name'] = ( + overcloud_auth['OS_PROJECT_DOMAIN_NAME']) + + +def _get_service_list(keystone_session): + """Retrieve list of services from keystone. + + :param keystone_session: keystoneauth1.session.Session object + :type: keystoneauth1.session.Session + :returns: None + :rtype: None + """ + keystone_client = openstack_utils.get_keystone_session_client( + keystone_session) + return [s.name for s in keystone_client.services.list() if s.enabled]