Retain the ordering when using with MultiStringOp
When using config_template with a MultiStringOp the order was subject to change because of the use of set theory. This change converts the use of sets to tuples which allow us to retain the ability to override options without losing the ordering of keys. Change-Id: Id0bba86629a33ce74528c0bd51b11183f5315d86 Signed-off-by: Kevin Carter <kevin.carter@rackspace.com> (cherry picked from commit 662a2805c0dce43a1efec31a85e09056207ec3d2)
This commit is contained in:
parent
371ed922f4
commit
0f91706487
|
@ -33,6 +33,7 @@ import re
|
||||||
import time
|
import time
|
||||||
import yaml
|
import yaml
|
||||||
import tempfile as tmpfilelib
|
import tempfile as tmpfilelib
|
||||||
|
|
||||||
from ansible.plugins.action import ActionBase
|
from ansible.plugins.action import ActionBase
|
||||||
from ansible.module_utils._text import to_bytes, to_text
|
from ansible.module_utils._text import to_bytes, to_text
|
||||||
from ansible import constants as C
|
from ansible import constants as C
|
||||||
|
@ -58,7 +59,7 @@ class MultiKeyDict(dict):
|
||||||
"""Dictionary class which supports duplicate keys.
|
"""Dictionary class which supports duplicate keys.
|
||||||
This class allows for an item to be added into a standard python dictionary
|
This class allows for an item to be added into a standard python dictionary
|
||||||
however if a key is created more than once the dictionary will convert the
|
however if a key is created more than once the dictionary will convert the
|
||||||
singular value to a python set. This set type forces all values to be a
|
singular value to a python tuple. This tuple type forces all values to be a
|
||||||
string.
|
string.
|
||||||
Example Usage:
|
Example Usage:
|
||||||
>>> z = MultiKeyDict()
|
>>> z = MultiKeyDict()
|
||||||
|
@ -69,17 +70,19 @@ class MultiKeyDict(dict):
|
||||||
... {'a': 1, 'b': ['a', 'b', 'c'], 'c': {'a': 1}}
|
... {'a': 1, 'b': ['a', 'b', 'c'], 'c': {'a': 1}}
|
||||||
>>> z['a'] = 2
|
>>> z['a'] = 2
|
||||||
>>> print(z)
|
>>> print(z)
|
||||||
... {'a': set(['1', '2']), 'c': {'a': 1}, 'b': ['a', 'b', 'c']}
|
... {'a': tuple(['1', '2']), 'c': {'a': 1}, 'b': ['a', 'b', 'c']}
|
||||||
"""
|
"""
|
||||||
def __setitem__(self, key, value):
|
def __setitem__(self, key, value):
|
||||||
if key in self:
|
if key in self:
|
||||||
if isinstance(self[key], set):
|
if isinstance(self[key], tuple):
|
||||||
items = self[key]
|
items = self[key]
|
||||||
items.add(str(value))
|
if str(value) not in items:
|
||||||
super(MultiKeyDict, self).__setitem__(key, items)
|
items += tuple([str(value)])
|
||||||
|
super(MultiKeyDict, self).__setitem__(key, items)
|
||||||
else:
|
else:
|
||||||
items = [str(value), str(self[key])]
|
if str(self[key]) != str(value):
|
||||||
super(MultiKeyDict, self).__setitem__(key, set(items))
|
items = tuple([str(self[key]), str(value)])
|
||||||
|
super(MultiKeyDict, self).__setitem__(key, items)
|
||||||
else:
|
else:
|
||||||
return dict.__setitem__(self, key, value)
|
return dict.__setitem__(self, key, value)
|
||||||
|
|
||||||
|
@ -148,7 +151,7 @@ class ConfigTemplateParser(ConfigParser.RawConfigParser):
|
||||||
fp.write(entry)
|
fp.write(entry)
|
||||||
|
|
||||||
def _write_check(self, fp, key, value, section=False):
|
def _write_check(self, fp, key, value, section=False):
|
||||||
if isinstance(value, set):
|
if isinstance(value, (tuple, set)):
|
||||||
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)
|
||||||
|
@ -210,7 +213,7 @@ class ConfigTemplateParser(ConfigParser.RawConfigParser):
|
||||||
if line[0].isspace() and cursect is not None and optname:
|
if line[0].isspace() and cursect is not None and optname:
|
||||||
value = line.strip()
|
value = line.strip()
|
||||||
if value:
|
if value:
|
||||||
if isinstance(cursect[optname], set):
|
if isinstance(cursect[optname], (tuple, set)):
|
||||||
_temp_item = list(cursect[optname])
|
_temp_item = list(cursect[optname])
|
||||||
del cursect[optname]
|
del cursect[optname]
|
||||||
cursect[optname] = _temp_item
|
cursect[optname] = _temp_item
|
||||||
|
@ -350,11 +353,13 @@ class ActionModule(ActionBase):
|
||||||
def _option_write(config, section, key, value):
|
def _option_write(config, section, key, value):
|
||||||
config.remove_option(str(section), str(key))
|
config.remove_option(str(section), str(key))
|
||||||
try:
|
try:
|
||||||
if not any(i for i in value.values()):
|
if not any(list(value.values())):
|
||||||
value = set(value)
|
value = tuple(value.keys())
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
if isinstance(value, set):
|
if isinstance(value, (tuple, set)):
|
||||||
|
config.set(str(section), str(key), value)
|
||||||
|
elif isinstance(value, set):
|
||||||
config.set(str(section), str(key), value)
|
config.set(str(section), str(key), value)
|
||||||
elif isinstance(value, list):
|
elif isinstance(value, list):
|
||||||
config.set(str(section), str(key), ','.join(str(i) for i in value))
|
config.set(str(section), str(key), ','.join(str(i) for i in value))
|
||||||
|
@ -434,6 +439,13 @@ class ActionModule(ActionBase):
|
||||||
base_items[key].extend(value)
|
base_items[key].extend(value)
|
||||||
else:
|
else:
|
||||||
base_items[key] = value
|
base_items[key] = value
|
||||||
|
elif isinstance(value, (tuple, set)):
|
||||||
|
if isinstance(base_items.get(key), tuple) and list_extend:
|
||||||
|
base_items[key] += tuple(value)
|
||||||
|
elif isinstance(base_items.get(key), list) and list_extend:
|
||||||
|
base_items[key].extend(list(value))
|
||||||
|
else:
|
||||||
|
base_items[key] = value
|
||||||
else:
|
else:
|
||||||
base_items[key] = new_items[key]
|
base_items[key] = new_items[key]
|
||||||
return base_items
|
return base_items
|
||||||
|
|
Loading…
Reference in New Issue