config_template does not respect yaml multiline as overrides

Added a flag called yml_multilines which when used will not split on
lines that have a newline UNLESS they have a comma.

Change-Id: I90364403e215a67b320dfc7e67a85d47c774e634
Partial-Bug: #1819974
This commit is contained in:
Georgina 2019-04-24 16:27:21 +00:00
parent 937d9956e6
commit 1769158a0e
5 changed files with 79 additions and 11 deletions

View File

@ -46,7 +46,6 @@ from ansible import __version__ as __ansible_version__
__metaclass__ = type __metaclass__ = type
CONFIG_TYPES = { CONFIG_TYPES = {
'ini': 'return_config_overrides_ini', 'ini': 'return_config_overrides_ini',
'json': 'return_config_overrides_json', 'json': 'return_config_overrides_json',
@ -144,6 +143,7 @@ class ConfigTemplateParser(ConfigParser.RawConfigParser):
self._comments = {} self._comments = {}
self.ignore_none_type = bool(kwargs.pop('ignore_none_type', True)) self.ignore_none_type = bool(kwargs.pop('ignore_none_type', True))
self.default_section = str(kwargs.pop('default_section', 'DEFAULT')) self.default_section = str(kwargs.pop('default_section', 'DEFAULT'))
self.yml_multilines = bool(kwargs.pop('yml_multilines', False))
ConfigParser.RawConfigParser.__init__(self, *args, **kwargs) ConfigParser.RawConfigParser.__init__(self, *args, **kwargs)
def _write(self, fp, section, key, item, entry): def _write(self, fp, section, key, item, entry):
@ -398,7 +398,8 @@ class ActionModule(ActionBase):
resultant, resultant,
list_extend=True, list_extend=True,
ignore_none_type=True, ignore_none_type=True,
default_section='DEFAULT'): default_section='DEFAULT',
yml_multilines=False):
"""Returns string value from a modified config file and dict of """Returns string value from a modified config file and dict of
merged config merged config
@ -414,7 +415,8 @@ class ActionModule(ActionBase):
allow_no_value=True, allow_no_value=True,
dict_type=MultiKeyDict, dict_type=MultiKeyDict,
ignore_none_type=ignore_none_type, ignore_none_type=ignore_none_type,
default_section=default_section default_section=default_section,
yml_multilines=yml_multilines
) )
config.optionxform = str config.optionxform = str
except Exception: except Exception:
@ -498,7 +500,8 @@ class ActionModule(ActionBase):
resultant, resultant,
list_extend=True, list_extend=True,
ignore_none_type=True, ignore_none_type=True,
default_section='DEFAULT'): default_section='DEFAULT',
yml_multilines=False):
"""Returns config json and dict of merged config """Returns config json and dict of merged config
Its important to note that file ordering will not be preserved as the Its important to note that file ordering will not be preserved as the
@ -525,7 +528,8 @@ class ActionModule(ActionBase):
resultant, resultant,
list_extend=True, list_extend=True,
ignore_none_type=True, ignore_none_type=True,
default_section='DEFAULT'): default_section='DEFAULT',
yml_multilines=False):
"""Return config yaml and dict of merged config """Return config yaml and dict of merged config
:param config_overrides: ``dict`` :param config_overrides: ``dict``
@ -536,7 +540,8 @@ class ActionModule(ActionBase):
merged_resultant = self._merge_dict( merged_resultant = self._merge_dict(
base_items=original_resultant, base_items=original_resultant,
new_items=config_overrides, new_items=config_overrides,
list_extend=list_extend list_extend=list_extend,
yml_multilines=yml_multilines
) )
return yaml.dump( return yaml.dump(
merged_resultant, merged_resultant,
@ -545,7 +550,11 @@ class ActionModule(ActionBase):
width=1000, width=1000,
), merged_resultant ), merged_resultant
def _merge_dict(self, base_items, new_items, list_extend=True): def _merge_dict(self,
base_items,
new_items,
list_extend=True,
yml_multilines=False):
"""Recursively merge new_items into base_items. """Recursively merge new_items into base_items.
:param base_items: ``dict`` :param base_items: ``dict``
@ -560,7 +569,8 @@ class ActionModule(ActionBase):
list_extend=list_extend list_extend=list_extend
) )
elif (not isinstance(value, int) and elif (not isinstance(value, int) and
(',' in value or '\n' in value)): (',' in value or
('\n' in value and not yml_multilines))):
base_items[key] = re.split(',|\n', value) base_items[key] = re.split(',|\n', value)
base_items[key] = [i.strip() for i in base_items[key] if i] base_items[key] = [i.strip() for i in base_items[key] if i]
elif isinstance(value, list): elif isinstance(value, list):
@ -662,6 +672,8 @@ class ActionModule(ActionBase):
default_section = self._task.args.get('default_section', 'DEFAULT') default_section = self._task.args.get('default_section', 'DEFAULT')
yml_multilines = self._task.args.get('yml_multilines', False)
return True, dict( return True, dict(
source=source, source=source,
dest=user_dest, dest=user_dest,
@ -670,7 +682,8 @@ class ActionModule(ActionBase):
searchpath=searchpath, searchpath=searchpath,
list_extend=list_extend, list_extend=list_extend,
ignore_none_type=ignore_none_type, ignore_none_type=ignore_none_type,
default_section=default_section default_section=default_section,
yml_multilines=yml_multilines
) )
def run(self, tmp=None, task_vars=None): def run(self, tmp=None, task_vars=None):
@ -745,7 +758,8 @@ class ActionModule(ActionBase):
resultant=resultant, resultant=resultant,
list_extend=_vars.get('list_extend', True), list_extend=_vars.get('list_extend', True),
ignore_none_type=_vars.get('ignore_none_type', True), ignore_none_type=_vars.get('ignore_none_type', True),
default_section=_vars.get('default_section', 'DEFAULT') default_section=_vars.get('default_section', 'DEFAULT'),
yml_multilines=_vars.get('yml_multilines', False)
) )
changed = False changed = False
@ -773,7 +787,8 @@ class ActionModule(ActionBase):
resultant=resultant_dest, resultant=resultant_dest,
list_extend=_vars.get('list_extend', True), list_extend=_vars.get('list_extend', True),
ignore_none_type=_vars.get('ignore_none_type', True), ignore_none_type=_vars.get('ignore_none_type', True),
default_section=_vars.get('default_section', 'DEFAULT') default_section=_vars.get('default_section', 'DEFAULT'),
yml_multilines=_vars.get('yml_multilines', False)
) )
# Compare source+overrides with dest to look for changes and # Compare source+overrides with dest to look for changes and
@ -822,6 +837,7 @@ class ActionModule(ActionBase):
new_module_args.pop('list_extend', None) new_module_args.pop('list_extend', None)
new_module_args.pop('ignore_none_type', None) new_module_args.pop('ignore_none_type', None)
new_module_args.pop('default_section', None) new_module_args.pop('default_section', None)
new_module_args.pop('yml_multilines', None)
# Content from config_template is converted to src # Content from config_template is converted to src
new_module_args.pop('content', None) new_module_args.pop('content', None)

