| # 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 hashlib |
| import os |
| |
| import yaml |
| |
| from tempest import auth |
| from tempest.common import cred_provider |
| from tempest import config |
| from tempest import exceptions |
| from tempest.openstack.common import lockutils |
| from tempest.openstack.common import log as logging |
| |
| CONF = config.CONF |
| LOG = logging.getLogger(__name__) |
| |
| |
| def read_accounts_yaml(path): |
| yaml_file = open(path, 'r') |
| accounts = yaml.load(yaml_file) |
| return accounts |
| |
| |
| class Accounts(cred_provider.CredentialProvider): |
| |
| def __init__(self, name): |
| super(Accounts, self).__init__(name) |
| if os.path.isfile(CONF.auth.test_accounts_file): |
| accounts = read_accounts_yaml(CONF.auth.test_accounts_file) |
| self.use_default_creds = False |
| else: |
| accounts = {} |
| self.use_default_creds = True |
| self.hash_dict = self.get_hash_dict(accounts) |
| self.accounts_dir = os.path.join(CONF.lock_path, 'test_accounts') |
| self.isolated_creds = {} |
| |
| @classmethod |
| def get_hash_dict(cls, accounts): |
| hash_dict = {} |
| for account in accounts: |
| temp_hash = hashlib.md5() |
| temp_hash.update(str(account)) |
| hash_dict[temp_hash.hexdigest()] = account |
| return hash_dict |
| |
| def is_multi_user(self): |
| return len(self.hash_dict) > 1 |
| |
| def _create_hash_file(self, hash_string): |
| path = os.path.join(os.path.join(self.accounts_dir, hash_string)) |
| if not os.path.isfile(path): |
| open(path, 'w').close() |
| return True |
| return False |
| |
| @lockutils.synchronized('test_accounts_io', external=True) |
| def _get_free_hash(self, hashes): |
| if not os.path.isdir(self.accounts_dir): |
| os.mkdir(self.accounts_dir) |
| # Create File from first hash (since none are in use) |
| self._create_hash_file(hashes[0]) |
| return hashes[0] |
| for _hash in hashes: |
| res = self._create_hash_file(_hash) |
| if res: |
| return _hash |
| msg = 'Insufficient number of users provided' |
| raise exceptions.InvalidConfiguration(msg) |
| |
| def _get_creds(self): |
| if self.use_default_creds: |
| raise exceptions.InvalidConfiguration( |
| "Account file %s doesn't exist" % CONF.auth.test_accounts_file) |
| free_hash = self._get_free_hash(self.hash_dict.keys()) |
| return self.hash_dict[free_hash] |
| |
| @lockutils.synchronized('test_accounts_io', external=True) |
| def remove_hash(self, hash_string): |
| hash_path = os.path.join(self.accounts_dir, hash_string) |
| if not os.path.isfile(hash_path): |
| LOG.warning('Expected an account lock file %s to remove, but ' |
| 'one did not exist') |
| else: |
| os.remove(hash_path) |
| if not os.listdir(self.accounts_dir): |
| os.rmdir(self.accounts_dir) |
| |
| def get_hash(self, creds): |
| for _hash in self.hash_dict: |
| # Comparing on the attributes that are expected in the YAML |
| if all([getattr(creds, k) == self.hash_dict[_hash][k] for k in |
| creds.CONF_ATTRIBUTES]): |
| return _hash |
| raise AttributeError('Invalid credentials %s' % creds) |
| |
| def remove_credentials(self, creds): |
| _hash = self.get_hash(creds) |
| self.remove_hash(_hash) |
| |
| def get_primary_creds(self): |
| if self.isolated_creds.get('primary'): |
| return self.isolated_creds.get('primary') |
| creds = self._get_creds() |
| primary_credential = auth.get_credentials(**creds) |
| self.isolated_creds['primary'] = primary_credential |
| return primary_credential |
| |
| def get_alt_creds(self): |
| if self.isolated_creds.get('alt'): |
| return self.isolated_creds.get('alt') |
| creds = self._get_creds() |
| alt_credential = auth.get_credentials(**creds) |
| self.isolated_creds['alt'] = alt_credential |
| return alt_credential |
| |
| def clear_isolated_creds(self): |
| for creds in self.isolated_creds.values(): |
| self.remove_credentials(creds) |
| |
| def get_admin_creds(self): |
| msg = ('If admin credentials are available tenant_isolation should be' |
| ' used instead') |
| raise NotImplementedError(msg) |
| |
| |
| class NotLockingAccounts(Accounts): |
| """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 get_creds(self, id): |
| try: |
| # No need to sort the dict as within the same python process |
| # the HASH seed won't change, so subsequent calls to keys() |
| # will return the same result |
| _hash = self.hash_dict.keys()[id] |
| except IndexError: |
| msg = 'Insufficient number of users provided' |
| raise exceptions.InvalidConfiguration(msg) |
| return self.hash_dict[_hash] |
| |
| def get_primary_creds(self): |
| if self.isolated_creds.get('primary'): |
| return self.isolated_creds.get('primary') |
| if not self.use_default_creds: |
| creds = self.get_creds(0) |
| primary_credential = auth.get_credentials(**creds) |
| else: |
| primary_credential = auth.get_default_credentials('user') |
| self.isolated_creds['primary'] = primary_credential |
| return primary_credential |
| |
| def get_alt_creds(self): |
| if self.isolated_creds.get('alt'): |
| return self.isolated_creds.get('alt') |
| if not self.use_default_creds: |
| creds = self.get_creds(1) |
| alt_credential = auth.get_credentials(**creds) |
| else: |
| alt_credential = auth.get_default_credentials('alt_user') |
| self.isolated_creds['alt'] = alt_credential |
| return alt_credential |
| |
| def clear_isolated_creds(self): |
| self.isolated_creds = {} |
| |
| def get_admin_creds(self): |
| return auth.get_default_credentials("identity_admin", fill_in=False) |