Fixes ordering of environment files in a deployment plan

Sometimes making changes in basic deployment breaks the order of
passed env files and leads to a failed deployment.  This patch
orders the environment files according to the rules defined in
the capabilities-map.yaml file.

Change-Id: Idbb6f0f3adebebd429bcb3447e559838180f4b1c
(cherry picked from commit bae4296502)
This commit is contained in:
Ryan Brady 2018-05-23 11:03:36 -04:00
parent 451aace65e
commit e95d51f989
4 changed files with 109 additions and 2 deletions

View File

@ -193,6 +193,23 @@ class UpdateCapabilitiesAction(base.TripleOAction):
self.cache_delete(context, self.container, "tripleo.parameters.get")
# get the capabilities-map content to perform the environment ordering
try:
swift = self.get_object_client(context)
map_file = swift.get_object(
self.container, 'capabilities-map.yaml')
capabilities = yaml.safe_load(map_file[1])
except swiftexceptions.ClientException as err:
err_msg = ("Error retrieving capabilities-map.yaml for "
"plan %s: %s" % (self.container, err))
LOG.exception(err_msg)
return actions.Result(error=err_msg)
ordered_env = plan_utils.apply_environments_order(
capabilities, env.get('environments', []))
env['environments'] = ordered_env
try:
plan_utils.put_env(swift, env)
except swiftexceptions.ClientException as err:

View File

@ -246,7 +246,9 @@ class UpdateCapabilitiesActionTest(base.TestCase):
- path: /path/to/overcloud-default-env.yaml
- path: /path/to/ceph-storage-env.yaml
"""
swift.get_object.return_value = ({}, mocked_env)
swift.get_object.side_effect = (
({}, mocked_env),
({}, MAPPING_YAML_CONTENTS))
get_object_client_mock.return_value = swift
environments = {
@ -287,7 +289,9 @@ class UpdateCapabilitiesActionTest(base.TestCase):
- path: /path/to/overcloud-default-env.yaml
- path: /path/to/ceph-storage-env.yaml
"""
swift.get_object.return_value = ({}, mocked_env)
swift.get_object.side_effect = (
({}, mocked_env),
({}, MAPPING_YAML_CONTENTS))
get_object_client_mock.return_value = swift
environments = {

View File

@ -37,6 +37,41 @@ passwords:
ZaqarPassword: zzzz
"""
USER_ENV_CONTENTS = """
resource_registry:
OS::TripleO::Foo: bar.yaml
"""
UNORDERED_PLAN_ENV_LIST = [
{'path': 'overcloud-resource-registry-puppet.yaml'},
{'path': 'environments/docker-ha.yaml'},
{'path': 'environments/containers-default-parameters.yaml'},
{'path': 'environments/docker.yaml'}
]
CAPABILITIES_DICT = {
'topics': [{
'environment_groups': [{
'environments': [{
'file': 'overcloud-resource-registry-puppet.yaml'}
]}, {
'environments': [{
'file': 'environments/docker.yaml',
'requires': ['overcloud-resource-registry-puppet.yaml']
}, {
'file': 'environments/containers-default-parameters.yaml',
'requires': ['overcloud-resource-registry-puppet.yaml',
'environments/docker.yaml']
}]}, {
'environments': [{
'file': 'environments/docker-ha.yaml',
'requires': ['overcloud-resource-registry-puppet.yaml',
'environments/docker.yaml']
}]}
]
}]
}
class PlanTest(base.TestCase):
def setUp(self):
@ -90,3 +125,15 @@ class PlanTest(base.TestCase):
self.swift.get_object.assert_called()
self.swift.put_object.assert_called()
def test_apply_env_order(self):
ordered_plan_env_list = [
{'path': 'overcloud-resource-registry-puppet.yaml'},
{'path': 'environments/docker.yaml'},
{'path': 'environments/docker-ha.yaml'},
{'path': 'environments/containers-default-parameters.yaml'}
]
ordered_env = plan_utils.apply_environments_order(
CAPABILITIES_DICT, UNORDERED_PLAN_ENV_LIST)
self.assertEqual(ordered_env, ordered_plan_env_list)

View File

@ -56,3 +56,42 @@ def put_env(swift, env):
constants.PLAN_ENVIRONMENT,
yaml.safe_dump(env, default_flow_style=False)
)
def apply_environments_order(capabilities, environments):
"""traverses the capabilities and orders the environment files
by dependency rules defined in capabilities-map, so that parent
environments are first and children environments override these
parents
:param capabilities: dict representing capabilities-map.yaml file
:param environments: list representing the environments section of the
plan-environments.yaml file
:return: list containing ordered environments
"""
# get ordering rules from capabilities-map file
order_rules = {}
for topic in capabilities.get('topics', []):
for group in topic.get('environment_groups', []):
for environment in group.get('environments', []):
order_rules[environment['file']] = []
if 'requires' in environment:
order_rules[environment['file']] \
= environment.get('requires', [])
# apply ordering rules
for e in environments:
path = e.get('path', '')
if path not in order_rules:
continue
path_pos = environments.index(e)
for requirement in order_rules[path]:
if {'path': requirement} in environments:
requirement_pos = environments.index({'path': requirement})
if requirement_pos > path_pos:
item = environments.pop(requirement_pos)
environments.insert(path_pos, item)
return environments