summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2017-06-16 16:35:00 +0000
committerGerrit Code Review <review@openstack.org>2017-06-16 16:35:00 +0000
commit5852482c201540ababf7fee59b23bfcd8799e77f (patch)
tree74f3db1ba37552cfc41a10c28ba9856118aa7c13
parent93d87e069c526c17472f5c8b1a19f431342ef8fc (diff)
parentfcb992a6b9980f83b906dcf547826bc49395755c (diff)
Merge "Add fernet keys purging based no t-h-t parameter"
-rw-r--r--tripleo_common/actions/parameters.py50
-rw-r--r--tripleo_common/tests/actions/test_parameters.py51
2 files changed, 89 insertions, 12 deletions
diff --git a/tripleo_common/actions/parameters.py b/tripleo_common/actions/parameters.py
index 08bc814..9229ce7 100644
--- a/tripleo_common/actions/parameters.py
+++ b/tripleo_common/actions/parameters.py
@@ -263,11 +263,14 @@ class GetPasswordsAction(base.TripleOAction):
263 263
264 parameter_defaults = env.get('parameter_defaults', {}) 264 parameter_defaults = env.get('parameter_defaults', {})
265 passwords = env.get('passwords', {}) 265 passwords = env.get('passwords', {})
266
267 return self._get_overriden_passwords(passwords, parameter_defaults)
268
269 def _get_overriden_passwords(self, env_passwords, parameter_defaults):
266 for name in constants.PASSWORD_PARAMETER_NAMES: 270 for name in constants.PASSWORD_PARAMETER_NAMES:
267 if name in parameter_defaults: 271 if name in parameter_defaults:
268 passwords[name] = parameter_defaults[name] 272 env_passwords[name] = parameter_defaults[name]
269 273 return env_passwords
270 return passwords
271 274
272 275
273class GenerateFencingParametersAction(base.TripleOAction): 276class GenerateFencingParametersAction(base.TripleOAction):
@@ -479,14 +482,14 @@ class RotateFernetKeysAction(GetPasswordsAction):
479 return mistral_workflow_utils.Result(error=err_msg) 482 return mistral_workflow_utils.Result(error=err_msg)
480 483
481 parameter_defaults = env.get('parameter_defaults', {}) 484 parameter_defaults = env.get('parameter_defaults', {})
482 passwords = env.get('passwords', {}) 485 passwords = self._get_overriden_passwords(env.get('passwords', {}),
483 for name in constants.PASSWORD_PARAMETER_NAMES: 486 parameter_defaults)
484 if name in parameter_defaults:
485 passwords[name] = parameter_defaults[name]
486 487
487 next_index = self.get_next_index(passwords['KeystoneFernetKeys']) 488 next_index = self.get_next_index(passwords['KeystoneFernetKeys'])
488 keys_map = self.rotate_keys(passwords['KeystoneFernetKeys'], 489 keys_map = self.rotate_keys(passwords['KeystoneFernetKeys'],
489 next_index) 490 next_index)
491 max_keys = self.get_max_keys_value(parameter_defaults)
492 keys_map = self.purge_excess_keys(max_keys, keys_map)
490 493
491 env['passwords']['KeystoneFernetKeys'] = keys_map 494 env['passwords']['KeystoneFernetKeys'] = keys_map
492 495
@@ -503,14 +506,20 @@ class RotateFernetKeysAction(GetPasswordsAction):
503 506
504 return keys_map 507 return keys_map
505 508
509 @staticmethod
510 def get_key_index_from_path(path):
511 return int(path[path.rfind('/') + 1:])
512
506 def get_next_index(self, keys_map): 513 def get_next_index(self, keys_map):
507 def get_index(path): 514 return self.get_key_index_from_path(
508 return int(path[path.rfind('/') + 1:]) 515 max(keys_map, key=self.get_key_index_from_path)) + 1
509 return get_index(max(keys_map, key=get_index)) + 1 516
517 def get_key_path(self, index):
518 return password_utils.KEYSTONE_FERNET_REPO + str(index)
510 519
511 def rotate_keys(self, keys_map, next_index): 520 def rotate_keys(self, keys_map, next_index):
512 next_index_path = password_utils.KEYSTONE_FERNET_REPO + str(next_index) 521 next_index_path = self.get_key_path(next_index)
513 zero_index_path = password_utils.KEYSTONE_FERNET_REPO + '0' 522 zero_index_path = self.get_key_path(0)
514 523
515 # promote staged key to be new primary 524 # promote staged key to be new primary
516 keys_map[next_index_path] = keys_map[zero_index_path] 525 keys_map[next_index_path] = keys_map[zero_index_path]
@@ -518,3 +527,20 @@ class RotateFernetKeysAction(GetPasswordsAction):
518 keys_map[zero_index_path] = { 527 keys_map[zero_index_path] = {
519 'content': password_utils.create_keystone_credential()} 528 'content': password_utils.create_keystone_credential()}
520 return keys_map 529 return keys_map
530
531 def get_max_keys_value(self, parameter_defaults):
532 # The number of max keys should always be positive. The minimum amount
533 # of keys is 3.
534 return max(parameter_defaults.get('KeystoneFernetMaxActiveKeys', 5), 3)
535
536 def purge_excess_keys(self, max_keys, keys_map):
537 current_repo_size = len(keys_map)
538 if current_repo_size <= max_keys:
539 return keys_map
540 key_paths = sorted(keys_map.keys(), key=self.get_key_index_from_path)
541
542 keys_to_be_purged = current_repo_size - max_keys
543
544 for key_path in key_paths[1:keys_to_be_purged + 1]:
545 del keys_map[key_path]
546 return keys_map
diff --git a/tripleo_common/tests/actions/test_parameters.py b/tripleo_common/tests/actions/test_parameters.py
index 5ecb5c8..835d441 100644
--- a/tripleo_common/tests/actions/test_parameters.py
+++ b/tripleo_common/tests/actions/test_parameters.py
@@ -917,3 +917,54 @@ class RotateFernetKeysActionTest(base.TestCase):
917 # primary key should be the previous staged key 917 # primary key should be the previous staged key
918 self.assertEqual('Some key', 918 self.assertEqual('Some key',
919 new_keys_map[new_primary_key_index]['content']) 919 new_keys_map[new_primary_key_index]['content'])
920
921 def test_purge_excess_keys_should_purge(self):
922 action = parameters.RotateFernetKeysAction()
923 keys_map = {
924 password_utils.KEYSTONE_FERNET_REPO + '0': {
925 'content': 'key0'},
926 password_utils.KEYSTONE_FERNET_REPO + '1': {
927 'content': 'key1'},
928 password_utils.KEYSTONE_FERNET_REPO + '2': {
929 'content': 'key2'},
930 password_utils.KEYSTONE_FERNET_REPO + '3': {
931 'content': 'key3'},
932 password_utils.KEYSTONE_FERNET_REPO + '4': {
933 'content': 'key4'},
934 }
935 max_keys = 3
936 keys_map = action.purge_excess_keys(max_keys, keys_map)
937 self.assertEqual(max_keys, len(keys_map))
938 # It should keep index 0, 3 and 4
939 self.assertIn(password_utils.KEYSTONE_FERNET_REPO + '0', keys_map)
940 self.assertIn(password_utils.KEYSTONE_FERNET_REPO + '3', keys_map)
941 self.assertIn(password_utils.KEYSTONE_FERNET_REPO + '4', keys_map)
942 # It sould have removed index 1 and 2
943 self.assertNotIn(password_utils.KEYSTONE_FERNET_REPO + '1', keys_map)
944 self.assertNotIn(password_utils.KEYSTONE_FERNET_REPO + '2', keys_map)
945
946 def test_purge_excess_keys_should_not_purge_if_equal_to_max(self):
947 action = parameters.RotateFernetKeysAction()
948 keys_map = {
949 password_utils.KEYSTONE_FERNET_REPO + '0': {
950 'content': 'key0'},
951 password_utils.KEYSTONE_FERNET_REPO + '1': {
952 'content': 'key1'},
953 password_utils.KEYSTONE_FERNET_REPO + '2': {
954 'content': 'key2'},
955 }
956 max_keys = 3
957 keys_map = action.purge_excess_keys(max_keys, keys_map)
958 self.assertEqual(max_keys, len(keys_map))
959
960 def test_purge_excess_keys_should_not_purge_if_less_than_max(self):
961 action = parameters.RotateFernetKeysAction()
962 keys_map = {
963 password_utils.KEYSTONE_FERNET_REPO + '0': {
964 'content': 'key0'},
965 password_utils.KEYSTONE_FERNET_REPO + '1': {
966 'content': 'key1'},
967 }
968 max_keys = 3
969 keys_map = action.purge_excess_keys(max_keys, keys_map)
970 self.assertEqual(2, len(keys_map))