blob: 9ecf596cda955212958beac731b8f1331339f3a5 [file] [log] [blame]
Matthew Treinishc791ac42014-07-16 09:15:23 -04001# Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may
4# not use this file except in compliance with the License. You may obtain
5# a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations
13# under the License.
14
15import hashlib
16import os
Matthew Treinish96e9e882014-06-09 18:37:19 -040017
Matthew Treinishc791ac42014-07-16 09:15:23 -040018import yaml
19
Matthew Treinishc791ac42014-07-16 09:15:23 -040020from tempest.common import cred_provider
21from tempest import config
22from tempest import exceptions
23from tempest.openstack.common import lockutils
24from tempest.openstack.common import log as logging
25
26CONF = config.CONF
27LOG = logging.getLogger(__name__)
28
29
30def read_accounts_yaml(path):
31 yaml_file = open(path, 'r')
32 accounts = yaml.load(yaml_file)
33 return accounts
34
35
36class Accounts(cred_provider.CredentialProvider):
37
38 def __init__(self, name):
39 super(Accounts, self).__init__(name)
Matthew Treinishb19eeb82014-09-04 09:57:46 -040040 if os.path.isfile(CONF.auth.test_accounts_file):
41 accounts = read_accounts_yaml(CONF.auth.test_accounts_file)
42 self.use_default_creds = False
43 else:
44 accounts = {}
45 self.use_default_creds = True
Matthew Treinishc791ac42014-07-16 09:15:23 -040046 self.hash_dict = self.get_hash_dict(accounts)
47 self.accounts_dir = os.path.join(CONF.lock_path, 'test_accounts')
48 self.isolated_creds = {}
49
50 @classmethod
51 def get_hash_dict(cls, accounts):
52 hash_dict = {}
53 for account in accounts:
54 temp_hash = hashlib.md5()
55 temp_hash.update(str(account))
56 hash_dict[temp_hash.hexdigest()] = account
57 return hash_dict
58
Matthew Treinish09f17832014-08-15 15:22:50 -040059 def is_multi_user(self):
Andrea Frittoli8283b4e2014-07-17 13:28:58 +010060 # Default credentials is not a valid option with locking Account
61 if self.use_default_creds:
62 raise exceptions.InvalidConfiguration(
63 "Account file %s doesn't exist" % CONF.auth.test_accounts_file)
64 else:
65 return len(self.hash_dict) > 1
Matthew Treinish09f17832014-08-15 15:22:50 -040066
Yair Fried76488d72014-10-21 10:13:19 +030067 def is_multi_tenant(self):
68 return self.is_multi_user()
69
Matthew Treinish09f17832014-08-15 15:22:50 -040070 def _create_hash_file(self, hash_string):
71 path = os.path.join(os.path.join(self.accounts_dir, hash_string))
Matthew Treinishc791ac42014-07-16 09:15:23 -040072 if not os.path.isfile(path):
73 open(path, 'w').close()
74 return True
75 return False
76
77 @lockutils.synchronized('test_accounts_io', external=True)
78 def _get_free_hash(self, hashes):
79 if not os.path.isdir(self.accounts_dir):
80 os.mkdir(self.accounts_dir)
81 # Create File from first hash (since none are in use)
82 self._create_hash_file(hashes[0])
83 return hashes[0]
Matthew Treinish09f17832014-08-15 15:22:50 -040084 for _hash in hashes:
85 res = self._create_hash_file(_hash)
Matthew Treinishc791ac42014-07-16 09:15:23 -040086 if res:
Matthew Treinish09f17832014-08-15 15:22:50 -040087 return _hash
Matthew Treinishc791ac42014-07-16 09:15:23 -040088 msg = 'Insufficient number of users provided'
89 raise exceptions.InvalidConfiguration(msg)
90
91 def _get_creds(self):
Matthew Treinishb19eeb82014-09-04 09:57:46 -040092 if self.use_default_creds:
93 raise exceptions.InvalidConfiguration(
94 "Account file %s doesn't exist" % CONF.auth.test_accounts_file)
Matthew Treinish09f17832014-08-15 15:22:50 -040095 free_hash = self._get_free_hash(self.hash_dict.keys())
Matthew Treinishc791ac42014-07-16 09:15:23 -040096 return self.hash_dict[free_hash]
97
98 @lockutils.synchronized('test_accounts_io', external=True)
Matthew Treinish09f17832014-08-15 15:22:50 -040099 def remove_hash(self, hash_string):
100 hash_path = os.path.join(self.accounts_dir, hash_string)
Matthew Treinishc791ac42014-07-16 09:15:23 -0400101 if not os.path.isfile(hash_path):
102 LOG.warning('Expected an account lock file %s to remove, but '
Matthew Treinish53a2b4b2015-02-24 23:32:07 -0500103 'one did not exist' % hash_path)
Matthew Treinishc791ac42014-07-16 09:15:23 -0400104 else:
105 os.remove(hash_path)
106 if not os.listdir(self.accounts_dir):
107 os.rmdir(self.accounts_dir)
108
109 def get_hash(self, creds):
Matthew Treinish09f17832014-08-15 15:22:50 -0400110 for _hash in self.hash_dict:
Andrea Frittoli9efbe952015-01-29 12:43:09 +0000111 # Comparing on the attributes that were read from the YAML
Matthew Treinish09f17832014-08-15 15:22:50 -0400112 if all([getattr(creds, k) == self.hash_dict[_hash][k] for k in
Andrea Frittoli9efbe952015-01-29 12:43:09 +0000113 creds.get_init_attributes()]):
Matthew Treinish09f17832014-08-15 15:22:50 -0400114 return _hash
Matthew Treinishc791ac42014-07-16 09:15:23 -0400115 raise AttributeError('Invalid credentials %s' % creds)
116
117 def remove_credentials(self, creds):
Matthew Treinish09f17832014-08-15 15:22:50 -0400118 _hash = self.get_hash(creds)
119 self.remove_hash(_hash)
Matthew Treinishc791ac42014-07-16 09:15:23 -0400120
121 def get_primary_creds(self):
Matthew Treinish09f17832014-08-15 15:22:50 -0400122 if self.isolated_creds.get('primary'):
123 return self.isolated_creds.get('primary')
Matthew Treinishc791ac42014-07-16 09:15:23 -0400124 creds = self._get_creds()
Andrea Frittoli878d5ab2015-01-30 13:22:50 +0000125 primary_credential = cred_provider.get_credentials(**creds)
Matthew Treinish09f17832014-08-15 15:22:50 -0400126 self.isolated_creds['primary'] = primary_credential
Matthew Treinishc791ac42014-07-16 09:15:23 -0400127 return primary_credential
128
129 def get_alt_creds(self):
Matthew Treinish09f17832014-08-15 15:22:50 -0400130 if self.isolated_creds.get('alt'):
131 return self.isolated_creds.get('alt')
Matthew Treinishc791ac42014-07-16 09:15:23 -0400132 creds = self._get_creds()
Andrea Frittoli878d5ab2015-01-30 13:22:50 +0000133 alt_credential = cred_provider.get_credentials(**creds)
Matthew Treinish09f17832014-08-15 15:22:50 -0400134 self.isolated_creds['alt'] = alt_credential
Matthew Treinishc791ac42014-07-16 09:15:23 -0400135 return alt_credential
136
137 def clear_isolated_creds(self):
Matthew Treinish09f17832014-08-15 15:22:50 -0400138 for creds in self.isolated_creds.values():
Matthew Treinishc791ac42014-07-16 09:15:23 -0400139 self.remove_credentials(creds)
140
141 def get_admin_creds(self):
142 msg = ('If admin credentials are available tenant_isolation should be'
143 ' used instead')
144 raise NotImplementedError(msg)
Andrea Frittolib1c23fc2014-09-03 13:40:08 +0100145
146
147class NotLockingAccounts(Accounts):
148 """Credentials provider which always returns the first and second
149 configured accounts as primary and alt users.
150 This credential provider can be used in case of serial test execution
151 to preserve the current behaviour of the serial tempest run.
152 """
153
Yair Fried76488d72014-10-21 10:13:19 +0300154 def _unique_creds(self, cred_arg=None):
155 """Verify that the configured credentials are valid and distinct """
Andrea Frittoli8283b4e2014-07-17 13:28:58 +0100156 if self.use_default_creds:
Andrea Frittoli8283b4e2014-07-17 13:28:58 +0100157 try:
158 user = self.get_primary_creds()
159 alt_user = self.get_alt_creds()
Yair Fried76488d72014-10-21 10:13:19 +0300160 return getattr(user, cred_arg) != getattr(alt_user, cred_arg)
Andrea Frittoli8283b4e2014-07-17 13:28:58 +0100161 except exceptions.InvalidCredentials as ic:
162 msg = "At least one of the configured credentials is " \
163 "not valid: %s" % ic.message
164 raise exceptions.InvalidConfiguration(msg)
165 else:
166 # TODO(andreaf) Add a uniqueness check here
167 return len(self.hash_dict) > 1
168
Yair Fried76488d72014-10-21 10:13:19 +0300169 def is_multi_user(self):
170 return self._unique_creds('username')
171
172 def is_multi_tenant(self):
173 return self._unique_creds('tenant_id')
174
Andrea Frittolib1c23fc2014-09-03 13:40:08 +0100175 def get_creds(self, id):
176 try:
177 # No need to sort the dict as within the same python process
178 # the HASH seed won't change, so subsequent calls to keys()
179 # will return the same result
180 _hash = self.hash_dict.keys()[id]
181 except IndexError:
182 msg = 'Insufficient number of users provided'
183 raise exceptions.InvalidConfiguration(msg)
184 return self.hash_dict[_hash]
185
186 def get_primary_creds(self):
187 if self.isolated_creds.get('primary'):
188 return self.isolated_creds.get('primary')
Matthew Treinishb19eeb82014-09-04 09:57:46 -0400189 if not self.use_default_creds:
190 creds = self.get_creds(0)
Andrea Frittoli878d5ab2015-01-30 13:22:50 +0000191 primary_credential = cred_provider.get_credentials(**creds)
Matthew Treinishb19eeb82014-09-04 09:57:46 -0400192 else:
Andrea Frittoli9efbe952015-01-29 12:43:09 +0000193 primary_credential = cred_provider.get_configured_credentials(
194 'user')
Andrea Frittolib1c23fc2014-09-03 13:40:08 +0100195 self.isolated_creds['primary'] = primary_credential
196 return primary_credential
197
198 def get_alt_creds(self):
199 if self.isolated_creds.get('alt'):
200 return self.isolated_creds.get('alt')
Matthew Treinishb19eeb82014-09-04 09:57:46 -0400201 if not self.use_default_creds:
202 creds = self.get_creds(1)
Andrea Frittoli878d5ab2015-01-30 13:22:50 +0000203 alt_credential = cred_provider.get_credentials(**creds)
Matthew Treinishb19eeb82014-09-04 09:57:46 -0400204 else:
Andrea Frittoli9efbe952015-01-29 12:43:09 +0000205 alt_credential = cred_provider.get_configured_credentials(
206 'alt_user')
Andrea Frittolib1c23fc2014-09-03 13:40:08 +0100207 self.isolated_creds['alt'] = alt_credential
208 return alt_credential
209
210 def clear_isolated_creds(self):
211 self.isolated_creds = {}
212
213 def get_admin_creds(self):
Andrea Frittoli9efbe952015-01-29 12:43:09 +0000214 return cred_provider.get_configured_credentials(
215 "identity_admin", fill_in=False)