Merge "Improve deep merge for parameters"
This commit is contained in:
commit
ccaf7d1777
@ -12,7 +12,9 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
import collections
|
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) = (
|
ALLOWED_PARAM_MERGE_STRATEGIES = (OVERWRITE, MERGE, DEEP_MERGE) = (
|
||||||
'overwrite', 'merge', 'deep_merge')
|
'overwrite', 'merge', 'deep_merge')
|
||||||
@ -32,14 +34,37 @@ def get_param_merge_strategy(merge_strategies, param_key):
|
|||||||
return env_default
|
return env_default
|
||||||
|
|
||||||
|
|
||||||
def deep_update(old, new):
|
def merge_list(old, new):
|
||||||
'''Merge nested dictionaries.'''
|
"""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():
|
for k, v in new.items():
|
||||||
if isinstance(v, collections.Mapping):
|
if v:
|
||||||
r = deep_update(old.get(k, {}), v)
|
if not deep_merge:
|
||||||
old[k] = r
|
old[k] = v
|
||||||
else:
|
elif isinstance(v, collections.Mapping):
|
||||||
old[k] = new[k]
|
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
|
return old
|
||||||
|
|
||||||
|
|
||||||
@ -60,8 +85,14 @@ def merge_environments(environment_files, files, params):
|
|||||||
:param params: parameters describing the stack
|
:param params: parameters describing the stack
|
||||||
:type dict:
|
:type dict:
|
||||||
"""
|
"""
|
||||||
if environment_files:
|
if not environment_files:
|
||||||
for filename in environment_files:
|
return
|
||||||
raw_env = files[filename]
|
|
||||||
parsed_env = environment_format.parse(raw_env)
|
for filename in environment_files:
|
||||||
deep_update(params, parsed_env)
|
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)
|
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):
|
def test_merge_environments_no_env_files(self):
|
||||||
params = {'parameters': {'p0': 'CORRECT'}}
|
params = {'parameters': {'p0': 'CORRECT'}}
|
||||||
env_1 = '''
|
env_1 = '''
|
||||||
|
Loading…
Reference in New Issue
Block a user