diff --git a/manila_tempest_tests/tests/api/base.py b/manila_tempest_tests/tests/api/base.py index 862a1693..7915eaf3 100755 --- a/manila_tempest_tests/tests/api/base.py +++ b/manila_tempest_tests/tests/api/base.py @@ -14,21 +14,15 @@ # under the License. import copy -import inspect -import ipaddress import re import traceback -from oslo_concurrency import lockutils from oslo_log import log import six -from tempest.common import credentials_factory as common_creds from tempest import config from tempest.lib.common import cred_client -from tempest.lib.common import dynamic_creds from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils from tempest.lib import exceptions from tempest import test @@ -99,20 +93,6 @@ class handle_cleanup_exceptions(object): return True # Suppress error if any -def network_synchronized(f): - - def wrapped_func(self, *args, **kwargs): - - # Use lock assuming reusage of common network. - @lockutils.synchronized("manila_network_lock", external=True) - def source_func(self, *args, **kwargs): - return f(self, *args, **kwargs) - - return source_func(self, *args, **kwargs) - - return wrapped_func - - skip_if_microversion_not_supported = utils.skip_if_microversion_not_supported skip_if_microversion_lt = utils.skip_if_microversion_lt @@ -146,36 +126,6 @@ class BaseSharesTest(test.BaseTestCase): "Microversion must be greater than or equal to '%s'." % microversion) - @classmethod - def _get_dynamic_creds(cls, name, network_resources=None): - identity_version = CONF.identity.auth_version - if identity_version == 'v3': - identity_uri = CONF.identity.uri_v3 - identity_admin_endpoint_type = CONF.identity.v3_endpoint_type - elif identity_version == 'v2': - identity_uri = CONF.identity.uri - identity_admin_endpoint_type = CONF.identity.v2_admin_endpoint_type - - return dynamic_creds.DynamicCredentialProvider( - identity_version=identity_version, - name=name, - network_resources=network_resources, - credentials_domain=CONF.auth.default_credentials_domain_name, - admin_role=CONF.identity.admin_role, - admin_creds=common_creds.get_configured_admin_credentials(), - identity_admin_domain_scope=CONF.identity.admin_domain_scope, - identity_admin_role=CONF.identity.admin_role, - extra_roles=None, - neutron_available=CONF.service_available.neutron, - create_networks=( - CONF.share.create_networks_when_multitenancy_enabled), - project_network_cidr=CONF.network.project_network_cidr, - project_network_mask_bits=CONF.network.project_network_mask_bits, - public_network_id=CONF.network.public_network_id, - resource_prefix='tempest', - identity_admin_endpoint_type=identity_admin_endpoint_type, - identity_uri=identity_uri) - @classmethod def skip_checks(cls): super(BaseSharesTest, cls).skip_checks() @@ -191,6 +141,24 @@ class BaseSharesTest(test.BaseTestCase): msg = "Missing API credentials in configuration." raise cls.skipException(msg) + @classmethod + def setup_credentials(cls): + # This call is used to tell the credential allocator to create + # network resources for this test case. NOTE: it must go before the + # super call, to override decisions in the base classes. + network_resources = {} + if (CONF.share.multitenancy_enabled and + CONF.share.create_networks_when_multitenancy_enabled): + # We're testing a DHSS=True driver, and manila is configured with + # NeutronNetworkPlugin (or a derivative) that supports creating + # share networks with project neutron networks, so lets ask for + # neutron network resources to be created with test credentials + network_resources.update({'network': True, + 'subnet': True, + 'router': True}) + cls.set_network_resources(**network_resources) + super(BaseSharesTest, cls).setup_credentials() + @classmethod def setup_clients(cls): super(BaseSharesTest, cls).setup_clients() @@ -198,46 +166,26 @@ class BaseSharesTest(test.BaseTestCase): # Initialise share clients for test credentials cls.shares_client = os.share_v1.SharesClient() cls.shares_v2_client = os.share_v2.SharesV2Client() - cls.admin_nc = cls.admin_snc = cls.admin_rc = cls.admin_net_cred = None # Initialise network clients for test credentials + cls.networks_client = None + cls.subnets_client = None if CONF.service_available.neutron: cls.networks_client = os.network.NetworksClient() cls.subnets_client = os.network.SubnetsClient() - if CONF.share.multitenancy_enabled and ( - CONF.auth.use_dynamic_credentials): - # Get admin credentials so we can create neutron networks - # dynamically if/when needed - (cls.admin_nc, cls.admin_snc, - cls.admin_rc, cls.admin_net_cred) = ( - cls.get_network_clients_with_isolated_creds()) - else: - cls.networks_client = None - cls.subnets_client = None - - cls.project_network_cidr = CONF.network.project_network_cidr - cls.public_network_id = CONF.network.public_network_id - - if CONF.identity.auth_version == 'v3': - project_id = os.auth_provider.auth_data[1]['project']['id'] - else: - project_id = os.auth_provider.auth_data[1]['token']['tenant']['id'] - cls.tenant_id = project_id - cls.user_id = os.auth_provider.auth_data[1]['user']['id'] + # If DHSS=True, create a share network and set it in the client + # for easy access. if CONF.share.multitenancy_enabled: if (not CONF.service_available.neutron and CONF.share.create_networks_when_multitenancy_enabled): - raise cls.skipException("Neutron support is required") + raise cls.skipException( + "Neutron support is required when " + "CONF.share.create_networks_when_multitenancy_enabled " + "is set to True") share_network_id = cls.provide_share_network( - cls.shares_v2_client, cls.networks_client) + cls.shares_client, cls.networks_client) cls.shares_client.share_network_id = share_network_id cls.shares_v2_client.share_network_id = share_network_id - resource = { - "type": "share_network", - "id": share_network_id, - "client": cls.shares_v2_client, - } - cls.class_resources.insert(0, resource) def setUp(self): super(BaseSharesTest, self).setUp() @@ -247,8 +195,6 @@ class BaseSharesTest(test.BaseTestCase): @classmethod def resource_cleanup(cls): cls.clear_resources(cls.class_resources) - if cls.admin_net_cred: - cls.admin_net_cred.clear_creds() super(BaseSharesTest, cls).resource_cleanup() @classmethod @@ -335,170 +281,73 @@ class BaseSharesTest(test.BaseTestCase): cls.method_resources.insert(0, resource) @classmethod - @network_synchronized def provide_share_network(cls, shares_client, networks_client, ignore_multitenancy_config=False): - """Used for finding/creating share network for multitenant driver. + """Get or create share network for DHSS=True drivers - This method creates/gets entity share-network for one tenant. This - share-network will be used for creation of service vm. - - :param shares_client: shares client, which requires share-network - :param networks_client: network client from same tenant as shares - :param ignore_multitenancy_config: provide a share network regardless - of 'multitenancy_enabled' configuration value. + When testing DHSS=True (multitenancy_enabled) drivers, shares must + be requested on share networks. :returns: str -- share network id for shares_client tenant - :returns: None -- if single-tenant driver used + :returns: None -- if single-tenant driver (DHSS=False) is used """ - sc = shares_client - sn_name = "autogenerated_by_tempest" - if (not ignore_multitenancy_config and not CONF.share.multitenancy_enabled): - # Assumed usage of a single-tenant driver + # Assumed usage of a single-tenant driver (DHSS=False) return None - else: - if sc.share_network_id: - # Share-network already exists, use it - return sc.share_network_id - elif not CONF.share.create_networks_when_multitenancy_enabled: - # We need a new share network, but don't need to associate - # any neutron networks to it - this configuration is used - # when manila is configured with "StandaloneNetworkPlugin" - # or "NeutronSingleNetworkPlugin" where all tenants share - # a single backend network where shares are exported. - sn_desc = "This share-network was created by tempest" - sn = cls.create_share_network(cleanup_in_class=True, - add_security_services=True, - name=sn_name, - description=sn_desc) - return sn['id'] - else: - net_id = subnet_id = None - # Retrieve non-public network list owned by the tenant - search_opts = {'tenant_id': sc.tenant_id, 'shared': False} - tenant_networks = ( - networks_client.list_networks( - **search_opts).get('networks', []) - ) - tenant_networks_with_subnet = ( - [n for n in tenant_networks if n['subnets']] - ) - if tenant_networks_with_subnet: - net_id = tenant_networks_with_subnet[0]['id'] - subnet_id = tenant_networks_with_subnet[0]['subnets'][0] + if shares_client.share_network_id: + # Share-network already exists, use it + return shares_client.share_network_id - if net_id is None or subnet_id is None: - network, subnet, router = ( - cls.provide_network_resources_for_tenant_id( - sc.tenant_id) - ) - net_id = network['network']['id'] - subnet_id = subnet['subnet']['id'] + sn_name = "autogenerated_by_tempest" + sn_desc = "This share-network was created by tempest" - # Create suitable share-network - sn_desc = "This share-network was created by tempest" - sn = cls.create_share_network(cleanup_in_class=True, - add_security_services=True, - name=sn_name, - description=sn_desc, - neutron_net_id=net_id, - neutron_subnet_id=subnet_id) + if not CONF.share.create_networks_when_multitenancy_enabled: + # We need a new share network, but don't need to associate + # any neutron networks to it - this configuration is used + # when manila is configured with "StandaloneNetworkPlugin" + # or "NeutronSingleNetworkPlugin" where all tenants share + # a single backend network where shares are exported. + sn = cls.create_share_network(cleanup_in_class=True, + client=shares_client, + add_security_services=True, + name=sn_name, + description=sn_desc) + return sn['id'] - return sn['id'] + # Retrieve non-public network list owned by the tenant + filters = {'project_id': shares_client.tenant_id, + 'shared': False} + tenant_networks = ( + networks_client.list_networks(**filters).get('networks', []) + ) + tenant_networks_with_subnet = ( + [n for n in tenant_networks if n['subnets']] + ) - @classmethod - def provide_network_resources_for_tenant_id(cls, tenant_id): - """Used for creating neutron network resources. + if not tenant_networks_with_subnet: + # This can only occur if using tempest's pre-provisioned + # credentials and not allocating networks to them + raise cls.skipException( + "Test credentials must provide at least one " + "non-shared project network with a valid subnet when " + "CONF.share.create_networks_when_multitenancy_enabled is " + "set to True.") - This method creates a suitable network, subnet and router - to be used when providing a new share network in the tempest. - The tempest conf project_network_cidr is very important - in order to create a reachable network. Also, this method will - cleanup the neutron resources in the class teardown. + net_id = tenant_networks_with_subnet[0]['id'] + subnet_id = tenant_networks_with_subnet[0]['subnets'][0] - :param tenant_id: tenant_id to be used for network resources creation - :returns network, subnet, router: the neutron resources created - """ + # Create suitable share-network + sn = cls.create_share_network(cleanup_in_class=True, + client=shares_client, + add_security_services=True, + name=sn_name, + description=sn_desc, + neutron_net_id=net_id, + neutron_subnet_id=subnet_id) - network = cls.admin_nc.create_network( - tenant_id=tenant_id, - name="tempest-net") - cls.addClassResourceCleanup( - test_utils.call_and_ignore_notfound_exc, - cls.admin_nc.delete_network, - network['network']['id']) - - subnet = cls.admin_snc.create_subnet( - network_id=network['network']['id'], - tenant_id=tenant_id, - cidr=str(cls.project_network_cidr), - name="tempest-subnet", - ip_version=(ipaddress.ip_network( - six.text_type(cls.project_network_cidr)).version)) - cls.addClassResourceCleanup( - test_utils.call_and_ignore_notfound_exc, - cls.admin_snc.delete_subnet, - subnet['subnet']['id']) - - router = None - if cls.public_network_id: - kwargs = {'name': "tempest-router", - 'tenant_id': tenant_id, - 'external_gateway_info': cls.public_network_id} - body = cls.routers_client.create_router(**kwargs) - router = body['router'] - - cls.admin_rc.add_router_interface( - router['id'], - subnet_id=subnet['subnet']['id']) - cls.addClassResourceCleanup( - test_utils.call_and_ignore_notfound_exc, - cls.admin_rc.delete_router, router) - cls.addClassResourceCleanup( - test_utils.call_and_ignore_notfound_exc, - cls.admin_rc.remove_router_interface, - router['id'], - subnet_id=subnet['subnet']['id']) - - return network, subnet, router - - @classmethod - def get_network_clients_with_isolated_creds(cls, - name=None, - type_of_creds='admin'): - """Creates isolated creds and provide network clients. - - :param name: name, will be used for naming ic and related stuff - :param type_of_creds: defines the type of creds to be created - :returns: NetworksClient, SubnetsClient, RoutersClient, - Isolated Credentials - """ - - if name is None: - # Get name of test method - name = inspect.stack()[1][3] - if len(name) > 32: - name = name[0:32] - # Choose type of isolated creds - ic = cls._get_dynamic_creds(name) - if "admin" in type_of_creds: - creds = ic.get_admin_creds().credentials - elif "alt" in type_of_creds: - creds = ic.get_alt_creds().credentials - else: - creds = ic.get_credentials(type_of_creds).credentials - ic.type_of_creds = type_of_creds - # create client with isolated creds - os = clients.Clients(creds) - - net_client = os.network.NetworksClient() - subnet_client = os.network.SubnetsClient() - router_client = os.network.RoutersClient() - - return net_client, subnet_client, router_client, ic + return sn['id'] @classmethod def _create_share(cls, share_protocol=None, size=None, name=None, @@ -1403,12 +1252,6 @@ class BaseSharesMixedTest(BaseSharesTest): cls.alt_shares_v2_client, cls.os_alt.networks_client) cls.alt_shares_client.share_network_id = alt_share_network_id cls.alt_shares_v2_client.share_network_id = alt_share_network_id - resource = { - "type": "share_network", - "id": alt_share_network_id, - "client": cls.alt_shares_v2_client, - } - cls.class_resources.insert(0, resource) @classmethod def create_user_and_get_client(cls, project=None):