blob: 66285e4605388114f78e4c507f8f3621308f7405 [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
20from tempest import auth
21from tempest.common import cred_provider
22from tempest import config
23from tempest import exceptions
24from tempest.openstack.common import lockutils
25from tempest.openstack.common import log as logging
26
27CONF = config.CONF
28LOG = logging.getLogger(__name__)
29
30
31def read_accounts_yaml(path):
32 yaml_file = open(path, 'r')
33 accounts = yaml.load(yaml_file)
34 return accounts
35
36
37class Accounts(cred_provider.CredentialProvider):
38
39 def __init__(self, name):
40 super(Accounts, self).__init__(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):
74 open(path, 'w').close()
75 return True
76 return False
77
78 @lockutils.synchronized('test_accounts_io', external=True)
79 def _get_free_hash(self, hashes):
80 if not os.path.isdir(self.accounts_dir):
81 os.mkdir(self.accounts_dir)
82 # Create File from first hash (since none are in use)
83 self._create_hash_file(hashes[0])
84 return hashes[0]
Matthew Treinish09f17832014-08-15 15:22:50 -040085 for _hash in hashes:
86 res = self._create_hash_file(_hash)
Matthew Treinishc791ac42014-07-16 09:15:23 -040087 if res:
Matthew Treinish09f17832014-08-15 15:22:50 -040088 return _hash
Matthew Treinishc791ac42014-07-16 09:15:23 -040089 msg = 'Insufficient number of users provided'
90 raise exceptions.InvalidConfiguration(msg)
91
92 def _get_creds(self):
Matthew Treinishb19eeb82014-09-04 09:57:46 -040093 if self.use_default_creds:
94 raise exceptions.InvalidConfiguration(
95 "Account file %s doesn't exist" % CONF.auth.test_accounts_file)
Matthew Treinish09f17832014-08-15 15:22:50 -040096 free_hash = self._get_free_hash(self.hash_dict.keys())
Matthew Treinishc791ac42014-07-16 09:15:23 -040097 return self.hash_dict[free_hash]
98
99 @lockutils.synchronized('test_accounts_io', external=True)
Matthew Treinish09f17832014-08-15 15:22:50 -0400100 def remove_hash(self, hash_string):
101 hash_path = os.path.join(self.accounts_dir, hash_string)
Matthew Treinishc791ac42014-07-16 09:15:23 -0400102 if not os.path.isfile(hash_path):
103 LOG.warning('Expected an account lock file %s to remove, but '
104 'one did not exist')
105 else:
106 os.remove(hash_path)
107 if not os.listdir(self.accounts_dir):
108 os.rmdir(self.accounts_dir)
109
110 def get_hash(self, creds):
Matthew Treinish09f17832014-08-15 15:22:50 -0400111 for _hash in self.hash_dict:
112 # Comparing on the attributes that are expected in the YAML
113 if all([getattr(creds, k) == self.hash_dict[_hash][k] for k in
114 creds.CONF_ATTRIBUTES]):
115 return _hash
Matthew Treinishc791ac42014-07-16 09:15:23 -0400116 raise AttributeError('Invalid credentials %s' % creds)
117
118 def remove_credentials(self, creds):
Matthew Treinish09f17832014-08-15 15:22:50 -0400119 _hash = self.get_hash(creds)
120 self.remove_hash(_hash)
Matthew Treinishc791ac42014-07-16 09:15:23 -0400121
122 def get_primary_creds(self):
Matthew Treinish09f17832014-08-15 15:22:50 -0400123 if self.isolated_creds.get('primary'):
124 return self.isolated_creds.get('primary')
Matthew Treinishc791ac42014-07-16 09:15:23 -0400125 creds = self._get_creds()
126 primary_credential = auth.get_credentials(**creds)
Matthew Treinish09f17832014-08-15 15:22:50 -0400127 self.isolated_creds['primary'] = primary_credential
Matthew Treinishc791ac42014-07-16 09:15:23 -0400128 return primary_credential
129
130 def get_alt_creds(self):
Matthew Treinish09f17832014-08-15 15:22:50 -0400131 if self.isolated_creds.get('alt'):
132 return self.isolated_creds.get('alt')
Matthew Treinishc791ac42014-07-16 09:15:23 -0400133 creds = self._get_creds()
134 alt_credential = auth.get_credentials(**creds)
Matthew Treinish09f17832014-08-15 15:22:50 -0400135 self.isolated_creds['alt'] = alt_credential
Matthew Treinishc791ac42014-07-16 09:15:23 -0400136 return alt_credential
137
138 def clear_isolated_creds(self):
Matthew Treinish09f17832014-08-15 15:22:50 -0400139 for creds in self.isolated_creds.values():
Matthew Treinishc791ac42014-07-16 09:15:23 -0400140 self.remove_credentials(creds)
141
142 def get_admin_creds(self):
143 msg = ('If admin credentials are available tenant_isolation should be'
144 ' used instead')
145 raise NotImplementedError(msg)
Andrea Frittolib1c23fc2014-09-03 13:40:08 +0100146
147
148class NotLockingAccounts(Accounts):
149 """Credentials provider which always returns the first and second
150 configured accounts as primary and alt users.
151 This credential provider can be used in case of serial test execution
152 to preserve the current behaviour of the serial tempest run.
153 """
154
Yair Fried76488d72014-10-21 10:13:19 +0300155 def _unique_creds(self, cred_arg=None):
156 """Verify that the configured credentials are valid and distinct """
Andrea Frittoli8283b4e2014-07-17 13:28:58 +0100157 if self.use_default_creds:
Andrea Frittoli8283b4e2014-07-17 13:28:58 +0100158 try:
159 user = self.get_primary_creds()
160 alt_user = self.get_alt_creds()
Yair Fried76488d72014-10-21 10:13:19 +0300161 return getattr(user, cred_arg) != getattr(alt_user, cred_arg)
Andrea Frittoli8283b4e2014-07-17 13:28:58 +0100162 except exceptions.InvalidCredentials as ic:
163 msg = "At least one of the configured credentials is " \
164 "not valid: %s" % ic.message
165 raise exceptions.InvalidConfiguration(msg)
166 else:
167 # TODO(andreaf) Add a uniqueness check here
168 return len(self.hash_dict) > 1
169
Yair Fried76488d72014-10-21 10:13:19 +0300170 def is_multi_user(self):
171 return self._unique_creds('username')
172
173 def is_multi_tenant(self):
174 return self._unique_creds('tenant_id')
175
Andrea Frittolib1c23fc2014-09-03 13:40:08 +0100176 def get_creds(self, id):
177 try:
178 # No need to sort the dict as within the same python process
179 # the HASH seed won't change, so subsequent calls to keys()
180 # will return the same result
181 _hash = self.hash_dict.keys()[id]
182 except IndexError:
183 msg = 'Insufficient number of users provided'
184 raise exceptions.InvalidConfiguration(msg)
185 return self.hash_dict[_hash]
186
187 def get_primary_creds(self):
188 if self.isolated_creds.get('primary'):
189 return self.isolated_creds.get('primary')
Matthew Treinishb19eeb82014-09-04 09:57:46 -0400190 if not self.use_default_creds:
191 creds = self.get_creds(0)
192 primary_credential = auth.get_credentials(**creds)
193 else:
194 primary_credential = auth.get_default_credentials('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)
203 alt_credential = auth.get_credentials(**creds)
204 else:
205 alt_credential = auth.get_default_credentials('alt_user')
Andrea Frittolib1c23fc2014-09-03 13:40:08 +0100206 self.isolated_creds['alt'] = alt_credential
207 return alt_credential
208
209 def clear_isolated_creds(self):
210 self.isolated_creds = {}
211
212 def get_admin_creds(self):
213 return auth.get_default_credentials("identity_admin", fill_in=False)