Improve deep merge for parameters
This allows for merging lists and deep merging maps. This does not support comma_delimited_lists and is implemented by using parameter schema in the subsequent patches. Change-Id: I89df95eca713a7125cc53ed8bf352274f28bf6d9 Blueprint: environment_merging
This commit is contained in:
parent
59b2a559ec
commit
5b0fe81270
@ -12,7 +12,9 @@
|
||||
# under the License.
|
||||
import collections
|
||||
|
||||
from heat.common import environment_format
|
||||
import six
|
||||
|
||||
from heat.common import environment_format as env_fmt
|
||||
|
||||
ALLOWED_PARAM_MERGE_STRATEGIES = (OVERWRITE, MERGE, DEEP_MERGE) = (
|
||||
'overwrite', 'merge', 'deep_merge')
|
||||
@ -32,14 +34,37 @@ def get_param_merge_strategy(merge_strategies, param_key):
|
||||
return env_default
|
||||
|
||||
|
||||
def deep_update(old, new):
|
||||
'''Merge nested dictionaries.'''
|
||||
def merge_list(old, new):
|
||||
"""merges lists and comma delimited lists."""
|
||||
if not old:
|
||||
return new
|
||||
|
||||
if isinstance(new, list):
|
||||
old.extend(new)
|
||||
return old
|
||||
else:
|
||||
return ','.join([old, new])
|
||||
|
||||
|
||||
def merge_map(old, new, deep_merge=False):
|
||||
"""Merge nested dictionaries."""
|
||||
if not old:
|
||||
return new
|
||||
|
||||
for k, v in new.items():
|
||||
if isinstance(v, collections.Mapping):
|
||||
r = deep_update(old.get(k, {}), v)
|
||||
old[k] = r
|
||||
else:
|
||||
old[k] = new[k]
|
||||
if v:
|
||||
if not deep_merge:
|
||||
old[k] = v
|
||||
elif isinstance(v, collections.Mapping):
|
||||
old_v = old.get(k)
|
||||
old[k] = merge_map(old_v, v, deep_merge) if old_v else v
|
||||
elif (isinstance(v, collections.Sequence) and
|
||||
not isinstance(v, six.string_types)):
|
||||
old_v = old.get(k)
|
||||
old[k] = merge_list(old_v, v) if old_v else v
|
||||
else:
|
||||
old[k] = v
|
||||
|
||||
return old
|
||||
|
||||
|
||||
@ -60,8 +85,14 @@ def merge_environments(environment_files, files, params):
|
||||
:param params: parameters describing the stack
|
||||
:type dict:
|
||||
"""
|
||||
if environment_files:
|
||||
for filename in environment_files:
|
||||
raw_env = files[filename]
|
||||
parsed_env = environment_format.parse(raw_env)
|
||||
deep_update(params, parsed_env)
|
||||
if not environment_files:
|
||||
return
|
||||
|
||||
for filename in environment_files:
|
||||
raw_env = files[filename]
|
||||
parsed_env = env_fmt.parse(raw_env)
|
||||
for section_key, section_value in parsed_env.items():
|
||||
if section_value:
|
||||
params[section_key] = merge_map(params[section_key],
|
||||
section_value,
|
||||
deep_merge=True)
|
||||
|
@ -83,6 +83,45 @@ class TestMergeEnvironments(common.HeatTestCase):
|
||||
}}
|
||||
self.assertEqual(expected, params)
|
||||
|
||||
def test_merge_environments_deep_merge(self):
|
||||
# Setup
|
||||
params = {'parameters': {
|
||||
'p0': 'CORRECT',
|
||||
'p1': ['CORRECT1'],
|
||||
'p2': {'A': ['CORRECT1', 'CORRECT2']},
|
||||
'p3': 'CORRECT1,CORRECT2'}
|
||||
}
|
||||
env_1 = '''
|
||||
{'parameters' : {
|
||||
'p1': ['CORRECT2', 'CORRECT3'],
|
||||
'p2': {'B': ['CORRECT3', 'CORRECT4'],
|
||||
'C': [CORRECT5]},
|
||||
'p3': 'CORRECT3,CORRECT4'
|
||||
}}'''
|
||||
env_2 = '''
|
||||
{'parameters': {
|
||||
'p2': {'C': ['CORRECT6']},
|
||||
'p3': 'CORRECT5,CORRECT6'
|
||||
}}'''
|
||||
|
||||
files = {'env_1': env_1, 'env_2': env_2}
|
||||
environment_files = ['env_1', 'env_2']
|
||||
|
||||
# Test
|
||||
env_util.merge_environments(environment_files, files, params)
|
||||
|
||||
# Verify
|
||||
# Does not work for comma_delimited_list.
|
||||
expected = {'parameters': {
|
||||
'p0': 'CORRECT',
|
||||
'p1': ['CORRECT1', 'CORRECT2', 'CORRECT3'],
|
||||
'p2': {'A': ['CORRECT1', 'CORRECT2'],
|
||||
'B': ['CORRECT3', 'CORRECT4'],
|
||||
'C': ['CORRECT5', 'CORRECT6']},
|
||||
'p3': 'CORRECT5,CORRECT6'
|
||||
}}
|
||||
self.assertEqual(expected, params)
|
||||
|
||||
def test_merge_environments_no_env_files(self):
|
||||
params = {'parameters': {'p0': 'CORRECT'}}
|
||||
env_1 = '''
|
||||
|
Loading…
Reference in New Issue
Block a user