ansible.utils/plugins/module_utils/common/utils.py

113 lines
3.6 KiB
Python
Raw Normal View History

# -*- coding: utf-8 -*-
# Copyright 2020 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
from copy import deepcopy
from ansible.module_utils.common._collections_compat import Mapping
from ansible.module_utils.six import iteritems
def sort_list(val):
if isinstance(val, list):
if isinstance(val[0], dict):
sorted_keys = [tuple(sorted(dict_.keys())) for dict_ in val]
# All keys should be identical
if len(set(sorted_keys)) != 1:
raise ValueError("dictionaries do not match")
return sorted(
val, key=lambda d: tuple(d[k] for k in sorted_keys[0])
)
return sorted(val)
return val
def dict_merge(base, other):
"""Return a new dict object that combines base and other
This will create a new dict object that is a combination of the key/value
pairs from base and other. When both keys exist, the value will be
selected from other.
If the value in base is a list, and the value in other is a list
the base list will be extended with the values from the other list that were
not already present in the base list
If the value in base is a list, and the value in other is a list
and the two have the same entries, the value from other will be
used, preserving the order from the other list
If the value in base is a list, and the value in other is not a list
the value from other will be used
:param base: dict object to serve as base
:param other: dict object to combine with base
:returns: new combined dict object
"""
if not isinstance(base, dict):
raise AssertionError("`base` must be of type <dict>")
if not isinstance(other, dict):
raise AssertionError("`other` must be of type <dict>")
combined = dict()
for key, value in iteritems(deepcopy(base)):
if isinstance(value, dict):
if key in other:
item = other.get(key)
if item is not None:
if isinstance(other[key], Mapping):
combined[key] = dict_merge(value, other[key])
else:
combined[key] = other[key]
else:
combined[key] = item
else:
combined[key] = value
elif isinstance(value, list):
if key in other:
item = other.get(key)
if isinstance(item, list):
if sort_list(value) == sort_list(item):
combined[key] = item
else:
value.extend([i for i in item if i not in value])
combined[key] = value
else:
combined[key] = item
else:
combined[key] = value
else:
if key in other:
other_value = other.get(key)
if other_value is not None:
if sort_list(base[key]) != sort_list(other_value):
combined[key] = other_value
else:
combined[key] = value
else:
combined[key] = other_value
else:
combined[key] = value
for key in set(other.keys()).difference(base.keys()):
combined[key] = other.get(key)
return combined
def to_list(val):
if isinstance(val, (list, tuple, set)):
return list(val)
elif val is not None:
return [val]
else:
return list()