blob: e21a85e5e74d996efd7dd0f3794e186ebcb335aa [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 Treinish4041b262015-02-27 11:18:54 -050040 self.name = name
Matthew Treinishb19eeb82014-09-04 09:57:46 -040041 if os.path.isfile(CONF.auth.test_accounts_file):
42 accounts = read_accounts_yaml(CONF.auth.test_accounts_file)
43 self.use_default_creds = False
44 else:
45 accounts = {}
46 self.use_default_creds = True
Matthew Treinishc791ac42014-07-16 09:15:23 -040047 self.hash_dict = self.get_hash_dict(accounts)
48 self.accounts_dir = os.path.join(CONF.lock_path, 'test_accounts')
49 self.isolated_creds = {}
50
51 @classmethod
52 def get_hash_dict(cls, accounts):
53 hash_dict = {}
54 for account in accounts:
55 temp_hash = hashlib.md5()
56 temp_hash.update(str(account))
57 hash_dict[temp_hash.hexdigest()] = account
58 return hash_dict
59
Matthew Treinish09f17832014-08-15 15:22:50 -040060 def is_multi_user(self):
Andrea Frittoli8283b4e2014-07-17 13:28:58 +010061 # Default credentials is not a valid option with locking Account
62 if self.use_default_creds:
63 raise exceptions.InvalidConfiguration(
64 "Account file %s doesn't exist" % CONF.auth.test_accounts_file)
65 else:
66 return len(self.hash_dict) > 1
Matthew Treinish09f17832014-08-15 15:22:50 -040067
Yair Fried76488d72014-10-21 10:13:19 +030068 def is_multi_tenant(self):
69 return self.is_multi_user()
70
Matthew Treinish09f17832014-08-15 15:22:50 -040071 def _create_hash_file(self, hash_string):
72 path = os.path.join(os.path.join(self.accounts_dir, hash_string))
Matthew Treinishc791ac42014-07-16 09:15:23 -040073 if not os.path.isfile(path):
Matthew Treinish4041b262015-02-27 11:18:54 -050074 with open(path, 'w') as fd:
75 fd.write(self.name)
Matthew Treinishc791ac42014-07-16 09:15:23 -040076 return True
77 return False
78
79 @lockutils.synchronized('test_accounts_io', external=True)
80 def _get_free_hash(self, hashes):
81 if not os.path.isdir(self.accounts_dir):
82 os.mkdir(self.accounts_dir)
83 # Create File from first hash (since none are in use)
84 self._create_hash_file(hashes[0])
85 return hashes[0]
Matthew Treinish4041b262015-02-27 11:18:54 -050086 names = []
Matthew Treinish09f17832014-08-15 15:22:50 -040087 for _hash in hashes:
88 res = self._create_hash_file(_hash)
Matthew Treinishc791ac42014-07-16 09:15:23 -040089 if res:
Matthew Treinish09f17832014-08-15 15:22:50 -040090 return _hash
Matthew Treinish4041b262015-02-27 11:18:54 -050091 else:
92 path = os.path.join(os.path.join(self.accounts_dir,
93 _hash))
94 with open(path, 'r') as fd:
95 names.append(fd.read())
96 msg = ('Insufficient number of users provided. %s have allocated all '
97 'the credentials for this allocation request' % ','.join(names))
Matthew Treinishc791ac42014-07-16 09:15:23 -040098 raise exceptions.InvalidConfiguration(msg)
99
100 def _get_creds(self):
Matthew Treinishb19eeb82014-09-04 09:57:46 -0400101 if self.use_default_creds:
102 raise exceptions.InvalidConfiguration(
103 "Account file %s doesn't exist" % CONF.auth.test_accounts_file)
Matthew Treinish09f17832014-08-15 15:22:50 -0400104 free_hash = self._get_free_hash(self.hash_dict.keys())
Matthew Treinishc791ac42014-07-16 09:15:23 -0400105 return self.hash_dict[free_hash]
106
107 @lockutils.synchronized('test_accounts_io', external=True)
Matthew Treinish09f17832014-08-15 15:22:50 -0400108 def remove_hash(self, hash_string):
109 hash_path = os.path.join(self.accounts_dir, hash_string)
Matthew Treinishc791ac42014-07-16 09:15:23 -0400110 if not os.path.isfile(hash_path):
111 LOG.warning('Expected an account lock file %s to remove, but '
Matthew Treinish53a2b4b2015-02-24 23:32:07 -0500112 'one did not exist' % hash_path)
Matthew Treinishc791ac42014-07-16 09:15:23 -0400113 else:
114 os.remove(hash_path)
115 if not os.listdir(self.accounts_dir):
116 os.rmdir(self.accounts_dir)
117
118 def get_hash(self, creds):
Matthew Treinish09f17832014-08-15 15:22:50 -0400119 for _hash in self.hash_dict:
Andrea Frittoli9efbe952015-01-29 12:43:09 +0000120 # Comparing on the attributes that were read from the YAML
Matthew Treinish09f17832014-08-15 15:22:50 -0400121 if all([getattr(creds, k) == self.hash_dict[_hash][k] for k in
Andrea Frittoli9efbe952015-01-29 12:43:09 +0000122 creds.get_init_attributes()]):
Matthew Treinish09f17832014-08-15 15:22:50 -0400123 return _hash
Matthew Treinishc791ac42014-07-16 09:15:23 -0400124 raise AttributeError('Invalid credentials %s' % creds)
125
126 def remove_credentials(self, creds):
Matthew Treinish09f17832014-08-15 15:22:50 -0400127 _hash = self.get_hash(creds)
128 self.remove_hash(_hash)
Matthew Treinishc791ac42014-07-16 09:15:23 -0400129
130 def get_primary_creds(self):
Matthew Treinish09f17832014-08-15 15:22:50 -0400131 if self.isolated_creds.get('primary'):
132 return self.isolated_creds.get('primary')
Matthew Treinishc791ac42014-07-16 09:15:23 -0400133 creds = self._get_creds()
Andrea Frittoli878d5ab2015-01-30 13:22:50 +0000134 primary_credential = cred_provider.get_credentials(**creds)
Matthew Treinish09f17832014-08-15 15:22:50 -0400135 self.isolated_creds['primary'] = primary_credential
Matthew Treinishc791ac42014-07-16 09:15:23 -0400136 return primary_credential
137
138 def get_alt_creds(self):
Matthew Treinish09f17832014-08-15 15:22:50 -0400139 if self.isolated_creds.get('alt'):
140 return self.isolated_creds.get('alt')
Matthew Treinishc791ac42014-07-16 09:15:23 -0400141 creds = self._get_creds()
Andrea Frittoli878d5ab2015-01-30 13:22:50 +0000142 alt_credential = cred_provider.get_credentials(**creds)
Matthew Treinish09f17832014-08-15 15:22:50 -0400143 self.isolated_creds['alt'] = alt_credential
Matthew Treinishc791ac42014-07-16 09:15:23 -0400144 return alt_credential
145
146 def clear_isolated_creds(self):
Matthew Treinish09f17832014-08-15 15:22:50 -0400147 for creds in self.isolated_creds.values():
Matthew Treinishc791ac42014-07-16 09:15:23 -0400148 self.remove_credentials(creds)
149
150 def get_admin_creds(self):
151 msg = ('If admin credentials are available tenant_isolation should be'
152 ' used instead')
153 raise NotImplementedError(msg)
Andrea Frittolib1c23fc2014-09-03 13:40:08 +0100154
155
156class NotLockingAccounts(Accounts):
157 """Credentials provider which always returns the first and second
158 configured accounts as primary and alt users.
159 This credential provider can be used in case of serial test execution
160 to preserve the current behaviour of the serial tempest run.
161 """
162
Yair Fried76488d72014-10-21 10:13:19 +0300163 def _unique_creds(self, cred_arg=None):
164 """Verify that the configured credentials are valid and distinct """
Andrea Frittoli8283b4e2014-07-17 13:28:58 +0100165 if self.use_default_creds:
Andrea Frittoli8283b4e2014-07-17 13:28:58 +0100166 try:
167 user = self.get_primary_creds()
168 alt_user = self.get_alt_creds()
Yair Fried76488d72014-10-21 10:13:19 +0300169 return getattr(user, cred_arg) != getattr(alt_user, cred_arg)
Andrea Frittoli8283b4e2014-07-17 13:28:58 +0100170 except exceptions.InvalidCredentials as ic:
171 msg = "At least one of the configured credentials is " \
172 "not valid: %s" % ic.message
173 raise exceptions.InvalidConfiguration(msg)
174 else:
175 # TODO(andreaf) Add a uniqueness check here
176 return len(self.hash_dict) > 1
177
Yair Fried76488d72014-10-21 10:13:19 +0300178 def is_multi_user(self):
179 return self._unique_creds('username')
180
181 def is_multi_tenant(self):
182 return self._unique_creds('tenant_id')
183
Andrea Frittolib1c23fc2014-09-03 13:40:08 +0100184 def get_creds(self, id):
185 try:
186 # No need to sort the dict as within the same python process
187 # the HASH seed won't change, so subsequent calls to keys()
188 # will return the same result
189 _hash = self.hash_dict.keys()[id]
190 except IndexError:
191 msg = 'Insufficient number of users provided'
192 raise exceptions.InvalidConfiguration(msg)
193 return self.hash_dict[_hash]
194
195 def get_primary_creds(self):
196 if self.isolated_creds.get('primary'):
197 return self.isolated_creds.get('primary')
Matthew Treinishb19eeb82014-09-04 09:57:46 -0400198 if not self.use_default_creds:
199 creds = self.get_creds(0)
Andrea Frittoli878d5ab2015-01-30 13:22:50 +0000200 primary_credential = cred_provider.get_credentials(**creds)
Matthew Treinishb19eeb82014-09-04 09:57:46 -0400201 else:
Andrea Frittoli9efbe952015-01-29 12:43:09 +0000202 primary_credential = cred_provider.get_configured_credentials(
203 'user')
Andrea Frittolib1c23fc2014-09-03 13:40:08 +0100204 self.isolated_creds['primary'] = primary_credential
205 return primary_credential
206
207 def get_alt_creds(self):
208 if self.isolated_creds.get('alt'):
209 return self.isolated_creds.get('alt')
Matthew Treinishb19eeb82014-09-04 09:57:46 -0400210 if not self.use_default_creds:
211 creds = self.get_creds(1)
Andrea Frittoli878d5ab2015-01-30 13:22:50 +0000212 alt_credential = cred_provider.get_credentials(**creds)
Matthew Treinishb19eeb82014-09-04 09:57:46 -0400213 else:
Andrea Frittoli9efbe952015-01-29 12:43:09 +0000214 alt_credential = cred_provider.get_configured_credentials(
215 'alt_user')
Andrea Frittolib1c23fc2014-09-03 13:40:08 +0100216 self.isolated_creds['alt'] = alt_credential
217 return alt_credential
218
219 def clear_isolated_creds(self):
220 self.isolated_creds = {}
221
222 def get_admin_creds(self):
Andrea Frittoli9efbe952015-01-29 12:43:09 +0000223 return cred_provider.get_configured_credentials(
224 "identity_admin", fill_in=False)