View File

@ -0,0 +1,14 @@
existing_multiline: 'This multiline string
already exists and will
be dumped out by PyYaml.
'
new_multiline_str: 'This should not
be a list
'
test_category1: a
test_category2: b

View File

@ -0,0 +1,6 @@
test_category1: a
test_category2: b
existing_multiline: |
This multiline string
already exists and will
be dumped out by PyYaml.

View File

@ -14,6 +14,7 @@
# limitations under the License. # limitations under the License.
# #
# Test basic function of config_template # Test basic function of config_template
- name: Template test INI template - name: Template test INI template
config_template: config_template:
src: "{{ playbook_dir }}/templates/test.ini" src: "{{ playbook_dir }}/templates/test.ini"
@ -128,6 +129,28 @@
that: that:
- "((hostvars_file.content | b64decode | from_yaml).test_hostvar) == (test_config_yml_hostvars_overrides.test_hostvar)" - "((hostvars_file.content | b64decode | from_yaml).test_hostvar) == (test_config_yml_hostvars_overrides.test_hostvar)"
# Values containing newlines should not be chopped into a list
# when yml_multilines is set to True
- name: Test multiline strings in yaml
config_template:
src: "{{ playbook_dir }}/templates/test_multiline_strs.yml"
dest: "/tmp/multiline_strs.yml"
config_overrides: "{{ test_multiline_strs_yml_overrides }}"
config_type: yaml
yml_multilines: True
- name: Read multiline_strs.yml
slurp:
src: /tmp/multiline_strs.yml
register: multiline_strs_file
- debug:
msg: "Multiline Yaml Strings - {{ multiline_strs_file.content | b64decode }}"
- debug:
msg: "Multiline Yaml Strings Expected - {{ multiline_strs_file_expected.content | b64decode }}"
- name: Compare files
assert:
that:
- "(multiline_strs_file_expected.content | b64decode) == (multiline_strs_file.content | b64decode)"
# Test multistropt ordering # Test multistropt ordering
- name: Template MultiStrOpts using overrides - name: Template MultiStrOpts using overrides
config_template: config_template:

View File

@ -58,6 +58,11 @@
src: "{{ playbook_dir }}/files/test_content_no_overrides.json.expected" src: "{{ playbook_dir }}/files/test_content_no_overrides.json.expected"
register: content_no_overrides_file_expected register: content_no_overrides_file_expected
- name: Read expected test_multiline_strs.yml
slurp:
src: "{{ playbook_dir }}/files/test_multiline_strs.yml.expected"
register: multiline_strs_file_expected
- import_tasks: test-common-tasks.yml - import_tasks: test-common-tasks.yml
- import_tasks: test-common-tasks.yml - import_tasks: test-common-tasks.yml
@ -161,6 +166,10 @@
- 4 - 4
test_config_yml_hostvars_overrides: test_config_yml_hostvars_overrides:
test_hostvar: "{{ ansible_default_ipv4.address }}" test_hostvar: "{{ ansible_default_ipv4.address }}"
test_multiline_strs_yml_overrides:
new_multiline_str: |
This should not
be a list
test_default_section_overrides: test_default_section_overrides:
global: global:
test2: 2 test2: 2