Add network support to the accounts providers
This commits adds support for specifying the network to use with a user/tenant into the accounts.yaml file. You can only specify a single network which will be the network used for all that requires a pre-existing network. This also means regardless of which cred provider is configured the fixed_network can assume a TestResource object will be returned from a get_creds call. As part of this change a common method to return the full network dict from a just a network name is abstracted out into tempest.common.fixed_network module since this same method is needed to have the accounts file provide a network by name. Partially-implements: bp test-accounts-continued Change-Id: I6f5ac1239d18f2935847b385a08de608f40fdda5
This commit is contained in:
parent
a47c3edc2d
commit
f83f35c9e2
|
@ -33,3 +33,5 @@
|
||||||
password: 'test_password'
|
password: 'test_password'
|
||||||
types:
|
types:
|
||||||
- 'admin'
|
- 'admin'
|
||||||
|
resources:
|
||||||
|
network: 'public'
|
||||||
|
|
|
@ -69,7 +69,10 @@ class ListServerFiltersTestJSON(base.BaseV2ComputeTest):
|
||||||
|
|
||||||
network = cls.get_tenant_network()
|
network = cls.get_tenant_network()
|
||||||
if network:
|
if network:
|
||||||
cls.fixed_network_name = network['name']
|
if network.get('name'):
|
||||||
|
cls.fixed_network_name = network['name']
|
||||||
|
else:
|
||||||
|
cls.fixed_network_name = None
|
||||||
else:
|
else:
|
||||||
cls.fixed_network_name = None
|
cls.fixed_network_name = None
|
||||||
network_kwargs = fixed_network.set_networks_kwarg(network)
|
network_kwargs = fixed_network.set_networks_kwarg(network)
|
||||||
|
|
|
@ -19,7 +19,9 @@ from oslo_concurrency import lockutils
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
|
from tempest import clients
|
||||||
from tempest.common import cred_provider
|
from tempest.common import cred_provider
|
||||||
|
from tempest.common import fixed_network
|
||||||
from tempest import config
|
from tempest import config
|
||||||
from tempest import exceptions
|
from tempest import exceptions
|
||||||
|
|
||||||
|
@ -60,15 +62,18 @@ class Accounts(cred_provider.CredentialProvider):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_hash_dict(cls, accounts):
|
def get_hash_dict(cls, accounts):
|
||||||
hash_dict = {'roles': {}, 'creds': {}}
|
hash_dict = {'roles': {}, 'creds': {}, 'networks': {}}
|
||||||
# Loop over the accounts read from the yaml file
|
# Loop over the accounts read from the yaml file
|
||||||
for account in accounts:
|
for account in accounts:
|
||||||
roles = []
|
roles = []
|
||||||
types = []
|
types = []
|
||||||
|
resources = []
|
||||||
if 'roles' in account:
|
if 'roles' in account:
|
||||||
roles = account.pop('roles')
|
roles = account.pop('roles')
|
||||||
if 'types' in account:
|
if 'types' in account:
|
||||||
types = account.pop('types')
|
types = account.pop('types')
|
||||||
|
if 'resources' in account:
|
||||||
|
resources = account.pop('resources')
|
||||||
temp_hash = hashlib.md5()
|
temp_hash = hashlib.md5()
|
||||||
temp_hash.update(str(account))
|
temp_hash.update(str(account))
|
||||||
temp_hash_key = temp_hash.hexdigest()
|
temp_hash_key = temp_hash.hexdigest()
|
||||||
|
@ -91,6 +96,13 @@ class Accounts(cred_provider.CredentialProvider):
|
||||||
CONF.object_storage.reseller_admin_role,
|
CONF.object_storage.reseller_admin_role,
|
||||||
temp_hash_key,
|
temp_hash_key,
|
||||||
hash_dict)
|
hash_dict)
|
||||||
|
# Populate the network subdict
|
||||||
|
for resource in resources:
|
||||||
|
if resource == 'network':
|
||||||
|
hash_dict['networks'][temp_hash_key] = resources[resource]
|
||||||
|
else:
|
||||||
|
LOG.warning('Unkown resource type %s, ignoring this field'
|
||||||
|
% resource)
|
||||||
return hash_dict
|
return hash_dict
|
||||||
|
|
||||||
def is_multi_user(self):
|
def is_multi_user(self):
|
||||||
|
@ -174,7 +186,7 @@ class Accounts(cred_provider.CredentialProvider):
|
||||||
"Account file %s doesn't exist" % CONF.auth.test_accounts_file)
|
"Account file %s doesn't exist" % CONF.auth.test_accounts_file)
|
||||||
useable_hashes = self._get_match_hash_list(roles)
|
useable_hashes = self._get_match_hash_list(roles)
|
||||||
free_hash = self._get_free_hash(useable_hashes)
|
free_hash = self._get_free_hash(useable_hashes)
|
||||||
return self.hash_dict['creds'][free_hash]
|
return self._wrap_creds_with_network(free_hash)
|
||||||
|
|
||||||
@lockutils.synchronized('test_accounts_io', external=True)
|
@lockutils.synchronized('test_accounts_io', external=True)
|
||||||
def remove_hash(self, hash_string):
|
def remove_hash(self, hash_string):
|
||||||
|
@ -209,20 +221,16 @@ class Accounts(cred_provider.CredentialProvider):
|
||||||
def get_primary_creds(self):
|
def get_primary_creds(self):
|
||||||
if self.isolated_creds.get('primary'):
|
if self.isolated_creds.get('primary'):
|
||||||
return self.isolated_creds.get('primary')
|
return self.isolated_creds.get('primary')
|
||||||
creds = self._get_creds()
|
net_creds = self._get_creds()
|
||||||
primary_credential = cred_provider.get_credentials(
|
self.isolated_creds['primary'] = net_creds
|
||||||
identity_version=self.identity_version, **creds)
|
return net_creds
|
||||||
self.isolated_creds['primary'] = primary_credential
|
|
||||||
return primary_credential
|
|
||||||
|
|
||||||
def get_alt_creds(self):
|
def get_alt_creds(self):
|
||||||
if self.isolated_creds.get('alt'):
|
if self.isolated_creds.get('alt'):
|
||||||
return self.isolated_creds.get('alt')
|
return self.isolated_creds.get('alt')
|
||||||
creds = self._get_creds()
|
net_creds = self._get_creds()
|
||||||
alt_credential = cred_provider.get_credentials(
|
self.isolated_creds['alt'] = net_creds
|
||||||
identity_version=self.identity_version, **creds)
|
return net_creds
|
||||||
self.isolated_creds['alt'] = alt_credential
|
|
||||||
return alt_credential
|
|
||||||
|
|
||||||
def get_creds_by_roles(self, roles, force_new=False):
|
def get_creds_by_roles(self, roles, force_new=False):
|
||||||
roles = list(set(roles))
|
roles = list(set(roles))
|
||||||
|
@ -235,11 +243,9 @@ class Accounts(cred_provider.CredentialProvider):
|
||||||
elif exist_creds and force_new:
|
elif exist_creds and force_new:
|
||||||
new_index = str(roles) + '-' + str(len(self.isolated_creds))
|
new_index = str(roles) + '-' + str(len(self.isolated_creds))
|
||||||
self.isolated_creds[new_index] = exist_creds
|
self.isolated_creds[new_index] = exist_creds
|
||||||
creds = self._get_creds(roles=roles)
|
net_creds = self._get_creds(roles=roles)
|
||||||
role_credential = cred_provider.get_credentials(
|
self.isolated_creds[str(roles)] = net_creds
|
||||||
identity_version=self.identity_version, **creds)
|
return net_creds
|
||||||
self.isolated_creds[str(roles)] = role_credential
|
|
||||||
return role_credential
|
|
||||||
|
|
||||||
def clear_isolated_creds(self):
|
def clear_isolated_creds(self):
|
||||||
for creds in self.isolated_creds.values():
|
for creds in self.isolated_creds.values():
|
||||||
|
@ -259,6 +265,19 @@ class Accounts(cred_provider.CredentialProvider):
|
||||||
def admin_available(self):
|
def admin_available(self):
|
||||||
return self.is_role_available(CONF.identity.admin_role)
|
return self.is_role_available(CONF.identity.admin_role)
|
||||||
|
|
||||||
|
def _wrap_creds_with_network(self, hash):
|
||||||
|
creds_dict = self.hash_dict['creds'][hash]
|
||||||
|
credential = cred_provider.get_credentials(
|
||||||
|
identity_version=self.identity_version, **creds_dict)
|
||||||
|
net_creds = cred_provider.TestResources(credential)
|
||||||
|
net_clients = clients.Manager(credentials=credential)
|
||||||
|
compute_network_client = net_clients.networks_client
|
||||||
|
net_name = self.hash_dict['networks'].get(hash, None)
|
||||||
|
network = fixed_network.get_network_from_name(
|
||||||
|
net_name, compute_network_client)
|
||||||
|
net_creds.set_resources(network=network)
|
||||||
|
return net_creds
|
||||||
|
|
||||||
|
|
||||||
class NotLockingAccounts(Accounts):
|
class NotLockingAccounts(Accounts):
|
||||||
"""Credentials provider which always returns the first and second
|
"""Credentials provider which always returns the first and second
|
||||||
|
@ -289,8 +308,9 @@ class NotLockingAccounts(Accounts):
|
||||||
return self.isolated_creds.get('primary')
|
return self.isolated_creds.get('primary')
|
||||||
primary_credential = cred_provider.get_configured_credentials(
|
primary_credential = cred_provider.get_configured_credentials(
|
||||||
credential_type='user', identity_version=self.identity_version)
|
credential_type='user', identity_version=self.identity_version)
|
||||||
self.isolated_creds['primary'] = primary_credential
|
self.isolated_creds['primary'] = cred_provider.TestResources(
|
||||||
return primary_credential
|
primary_credential)
|
||||||
|
return self.isolated_creds['primary']
|
||||||
|
|
||||||
def get_alt_creds(self):
|
def get_alt_creds(self):
|
||||||
if self.isolated_creds.get('alt'):
|
if self.isolated_creds.get('alt'):
|
||||||
|
@ -298,8 +318,9 @@ class NotLockingAccounts(Accounts):
|
||||||
alt_credential = cred_provider.get_configured_credentials(
|
alt_credential = cred_provider.get_configured_credentials(
|
||||||
credential_type='alt_user',
|
credential_type='alt_user',
|
||||||
identity_version=self.identity_version)
|
identity_version=self.identity_version)
|
||||||
self.isolated_creds['alt'] = alt_credential
|
self.isolated_creds['alt'] = cred_provider.TestResources(
|
||||||
return alt_credential
|
alt_credential)
|
||||||
|
return self.isolated_creds['alt']
|
||||||
|
|
||||||
def clear_isolated_creds(self):
|
def clear_isolated_creds(self):
|
||||||
self.isolated_creds = {}
|
self.isolated_creds = {}
|
||||||
|
@ -307,8 +328,8 @@ class NotLockingAccounts(Accounts):
|
||||||
def get_admin_creds(self):
|
def get_admin_creds(self):
|
||||||
creds = cred_provider.get_configured_credentials(
|
creds = cred_provider.get_configured_credentials(
|
||||||
"identity_admin", fill_in=False)
|
"identity_admin", fill_in=False)
|
||||||
self.isolated_creds['admin'] = creds
|
self.isolated_creds['admin'] = cred_provider.TestResources(creds)
|
||||||
return creds
|
return self.isolated_creds['admin']
|
||||||
|
|
||||||
def get_creds_by_roles(self, roles, force_new=False):
|
def get_creds_by_roles(self, roles, force_new=False):
|
||||||
msg = "Credentials being specified through the config file can not be"\
|
msg = "Credentials being specified through the config file can not be"\
|
||||||
|
|
|
@ -16,15 +16,67 @@ from oslo_log import log as logging
|
||||||
from tempest_lib.common.utils import misc as misc_utils
|
from tempest_lib.common.utils import misc as misc_utils
|
||||||
from tempest_lib import exceptions as lib_exc
|
from tempest_lib import exceptions as lib_exc
|
||||||
|
|
||||||
from tempest.common import isolated_creds
|
|
||||||
from tempest import config
|
from tempest import config
|
||||||
from tempest import exceptions
|
|
||||||
|
|
||||||
CONF = config.CONF
|
CONF = config.CONF
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def get_network_from_name(name, compute_networks_client):
|
||||||
|
"""Get a full network dict from just a network name
|
||||||
|
|
||||||
|
:param str name: the name of the network to use
|
||||||
|
:param NetworksClientJSON compute_networks_client: The network client
|
||||||
|
object to use for making the network lists api request
|
||||||
|
:return: The full dictionary for the network in question, unless the
|
||||||
|
network for the supplied name can not be found. In which case a dict
|
||||||
|
with just the name will be returned.
|
||||||
|
:rtype: dict
|
||||||
|
"""
|
||||||
|
caller = misc_utils.find_test_caller()
|
||||||
|
if not name:
|
||||||
|
network = {'name': name}
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
resp = compute_networks_client.list_networks(name=name)
|
||||||
|
if isinstance(resp, list):
|
||||||
|
networks = resp
|
||||||
|
elif isinstance(resp, dict):
|
||||||
|
networks = resp['networks']
|
||||||
|
else:
|
||||||
|
raise lib_exc.NotFound()
|
||||||
|
if len(networks) > 0:
|
||||||
|
network = networks[0]
|
||||||
|
else:
|
||||||
|
msg = "Network with name: %s not found" % name
|
||||||
|
if caller:
|
||||||
|
LOG.warn('(%s) %s' % (caller, msg))
|
||||||
|
else:
|
||||||
|
LOG.warn(msg)
|
||||||
|
raise lib_exc.NotFound()
|
||||||
|
# To be consistent with network isolation, add name is only
|
||||||
|
# label is available
|
||||||
|
name = network.get('name', network.get('label'))
|
||||||
|
if name:
|
||||||
|
network['name'] = name
|
||||||
|
else:
|
||||||
|
raise lib_exc.NotFound()
|
||||||
|
except lib_exc.NotFound:
|
||||||
|
# In case of nova network, if the fixed_network_name is not
|
||||||
|
# owned by the tenant, and the network client is not an admin
|
||||||
|
# one, list_networks will not find it
|
||||||
|
msg = ('Unable to find network %s. '
|
||||||
|
'Starting instance without specifying a network.' %
|
||||||
|
name)
|
||||||
|
if caller:
|
||||||
|
LOG.info('(%s) %s' % (caller, msg))
|
||||||
|
else:
|
||||||
|
LOG.info(msg)
|
||||||
|
network = {'name': name}
|
||||||
|
return network
|
||||||
|
|
||||||
|
|
||||||
def get_tenant_network(creds_provider, compute_networks_client):
|
def get_tenant_network(creds_provider, compute_networks_client):
|
||||||
"""Get a network usable by the primary tenant
|
"""Get a network usable by the primary tenant
|
||||||
|
|
||||||
|
@ -38,15 +90,9 @@ def get_tenant_network(creds_provider, compute_networks_client):
|
||||||
"""
|
"""
|
||||||
caller = misc_utils.find_test_caller()
|
caller = misc_utils.find_test_caller()
|
||||||
fixed_network_name = CONF.compute.fixed_network_name
|
fixed_network_name = CONF.compute.fixed_network_name
|
||||||
network = None
|
net_creds = creds_provider.get_primary_creds()
|
||||||
# NOTE(andreaf) get_primary_network will always be available once
|
network = getattr(net_creds, 'network', None)
|
||||||
# bp test-accounts-continued is implemented
|
if not network or not network.get('name'):
|
||||||
if (isinstance(creds_provider, isolated_creds.IsolatedCreds) and
|
|
||||||
(CONF.service_available.neutron and
|
|
||||||
not CONF.service_available.ironic)):
|
|
||||||
# tenant_allow_isolation == True, so network is defined
|
|
||||||
network = creds_provider.get_primary_creds().network
|
|
||||||
else:
|
|
||||||
if fixed_network_name:
|
if fixed_network_name:
|
||||||
msg = ('No valid network provided or created, defaulting to '
|
msg = ('No valid network provided or created, defaulting to '
|
||||||
'fixed_network_name')
|
'fixed_network_name')
|
||||||
|
@ -54,41 +100,8 @@ def get_tenant_network(creds_provider, compute_networks_client):
|
||||||
LOG.debug('(%s) %s' % (caller, msg))
|
LOG.debug('(%s) %s' % (caller, msg))
|
||||||
else:
|
else:
|
||||||
LOG.debug(msg)
|
LOG.debug(msg)
|
||||||
try:
|
network = get_network_from_name(fixed_network_name,
|
||||||
resp = compute_networks_client.list_networks(
|
compute_networks_client)
|
||||||
name=fixed_network_name)
|
|
||||||
if isinstance(resp, list):
|
|
||||||
networks = resp
|
|
||||||
elif isinstance(resp, dict):
|
|
||||||
networks = resp['networks']
|
|
||||||
else:
|
|
||||||
raise lib_exc.NotFound()
|
|
||||||
if len(networks) > 0:
|
|
||||||
network = networks[0]
|
|
||||||
else:
|
|
||||||
msg = "Configured fixed_network_name not found"
|
|
||||||
if caller:
|
|
||||||
msg = '(%s) %s' % (caller, msg)
|
|
||||||
raise exceptions.InvalidConfiguration(msg)
|
|
||||||
# To be consistent with network isolation, add name is only
|
|
||||||
# label is available
|
|
||||||
name = network.get('name', network.get('label'))
|
|
||||||
if name:
|
|
||||||
network['name'] = name
|
|
||||||
else:
|
|
||||||
raise lib_exc.NotFound()
|
|
||||||
except lib_exc.NotFound:
|
|
||||||
# In case of nova network, if the fixed_network_name is not
|
|
||||||
# owned by the tenant, and the network client is not an admin
|
|
||||||
# one, list_networks will not find it
|
|
||||||
msg = ('Unable to find network %s. '
|
|
||||||
'Starting instance without specifying a network.' %
|
|
||||||
fixed_network_name)
|
|
||||||
if caller:
|
|
||||||
LOG.info('(%s) %s' % (caller, msg))
|
|
||||||
else:
|
|
||||||
LOG.info(msg)
|
|
||||||
network = {'name': fixed_network_name}
|
|
||||||
msg = ('Found network %s available for tenant' % network)
|
msg = ('Found network %s available for tenant' % network)
|
||||||
if caller:
|
if caller:
|
||||||
LOG.info('(%s) %s' % (caller, msg))
|
LOG.info('(%s) %s' % (caller, msg))
|
||||||
|
|
|
@ -23,11 +23,13 @@ from oslotest import mockpatch
|
||||||
|
|
||||||
from tempest import auth
|
from tempest import auth
|
||||||
from tempest.common import accounts
|
from tempest.common import accounts
|
||||||
|
from tempest.common import cred_provider
|
||||||
from tempest import config
|
from tempest import config
|
||||||
from tempest import exceptions
|
from tempest import exceptions
|
||||||
from tempest.services.identity.v2.json import token_client
|
from tempest.services.identity.v2.json import token_client
|
||||||
from tempest.tests import base
|
from tempest.tests import base
|
||||||
from tempest.tests import fake_config
|
from tempest.tests import fake_config
|
||||||
|
from tempest.tests import fake_http
|
||||||
from tempest.tests import fake_identity
|
from tempest.tests import fake_identity
|
||||||
|
|
||||||
|
|
||||||
|
@ -37,6 +39,9 @@ class TestAccount(base.TestCase):
|
||||||
super(TestAccount, self).setUp()
|
super(TestAccount, self).setUp()
|
||||||
self.useFixture(fake_config.ConfigFixture())
|
self.useFixture(fake_config.ConfigFixture())
|
||||||
self.stubs.Set(config, 'TempestConfigPrivate', fake_config.FakePrivate)
|
self.stubs.Set(config, 'TempestConfigPrivate', fake_config.FakePrivate)
|
||||||
|
self.fake_http = fake_http.fake_httplib2(return_type=200)
|
||||||
|
self.stubs.Set(token_client.TokenClientJSON, 'raw_request',
|
||||||
|
fake_identity._fake_v2_response)
|
||||||
self.useFixture(lockutils_fixtures.ExternalLockFixture())
|
self.useFixture(lockutils_fixtures.ExternalLockFixture())
|
||||||
self.test_accounts = [
|
self.test_accounts = [
|
||||||
{'username': 'test_user1', 'tenant_name': 'test_tenant1',
|
{'username': 'test_user1', 'tenant_name': 'test_tenant1',
|
||||||
|
@ -63,6 +68,11 @@ class TestAccount(base.TestCase):
|
||||||
'password': 'p', 'roles': [cfg.CONF.identity.admin_role]},
|
'password': 'p', 'roles': [cfg.CONF.identity.admin_role]},
|
||||||
{'username': 'test_user12', 'tenant_name': 'test_tenant12',
|
{'username': 'test_user12', 'tenant_name': 'test_tenant12',
|
||||||
'password': 'p', 'roles': [cfg.CONF.identity.admin_role]},
|
'password': 'p', 'roles': [cfg.CONF.identity.admin_role]},
|
||||||
|
{'username': 'test_user13', 'tenant_name': 'test_tenant13',
|
||||||
|
'password': 'p', 'resources': {'network': 'network-1'}},
|
||||||
|
{'username': 'test_user14', 'tenant_name': 'test_tenant14',
|
||||||
|
'password': 'p', 'roles': ['role-7', 'role-11'],
|
||||||
|
'resources': {'network': 'network-2'}},
|
||||||
]
|
]
|
||||||
self.useFixture(mockpatch.Patch(
|
self.useFixture(mockpatch.Patch(
|
||||||
'tempest.common.accounts.read_accounts_yaml',
|
'tempest.common.accounts.read_accounts_yaml',
|
||||||
|
@ -271,10 +281,27 @@ class TestAccount(base.TestCase):
|
||||||
calls = get_free_hash_mock.mock.mock_calls
|
calls = get_free_hash_mock.mock.mock_calls
|
||||||
self.assertEqual(len(calls), 1)
|
self.assertEqual(len(calls), 1)
|
||||||
args = calls[0][1][0]
|
args = calls[0][1][0]
|
||||||
self.assertEqual(len(args), 10)
|
self.assertEqual(len(args), 12)
|
||||||
for i in admin_hashes:
|
for i in admin_hashes:
|
||||||
self.assertNotIn(i, args)
|
self.assertNotIn(i, args)
|
||||||
|
|
||||||
|
def test_networks_returned_with_creds(self):
|
||||||
|
self.useFixture(mockpatch.Patch(
|
||||||
|
'tempest.common.accounts.read_accounts_yaml',
|
||||||
|
return_value=self.test_accounts))
|
||||||
|
test_accounts_class = accounts.Accounts('v2', 'test_name')
|
||||||
|
with mock.patch('tempest.services.compute.json.networks_client.'
|
||||||
|
'NetworksClientJSON.list_networks',
|
||||||
|
return_value=[{'name': 'network-2', 'id': 'fake-id'}]):
|
||||||
|
creds = test_accounts_class.get_creds_by_roles(['role-7'])
|
||||||
|
self.assertTrue(isinstance(creds, cred_provider.TestResources))
|
||||||
|
network = creds.network
|
||||||
|
self.assertIsNotNone(network)
|
||||||
|
self.assertIn('name', network)
|
||||||
|
self.assertIn('id', network)
|
||||||
|
self.assertEqual('fake-id', network['id'])
|
||||||
|
self.assertEqual('network-2', network['name'])
|
||||||
|
|
||||||
|
|
||||||
class TestNotLockingAccount(base.TestCase):
|
class TestNotLockingAccount(base.TestCase):
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue