mirror of
https://github.com/ansible-collections/community.docker.git
synced 2025-12-16 11:58:43 +00:00
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:
parent
9580c25579
commit
497c2fda91
2
changelogs/fragments/370-add-image-label-mismatch.yml
Normal file
2
changelogs/fragments/370-add-image-label-mismatch.yml
Normal 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)."
|
||||
@ -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'),
|
||||
|
||||
@ -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 }}"
|
||||
|
||||
@ -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 ########################################################
|
||||
####################################################################
|
||||
|
||||
Loading…
Reference in New Issue
Block a user