From 026a13b7dc22c2ee37909ef20bcb3d775371ebc9 Mon Sep 17 00:00:00 2001 From: Andrew Pantuso Date: Mon, 21 Jun 2021 18:20:56 -0400 Subject: [PATCH 1/5] Initial Commit --- plugins/module_utils/common.py | 21 +++++++++++++-------- plugins/modules/docker_host_info.py | 2 +- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/plugins/module_utils/common.py b/plugins/module_utils/common.py index fbe2ba28c..96d583f89 100644 --- a/plugins/module_utils/common.py +++ b/plugins/module_utils/common.py @@ -15,6 +15,7 @@ from ansible.module_utils.basic import AnsibleModule, env_fallback, missing_required_lib +from ansible.module_utils.common.collections import is_sequence from ansible.module_utils.common._collections_compat import Mapping, Sequence from ansible.module_utils.six import string_types from ansible.module_utils.six.moves.urllib.parse import urlparse @@ -921,23 +922,27 @@ def get_legacy_docker_diffs(self): return result -def clean_dict_booleans_for_docker_api(data): +def clean_dict_booleans_for_docker_api(data, allow_sequences=False): ''' Go doesn't like Python booleans 'True' or 'False', while Ansible is just fine with them in YAML. As such, they need to be converted in cases where we pass dictionaries to the Docker API (e.g. docker_network's driver_options and docker_prune's filters). ''' + def sanitize_value(value): + if allow_sequences and is_sequence(value): + return type(value)(sanitize_value(v) for v in value) + elif value is True: + return 'true' + elif value is False: + return 'false' + else: + return str(value) + result = dict() if data is not None: for k, v in data.items(): - if v is True: - v = 'true' - elif v is False: - v = 'false' - else: - v = str(v) - result[str(k)] = v + result[str(k)] = sanitize_value(v) return result diff --git a/plugins/modules/docker_host_info.py b/plugins/modules/docker_host_info.py index 3700a32a8..668c9fa27 100644 --- a/plugins/modules/docker_host_info.py +++ b/plugins/modules/docker_host_info.py @@ -223,7 +223,7 @@ def __init__(self, client, results): if self.client.module.params[docker_object]: returned_name = docker_object filter_name = docker_object + "_filters" - filters = clean_dict_booleans_for_docker_api(client.module.params.get(filter_name)) + filters = clean_dict_booleans_for_docker_api(client.module.params.get(filter_name), True) self.results[returned_name] = self.get_docker_items_list(docker_object, filters) def get_docker_host_info(self): From 2ccd25b7bff708f019dea726de1a6b3136ceefc5 Mon Sep 17 00:00:00 2001 From: Andrew Pantuso Date: Mon, 21 Jun 2021 18:36:42 -0400 Subject: [PATCH 2/5] Adding integration tests --- .../docker_host_info/tasks/test_host_info.yml | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/tests/integration/targets/docker_host_info/tasks/test_host_info.yml b/tests/integration/targets/docker_host_info/tasks/test_host_info.yml index ef2a58a61..9c456ea80 100644 --- a/tests/integration/targets/docker_host_info/tasks/test_host_info.yml +++ b/tests/integration/targets/docker_host_info/tasks/test_host_info.yml @@ -31,6 +31,9 @@ image: "{{ docker_test_image_alpine }}" command: '/bin/sh -c "sleep 10m"' name: "{{ cname }}" + labels: + key1: value1 + key2: value2 state: started register: container_output @@ -63,6 +66,44 @@ - 'output.containers[0].Image is string' - 'output.containers[0].ImageID is not defined' + - name: Get info on Docker host and list containers matching filters (single label) + docker_host_info: + containers: yes + containers_filters: + label: key1=value1 + register: output + + - name: assert container is returned when filters are matched (single label) + assert: + that: "{{ output.containers | length }} == 1" + + - name: Get info on Docker host and list containers matching filters (multiple labels) + docker_host_info: + containers: yes + containers_filters: + label: + - key1=value1 + - key2=value2 + register: output + + - name: assert container is returned when filters are matched (multiple labels) + assert: + that: "{{ output.containers | length }} == 1" + + - name: Get info on Docker host and do not list containers which do not match filters + docker_host_info: + containers: yes + containers_filters: + label: + - key1=value1 + - key2=value2 + - key3=value3 + register: output + + - name: assert no container is returned when filters are not matched + assert: + that: "{{ output.containers | length }} == 0" + - name: Get info on Docker host and list containers with verbose output docker_host_info: containers: yes From e2e726ab1839ca0077e5e0b88c136931ac6b25c1 Mon Sep 17 00:00:00 2001 From: Andrew Pantuso Date: Mon, 21 Jun 2021 18:47:26 -0400 Subject: [PATCH 3/5] Adding example in docs --- plugins/modules/docker_host_info.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/plugins/modules/docker_host_info.py b/plugins/modules/docker_host_info.py index 668c9fa27..22c7ca526 100644 --- a/plugins/modules/docker_host_info.py +++ b/plugins/modules/docker_host_info.py @@ -126,6 +126,15 @@ disk_usage: yes register: result +- name: Get info on docker host and list containers matching the filter + community.docker.docker_host_info: + containers: yes + containers_filters: + label: + - key1=value1 + - key2=value2 + register: result + - ansible.builtin.debug: var: result.host_info From 56311328110434fad2674aea614ffcd416fed461 Mon Sep 17 00:00:00 2001 From: Andrew Pantuso Date: Mon, 21 Jun 2021 19:17:06 -0400 Subject: [PATCH 4/5] Adding changelog fragment --- .../fragments/160-docker_host_info-label-fitler-lists.yml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 changelogs/fragments/160-docker_host_info-label-fitler-lists.yml diff --git a/changelogs/fragments/160-docker_host_info-label-fitler-lists.yml b/changelogs/fragments/160-docker_host_info-label-fitler-lists.yml new file mode 100644 index 000000000..f833ea0c2 --- /dev/null +++ b/changelogs/fragments/160-docker_host_info-label-fitler-lists.yml @@ -0,0 +1,3 @@ +--- +minor_changes: + - docker_host_info - allow values for keys in ``containers_filters`` to be passed as YAML lists (https://github.com/ansible-collections/community.docker/pull/160). From df7c086cc6dac4ee32f71fc98a9b9cf86fc0498d Mon Sep 17 00:00:00 2001 From: Andrew Pantuso Date: Tue, 22 Jun 2021 08:40:01 -0400 Subject: [PATCH 5/5] Applying initial review suggestions --- .../160-docker_host_info-label-fitler-lists.yml | 3 ++- plugins/module_utils/common.py | 12 ++++++------ plugins/modules/docker_host_info.py | 8 ++++++++ 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/changelogs/fragments/160-docker_host_info-label-fitler-lists.yml b/changelogs/fragments/160-docker_host_info-label-fitler-lists.yml index f833ea0c2..4b58bfc42 100644 --- a/changelogs/fragments/160-docker_host_info-label-fitler-lists.yml +++ b/changelogs/fragments/160-docker_host_info-label-fitler-lists.yml @@ -1,3 +1,4 @@ --- minor_changes: - - docker_host_info - allow values for keys in ``containers_filters`` to be passed as YAML lists (https://github.com/ansible-collections/community.docker/pull/160). + - docker_host_info - allow values for keys in ``containers_filters``, ``images_filters``, ``networks_filters``, and + ``volumes_filters`` to be passed as YAML lists (https://github.com/ansible-collections/community.docker/pull/160). diff --git a/plugins/module_utils/common.py b/plugins/module_utils/common.py index 96d583f89..5c3399a68 100644 --- a/plugins/module_utils/common.py +++ b/plugins/module_utils/common.py @@ -927,12 +927,12 @@ def clean_dict_booleans_for_docker_api(data, allow_sequences=False): Go doesn't like Python booleans 'True' or 'False', while Ansible is just fine with them in YAML. As such, they need to be converted in cases where we pass dictionaries to the Docker API (e.g. docker_network's - driver_options and docker_prune's filters). + driver_options and docker_prune's filters). When `allow_sequences=True` + YAML sequences (lists, tuples) are converted to [str] instead of str([...]) + which is the expected format of filters which accept lists such as labels. ''' - def sanitize_value(value): - if allow_sequences and is_sequence(value): - return type(value)(sanitize_value(v) for v in value) - elif value is True: + def sanitize(value): + if value is True: return 'true' elif value is False: return 'false' @@ -942,7 +942,7 @@ def sanitize_value(value): result = dict() if data is not None: for k, v in data.items(): - result[str(k)] = sanitize_value(v) + result[str(k)] = [sanitize(e) for e in v] if allow_sequences and is_sequence(v) else sanitize(v) return result diff --git a/plugins/modules/docker_host_info.py b/plugins/modules/docker_host_info.py index 22c7ca526..599a92d75 100644 --- a/plugins/modules/docker_host_info.py +++ b/plugins/modules/docker_host_info.py @@ -33,6 +33,8 @@ description: - A dictionary of filter values used for selecting containers to list. - "For example, C(until: 24h)." + - C(label) is a special case of filter which can be a string C() matching when a label is present, a string + C(=) matching when a label has a particular value, or a list of strings C()/C(=) matching when a label is present, a string + C(=) matching when a label has a particular value, or a list of strings C()/C(=) matching when a label is present, a string + C(=) matching when a label has a particular value, or a list of strings C()/C(=) matching when a label is present, a string + C(=) matching when a label has a particular value, or a list of strings C()/C(=