Add image_label_mismatch parameter to docker_container (#370)

* Add image_label_mismatch to docker_container

* Apply suggestions from code review

Co-authored-by: Felix Fontein <felix@fontein.de>

* Test image_label_mismatch error message

* Add change fragment for image_label_mismatch

* Break long line in docker_container.py for pep-8 compliance

* pep8 compliance

* Update changelogs/fragments/370-add-image-label-mismatch.yml

Co-authored-by: Felix Fontein <felix@fontein.de>

* fix: add expected_labels to parameters_map in docker_container

* Apply suggestions from code review

* Apply suggestions from code review

* Update tests/integration/targets/docker_container/tasks/tests/options.yml

Co-authored-by: Felix Fontein <felix@fontein.de>
This commit is contained in:
Rodrigo Candido Gryzinski 2022-05-24 03:35:33 -03:00 committed by GitHub
parent 9580c25579
commit 497c2fda91
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 223 additions and 1 deletions

View File

@ -0,0 +1,2 @@
minor_changes:
- "docker_container - added ``image_label_mismatch`` parameter (https://github.com/ansible-collections/community.docker/issues/314, https://github.com/ansible-collections/community.docker/pull/370)."

View File

@ -394,6 +394,22 @@ options:
- Can also be an image ID. If this is the case, the image is assumed to be available locally.
The I(pull) option is ignored for this case.
type: str
image_label_mismatch:
description:
- How to handle labels inherited from the image that are not set explicitly.
- When C(ignore), labels that are present in the image but not specified in I(labels) will be
ignored. This is useful to avoid having to specify the image labels in I(labels) while keeping
labels I(comparisons) C(strict).
- When C(fail), if there are labels present in the image which are not set from I(labels), the
module will fail. This prevents introducing unexpected labels from the base image.
- "B(Warning:) This option is ignored unless C(labels: strict) or C(*: strict) is specified in
the I(comparisons) option."
type: str
choices:
- 'ignore'
- 'fail'
default: ignore
version_added: 2.6.0
init:
description:
- Run an init inside the container that forwards signals and reaps processes.
@ -2170,6 +2186,7 @@ class Container(DockerBaseClass):
self.parameters.expected_env = None
self.parameters.expected_device_requests = None
self.parameters_map = dict()
self.parameters_map['expected_labels'] = 'labels'
self.parameters_map['expected_links'] = 'links'
self.parameters_map['expected_ports'] = 'expected_ports'
self.parameters_map['expected_exposed'] = 'exposed_ports'
@ -2180,6 +2197,7 @@ class Container(DockerBaseClass):
self.parameters_map['expected_env'] = 'env'
self.parameters_map['expected_entrypoint'] = 'entrypoint'
self.parameters_map['expected_binds'] = 'volumes'
self.parameters_map['expected_labels'] = 'labels'
self.parameters_map['expected_cmd'] = 'command'
self.parameters_map['expected_devices'] = 'devices'
self.parameters_map['expected_healthcheck'] = 'healthcheck'
@ -2251,6 +2269,7 @@ class Container(DockerBaseClass):
self.parameters.expected_exposed = self._get_expected_exposed(image)
self.parameters.expected_volumes = self._get_expected_volumes(image)
self.parameters.expected_binds = self._get_expected_binds(image)
self.parameters.expected_labels = self._get_expected_labels(image)
self.parameters.expected_ulimits = self._get_expected_ulimits(self.parameters.ulimits)
self.parameters.expected_sysctls = self._get_expected_sysctls(self.parameters.sysctls)
self.parameters.expected_etc_hosts = self._convert_simple_dict_to_list('etc_hosts')
@ -2304,7 +2323,7 @@ class Container(DockerBaseClass):
expected_exposed=expected_exposed,
groups=host_config.get('GroupAdd'),
ipc_mode=host_config.get("IpcMode"),
labels=config.get('Labels'),
expected_labels=config.get('Labels'),
expected_links=host_config.get('Links'),
mac_address=config.get('MacAddress', network.get('MacAddress')),
memory_swappiness=host_config.get('MemorySwappiness'),
@ -2406,6 +2425,20 @@ class Container(DockerBaseClass):
# expected_healthcheck comparison in this case.
continue
if key == 'expected_labels' and compare['comparison'] == 'strict' and self.parameters.image_label_mismatch == 'fail':
# If there are labels from the base image that should be removed and
# base_image_mismatch is fail we want raise an error.
image_labels = self._get_image_labels(image)
would_remove_labels = []
for label in image_labels:
if label not in self.parameters.labels:
# Format label for error message
would_remove_labels.append(label)
if would_remove_labels:
msg = ("Some labels should be removed but are present in the base image. You can set image_label_mismatch to 'ignore' to ignore"
" this error. Labels: {0}")
self.fail(msg.format(', '.join(['"%s"' % label for label in would_remove_labels])))
# no match. record the differences
p = getattr(self.parameters, key)
c = value
@ -2644,6 +2677,23 @@ class Container(DockerBaseClass):
self.log(result, pretty_print=True)
return result
def _get_expected_labels(self, image):
if self.parameters.labels is None:
return None
if self.parameters.image_label_mismatch == 'ignore':
expected_labels = dict(self._get_image_labels(image))
else:
expected_labels = {}
expected_labels.update(self.parameters.labels)
return expected_labels
def _get_image_labels(self, image):
if not image:
return {}
# Can't use get('Labels', {}) because 'Labels' may be present and be None
return image[self.parameters.client.image_inspect_source].get('Labels') or {}
def _get_expected_device_requests(self):
if self.parameters.device_requests is None:
return None
@ -3555,6 +3605,7 @@ def main():
hostname=dict(type='str'),
ignore_image=dict(type='bool', default=False),
image=dict(type='str'),
image_label_mismatch=dict(type='str', choices=['ignore', 'fail'], default='ignore'),
init=dict(type='bool'),
interactive=dict(type='bool'),
ipc_mode=dict(type='str'),

View File

@ -22,6 +22,7 @@
set_fact:
cname_prefix: "{{ 'ansible-docker-test-%0x' % ((2**32) | random) }}"
cnames: []
inames: []
dnetworks: []
- debug:
@ -41,6 +42,11 @@
force_kill: yes
with_items: "{{ cnames }}"
diff: no
- name: "Make sure all images are removed"
docker_image:
name: "{{ item }}"
state: absent
with_items: "{{ inames }}"
- name: "Make sure all networks are removed"
docker_network:
name: "{{ item }}"

View File

@ -2194,6 +2194,169 @@
- ignore_image is not changed
- image_change is changed
####################################################################
## image_label_mismatch ############################################
####################################################################
- name: Registering image name
set_fact:
iname_labels: "{{ cname_prefix ~ '-labels' }}"
- name: Registering image name
set_fact:
inames: "{{ inames + [iname_labels] }}"
- name: build image with labels
command:
cmd: "docker build --label img_label=base --tag {{ iname_labels }} -"
stdin: "FROM {{ docker_test_image_alpine }}"
- name: image_label_mismatch
docker_container:
image: "{{ iname_labels }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
register: image_label_mismatch_1
- name: image_label_mismatch (ignore,unmanaged labels)
docker_container:
image: "{{ iname_labels }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
image_label_mismatch: ignore
state: started
register: image_label_mismatch_2
- name: image_label_mismatch (ignore,missing img label)
docker_container:
image: "{{ iname_labels }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
image_label_mismatch: ignore
labels: {}
state: started
register: image_label_mismatch_3
- name: image_label_mismatch (ignore,match img label)
docker_container:
image: "{{ iname_labels }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
image_label_mismatch: ignore
labels:
img_label: base
state: started
register: image_label_mismatch_4
- name: image_label_mismatch (ignore,mismatched img label)
docker_container:
image: "{{ iname_labels }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
image_label_mismatch: ignore
labels:
img_label: override
state: started
force_kill: yes
register: image_label_mismatch_5
- name: image_label_mismatch (ignore,remove img label)
docker_container:
image: "{{ iname_labels }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
image_label_mismatch: ignore
labels: {}
state: started
force_kill: yes
register: image_label_mismatch_6
- name: image_label_mismatch (fail,unmanaged labels)
docker_container:
image: "{{ iname_labels }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
image_label_mismatch: fail
state: started
register: image_label_mismatch_7
- name: image_label_mismatch (fail,non-strict,missing img label)
docker_container:
image: "{{ iname_labels }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
image_label_mismatch: fail
labels: {}
state: started
register: image_label_mismatch_8
- name: image_label_mismatch (fail,strict,missing img label)
docker_container:
image: "{{ iname_labels }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
image_label_mismatch: fail
comparisons:
labels: strict
labels: {}
state: started
ignore_errors: yes
register: image_label_mismatch_9
- name: image_label_mismatch (fail,match img label)
docker_container:
image: "{{ iname_labels }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
image_label_mismatch: fail
labels:
img_label: base
state: started
register: image_label_mismatch_10
- name: image_label_mismatch (fail,mismatched img label)
docker_container:
image: "{{ iname_labels }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
image_label_mismatch: fail
labels:
img_label: override
state: started
force_kill: yes
register: image_label_mismatch_11
- name: cleanup container
docker_container:
name: "{{ cname }}"
state: absent
force_kill: yes
diff: no
- name: cleanup image
docker_image:
name: "{{ iname_labels }}"
state: absent
diff: no
- assert:
that:
- image_label_mismatch_1 is changed
- image_label_mismatch_1.container.Config.Labels.img_label == "base"
- image_label_mismatch_2 is not changed
- image_label_mismatch_3 is not changed
- image_label_mismatch_4 is not changed
- image_label_mismatch_5 is changed
- image_label_mismatch_5.container.Config.Labels.img_label == "override"
- image_label_mismatch_6 is changed
- image_label_mismatch_6.container.Config.Labels.img_label == "base"
- image_label_mismatch_7 is not changed
- image_label_mismatch_8 is not changed
- image_label_mismatch_9 is failed
- >-
image_label_mismatch_9.msg == ("Some labels should be removed but are present in the base image. You can set image_label_mismatch to 'ignore' to ignore this error. " ~ 'Labels: "img_label"')
- image_label_mismatch_10 is not changed
- image_label_mismatch_11 is changed
####################################################################
## ipc_mode ########################################################
####################################################################