Merge "Fix H404/405 violations for service clients"
diff --git a/doc/source/configuration.rst b/doc/source/configuration.rst
index 02fa0d8..1b2b6d2 100644
--- a/doc/source/configuration.rst
+++ b/doc/source/configuration.rst
@@ -127,16 +127,16 @@
unexpected failures in some tests.
-Non-locking test accounts (aka credentials config options)
-""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+Legacy test accounts (aka credentials config options)
+"""""""""""""""""""""""""""""""""""""""""""""""""""""
**Starting in the Liberty release this mechanism was deprecated and will be
removed in a future release**
When Tempest was refactored to allow for locking test accounts, the original
non-tenant isolated case was converted to internally work similarly to the
-accounts.yaml file. This mechanism was then called the non-locking test accounts
-provider. To use the non-locking test accounts provider you can specify the sets
-of credentials in the configuration file like detailed above with following 9
+accounts.yaml file. This mechanism was then called the legacy test accounts
+provider. To use the legacy test accounts provider you can specify the sets of
+credentials in the configuration file like detailed above with following 9
options in the identity section:
#. username
diff --git a/tempest/api/identity/admin/v3/test_trusts.py b/tempest/api/identity/admin/v3/test_trusts.py
index fac8826..a8b0af9 100644
--- a/tempest/api/identity/admin/v3/test_trusts.py
+++ b/tempest/api/identity/admin/v3/test_trusts.py
@@ -18,7 +18,7 @@
from tempest.api.identity import base
from tempest import clients
-from tempest.common import cred_provider
+from tempest.common import credentials_factory as common_creds
from tempest.common.utils import data_utils
from tempest import config
from tempest import test
@@ -89,7 +89,7 @@
self.assertIsNotNone(self.trustee_user_id)
# Initialize a new client with the trustor credentials
- creds = cred_provider.get_credentials(
+ creds = common_creds.get_credentials(
identity_version='v3',
username=self.trustor_username,
password=self.trustor_password,
diff --git a/tempest/api/identity/base.py b/tempest/api/identity/base.py
index 02ede3a..f9395bc 100644
--- a/tempest/api/identity/base.py
+++ b/tempest/api/identity/base.py
@@ -16,7 +16,7 @@
from oslo_log import log as logging
from tempest_lib import exceptions as lib_exc
-from tempest.common import cred_provider
+from tempest.common import credentials_factory as common_creds
from tempest.common.utils import data_utils
from tempest import config
import tempest.test
@@ -195,11 +195,11 @@
@property
def test_credentials(self):
- return cred_provider.get_credentials(username=self.test_user,
- user_id=self.user['id'],
- password=self.test_password,
- tenant_name=self.test_tenant,
- tenant_id=self.tenant['id'])
+ return common_creds.get_credentials(username=self.test_user,
+ user_id=self.user['id'],
+ password=self.test_password,
+ tenant_name=self.test_tenant,
+ tenant_id=self.tenant['id'])
def setup_test_user(self):
"""Set up a test user."""
diff --git a/tempest/api/identity/v2/test_users.py b/tempest/api/identity/v2/test_users.py
index 3b89b66..50aaa25 100644
--- a/tempest/api/identity/v2/test_users.py
+++ b/tempest/api/identity/v2/test_users.py
@@ -14,6 +14,7 @@
# under the License.
import copy
+import time
from tempest_lib.common.utils import data_utils
from tempest_lib import exceptions
@@ -54,6 +55,15 @@
new_pass=old_pass,
old_pass=new_pass)
+ # TODO(lbragstad): Sleeping after the response status has been checked
+ # and the body loaded as JSON allows requests to fail-fast. The sleep
+ # is necessary because keystone will err on the side of security and
+ # invalidate tokens within a small margin of error (within the same
+ # wall clock second) after a revocation event is issued (such as a
+ # password change). Remove this once keystone and Fernet support
+ # sub-second precision.
+ time.sleep(1)
+
# user updates own password
resp = self.non_admin_client.update_user_own_password(
user_id=user_id, new_pass=new_pass, old_pass=old_pass)['access']
diff --git a/tempest/api/identity/v3/test_users.py b/tempest/api/identity/v3/test_users.py
index a1f664f..14a866f 100644
--- a/tempest/api/identity/v3/test_users.py
+++ b/tempest/api/identity/v3/test_users.py
@@ -14,6 +14,7 @@
# under the License.
import copy
+import time
from tempest_lib.common.utils import data_utils
from tempest_lib import exceptions
@@ -53,6 +54,15 @@
password=old_pass,
original_password=new_pass)
+ # TODO(lbragstad): Sleeping after the response status has been checked
+ # and the body loaded as JSON allows requests to fail-fast. The sleep
+ # is necessary because keystone will err on the side of security and
+ # invalidate tokens within a small margin of error (within the same
+ # wall clock second) after a revocation event is issued (such as a
+ # password change). Remove this once keystone and Fernet support
+ # sub-second precision.
+ time.sleep(1)
+
# user updates own password
self.non_admin_client.update_user_password(
user_id=user_id, password=new_pass, original_password=old_pass)
diff --git a/tempest/api/orchestration/stacks/test_neutron_resources.py b/tempest/api/orchestration/stacks/test_neutron_resources.py
index d22fb25..e2ac455 100644
--- a/tempest/api/orchestration/stacks/test_neutron_resources.py
+++ b/tempest/api/orchestration/stacks/test_neutron_resources.py
@@ -16,7 +16,7 @@
import netaddr
from tempest.api.orchestration import base
-from tempest import clients
+from tempest.common import credentials_factory as credentials
from tempest.common.utils import data_utils
from tempest import config
from tempest import exceptions
@@ -38,7 +38,7 @@
@classmethod
def setup_credentials(cls):
super(NeutronResourcesTestJSON, cls).setup_credentials()
- cls.os = clients.Manager()
+ cls.os = credentials.ConfiguredUserManager()
@classmethod
def setup_clients(cls):
diff --git a/tempest/clients.py b/tempest/clients.py
index 6d25369..cab7512 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -38,7 +38,6 @@
from tempest_lib.services.identity.v2.token_client import TokenClient
from tempest_lib.services.identity.v3.token_client import V3TokenClient
-from tempest.common import cred_provider
from tempest.common import negative_rest_client
from tempest import config
from tempest import exceptions
@@ -175,7 +174,7 @@
}
default_params_with_timeout_values.update(default_params)
- def __init__(self, credentials=None, service=None):
+ def __init__(self, credentials, service=None):
super(Manager, self).__init__(credentials=credentials)
self._set_compute_clients()
@@ -484,17 +483,3 @@
self.account_client = AccountClient(self.auth_provider, **params)
self.container_client = ContainerClient(self.auth_provider, **params)
self.object_client = ObjectClient(self.auth_provider, **params)
-
-
-class AdminManager(Manager):
-
- """
- Manager object that uses the admin credentials for its
- managed client objects
- """
-
- def __init__(self, service=None):
- super(AdminManager, self).__init__(
- credentials=cred_provider.get_configured_credentials(
- 'identity_admin'),
- service=service)
diff --git a/tempest/cmd/cleanup.py b/tempest/cmd/cleanup.py
index 8b84bea..239b4e9 100644
--- a/tempest/cmd/cleanup.py
+++ b/tempest/cmd/cleanup.py
@@ -58,7 +58,7 @@
from tempest import clients
from tempest.cmd import cleanup_service
-from tempest.common import cred_provider
+from tempest.common import credentials_factory as credentials
from tempest import config
SAVED_STATE_JSON = "saved_state.json"
@@ -75,7 +75,7 @@
def take_action(self, parsed_args):
cleanup_service.init_conf()
self.options = parsed_args
- self.admin_mgr = clients.AdminManager()
+ self.admin_mgr = credentials.AdminManager()
self.dry_run_data = {}
self.json_data = {}
@@ -162,7 +162,7 @@
kwargs = {"username": CONF.auth.admin_username,
"password": CONF.auth.admin_password,
"tenant_name": tenant['name']}
- mgr = clients.Manager(credentials=cred_provider.get_credentials(
+ mgr = clients.Manager(credentials=credentials.get_credentials(
**kwargs))
kwargs = {'data': tenant_data,
'is_dry_run': is_dry_run,
@@ -235,7 +235,7 @@
LOG.debug("Remove admin user role for tenant: %s" % tenant_id)
# Must initialize AdminManager for each user role
# Otherwise authentication exception is thrown, weird
- id_cl = clients.AdminManager().identity_client
+ id_cl = credentials.AdminManager().identity_client
if (self._tenant_exists(tenant_id)):
try:
id_cl.remove_user_role(tenant_id, self.admin_id,
diff --git a/tempest/cmd/cleanup_service.py b/tempest/cmd/cleanup_service.py
index 40a079c..d2f6c03 100644
--- a/tempest/cmd/cleanup_service.py
+++ b/tempest/cmd/cleanup_service.py
@@ -16,7 +16,7 @@
from oslo_log import log as logging
-from tempest import clients
+from tempest.common import credentials_factory as credentials
from tempest import config
from tempest import test
@@ -82,7 +82,7 @@
def _get_network_id(net_name, tenant_name):
- am = clients.AdminManager()
+ am = credentials.AdminManager()
net_cl = am.networks_client
id_cl = am.identity_client
diff --git a/tempest/cmd/verify_tempest_config.py b/tempest/cmd/verify_tempest_config.py
index 2811070..9c8e2a0 100755
--- a/tempest/cmd/verify_tempest_config.py
+++ b/tempest/cmd/verify_tempest_config.py
@@ -24,7 +24,7 @@
from six.moves.urllib import parse as urlparse
from tempest import clients
-from tempest.common import credentials
+from tempest.common import credentials_factory as credentials
from tempest import config
diff --git a/tempest/common/cred_provider.py b/tempest/common/cred_provider.py
index 3575998..e5f24b3 100644
--- a/tempest/common/cred_provider.py
+++ b/tempest/common/cred_provider.py
@@ -18,83 +18,10 @@
import six
from tempest_lib import auth
-from tempest import config
from tempest import exceptions
-CONF = config.CONF
LOG = logging.getLogger(__name__)
-# Type of credentials available from configuration
-CREDENTIAL_TYPES = {
- 'identity_admin': ('auth', 'admin'),
- 'user': ('identity', None),
- 'alt_user': ('identity', 'alt')
-}
-
-DEFAULT_PARAMS = {
- 'disable_ssl_certificate_validation':
- CONF.identity.disable_ssl_certificate_validation,
- 'ca_certs': CONF.identity.ca_certificates_file,
- 'trace_requests': CONF.debug.trace_requests
-}
-
-
-# Read credentials from configuration, builds a Credentials object
-# based on the specified or configured version
-def get_configured_credentials(credential_type, fill_in=True,
- identity_version=None):
- identity_version = identity_version or CONF.identity.auth_version
- if identity_version not in ('v2', 'v3'):
- raise exceptions.InvalidConfiguration(
- 'Unsupported auth version: %s' % identity_version)
- if credential_type not in CREDENTIAL_TYPES:
- raise exceptions.InvalidCredentials()
- conf_attributes = ['username', 'password', 'tenant_name']
- if identity_version == 'v3':
- conf_attributes.append('domain_name')
- # Read the parts of credentials from config
- params = DEFAULT_PARAMS.copy()
- section, prefix = CREDENTIAL_TYPES[credential_type]
- for attr in conf_attributes:
- _section = getattr(CONF, section)
- if prefix is None:
- params[attr] = getattr(_section, attr)
- else:
- params[attr] = getattr(_section, prefix + "_" + attr)
- # Build and validate credentials. We are reading configured credentials,
- # so validate them even if fill_in is False
- credentials = get_credentials(fill_in=fill_in,
- identity_version=identity_version, **params)
- if not fill_in:
- if not credentials.is_valid():
- msg = ("The %s credentials are incorrectly set in the config file."
- " Double check that all required values are assigned" %
- credential_type)
- raise exceptions.InvalidConfiguration(msg)
- return credentials
-
-
-# Wrapper around auth.get_credentials to use the configured identity version
-# is none is specified
-def get_credentials(fill_in=True, identity_version=None, **kwargs):
- params = dict(DEFAULT_PARAMS, **kwargs)
- identity_version = identity_version or CONF.identity.auth_version
- # In case of "v3" add the domain from config if not specified
- if identity_version == 'v3':
- domain_fields = set(x for x in auth.KeystoneV3Credentials.ATTRIBUTES
- if 'domain' in x)
- if not domain_fields.intersection(kwargs.keys()):
- domain_name = CONF.auth.default_credentials_domain_name
- params['user_domain_name'] = domain_name
-
- auth_url = CONF.identity.uri_v3
- else:
- auth_url = CONF.identity.uri
- return auth.get_credentials(auth_url,
- fill_in=fill_in,
- identity_version=identity_version,
- **params)
-
@six.add_metaclass(abc.ABCMeta)
class CredentialProvider(object):
diff --git a/tempest/common/credentials.py b/tempest/common/credentials.py
deleted file mode 100644
index 76f8afe..0000000
--- a/tempest/common/credentials.py
+++ /dev/null
@@ -1,110 +0,0 @@
-# Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import os
-
-from tempest.common import cred_provider
-from tempest.common import dynamic_creds
-from tempest.common import preprov_creds
-from tempest import config
-from tempest import exceptions
-
-CONF = config.CONF
-
-
-# Return the right implementation of CredentialProvider based on config
-# Dropping interface and password, as they are never used anyways
-# TODO(andreaf) Drop them from the CredentialsProvider interface completely
-def get_credentials_provider(name, network_resources=None,
- force_tenant_isolation=False,
- identity_version=None):
- # If a test requires a new account to work, it can have it via forcing
- # dynamic credentials. A new account will be produced only for that test.
- # In case admin credentials are not available for the account creation,
- # the test should be skipped else it would fail.
- identity_version = identity_version or CONF.identity.auth_version
- if CONF.auth.use_dynamic_credentials or force_tenant_isolation:
- return dynamic_creds.DynamicCredentialProvider(
- name=name,
- network_resources=network_resources,
- identity_version=identity_version,
- credentials_domain=CONF.auth.default_credentials_domain_name,
- admin_role=CONF.identity.admin_role)
- else:
- if (CONF.auth.test_accounts_file and
- os.path.isfile(CONF.auth.test_accounts_file)):
- # Most params are not relevant for pre-created accounts
- return preprov_creds.PreProvisionedCredentialProvider(
- name=name, identity_version=identity_version,
- credentials_domain=CONF.auth.default_credentials_domain_name,
- admin_role=CONF.identity.admin_role)
- else:
- return preprov_creds.NonLockingCredentialProvider(
- name=name, identity_version=identity_version,
- admin_role=CONF.identity.admin_role)
-
-
-# We want a helper function here to check and see if admin credentials
-# are available so we can do a single call from skip_checks if admin
-# creds area available.
-# This depends on identity_version as there may be admin credentials
-# available for v2 but not for v3.
-def is_admin_available(identity_version):
- is_admin = True
- # If dynamic credentials is enabled admin will be available
- if CONF.auth.use_dynamic_credentials:
- return is_admin
- # Check whether test accounts file has the admin specified or not
- elif (CONF.auth.test_accounts_file and
- os.path.isfile(CONF.auth.test_accounts_file)):
- check_accounts = preprov_creds.PreProvisionedCredentialProvider(
- identity_version=identity_version, name='check_admin',
- admin_role=CONF.identity.admin_role)
- if not check_accounts.admin_available():
- is_admin = False
- else:
- try:
- cred_provider.get_configured_credentials(
- 'identity_admin', fill_in=False,
- identity_version=identity_version)
- except exceptions.InvalidConfiguration:
- is_admin = False
- return is_admin
-
-
-# We want a helper function here to check and see if alt credentials
-# are available so we can do a single call from skip_checks if alt
-# creds area available.
-# This depends on identity_version as there may be alt credentials
-# available for v2 but not for v3.
-def is_alt_available(identity_version):
- # If dynamic credentials is enabled alt will be available
- if CONF.auth.use_dynamic_credentials:
- return True
- # Check whether test accounts file has the admin specified or not
- if (CONF.auth.test_accounts_file and
- os.path.isfile(CONF.auth.test_accounts_file)):
- check_accounts = preprov_creds.PreProvisionedCredentialProvider(
- identity_version=identity_version, name='check_alt',
- admin_role=CONF.identity.admin_role)
- else:
- check_accounts = preprov_creds.NonLockingCredentialProvider(
- identity_version=identity_version, name='check_alt',
- admin_role=CONF.identity.admin_role)
- try:
- if not check_accounts.is_multi_user():
- return False
- else:
- return True
- except exceptions.InvalidConfiguration:
- return False
diff --git a/tempest/common/credentials_factory.py b/tempest/common/credentials_factory.py
new file mode 100644
index 0000000..486b7fd
--- /dev/null
+++ b/tempest/common/credentials_factory.py
@@ -0,0 +1,316 @@
+# Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+
+from oslo_log import log as logging
+from tempest_lib import auth
+
+from tempest import clients
+from tempest.common import cred_provider
+from tempest.common import dynamic_creds
+from tempest.common import preprov_creds
+from tempest import config
+from tempest import exceptions
+
+CONF = config.CONF
+LOG = logging.getLogger(__name__)
+
+
+"""This module provides factories of credential and credential providers
+
+Credentials providers and clients are (going to be) part of tempest-lib,
+and so they may not hold any dependency to tempest configuration.
+
+Methods in this module collect the relevant configuration details and pass
+them to credentials providers and clients, so that test can have easy
+access to these features.
+
+Client managers with hard-coded configured credentials are also moved here,
+to avoid circular dependencies."""
+
+# === Credential Providers
+
+
+class LegacyCredentialProvider(cred_provider.CredentialProvider):
+
+ def __init__(self, identity_version):
+ """Credentials provider which returns credentials from tempest.conf
+
+ Credentials provider which always returns the first and second
+ configured accounts as primary and alt users.
+ Credentials from tempest.conf are deprecated, and this credential
+ provider is also accordingly.
+
+ This credential provider can be used in case of serial test execution
+ to preserve the current behaviour of the serial tempest run.
+
+ :param identity_version: Version of the identity API
+ :return: CredentialProvider
+ """
+ super(LegacyCredentialProvider, self).__init__(
+ identity_version=identity_version)
+ self._creds = {}
+
+ def _unique_creds(self, cred_arg=None):
+ """Verify that the configured credentials are valid and distinct """
+ try:
+ user = self.get_primary_creds()
+ alt_user = self.get_alt_creds()
+ return getattr(user, cred_arg) != getattr(alt_user, cred_arg)
+ except exceptions.InvalidCredentials as ic:
+ msg = "At least one of the configured credentials is " \
+ "not valid: %s" % ic.message
+ raise exceptions.InvalidConfiguration(msg)
+
+ def is_multi_user(self):
+ return self._unique_creds('username')
+
+ def is_multi_tenant(self):
+ return self._unique_creds('tenant_id')
+
+ def get_primary_creds(self):
+ if self._creds.get('primary'):
+ return self._creds.get('primary')
+ primary_credential = get_configured_credentials(
+ credential_type='user', fill_in=False,
+ identity_version=self.identity_version)
+ self._creds['primary'] = cred_provider.TestResources(
+ primary_credential)
+ return self._creds['primary']
+
+ def get_alt_creds(self):
+ if self._creds.get('alt'):
+ return self._creds.get('alt')
+ alt_credential = get_configured_credentials(
+ credential_type='alt_user', fill_in=False,
+ identity_version=self.identity_version)
+ self._creds['alt'] = cred_provider.TestResources(
+ alt_credential)
+ return self._creds['alt']
+
+ def clear_creds(self):
+ self._creds = {}
+
+ def get_admin_creds(self):
+ if self._creds.get('admin'):
+ return self._creds.get('admin')
+ creds = get_configured_credentials(
+ "identity_admin", fill_in=False)
+ self._creds['admin'] = cred_provider.TestResources(creds)
+ return self._creds['admin']
+
+ def get_creds_by_roles(self, roles, force_new=False):
+ msg = "Credentials being specified through the config file can not be"\
+ " used with tests that specify using credentials by roles. "\
+ "Either exclude/skip the tests doing this or use either an "\
+ "test_accounts_file or dynamic credentials."
+ raise exceptions.InvalidConfiguration(msg)
+
+ def is_role_available(self, role):
+ msg = "Credentials being specified through the config file can not be"\
+ " used with tests that specify using credentials by roles. "\
+ "Either exclude/skip the tests doing this or use either an "\
+ "test_accounts_file or dynamic credentials."
+ raise exceptions.InvalidConfiguration(msg)
+
+
+# Return the right implementation of CredentialProvider based on config
+# Dropping interface and password, as they are never used anyways
+# TODO(andreaf) Drop them from the CredentialsProvider interface completely
+def get_credentials_provider(name, network_resources=None,
+ force_tenant_isolation=False,
+ identity_version=None):
+ # If a test requires a new account to work, it can have it via forcing
+ # dynamic credentials. A new account will be produced only for that test.
+ # In case admin credentials are not available for the account creation,
+ # the test should be skipped else it would fail.
+ identity_version = identity_version or CONF.identity.auth_version
+ if CONF.auth.use_dynamic_credentials or force_tenant_isolation:
+ admin_creds = get_configured_credentials(
+ 'identity_admin', fill_in=True, identity_version=identity_version)
+ return dynamic_creds.DynamicCredentialProvider(
+ name=name,
+ network_resources=network_resources,
+ identity_version=identity_version,
+ credentials_domain=CONF.auth.default_credentials_domain_name,
+ admin_role=CONF.identity.admin_role,
+ admin_creds=admin_creds)
+ else:
+ if (CONF.auth.test_accounts_file and
+ os.path.isfile(CONF.auth.test_accounts_file)):
+ # Most params are not relevant for pre-created accounts
+ return preprov_creds.PreProvisionedCredentialProvider(
+ name=name, identity_version=identity_version,
+ credentials_domain=CONF.auth.default_credentials_domain_name,
+ admin_role=CONF.identity.admin_role)
+ else:
+ # Dynamic credentials are disabled, and the account file is not
+ # defined - we fall back on credentials configured in tempest.conf
+ return LegacyCredentialProvider(identity_version=identity_version)
+
+
+# We want a helper function here to check and see if admin credentials
+# are available so we can do a single call from skip_checks if admin
+# creds area available.
+# This depends on identity_version as there may be admin credentials
+# available for v2 but not for v3.
+def is_admin_available(identity_version):
+ is_admin = True
+ # If dynamic credentials is enabled admin will be available
+ if CONF.auth.use_dynamic_credentials:
+ return is_admin
+ # Check whether test accounts file has the admin specified or not
+ elif (CONF.auth.test_accounts_file and
+ os.path.isfile(CONF.auth.test_accounts_file)):
+ check_accounts = preprov_creds.PreProvisionedCredentialProvider(
+ identity_version=identity_version, name='check_admin',
+ admin_role=CONF.identity.admin_role)
+ if not check_accounts.admin_available():
+ is_admin = False
+ else:
+ try:
+ get_configured_credentials('identity_admin', fill_in=False,
+ identity_version=identity_version)
+ except exceptions.InvalidConfiguration:
+ is_admin = False
+ return is_admin
+
+
+# We want a helper function here to check and see if alt credentials
+# are available so we can do a single call from skip_checks if alt
+# creds area available.
+# This depends on identity_version as there may be alt credentials
+# available for v2 but not for v3.
+def is_alt_available(identity_version):
+ # If dynamic credentials is enabled alt will be available
+ if CONF.auth.use_dynamic_credentials:
+ return True
+ # Check whether test accounts file has the admin specified or not
+ if (CONF.auth.test_accounts_file and
+ os.path.isfile(CONF.auth.test_accounts_file)):
+ check_accounts = preprov_creds.PreProvisionedCredentialProvider(
+ identity_version=identity_version, name='check_alt',
+ admin_role=CONF.identity.admin_role)
+ else:
+ check_accounts = LegacyCredentialProvider(identity_version)
+ try:
+ if not check_accounts.is_multi_user():
+ return False
+ else:
+ return True
+ except exceptions.InvalidConfiguration:
+ return False
+
+# === Credentials
+
+# Type of credentials available from configuration
+CREDENTIAL_TYPES = {
+ 'identity_admin': ('auth', 'admin'),
+ 'user': ('identity', None),
+ 'alt_user': ('identity', 'alt')
+}
+
+DEFAULT_PARAMS = {
+ 'disable_ssl_certificate_validation':
+ CONF.identity.disable_ssl_certificate_validation,
+ 'ca_certs': CONF.identity.ca_certificates_file,
+ 'trace_requests': CONF.debug.trace_requests
+}
+
+
+# Read credentials from configuration, builds a Credentials object
+# based on the specified or configured version
+def get_configured_credentials(credential_type, fill_in=True,
+ identity_version=None):
+ identity_version = identity_version or CONF.identity.auth_version
+
+ if identity_version not in ('v2', 'v3'):
+ raise exceptions.InvalidConfiguration(
+ 'Unsupported auth version: %s' % identity_version)
+
+ if credential_type not in CREDENTIAL_TYPES:
+ raise exceptions.InvalidCredentials()
+ conf_attributes = ['username', 'password', 'tenant_name']
+
+ if identity_version == 'v3':
+ conf_attributes.append('domain_name')
+ # Read the parts of credentials from config
+ params = DEFAULT_PARAMS.copy()
+ section, prefix = CREDENTIAL_TYPES[credential_type]
+ for attr in conf_attributes:
+ _section = getattr(CONF, section)
+ if prefix is None:
+ params[attr] = getattr(_section, attr)
+ else:
+ params[attr] = getattr(_section, prefix + "_" + attr)
+ # Build and validate credentials. We are reading configured credentials,
+ # so validate them even if fill_in is False
+ credentials = get_credentials(fill_in=fill_in,
+ identity_version=identity_version, **params)
+ if not fill_in:
+ if not credentials.is_valid():
+ msg = ("The %s credentials are incorrectly set in the config file."
+ " Double check that all required values are assigned" %
+ credential_type)
+ raise exceptions.InvalidConfiguration(msg)
+ return credentials
+
+
+# Wrapper around auth.get_credentials to use the configured identity version
+# is none is specified
+def get_credentials(fill_in=True, identity_version=None, **kwargs):
+ params = dict(DEFAULT_PARAMS, **kwargs)
+ identity_version = identity_version or CONF.identity.auth_version
+ # In case of "v3" add the domain from config if not specified
+ if identity_version == 'v3':
+ domain_fields = set(x for x in auth.KeystoneV3Credentials.ATTRIBUTES
+ if 'domain' in x)
+ if not domain_fields.intersection(kwargs.keys()):
+ domain_name = CONF.auth.default_credentials_domain_name
+ params['user_domain_name'] = domain_name
+
+ auth_url = CONF.identity.uri_v3
+ else:
+ auth_url = CONF.identity.uri
+ return auth.get_credentials(auth_url,
+ fill_in=fill_in,
+ identity_version=identity_version,
+ **params)
+
+# === Credential / client managers
+
+
+class ConfiguredUserManager(clients.Manager):
+ """
+ Manager object that uses the `user` credentials for its
+ managed client objects
+ """
+
+ def __init__(self, service=None):
+ super(ConfiguredUserManager, self).__init__(
+ credentials=get_configured_credentials('user'),
+ service=service)
+
+
+class AdminManager(clients.Manager):
+
+ """
+ Manager object that uses the admin credentials for its
+ managed client objects
+ """
+
+ def __init__(self, service=None):
+ super(AdminManager, self).__init__(
+ credentials=get_configured_credentials('identity_admin'),
+ service=service)
diff --git a/tempest/common/dynamic_creds.py b/tempest/common/dynamic_creds.py
index ce69c84..ae53543 100644
--- a/tempest/common/dynamic_creds.py
+++ b/tempest/common/dynamic_creds.py
@@ -31,16 +31,32 @@
class DynamicCredentialProvider(cred_provider.CredentialProvider):
def __init__(self, identity_version, name=None, network_resources=None,
- credentials_domain=None, admin_role=None):
+ credentials_domain=None, admin_role=None, admin_creds=None):
+ """Creates credentials dynamically for tests
+
+ A credential provider that, based on an initial set of
+ admin credentials, creates new credentials on the fly for
+ tests to use and then discard.
+
+ :param str identity_version: identity API version to use `v2` or `v3`
+ :param str admin_role: name of the admin role added to admin users
+ :param str name: names of dynamic resources include this parameter
+ when specified
+ :param str credentials_domain: name of the domain where the users
+ are created. If not defined, the project
+ domain from admin_credentials is used
+ :param dict network_resources: network resources to be created for
+ the created credentials
+ :param Credentials admin_creds: initial admin credentials
+ """
super(DynamicCredentialProvider, self).__init__(
- identity_version=identity_version, name=name,
- network_resources=network_resources,
- credentials_domain=credentials_domain, admin_role=admin_role)
+ identity_version=identity_version, admin_role=admin_role,
+ name=name, credentials_domain=credentials_domain,
+ network_resources=network_resources)
+ self.network_resources = network_resources
self._creds = {}
self.ports = []
- self.default_admin_creds = cred_provider.get_configured_credentials(
- 'identity_admin', fill_in=True,
- identity_version=self.identity_version)
+ self.default_admin_creds = admin_creds
(self.identity_admin_client, self.network_admin_client,
self.networks_admin_client,
self.subnets_admin_client,
diff --git a/tempest/common/preprov_creds.py b/tempest/common/preprov_creds.py
index dd27f08..f711302 100644
--- a/tempest/common/preprov_creds.py
+++ b/tempest/common/preprov_creds.py
@@ -310,64 +310,3 @@
if not user_domain_fields.intersection(set(creds_dict.keys())):
creds_dict['user_domain_name'] = self.credentials_domain
return creds_dict
-
-
-class NonLockingCredentialProvider(PreProvisionedCredentialProvider):
- """Credentials provider which always returns the first and second
- configured accounts as primary and alt users.
- This credential provider can be used in case of serial test execution
- to preserve the current behaviour of the serial tempest run.
- """
-
- def _unique_creds(self, cred_arg=None):
- """Verify that the configured credentials are valid and distinct """
- try:
- user = self.get_primary_creds()
- alt_user = self.get_alt_creds()
- return getattr(user, cred_arg) != getattr(alt_user, cred_arg)
- except exceptions.InvalidCredentials as ic:
- msg = "At least one of the configured credentials is " \
- "not valid: %s" % ic.message
- raise exceptions.InvalidConfiguration(msg)
-
- def is_multi_user(self):
- return self._unique_creds('username')
-
- def is_multi_tenant(self):
- return self._unique_creds('tenant_id')
-
- def get_primary_creds(self):
- if self._creds.get('primary'):
- return self._creds.get('primary')
- primary_credential = cred_provider.get_configured_credentials(
- fill_in=False, credential_type='user',
- identity_version=self.identity_version)
- self._creds['primary'] = cred_provider.TestResources(
- primary_credential)
- return self._creds['primary']
-
- def get_alt_creds(self):
- if self._creds.get('alt'):
- return self._creds.get('alt')
- alt_credential = cred_provider.get_configured_credentials(
- fill_in=False, credential_type='alt_user',
- identity_version=self.identity_version)
- self._creds['alt'] = cred_provider.TestResources(
- alt_credential)
- return self._creds['alt']
-
- def clear_creds(self):
- self._creds = {}
-
- def get_admin_creds(self):
- creds = cred_provider.get_configured_credentials(
- "identity_admin", fill_in=False)
- self._creds['admin'] = cred_provider.TestResources(creds)
- return self._creds['admin']
-
- def get_creds_by_roles(self, roles, force_new=False):
- msg = "Credentials being specified through the config file can not be"\
- " used with tests that specify using credentials by roles. "\
- "Either exclude/skip the tests doing this or use either an "\
- "test_accounts_file or dynamic credentials."
- raise exceptions.InvalidConfiguration(msg)
diff --git a/tempest/manager.py b/tempest/manager.py
index d7c3128..b0541e8 100644
--- a/tempest/manager.py
+++ b/tempest/manager.py
@@ -31,22 +31,18 @@
and a client object for a test case to use in performing actions.
"""
- def __init__(self, credentials=None):
+ def __init__(self, credentials):
"""
- We allow overriding of the credentials used within the various
- client classes managed by the Manager object. Left as None, the
- standard username/password/tenant_name[/domain_name] is used.
+ Credentials to be used within the various client classes managed by the
+ Manager object must be defined.
- :param credentials: Override of the credentials
+ :param credentials: type Credentials or TestResources
"""
- self.auth_version = CONF.identity.auth_version
- if credentials is None:
- self.credentials = cred_provider.get_configured_credentials('user')
- else:
- self.credentials = credentials
+ self.credentials = credentials
# Check if passed or default credentials are valid
if not self.credentials.is_valid():
raise exceptions.InvalidCredentials()
+ self.auth_version = CONF.identity.auth_version
# Tenant isolation creates TestResources, but
# PreProvisionedCredentialProvider and some tests create Credentials
if isinstance(credentials, cred_provider.TestResources):
diff --git a/tempest/scenario/utils.py b/tempest/scenario/utils.py
index ad9deea..fa7c0c9 100644
--- a/tempest/scenario/utils.py
+++ b/tempest/scenario/utils.py
@@ -24,7 +24,7 @@
import testtools
from tempest import clients
-from tempest.common import credentials
+from tempest.common import credentials_factory as credentials
from tempest import config
CONF = config.CONF
diff --git a/tempest/stress/cleanup.py b/tempest/stress/cleanup.py
index 66d2b36..993359d 100644
--- a/tempest/stress/cleanup.py
+++ b/tempest/stress/cleanup.py
@@ -16,14 +16,14 @@
from oslo_log import log as logging
-from tempest import clients
+from tempest.common import credentials_factory as credentials
from tempest.common import waiters
LOG = logging.getLogger(__name__)
def cleanup():
- admin_manager = clients.AdminManager()
+ admin_manager = credentials.AdminManager()
body = admin_manager.servers_client.list_servers(all_tenants=True)
LOG.info("Cleanup::remove %s servers" % len(body['servers']))
diff --git a/tempest/stress/driver.py b/tempest/stress/driver.py
index 7634d2c..eec52cb 100644
--- a/tempest/stress/driver.py
+++ b/tempest/stress/driver.py
@@ -26,6 +26,7 @@
from tempest import clients
from tempest.common import cred_client
+from tempest.common import credentials_factory as credentials
from tempest.common.utils import data_utils
from tempest import config
from tempest import exceptions
@@ -122,7 +123,7 @@
"""
Workload driver. Executes an action function against a nova-cluster.
"""
- admin_manager = clients.AdminManager()
+ admin_manager = credentials.AdminManager()
ssh_user = CONF.stress.target_ssh_user
ssh_key = CONF.stress.target_private_key_path
@@ -145,7 +146,7 @@
if test.get('use_admin', False):
manager = admin_manager
else:
- manager = clients.Manager()
+ manager = credentials.ConfiguredUserManager()
for p_number in moves.xrange(test.get('threads', default_thread_num)):
if test.get('use_isolated_tenants', False):
username = data_utils.rand_name("stress_user")
diff --git a/tempest/test.py b/tempest/test.py
index b8ba5f4..4be6779 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -32,7 +32,7 @@
from tempest import clients
from tempest.common import cred_client
-from tempest.common import credentials
+from tempest.common import credentials_factory as credentials
from tempest.common import fixed_network
import tempest.common.generator.valid_generator as valid
import tempest.common.validation_resources as vresources
diff --git a/tempest/tests/common/test_admin_available.py b/tempest/tests/common/test_admin_available.py
index a53ed5f..75401db 100644
--- a/tempest/tests/common/test_admin_available.py
+++ b/tempest/tests/common/test_admin_available.py
@@ -15,7 +15,7 @@
from oslo_config import cfg
from oslotest import mockpatch
-from tempest.common import credentials
+from tempest.common import credentials_factory as credentials
from tempest import config
from tempest.tests import base
from tempest.tests import fake_config
diff --git a/tempest/tests/common/test_alt_available.py b/tempest/tests/common/test_alt_available.py
index 6a86f73..db3f5ec 100644
--- a/tempest/tests/common/test_alt_available.py
+++ b/tempest/tests/common/test_alt_available.py
@@ -15,7 +15,7 @@
from oslo_config import cfg
from oslotest import mockpatch
-from tempest.common import credentials
+from tempest.common import credentials_factory as credentials
from tempest import config
from tempest.tests import base
from tempest.tests import fake_config
diff --git a/tempest/tests/common/test_cred_provider.py b/tempest/tests/common/test_configured_creds.py
similarity index 95%
rename from tempest/tests/common/test_cred_provider.py
rename to tempest/tests/common/test_configured_creds.py
index d404660..96b75fd 100644
--- a/tempest/tests/common/test_cred_provider.py
+++ b/tempest/tests/common/test_configured_creds.py
@@ -18,8 +18,7 @@
from tempest_lib.services.identity.v2 import token_client as v2_client
from tempest_lib.services.identity.v3 import token_client as v3_client
-
-from tempest.common import cred_provider
+from tempest.common import credentials_factory as common_creds
from tempest.common import tempest_fixtures as fixtures
from tempest import config
from tempest.tests import base
@@ -65,12 +64,12 @@
def _verify_credentials(self, credentials_class, filled=True,
identity_version=None):
- for ctype in cred_provider.CREDENTIAL_TYPES:
+ for ctype in common_creds.CREDENTIAL_TYPES:
if identity_version is None:
- creds = cred_provider.get_configured_credentials(
+ creds = common_creds.get_configured_credentials(
credential_type=ctype, fill_in=filled)
else:
- creds = cred_provider.get_configured_credentials(
+ creds = common_creds.get_configured_credentials(
credential_type=ctype, fill_in=filled,
identity_version=identity_version)
self._check(creds, credentials_class, filled)
diff --git a/tempest/tests/common/test_credentials.py b/tempest/tests/common/test_credentials.py
new file mode 100644
index 0000000..136ac02
--- /dev/null
+++ b/tempest/tests/common/test_credentials.py
@@ -0,0 +1,36 @@
+# Copyright 2015 Hewlett-Packard Development Company, L.P.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from tempest.common import credentials_factory as credentials
+from tempest import config
+from tempest import exceptions
+from tempest.tests import base
+from tempest.tests import fake_config
+
+
+class TestLegacyCredentialsProvider(base.TestCase):
+
+ fixed_params = {'identity_version': 'v2'}
+
+ def setUp(self):
+ super(TestLegacyCredentialsProvider, self).setUp()
+ self.useFixture(fake_config.ConfigFixture())
+ self.stubs.Set(config, 'TempestConfigPrivate', fake_config.FakePrivate)
+
+ def test_get_creds_roles_legacy_invalid(self):
+ test_accounts_class = credentials.LegacyCredentialProvider(
+ **self.fixed_params)
+ self.assertRaises(exceptions.InvalidConfiguration,
+ test_accounts_class.get_creds_by_roles,
+ ['fake_role'])
diff --git a/tempest/tests/common/test_dynamic_creds.py b/tempest/tests/common/test_dynamic_creds.py
index 73e180e..78064a7 100644
--- a/tempest/tests/common/test_dynamic_creds.py
+++ b/tempest/tests/common/test_dynamic_creds.py
@@ -17,6 +17,7 @@
from oslotest import mockpatch
from tempest_lib.services.identity.v2 import token_client as json_token_client
+from tempest.common import credentials_factory as credentials
from tempest.common import dynamic_creds
from tempest.common import service_client
from tempest import config
@@ -46,6 +47,8 @@
cfg.CONF.set_default('operator_role', 'FakeRole',
group='object-storage')
self._mock_list_ec2_credentials('fake_user_id', 'fake_tenant_id')
+ self.fixed_params.update(
+ admin_creds=self._get_fake_admin_creds())
def test_tempest_client(self):
creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
@@ -54,6 +57,13 @@
self.assertTrue(isinstance(creds.network_admin_client,
json_network_client.NetworkClient))
+ def _get_fake_admin_creds(self):
+ return credentials.get_credentials(
+ fill_in=False,
+ identity_version=self.fixed_params['identity_version'],
+ username='fake_username', password='fake_password',
+ tenant_name='fake_tenant')
+
def _mock_user_create(self, id, name):
user_fix = self.useFixture(mockpatch.PatchObject(
json_iden_client.IdentityClient,
diff --git a/tempest/tests/common/test_preprov_creds.py b/tempest/tests/common/test_preprov_creds.py
index 8a014af..36dd976 100644
--- a/tempest/tests/common/test_preprov_creds.py
+++ b/tempest/tests/common/test_preprov_creds.py
@@ -329,36 +329,3 @@
self.assertIn('id', network)
self.assertEqual('fake-id', network['id'])
self.assertEqual('network-2', network['name'])
-
-
-class TestNotLockingAccount(base.TestCase):
-
- fixed_params = {'name': 'test class',
- 'identity_version': 'v2',
- 'admin_role': 'admin'}
-
- def setUp(self):
- super(TestNotLockingAccount, self).setUp()
- self.useFixture(fake_config.ConfigFixture())
- self.stubs.Set(config, 'TempestConfigPrivate', fake_config.FakePrivate)
- self.useFixture(lockutils_fixtures.ExternalLockFixture())
- self.test_accounts = [
- {'username': 'test_user1', 'tenant_name': 'test_tenant1',
- 'password': 'p'},
- {'username': 'test_user2', 'tenant_name': 'test_tenant2',
- 'password': 'p'},
- {'username': 'test_user3', 'tenant_name': 'test_tenant3',
- 'password': 'p'},
- ]
- self.useFixture(mockpatch.Patch(
- 'tempest.common.preprov_creds.read_accounts_yaml',
- return_value=self.test_accounts))
- cfg.CONF.set_default('test_accounts_file', '', group='auth')
- self.useFixture(mockpatch.Patch('os.path.isfile', return_value=True))
-
- def test_get_creds_roles_nonlocking_invalid(self):
- test_accounts_class = preprov_creds.NonLockingCredentialProvider(
- **self.fixed_params)
- self.assertRaises(exceptions.InvalidConfiguration,
- test_accounts_class.get_creds_by_roles,
- ['fake_role'])
diff --git a/tempest/thirdparty/boto/test.py b/tempest/thirdparty/boto/test.py
index 1ced180..05c47bb 100644
--- a/tempest/thirdparty/boto/test.py
+++ b/tempest/thirdparty/boto/test.py
@@ -27,7 +27,7 @@
from six.moves.urllib import parse as urlparse
from tempest_lib import exceptions as lib_exc
-import tempest.clients
+from tempest.common import credentials_factory as credentials
from tempest.common.utils import file_utils
from tempest import config
from tempest import exceptions
@@ -67,7 +67,7 @@
raise Exception("Unknown (Authentication?) Error")
# NOTE(andreaf) Setting up an extra manager here is redundant,
# and should be removed.
- openstack = tempest.clients.Manager()
+ openstack = credentials.ConfiguredUserManager()
try:
if urlparse.urlparse(CONF.boto.ec2_url).hostname is None:
raise Exception("Failed to get hostname from the ec2_url")