Add ignore_none_type to config template
It is sometimes useful to tell ConfigTemplateParser to write out options that are valueless and not suffixed with '=' or ':', such as when overriding a my.cnf. This commit adds the 'ignore_none_type' attribute to the config_template module. If this attribute is set to false, then valueless options will be written out to the resultant INI file as-is, without the '=' or ':' suffix. Change-Id: I5c88b2019c01b44193a5d0df9299ecce6de52f01 Partial-Bug: #1693234
This commit is contained in:
parent
30af08208d
commit
76d5f02a32
@ -155,9 +155,17 @@ class ConfigTemplateParser(ConfigParser.RawConfigParser):
|
|||||||
key = var3
|
key = var3
|
||||||
key = var2
|
key = var2
|
||||||
"""
|
"""
|
||||||
def _write(self, fp, section, item, entry):
|
def __init__(self, *args, **kwargs):
|
||||||
|
self.ignore_none_type = bool(kwargs.pop('ignore_none_type', True))
|
||||||
|
ConfigParser.RawConfigParser.__init__(self, *args, **kwargs)
|
||||||
|
|
||||||
|
def _write(self, fp, section, key, item, entry):
|
||||||
if section:
|
if section:
|
||||||
if (item is not None) or (self._optcre == self.OPTCRE):
|
# If we are not ignoring a none type value, then print out
|
||||||
|
# the option name only if the value type is None.
|
||||||
|
if not self.ignore_none_type and item is None:
|
||||||
|
fp.write(key + '\n')
|
||||||
|
elif (item is not None) or (self._optcre == self.OPTCRE):
|
||||||
fp.write(entry)
|
fp.write(entry)
|
||||||
else:
|
else:
|
||||||
fp.write(entry)
|
fp.write(entry)
|
||||||
@ -167,14 +175,14 @@ class ConfigTemplateParser(ConfigParser.RawConfigParser):
|
|||||||
for item in value:
|
for item in value:
|
||||||
item = str(item).replace('\n', '\n\t')
|
item = str(item).replace('\n', '\n\t')
|
||||||
entry = "%s = %s\n" % (key, item)
|
entry = "%s = %s\n" % (key, item)
|
||||||
self._write(fp, section, item, entry)
|
self._write(fp, section, key, item, entry)
|
||||||
else:
|
else:
|
||||||
if isinstance(value, list):
|
if isinstance(value, list):
|
||||||
_value = [str(i.replace('\n', '\n\t')) for i in value]
|
_value = [str(i.replace('\n', '\n\t')) for i in value]
|
||||||
entry = '%s = %s\n' % (key, ','.join(_value))
|
entry = '%s = %s\n' % (key, ','.join(_value))
|
||||||
else:
|
else:
|
||||||
entry = '%s = %s\n' % (key, str(value).replace('\n', '\n\t'))
|
entry = '%s = %s\n' % (key, str(value).replace('\n', '\n\t'))
|
||||||
self._write(fp, section, value, entry)
|
self._write(fp, section, key, value, entry)
|
||||||
|
|
||||||
def write(self, fp):
|
def write(self, fp):
|
||||||
if self._defaults:
|
if self._defaults:
|
||||||
@ -268,7 +276,11 @@ class ConfigTemplateParser(ConfigParser.RawConfigParser):
|
|||||||
class ActionModule(ActionBase):
|
class ActionModule(ActionBase):
|
||||||
TRANSFERS_FILES = True
|
TRANSFERS_FILES = True
|
||||||
|
|
||||||
def return_config_overrides_ini(self, config_overrides, resultant, list_extend=True):
|
def return_config_overrides_ini(self,
|
||||||
|
config_overrides,
|
||||||
|
resultant,
|
||||||
|
list_extend=True,
|
||||||
|
ignore_none_type=True):
|
||||||
"""Returns string value from a modified config file.
|
"""Returns string value from a modified config file.
|
||||||
|
|
||||||
:param config_overrides: ``dict``
|
:param config_overrides: ``dict``
|
||||||
@ -281,7 +293,8 @@ class ActionModule(ActionBase):
|
|||||||
try:
|
try:
|
||||||
config = ConfigTemplateParser(
|
config = ConfigTemplateParser(
|
||||||
allow_no_value=True,
|
allow_no_value=True,
|
||||||
dict_type=MultiKeyDict
|
dict_type=MultiKeyDict,
|
||||||
|
ignore_none_type=ignore_none_type
|
||||||
)
|
)
|
||||||
config.optionxform = str
|
config.optionxform = str
|
||||||
except Exception:
|
except Exception:
|
||||||
@ -344,7 +357,11 @@ class ActionModule(ActionBase):
|
|||||||
else:
|
else:
|
||||||
config.set(str(section), str(key), str(value))
|
config.set(str(section), str(key), str(value))
|
||||||
|
|
||||||
def return_config_overrides_json(self, config_overrides, resultant, list_extend=True):
|
def return_config_overrides_json(self,
|
||||||
|
config_overrides,
|
||||||
|
resultant,
|
||||||
|
list_extend=True,
|
||||||
|
ignore_none_type=True):
|
||||||
"""Returns config json
|
"""Returns config json
|
||||||
|
|
||||||
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
|
||||||
@ -366,7 +383,11 @@ class ActionModule(ActionBase):
|
|||||||
sort_keys=True
|
sort_keys=True
|
||||||
)
|
)
|
||||||
|
|
||||||
def return_config_overrides_yaml(self, config_overrides, resultant, list_extend=True):
|
def return_config_overrides_yaml(self,
|
||||||
|
config_overrides,
|
||||||
|
resultant,
|
||||||
|
list_extend=True,
|
||||||
|
ignore_none_type=True):
|
||||||
"""Return config yaml.
|
"""Return config yaml.
|
||||||
|
|
||||||
:param config_overrides: ``dict``
|
:param config_overrides: ``dict``
|
||||||
@ -484,13 +505,23 @@ class ActionModule(ActionBase):
|
|||||||
if user_dest.endswith(os.sep):
|
if user_dest.endswith(os.sep):
|
||||||
user_dest = os.path.join(user_dest, os.path.basename(source))
|
user_dest = os.path.join(user_dest, os.path.basename(source))
|
||||||
|
|
||||||
|
# Get ignore_none_type
|
||||||
|
# In some situations(i.e. my.cnf files), INI files can have valueless
|
||||||
|
# options that don't have a '=' or ':' suffix. In these cases,
|
||||||
|
# ConfigParser gives these options a "None" value. If ignore_none_type
|
||||||
|
# is set to true, these key/value options will be ignored, if it's set
|
||||||
|
# to false, then ConfigTemplateParser will write out only the option
|
||||||
|
# name with out the '=' or ':' suffix. The default is true.
|
||||||
|
ignore_none_type = self._task.args.get('ignore_none_type', True)
|
||||||
|
|
||||||
return True, dict(
|
return True, dict(
|
||||||
source=source,
|
source=source,
|
||||||
dest=user_dest,
|
dest=user_dest,
|
||||||
config_overrides=self._task.args.get('config_overrides', dict()),
|
config_overrides=self._task.args.get('config_overrides', dict()),
|
||||||
config_type=config_type,
|
config_type=config_type,
|
||||||
searchpath=searchpath,
|
searchpath=searchpath,
|
||||||
list_extend=list_extend
|
list_extend=list_extend,
|
||||||
|
ignore_none_type=ignore_none_type
|
||||||
)
|
)
|
||||||
|
|
||||||
def run(self, tmp=None, task_vars=None):
|
def run(self, tmp=None, task_vars=None):
|
||||||
@ -563,7 +594,8 @@ class ActionModule(ActionBase):
|
|||||||
resultant = type_merger(
|
resultant = type_merger(
|
||||||
config_overrides=_vars['config_overrides'],
|
config_overrides=_vars['config_overrides'],
|
||||||
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)
|
||||||
)
|
)
|
||||||
|
|
||||||
# Re-template the resultant object as it may have new data within it
|
# Re-template the resultant object as it may have new data within it
|
||||||
@ -595,6 +627,7 @@ class ActionModule(ActionBase):
|
|||||||
new_module_args.pop('config_overrides', None)
|
new_module_args.pop('config_overrides', None)
|
||||||
new_module_args.pop('config_type', None)
|
new_module_args.pop('config_type', None)
|
||||||
new_module_args.pop('list_extend', None)
|
new_module_args.pop('list_extend', None)
|
||||||
|
new_module_args.pop('ignore_none_type', 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)
|
||||||
|
|
||||||
|
@ -49,6 +49,16 @@ options:
|
|||||||
choices:
|
choices:
|
||||||
- True
|
- True
|
||||||
- False
|
- False
|
||||||
|
ignore_none_type:
|
||||||
|
description:
|
||||||
|
- Can be true or false. If ignore_none_type is set to true, then
|
||||||
|
valueless INI options will not be written out to the resultant file.
|
||||||
|
If it's set to false, then config_template will write out only
|
||||||
|
the option name without the '=' or ':' suffix. The default is true.
|
||||||
|
choices:
|
||||||
|
- True
|
||||||
|
- False
|
||||||
|
|
||||||
author: Kevin Carter
|
author: Kevin Carter
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
The config_template template module now supports writing out valueless
|
||||||
|
INI options without suffixing them with '=' or ':'. This is done via the
|
||||||
|
'ignore_none_type' attribute. If ignore_none_type is set to true, these
|
||||||
|
key/value entries will be ignored, if it's set to false, then
|
||||||
|
ConfigTemplateParser will write out only the option name without the
|
||||||
|
'=' or ':' suffix. The default is true.
|
8
tests/templates/test_ignore_none_type.ini
Normal file
8
tests/templates/test_ignore_none_type.ini
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
[alfa]
|
||||||
|
bravo = charlie
|
||||||
|
delta = echo
|
||||||
|
[foxtrot]
|
||||||
|
golf = hotel
|
||||||
|
india
|
||||||
|
juliett kilo
|
||||||
|
lima = mike
|
@ -136,6 +136,26 @@
|
|||||||
that:
|
that:
|
||||||
- "(content_no_overrides_file.content | b64decode | from_json) == (content_no_overrides_file_expected.content | b64decode | from_json)"
|
- "(content_no_overrides_file.content | b64decode | from_json) == (content_no_overrides_file_expected.content | b64decode | from_json)"
|
||||||
|
|
||||||
|
# Test the ignore_none_type attribute when set to False
|
||||||
|
- name: Template test with ignore_none_type set to false
|
||||||
|
config_template:
|
||||||
|
src: "{{ playbook_dir }}/templates/test_ignore_none_type.ini"
|
||||||
|
dest: "/tmp/test_ignore_none_type.ini"
|
||||||
|
config_overrides: "{{ test_config_ini_overrides }}"
|
||||||
|
config_type: "ini"
|
||||||
|
ignore_none_type: False
|
||||||
|
- name: Read test_ignore_none_type.ini
|
||||||
|
slurp:
|
||||||
|
src: /tmp/test_ignore_none_type.ini
|
||||||
|
register: test_ignore_none_type
|
||||||
|
- debug:
|
||||||
|
msg: "test_ignore_none_type.ini - {{ test_ignore_none_type.content | b64decode }}"
|
||||||
|
- name: Validate output has valueless options printed out
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- "{{ test_ignore_none_type.content | b64decode | search('(?m)^india$') }}"
|
||||||
|
- "{{ test_ignore_none_type.content | b64decode | search('(?m)^juliett kilo$') }}"
|
||||||
|
|
||||||
vars:
|
vars:
|
||||||
test_config_ini_overrides:
|
test_config_ini_overrides:
|
||||||
DEFAULT:
|
DEFAULT:
|
||||||
|
Loading…
Reference in New Issue
Block a user