mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-07-22 21:00:22 -07:00
docker_* modules: simplify idempotency comparisons (#47709)
* More generic comparison code from docker_container to docker_common. * More flexibility if a is None and method is allow_to_present. Note that this odes not affect docker_container, as there a is never None. * Update docker_secret and docker_config: simplify labels comparison. * Added unit tests. * Use proper subsequence test for allow_more_present for lists. Note that this does not affect existing code in docker_container, since lists don't use allow_more_present. Using allow_more_present will only be possible in Ansible 2.8. * pep8
This commit is contained in:
parent
e217ba6e19
commit
73533d3fc2
5 changed files with 577 additions and 103 deletions
|
@ -152,7 +152,7 @@ except ImportError:
|
|||
# missing docker-py handled in ansible.module_utils.docker
|
||||
pass
|
||||
|
||||
from ansible.module_utils.docker_common import AnsibleDockerClient, DockerBaseClass
|
||||
from ansible.module_utils.docker_common import AnsibleDockerClient, DockerBaseClass, compare_generic
|
||||
from ansible.module_utils._text import to_native, to_bytes
|
||||
|
||||
|
||||
|
@ -224,22 +224,8 @@ class ConfigManager(DockerBaseClass):
|
|||
if attrs.get('Labels', {}).get('ansible_key'):
|
||||
if attrs['Labels']['ansible_key'] != self.data_key:
|
||||
data_changed = True
|
||||
labels_changed = False
|
||||
if self.labels and attrs.get('Labels'):
|
||||
# check if user requested a label change
|
||||
for label in attrs['Labels']:
|
||||
if self.labels.get(label) and self.labels[label] != attrs['Labels'][label]:
|
||||
labels_changed = True
|
||||
# check if user added a label
|
||||
labels_added = False
|
||||
if self.labels:
|
||||
if attrs.get('Labels'):
|
||||
for label in self.labels:
|
||||
if label not in attrs['Labels']:
|
||||
labels_added = True
|
||||
else:
|
||||
labels_added = True
|
||||
if data_changed or labels_added or labels_changed or self.force:
|
||||
labels_changed = not compare_generic(self.labels, attrs.get('Labels'), 'allow_more_present', 'dict')
|
||||
if data_changed or labels_changed or self.force:
|
||||
# if something changed or force, delete and re-create the config
|
||||
self.absent()
|
||||
config_id = self.create_config()
|
||||
|
|
|
@ -753,6 +753,7 @@ from ansible.module_utils.basic import human_to_bytes
|
|||
from ansible.module_utils.docker_common import (
|
||||
HAS_DOCKER_PY_2, HAS_DOCKER_PY_3, AnsibleDockerClient,
|
||||
DockerBaseClass, sanitize_result, is_image_name_id,
|
||||
compare_generic,
|
||||
)
|
||||
from ansible.module_utils.six import string_types
|
||||
|
||||
|
@ -1537,79 +1538,11 @@ class Container(DockerBaseClass):
|
|||
return True
|
||||
return False
|
||||
|
||||
def _compare_dict_allow_more_present(self, av, bv):
|
||||
'''
|
||||
Compare two dictionaries for whether every entry of the first is in the second.
|
||||
'''
|
||||
for key, value in av.items():
|
||||
if key not in bv:
|
||||
return False
|
||||
if bv[key] != value:
|
||||
return False
|
||||
return True
|
||||
|
||||
def _compare(self, a, b, compare):
|
||||
'''
|
||||
Compare values a and b as described in compare.
|
||||
'''
|
||||
method = compare['comparison']
|
||||
if method == 'ignore':
|
||||
return True
|
||||
# If a or b is None:
|
||||
if a is None or b is None:
|
||||
# If both are None: equality
|
||||
if a == b:
|
||||
return True
|
||||
# Otherwise, not equal for values, and equal
|
||||
# if the other is empty for set/list/dict
|
||||
if compare['type'] == 'value':
|
||||
return False
|
||||
return len(b if a is None else a) == 0
|
||||
# Do proper comparison (both objects not None)
|
||||
if compare['type'] == 'value':
|
||||
return a == b
|
||||
elif compare['type'] == 'list':
|
||||
if method == 'strict':
|
||||
return a == b
|
||||
else:
|
||||
set_a = set(a)
|
||||
set_b = set(b)
|
||||
return set_b >= set_a
|
||||
elif compare['type'] == 'dict':
|
||||
if method == 'strict':
|
||||
return a == b
|
||||
else:
|
||||
return self._compare_dict_allow_more_present(a, b)
|
||||
elif compare['type'] == 'set':
|
||||
set_a = set(a)
|
||||
set_b = set(b)
|
||||
if method == 'strict':
|
||||
return set_a == set_b
|
||||
else:
|
||||
return set_b >= set_a
|
||||
elif compare['type'] == 'set(dict)':
|
||||
for av in a:
|
||||
found = False
|
||||
for bv in b:
|
||||
if self._compare_dict_allow_more_present(av, bv):
|
||||
found = True
|
||||
break
|
||||
if not found:
|
||||
return False
|
||||
if method == 'strict':
|
||||
# If we would know that both a and b do not contain duplicates,
|
||||
# we could simply compare len(a) to len(b) to finish this test.
|
||||
# We can assume that b has no duplicates (as it is returned by
|
||||
# docker), but we don't know for a.
|
||||
for bv in b:
|
||||
found = False
|
||||
for av in a:
|
||||
if self._compare_dict_allow_more_present(av, bv):
|
||||
found = True
|
||||
break
|
||||
if not found:
|
||||
return False
|
||||
return True
|
||||
return compare_generic(a, b, compare['comparison'], compare['type'])
|
||||
|
||||
def has_different_configuration(self, image):
|
||||
'''
|
||||
|
|
|
@ -147,7 +147,7 @@ except ImportError:
|
|||
# missing docker-py handled in ansible.module_utils.docker_common
|
||||
pass
|
||||
|
||||
from ansible.module_utils.docker_common import AnsibleDockerClient, DockerBaseClass
|
||||
from ansible.module_utils.docker_common import AnsibleDockerClient, DockerBaseClass, compare_generic
|
||||
from ansible.module_utils._text import to_native, to_bytes
|
||||
|
||||
|
||||
|
@ -219,22 +219,8 @@ class SecretManager(DockerBaseClass):
|
|||
if attrs.get('Labels', {}).get('ansible_key'):
|
||||
if attrs['Labels']['ansible_key'] != self.data_key:
|
||||
data_changed = True
|
||||
labels_changed = False
|
||||
if self.labels and attrs.get('Labels'):
|
||||
# check if user requested a label change
|
||||
for label in attrs['Labels']:
|
||||
if self.labels.get(label) and self.labels[label] != attrs['Labels'][label]:
|
||||
labels_changed = True
|
||||
# check if user added a label
|
||||
labels_added = False
|
||||
if self.labels:
|
||||
if attrs.get('Labels'):
|
||||
for label in self.labels:
|
||||
if label not in attrs['Labels']:
|
||||
labels_added = True
|
||||
else:
|
||||
labels_added = True
|
||||
if data_changed or labels_added or labels_changed or self.force:
|
||||
labels_changed = not compare_generic(self.labels, attrs.get('Labels'), 'allow_more_present', 'dict')
|
||||
if data_changed or labels_changed or self.force:
|
||||
# if something changed or force, delete and re-create the secret
|
||||
self.absent()
|
||||
secret_id = self.create_secret()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue