blob: 88e8ced081955a5bdbbf57832785dd0212653862 [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
68 def _create_hash_file(self, hash_string):
69 path = os.path.join(os.path.join(self.accounts_dir, hash_string))
Matthew Treinishc791ac42014-07-16 09:15:23 -040070 if not os.path.isfile(path):
71 open(path, 'w').close()
72 return True
73 return False
74
75 @lockutils.synchronized('test_accounts_io', external=True)
76 def _get_free_hash(self, hashes):
77 if not os.path.isdir(self.accounts_dir):
78 os.mkdir(self.accounts_dir)
79 # Create File from first hash (since none are in use)
80 self._create_hash_file(hashes[0])
81 return hashes[0]
Matthew Treinish09f17832014-08-15 15:22:50 -040082 for _hash in hashes:
83 res = self._create_hash_file(_hash)
Matthew Treinishc791ac42014-07-16 09:15:23 -040084 if res:
Matthew Treinish09f17832014-08-15 15:22:50 -040085 return _hash
Matthew Treinishc791ac42014-07-16 09:15:23 -040086 msg = 'Insufficient number of users provided'
87 raise exceptions.InvalidConfiguration(msg)
88
89 def _get_creds(self):
Matthew Treinishb19eeb82014-09-04 09:57:46 -040090 if self.use_default_creds:
91 raise exceptions.InvalidConfiguration(
92 "Account file %s doesn't exist" % CONF.auth.test_accounts_file)
Matthew Treinish09f17832014-08-15 15:22:50 -040093 free_hash = self._get_free_hash(self.hash_dict.keys())
Matthew Treinishc791ac42014-07-16 09:15:23 -040094 return self.hash_dict[free_hash]
95
96 @lockutils.synchronized('test_accounts_io', external=True)
Matthew Treinish09f17832014-08-15 15:22:50 -040097 def remove_hash(self, hash_string):
98 hash_path = os.path.join(self.accounts_dir, hash_string)
Matthew Treinishc791ac42014-07-16 09:15:23 -040099 if not os.path.isfile(hash_path):
100 LOG.warning('Expected an account lock file %s to remove, but '
101 'one did not exist')
102 else:
103 os.remove(hash_path)
104 if not os.listdir(self.accounts_dir):
105 os.rmdir(self.accounts_dir)
106
107 def get_hash(self, creds):
Matthew Treinish09f17832014-08-15 15:22:50 -0400108 for _hash in self.hash_dict:
109 # Comparing on the attributes that are expected in the YAML
110 if all([getattr(creds, k) == self.hash_dict[_hash][k] for k in
111 creds.CONF_ATTRIBUTES]):
112 return _hash
Matthew Treinishc791ac42014-07-16 09:15:23 -0400113 raise AttributeError('Invalid credentials %s' % creds)
114
115 def remove_credentials(self, creds):
Matthew Treinish09f17832014-08-15 15:22:50 -0400116 _hash = self.get_hash(creds)
117 self.remove_hash(_hash)
Matthew Treinishc791ac42014-07-16 09:15:23 -0400118
119 def get_primary_creds(self):
Matthew Treinish09f17832014-08-15 15:22:50 -0400120 if self.isolated_creds.get('primary'):
121 return self.isolated_creds.get('primary')
Matthew Treinishc791ac42014-07-16 09:15:23 -0400122 creds = self._get_creds()
123 primary_credential = auth.get_credentials(**creds)
Matthew Treinish09f17832014-08-15 15:22:50 -0400124 self.isolated_creds['primary'] = primary_credential
Matthew Treinishc791ac42014-07-16 09:15:23 -0400125 return primary_credential
126
127 def get_alt_creds(self):
Matthew Treinish09f17832014-08-15 15:22:50 -0400128 if self.isolated_creds.get('alt'):
129 return self.isolated_creds.get('alt')
Matthew Treinishc791ac42014-07-16 09:15:23 -0400130 creds = self._get_creds()
131 alt_credential = auth.get_credentials(**creds)
Matthew Treinish09f17832014-08-15 15:22:50 -0400132 self.isolated_creds['alt'] = alt_credential
Matthew Treinishc791ac42014-07-16 09:15:23 -0400133 return alt_credential
134
135 def clear_isolated_creds(self):
Matthew Treinish09f17832014-08-15 15:22:50 -0400136 for creds in self.isolated_creds.values():
Matthew Treinishc791ac42014-07-16 09:15:23 -0400137 self.remove_credentials(creds)
138
139 def get_admin_creds(self):
140 msg = ('If admin credentials are available tenant_isolation should be'
141 ' used instead')
142 raise NotImplementedError(msg)
Andrea Frittolib1c23fc2014-09-03 13:40:08 +0100143
144
145class NotLockingAccounts(Accounts):
146 """Credentials provider which always returns the first and second
147 configured accounts as primary and alt users.
148 This credential provider can be used in case of serial test execution
149 to preserve the current behaviour of the serial tempest run.
150 """
151
Andrea Frittoli8283b4e2014-07-17 13:28:58 +0100152 def is_multi_user(self):
153 if self.use_default_creds:
154 # Verify that the configured users are valid and distinct
155 try:
156 user = self.get_primary_creds()
157 alt_user = self.get_alt_creds()
158 return user.username != alt_user.username
159 except exceptions.InvalidCredentials as ic:
160 msg = "At least one of the configured credentials is " \
161 "not valid: %s" % ic.message
162 raise exceptions.InvalidConfiguration(msg)
163 else:
164 # TODO(andreaf) Add a uniqueness check here
165 return len(self.hash_dict) > 1
166
Andrea Frittolib1c23fc2014-09-03 13:40:08 +0100167 def get_creds(self, id):
168 try:
169 # No need to sort the dict as within the same python process
170 # the HASH seed won't change, so subsequent calls to keys()
171 # will return the same result
172 _hash = self.hash_dict.keys()[id]
173 except IndexError:
174 msg = 'Insufficient number of users provided'
175 raise exceptions.InvalidConfiguration(msg)
176 return self.hash_dict[_hash]
177
178 def get_primary_creds(self):
179 if self.isolated_creds.get('primary'):
180 return self.isolated_creds.get('primary')
Matthew Treinishb19eeb82014-09-04 09:57:46 -0400181 if not self.use_default_creds:
182 creds = self.get_creds(0)
183 primary_credential = auth.get_credentials(**creds)
184 else:
185 primary_credential = auth.get_default_credentials('user')
Andrea Frittolib1c23fc2014-09-03 13:40:08 +0100186 self.isolated_creds['primary'] = primary_credential
187 return primary_credential
188
189 def get_alt_creds(self):
190 if self.isolated_creds.get('alt'):
191 return self.isolated_creds.get('alt')
Matthew Treinishb19eeb82014-09-04 09:57:46 -0400192 if not self.use_default_creds:
193 creds = self.get_creds(1)
194 alt_credential = auth.get_credentials(**creds)
195 else:
196 alt_credential = auth.get_default_credentials('alt_user')
Andrea Frittolib1c23fc2014-09-03 13:40:08 +0100197 self.isolated_creds['alt'] = alt_credential
198 return alt_credential
199
200 def clear_isolated_creds(self):
201 self.isolated_creds = {}
202
203 def get_admin_creds(self):
204 return auth.get_default_credentials("identity_admin", fill_in=False)