From 7caf70db420c848cf0bb16a8d3adf70edf5506f4 Mon Sep 17 00:00:00 2001 From: Felix Fontein Date: Mon, 24 Sep 2018 11:40:05 +0200 Subject: [PATCH] docker_container: fix various idempotency problems and non-working options (#45905) * Sorting args. * Doing comparisons of options with container parameters in a more context-sensitive way. This prevents unnecessary restarts, or missing restarts (f.ex. if parameters are removed from ``cmd``). * Make blkio_weight work. * Fix cap_drop idempotency problem. * Making groups idempotent if it contains integers. * Make cpuset_mems work. * Make dns_opts work. * Fixing log_opts: docker expects string values, returns error for integer. * Adding tests from felixfontein/ansible-docker_container-test#2. * Make uts work. * Adding changelog entry. * Forgot option security_opts. * Fixing typo. * Explain strict set(dict) comparison a bit more. * Improving idempotency tests. * Making dns_servers a list, since the ordering is relevant. * Making dns_search_domains a list, since the ordering is relevant. * Improving dns_search_domains/dns_servers. * Fixing entrypoint test. * Making sure options are only supported for correct docker-py versions. --- .../docker_container-idempotency.yaml | 7 + .../modules/cloud/docker/docker_container.py | 290 +- .../targets/docker_container/files/env-file | 2 + .../targets/docker_container/tasks/main.yml | 46 +- .../docker_container/tasks/tests/options.yml | 3244 +++++++++++++++++ .../regression-45700-dont-parse-on-absent.yml | 2 +- .../tasks/tests/start-stop.yml | 22 +- 7 files changed, 3499 insertions(+), 114 deletions(-) create mode 100644 changelogs/fragments/docker_container-idempotency.yaml create mode 100644 test/integration/targets/docker_container/files/env-file create mode 100644 test/integration/targets/docker_container/tasks/tests/options.yml diff --git a/changelogs/fragments/docker_container-idempotency.yaml b/changelogs/fragments/docker_container-idempotency.yaml new file mode 100644 index 0000000000..2ce2c6a9bf --- /dev/null +++ b/changelogs/fragments/docker_container-idempotency.yaml @@ -0,0 +1,7 @@ +bugfixes: +- "docker_container - Makes ``blkio_weight``, ``cpuset_mems``, ``dns_opts`` and ``uts`` options actually work." +- "docker_container - Fix idempotency problems with ``cap_drop`` and ``groups`` (when numeric group IDs were used)." +- "docker_container - Fix type conversion errors for ``log_options``." +- "docker_container - Fixing various comparison/idempotency problems related to wrong comparisons. + In particular, comparisons for ``command`` and ``entrypoint`` (both lists) no longer ignore missing + elements during idempotency checks." diff --git a/lib/ansible/modules/cloud/docker/docker_container.py b/lib/ansible/modules/cloud/docker/docker_container.py index 34cc8d4c08..1a50e138ff 100644 --- a/lib/ansible/modules/cloud/docker/docker_container.py +++ b/lib/ansible/modules/cloud/docker/docker_container.py @@ -752,12 +752,18 @@ class TaskParameters(DockerBaseClass): for key, value in client.module.params.items(): setattr(self, key, value) + self.comparisons = client.comparisons # If state is 'absent', parameters do not have to be parsed or interpreted. # Only the container's name is needed. if self.state == 'absent': return + if self.groups: + # In case integers are passed as groups, we need to convert them to + # strings as docker internally treats them as strings. + self.groups = [str(g) for g in self.groups] + for param_name in REQUIRES_CONVERSION_TO_BYTES: if client.module.params.get(param_name): try: @@ -826,7 +832,6 @@ class TaskParameters(DockerBaseClass): ''' update_parameters = dict( - blkio_weight='blkio_weight', cpu_period='cpu_period', cpu_quota='cpu_quota', cpu_shares='cpu_shares', @@ -836,6 +841,15 @@ class TaskParameters(DockerBaseClass): memswap_limit='memory_swap', kernel_memory='kernel_memory', ) + + if self.client.HAS_BLKIO_WEIGHT_OPT: + # blkio_weight is only supported in docker>=1.9 + update_parameters['blkio_weight'] = 'blkio_weight' + + if self.client.HAS_CPUSET_MEMS_OPT: + # cpuset_mems is only supported in docker>=2.3 + update_parameters['cpuset_mems'] = 'cpuset_mems' + result = dict() for key, value in update_parameters.items(): if getattr(self, value, None) is not None: @@ -932,6 +946,7 @@ class TaskParameters(DockerBaseClass): links='links', privileged='privileged', dns='dns_servers', + dns_opt='dns_opts', dns_search='dns_search_domains', binds='volume_binds', volumes_from='volumes_from', @@ -962,6 +977,10 @@ class TaskParameters(DockerBaseClass): # auto_remove is only supported in docker>=2 host_config_params['auto_remove'] = 'auto_remove' + if self.client.HAS_BLKIO_WEIGHT_OPT: + # blkio_weight is only supported in docker>=1.9 + host_config_params['blkio_weight'] = 'blkio_weight' + if HAS_DOCKER_PY_3: # cpu_shares and volume_driver moved to create_host_config in > 3 host_config_params['cpu_shares'] = 'cpu_shares' @@ -970,6 +989,9 @@ class TaskParameters(DockerBaseClass): if self.client.HAS_INIT_OPT: host_config_params['init'] = 'init' + if self.client.HAS_UTS_MODE_OPT: + host_config_params['uts_mode'] = 'uts' + params = dict() for key, value in host_config_params.items(): if getattr(self, value, None) is not None: @@ -1153,7 +1175,9 @@ class TaskParameters(DockerBaseClass): ) if self.log_options is not None: - options['Config'] = self.log_options + options['Config'] = dict() + for k, v in self.log_options.items(): + options['Config'][k] = str(v) try: return LogConfig(**options) @@ -1223,6 +1247,19 @@ class Container(DockerBaseClass): self.parameters.expected_sysctls = None self.parameters.expected_etc_hosts = None self.parameters.expected_env = None + self.parameters_map = dict() + self.parameters_map['expected_links'] = 'links' + self.parameters_map['expected_ports'] = 'published_ports' + self.parameters_map['expected_exposed'] = 'exposed_ports' + self.parameters_map['expected_volumes'] = 'volumes' + self.parameters_map['expected_ulimits'] = 'ulimits' + self.parameters_map['expected_sysctls'] = 'sysctls' + self.parameters_map['expected_etc_hosts'] = 'etc_hosts' + self.parameters_map['expected_env'] = 'env' + self.parameters_map['expected_entrypoint'] = 'entrypoint' + self.parameters_map['expected_binds'] = 'volumes' + self.parameters_map['expected_cmd'] = 'command' + self.parameters_map['expected_devices'] = 'devices' def fail(self, msg): self.parameters.client.module.fail_json(msg=msg) @@ -1238,6 +1275,80 @@ 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 + def has_different_configuration(self, image): ''' Diff parameters vs existing container config. Returns tuple: (True | False, List of differences) @@ -1288,6 +1399,7 @@ class Container(DockerBaseClass): detach=detach, interactive=config.get('OpenStdin'), capabilities=host_config.get('CapAdd'), + cap_drop=host_config.get('CapDrop'), expected_devices=host_config.get('Devices'), dns_servers=host_config.get('Dns'), dns_opts=host_config.get('DnsOptions'), @@ -1341,36 +1453,10 @@ class Container(DockerBaseClass): differences = [] for key, value in config_mapping.items(): - self.log('check differences %s %s vs %s' % (key, getattr(self.parameters, key), str(value))) + compare = self.parameters.client.comparisons[self.parameters_map.get(key, key)] + self.log('check differences %s %s vs %s (%s)' % (key, getattr(self.parameters, key), str(value), compare)) if getattr(self.parameters, key, None) is not None: - if isinstance(getattr(self.parameters, key), list) and isinstance(value, list): - if len(getattr(self.parameters, key)) > 0 and isinstance(getattr(self.parameters, key)[0], dict): - # compare list of dictionaries - self.log("comparing list of dict: %s" % key) - match = self._compare_dictionary_lists(getattr(self.parameters, key), value) - else: - # compare two lists. Is list_a in list_b? - self.log("comparing lists: %s" % key) - set_a = set(getattr(self.parameters, key)) - set_b = set(value) - match = (set_b >= set_a) - elif isinstance(getattr(self.parameters, key), list) and not len(getattr(self.parameters, key)) \ - and value is None: - # an empty list and None are == - continue - elif isinstance(getattr(self.parameters, key), dict) and isinstance(value, dict): - # compare two dicts - self.log("comparing two dicts: %s" % key) - match = self._compare_dicts(getattr(self.parameters, key), value) - - elif isinstance(getattr(self.parameters, key), dict) and \ - not len(list(getattr(self.parameters, key).keys())) and value is None: - # an empty dict and None are == - continue - else: - # primitive compare - self.log("primitive compare: %s" % key) - match = (getattr(self.parameters, key) == value) + match = self._compare(getattr(self.parameters, key), value, compare) if not match: # no match. record the differences @@ -1384,43 +1470,6 @@ class Container(DockerBaseClass): has_differences = True if len(differences) > 0 else False return has_differences, differences - def _compare_dictionary_lists(self, list_a, list_b): - ''' - If all of list_a exists in list_b, return True - ''' - if not isinstance(list_a, list) or not isinstance(list_b, list): - return False - matches = 0 - for dict_a in list_a: - for dict_b in list_b: - if self._compare_dicts(dict_a, dict_b): - matches += 1 - break - result = (matches == len(list_a)) - return result - - def _compare_dicts(self, dict_a, dict_b): - ''' - If dict_a in dict_b, return True - ''' - if not isinstance(dict_a, dict) or not isinstance(dict_b, dict): - return False - for key, value in dict_a.items(): - if isinstance(value, dict): - match = self._compare_dicts(value, dict_b.get(key)) - elif isinstance(value, list): - if len(value) > 0 and isinstance(value[0], dict): - match = self._compare_dictionary_lists(value, dict_b.get(key)) - else: - set_a = set(value) - set_b = set(dict_b.get(key)) - match = (set_a == set_b) - else: - match = (value == dict_b.get(key)) - if not match: - return False - return True - def has_different_resource_limits(self): ''' Diff parameters and container resource limits @@ -1434,7 +1483,6 @@ class Container(DockerBaseClass): cpu_period=host_config.get('CpuPeriod'), cpu_quota=host_config.get('CpuQuota'), cpuset_cpus=host_config.get('CpusetCpus'), - cpuset_mems=host_config.get('CpusetMems'), kernel_memory=host_config.get("KernelMemory"), memory=host_config.get('Memory'), memory_reservation=host_config.get('MemoryReservation'), @@ -1443,20 +1491,32 @@ class Container(DockerBaseClass): oom_killer=host_config.get('OomKillDisable'), ) + if self.parameters.client.HAS_BLKIO_WEIGHT_OPT: + # blkio_weight is only supported in docker>=1.9 + config_mapping['blkio_weight'] = host_config.get('BlkioWeight') + + if self.parameters.client.HAS_CPUSET_MEMS_OPT: + # cpuset_mems is only supported in docker>=2.3 + config_mapping['cpuset_mems'] = host_config.get('CpusetMems') + if HAS_DOCKER_PY_3: # cpu_shares moved to create_host_config in > 3 config_mapping['cpu_shares'] = host_config.get('CpuShares') differences = [] for key, value in config_mapping.items(): - if getattr(self.parameters, key, None) and getattr(self.parameters, key) != value: - # no match. record the differences - item = dict() - item[key] = dict( - parameter=getattr(self.parameters, key), - container=value - ) - differences.append(item) + if getattr(self.parameters, key, None): + compare = self.parameters.client.comparisons[self.parameters_map.get(key, key)] + match = self._compare(getattr(self.parameters, key), value, compare) + + if not match: + # no match. record the differences + item = dict() + item[key] = dict( + parameter=getattr(self.parameters, key), + container=value + ) + differences.append(item) different = (len(differences) > 0) return different, differences @@ -1805,7 +1865,7 @@ class ContainerManager(DockerBaseClass): # Existing container different, differences = container.has_different_configuration(image) image_different = False - if not self.parameters.ignore_image: + if self.parameters.comparisons['image']['comparison'] == 'strict': image_different = self._image_is_different(image, container) if image_different or different or self.parameters.recreate: self.diff['differences'] = differences @@ -2065,6 +2125,51 @@ class ContainerManager(DockerBaseClass): class AnsibleDockerClientContainer(AnsibleDockerClient): + def _setup_comparisons(self): + comparisons = {} + comp_aliases = {} + # Put in defaults + explicit_types = dict( + command='list', + devices='set(dict)', + dns_search_domains='list', + dns_servers='list', + env='set', + entrypoint='list', + etc_hosts='set', + ulimits='set(dict)', + ) + for option, data in self.module.argument_spec.items(): + # Ignore options which aren't used as container properties + if option in ('docker_host', 'tls_hostname', 'api_version', 'timeout', 'cacert_path', 'cert_path', + 'key_path', 'ssl_version', 'tls', 'tls_verify', 'debug', 'env_file', 'force_kill', + 'keep_volumes', 'ignore_image', 'name', 'pull', 'purge_networks', 'recreate', + 'restart', 'state', 'stop_timeout', 'trust_image_content', 'networks'): + continue + # Determine option type + if option in explicit_types: + type = explicit_types[option] + elif data['type'] == 'list': + type = 'set' + elif data['type'] == 'dict': + type = 'dict' + else: + type = 'value' + # Determine comparison type + if type in ('list', 'value'): + comparison = 'strict' + else: + comparison = 'allow_more_present' + comparisons[option] = dict(type=type, comparison=comparison, name=option) + # Keep track of aliases + comp_aliases[option] = option + for alias in data.get('aliases', []): + comp_aliases[alias] = option + # Process legacy ignore options + if self.module.params['ignore_image']: + comparisons['image']['comparison'] = 'ignore' + self.comparisons = comparisons + def __init__(self, **kwargs): super(AnsibleDockerClientContainer, self).__init__(**kwargs) @@ -2078,11 +2183,30 @@ class AnsibleDockerClientContainer(AnsibleDockerClient): self.fail("docker or docker-py version is %s. Minimum version required is 2.2 to set init option. " "If you use the 'docker-py' module, you have to switch to the docker 'Python' package." % (docker_version,)) + uts_mode_supported = LooseVersion(docker_version) >= LooseVersion('3.5') + if self.module.params.get("uts") is not None and not uts_mode_supported: + self.fail("docker or docker-py version is %s. Minimum version required is 3.5 to set uts option. " + "If you use the 'docker-py' module, you have to switch to the docker 'Python' package." % (docker_version,)) + + blkio_weight_supported = LooseVersion(docker_version) >= LooseVersion('1.9') + if self.module.params.get("blkio_weight") is not None and not blkio_weight_supported: + self.fail("docker or docker-py version is %s. Minimum version required is 1.9 to set blkio_weight option.") + + cpuset_mems_supported = LooseVersion(docker_version) >= LooseVersion('2.3') + if self.module.params.get("cpuset_mems") is not None and not cpuset_mems_supported: + self.fail("docker or docker-py version is %s. Minimum version required is 2.3 to set cpuset_mems option. " + "If you use the 'docker-py' module, you have to switch to the docker 'Python' package." % (docker_version,)) + self.HAS_INIT_OPT = init_supported + self.HAS_UTS_MODE_OPT = uts_mode_supported + self.HAS_BLKIO_WEIGHT_OPT = blkio_weight_supported + self.HAS_CPUSET_MEMS_OPT = cpuset_mems_supported self.HAS_AUTO_REMOVE_OPT = HAS_DOCKER_PY_2 or HAS_DOCKER_PY_3 if self.module.params.get('auto_remove') and not self.HAS_AUTO_REMOVE_OPT: self.fail("'auto_remove' is not compatible with the 'docker-py' Python package. It requires the newer 'docker' Python package.") + self._setup_comparisons() + def main(): argument_spec = dict( @@ -2103,9 +2227,9 @@ def main(): dns_opts=dict(type='list'), dns_search_domains=dict(type='list'), domainname=dict(type='str'), + entrypoint=dict(type='list'), env=dict(type='dict'), env_file=dict(type='path'), - entrypoint=dict(type='list'), etc_hosts=dict(type='dict'), exposed_ports=dict(type='list', aliases=['exposed', 'expose']), force_kill=dict(type='bool', default=False, aliases=['forcekill']), @@ -2130,7 +2254,6 @@ def main(): memory_swappiness=dict(type='int'), name=dict(type='str', required=True), network_mode=dict(type='str'), - userns_mode=dict(type='str'), networks=dict(type='list'), oom_killer=dict(type='bool'), oom_score_adj=dict(type='int'), @@ -2146,21 +2269,22 @@ def main(): restart=dict(type='bool', default=False), restart_policy=dict(type='str', choices=['no', 'on-failure', 'always', 'unless-stopped']), restart_retries=dict(type='int', default=None), - shm_size=dict(type='str'), security_opts=dict(type='list'), + shm_size=dict(type='str'), state=dict(type='str', choices=['absent', 'present', 'started', 'stopped'], default='started'), stop_signal=dict(type='str'), stop_timeout=dict(type='int'), + sysctls=dict(type='dict'), tmpfs=dict(type='list'), trust_image_content=dict(type='bool', default=False), tty=dict(type='bool', default=False), ulimits=dict(type='list'), - sysctls=dict(type='dict'), user=dict(type='str'), + userns_mode=dict(type='str'), uts=dict(type='str'), + volume_driver=dict(type='str'), volumes=dict(type='list'), volumes_from=dict(type='list'), - volume_driver=dict(type='str'), working_dir=dict(type='str'), ) diff --git a/test/integration/targets/docker_container/files/env-file b/test/integration/targets/docker_container/files/env-file new file mode 100644 index 0000000000..b15f1b64cf --- /dev/null +++ b/test/integration/targets/docker_container/files/env-file @@ -0,0 +1,2 @@ +TEST3=val3 +TEST4=val4 diff --git a/test/integration/targets/docker_container/tasks/main.yml b/test/integration/targets/docker_container/tasks/main.yml index 0c107d4b2e..bb232f176c 100644 --- a/test/integration/targets/docker_container/tasks/main.yml +++ b/test/integration/targets/docker_container/tasks/main.yml @@ -1,23 +1,31 @@ --- +- name: Create random container name prefix + set_fact: + cname_prefix: "{{ 'ansible-test-%0x' % ((2**32) | random) }}" + cnames: [] + dnetworks: [] + +- debug: + msg: "Using container name prefix {{ cname_prefix }}" + - block: - - name: Create random container name prefix - set_fact: - cname_prefix: "{{ 'ansible-test-%0x' % ((2**32) | random) }}" - cnames: [] + - include_tasks: run-test.yml + with_fileglob: + - "tests/*.yml" - - debug: - msg: "Using container name prefix {{ cname_prefix }}" + always: + - name: "Make sure all containers are removed" + docker_container: + name: "{{ item }}" + state: absent + stop_timeout: 1 + with_items: "{{ cnames }}" + - name: "Make sure all networks are removed" + docker_network: + name: "{{ item }}" + state: absent + force: yes + with_items: "{{ dnetworks }}" - - block: - - include_tasks: run-test.yml - with_fileglob: - - "tests/*.yml" - - always: - - name: "Make sure all containers are removed" - docker_container: - name: "{{ item }}" - state: absent - stop_timeout: 1 - with_items: "{{ cnames }}" - when: ansible_os_family != 'RedHat' or ansible_distribution_major_version != '6' + # Skip for CentOS 6 + when: ansible_distribution != 'CentOS' or ansible_distribution_major_version|int > 6 diff --git a/test/integration/targets/docker_container/tasks/tests/options.yml b/test/integration/targets/docker_container/tasks/tests/options.yml new file mode 100644 index 0000000000..adbda30a58 --- /dev/null +++ b/test/integration/targets/docker_container/tasks/tests/options.yml @@ -0,0 +1,3244 @@ +--- +- name: Registering container name + set_fact: + cname: "{{ cname_prefix ~ '-options' }}" + cname_h1: "{{ cname_prefix ~ '-options-h1' }}" + cname_h2: "{{ cname_prefix ~ '-options-h2' }}" + cname_h3: "{{ cname_prefix ~ '-options-h3' }}" + nname_1: "{{ cname_prefix ~ '-network-1' }}" + nname_2: "{{ cname_prefix ~ '-network-2' }}" +- name: Registering container name + set_fact: + cnames: "{{ cnames }} + [cname, cname_h1, cname_h2, cname_h3]" + dnetworks: "{{ dnetworks }} + [nname_1, nname_2]" + +- name: Create networks + docker_network: + name: "{{ network_name }}" + state: present + loop: + - "{{ nname_1 }}" + - "{{ nname_2 }}" + loop_control: + loop_var: network_name + +#################################################################### +## auto_remove ##################################################### +#################################################################### + +- name: auto_remove + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "echo"' + name: "{{ cname }}" + state: started + auto_remove: yes + register: auto_remove_1 + +- name: Give container 1 second to be sure it terminated + pause: + seconds: 1 + +- name: auto_remove (verify) + docker_container: + name: "{{ cname }}" + state: absent + register: auto_remove_2 + +- assert: + that: + - auto_remove_1 is changed + - auto_remove_2 is not changed + +#################################################################### +## blkio_weight #################################################### +#################################################################### + +- name: blkio_weight + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + blkio_weight: 123 + register: blkio_weight_1 + +- name: blkio_weight (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + blkio_weight: 123 + register: blkio_weight_2 + +- name: blkio_weight (change) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + blkio_weight: 234 + stop_timeout: 1 + register: blkio_weight_3 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - blkio_weight_1 is changed + - blkio_weight_2 is not changed + - blkio_weight_3 is changed + +#################################################################### +## cap_drop, capabilities ########################################## +#################################################################### + +- name: capabilities, cap_drop + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + capabilities: + - sys_time + cap_drop: + - all + register: capabilities_1 + +- name: capabilities, cap_drop (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + capabilities: + - sys_time + cap_drop: + - all + register: capabilities_2 + +- name: capabilities, cap_drop (less) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + capabilities: [] + cap_drop: + - all + register: capabilities_3 + +- name: capabilities, cap_drop (changed) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + capabilities: + - setgid + cap_drop: + - all + stop_timeout: 1 + register: capabilities_4 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - capabilities_1 is changed + - capabilities_2 is not changed + - capabilities_3 is not changed + - capabilities_4 is changed + +#################################################################### +## cleanup ######################################################### +#################################################################### + +# TODO: - cleanup + +#################################################################### +## command ######################################################### +#################################################################### + +- name: command + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + state: started + register: command_1 + +- name: command (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + state: started + register: command_2 + +- name: command (less parameters) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + stop_timeout: 1 + register: command_3 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - command_1 is changed + - command_2 is not changed + - command_3 is changed + +#################################################################### +## cpu_period ###################################################### +#################################################################### + +- name: cpu_period + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + cpu_period: 90000 + state: started + register: cpu_period_1 + +- name: cpu_period (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + cpu_period: 90000 + state: started + register: cpu_period_2 + +- name: cpu_period (change) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + cpu_period: 50000 + state: started + stop_timeout: 1 + register: cpu_period_3 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - cpu_period_1 is changed + - cpu_period_2 is not changed + - cpu_period_3 is changed + +#################################################################### +## cpu_quota ####################################################### +#################################################################### + +- name: cpu_quota + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + cpu_quota: 150000 + state: started + register: cpu_quota_1 + +- name: cpu_quota (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + cpu_quota: 150000 + state: started + register: cpu_quota_2 + +- name: cpu_quota (change) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + cpu_quota: 50000 + state: started + stop_timeout: 1 + register: cpu_quota_3 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - cpu_quota_1 is changed + - cpu_quota_2 is not changed + - cpu_quota_3 is changed + +#################################################################### +## cpu_shares ###################################################### +#################################################################### + +- name: cpu_shares + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + cpu_shares: 900 + state: started + register: cpu_shares_1 + +- name: cpu_shares (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + cpu_shares: 900 + state: started + register: cpu_shares_2 + +- name: cpu_shares (change) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + cpu_shares: 1100 + state: started + stop_timeout: 1 + register: cpu_shares_3 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - cpu_shares_1 is changed + - cpu_shares_2 is not changed + - cpu_shares_3 is changed + +#################################################################### +## cpuset_cpus ##################################################### +#################################################################### + +- name: cpuset_cpus + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + cpuset_cpus: 0 + state: started + register: cpuset_cpus_1 + +- name: cpuset_cpus (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + cpuset_cpus: 0 + state: started + register: cpuset_cpus_2 + +- name: cpuset_cpus (change) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + cpuset_cpus: 1 + state: started + stop_timeout: 1 + # This will fail if the system the test is run on doesn't have + # multiple CPUs/cores available. + ignore_errors: yes + register: cpuset_cpus_3 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - cpuset_cpus_1 is changed + - cpuset_cpus_2 is not changed + - cpuset_cpus_3 is failed or cpuset_cpus_3 is changed + +#################################################################### +## cpuset_mems ##################################################### +#################################################################### + +- name: cpuset_mems + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + cpuset_mems: 0 + state: started + register: cpuset_mems_1 + +- name: cpuset_mems (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + cpuset_mems: 0 + state: started + register: cpuset_mems_2 + +- name: cpuset_mems (change) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + cpuset_mems: 1 + state: started + stop_timeout: 1 + # This will fail if the system the test is run on doesn't have + # multiple MEMs available. + ignore_errors: yes + register: cpuset_mems_3 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - cpuset_mems_1 is changed + - cpuset_mems_2 is not changed + - cpuset_mems_3 is failed or cpuset_mems_3 is changed + +#################################################################### +## debug ########################################################### +#################################################################### + +- name: debug (create) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: present + debug: yes + register: debug_1 + +- name: debug (start) + docker_container: + name: "{{ cname }}" + state: started + debug: yes + register: debug_2 + +- name: debug (stop) + docker_container: + image: alpine:3.8 + name: "{{ cname }}" + state: stopped + stop_timeout: 1 + debug: yes + register: debug_3 + +- name: debug (absent) + docker_container: + name: "{{ cname }}" + state: absent + debug: yes + stop_timeout: 1 + register: debug_4 + +- assert: + that: + - debug_1 is changed + - debug_2 is changed + - debug_3 is changed + - debug_4 is changed + +#################################################################### +## detach ########################################################## +#################################################################### + +# TODO: - detach + +#################################################################### +## devices ######################################################### +#################################################################### + +- name: devices + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + devices: + - "/dev/random:/dev/virt-random:rwm" + - "/dev/urandom:/dev/virt-urandom:rwm" + register: devices_1 + +- name: devices (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + devices: + - "/dev/urandom:/dev/virt-urandom:rwm" + - "/dev/random:/dev/virt-random:rwm" + register: devices_2 + +- name: devices (less) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + devices: + - "/dev/random:/dev/virt-random:rwm" + register: devices_3 + +- name: devices (changed) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + devices: + - "/dev/random:/dev/virt-random:rwm" + - "/dev/null:/dev/virt-null:rwm" + stop_timeout: 1 + register: devices_4 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - devices_1 is changed + - devices_2 is not changed + - devices_3 is not changed + - devices_4 is changed + +#################################################################### +## dns_opts ######################################################## +#################################################################### + +- name: dns_opts + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + dns_opts: + - "timeout:10" + - rotate + register: dns_opts_1 + +- name: dns_opts (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + dns_opts: + - rotate + - "timeout:10" + register: dns_opts_2 + +- name: dns_opts (less resolv.conf options) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + dns_opts: + - "timeout:10" + register: dns_opts_3 + +- name: dns_opts (more resolv.conf options) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + dns_opts: + - "timeout:10" + - no-check-names + stop_timeout: 1 + register: dns_opts_4 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - dns_opts_1 is changed + - dns_opts_2 is not changed + - dns_opts_3 is not changed + - dns_opts_4 is changed + +#################################################################### +## dns_search_domains ############################################## +#################################################################### + +- name: dns_search_domains + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + dns_search_domains: + - example.com + - example.org + register: dns_search_domains_1 + +- name: dns_search_domains (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + dns_search_domains: + - example.com + - example.org + register: dns_search_domains_2 + +- name: dns_search_domains (different order) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + dns_search_domains: + - example.org + - example.com + register: dns_search_domains_3 + +- name: dns_search_domains (changed elements) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + dns_search_domains: + - ansible.com + - example.com + stop_timeout: 1 + register: dns_search_domains_4 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - dns_search_domains_1 is changed + - dns_search_domains_2 is not changed + - dns_search_domains_3 is changed + - dns_search_domains_4 is changed + +#################################################################### +## dns_servers ##################################################### +#################################################################### + +- name: dns_servers + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + dns_servers: + - 1.1.1.1 + - 8.8.8.8 + register: dns_servers_1 + +- name: dns_servers (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + dns_servers: + - 1.1.1.1 + - 8.8.8.8 + register: dns_servers_2 + +- name: dns_servers (changed order) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + dns_servers: + - 8.8.8.8 + - 1.1.1.1 + register: dns_servers_3 + +- name: dns_servers (changed elements) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + dns_servers: + - 8.8.8.8 + - 9.9.9.9 + stop_timeout: 1 + register: dns_servers_4 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - dns_servers_1 is changed + - dns_servers_2 is not changed + - dns_servers_3 is changed + - dns_servers_4 is changed + +#################################################################### +## domainname ###################################################### +#################################################################### + +- name: domainname + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + domainname: example.com + state: started + register: domainname_1 + +- name: domainname (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + domainname: example.com + state: started + register: domainname_2 + +- name: domainname (change) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + domainname: example.org + state: started + stop_timeout: 1 + register: domainname_3 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - domainname_1 is changed + - domainname_2 is not changed + - domainname_3 is changed + +#################################################################### +## entrypoint ###################################################### +#################################################################### + +- name: entrypoint + docker_container: + image: alpine:3.8 + entrypoint: + - /bin/sh + - "-v" + - "-c" + - "'sleep 10m'" + name: "{{ cname }}" + state: started + register: entrypoint_1 + +- name: entrypoint (idempotency) + docker_container: + image: alpine:3.8 + entrypoint: + - /bin/sh + - "-v" + - "-c" + - "'sleep 10m'" + name: "{{ cname }}" + state: started + register: entrypoint_2 + +- name: entrypoint (change order idempotency) + docker_container: + image: alpine:3.8 + entrypoint: + - /bin/sh + - "-c" + - "'sleep 10m'" + - "-v" + name: "{{ cname }}" + state: started + register: entrypoint_3 + +- name: entrypoint (less parameters) + docker_container: + image: alpine:3.8 + entrypoint: + - /bin/sh + - "-c" + - "'sleep 10m'" + name: "{{ cname }}" + state: started + stop_timeout: 1 + register: entrypoint_4 + +- name: entrypoint (other parameters) + docker_container: + image: alpine:3.8 + entrypoint: + - /bin/sh + - "-c" + - "'sleep 5m'" + name: "{{ cname }}" + state: started + stop_timeout: 1 + register: entrypoint_5 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - entrypoint_1 is changed + - entrypoint_2 is not changed + - entrypoint_3 is changed + - entrypoint_4 is changed + - entrypoint_5 is changed + +#################################################################### +## env ############################################################# +#################################################################### + +- name: env + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + env: + TEST1: val1 + TEST2: val2 + register: env_1 + +- name: env (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + env: + TEST2: val2 + TEST1: val1 + register: env_2 + +- name: env (less environment variables) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + env: + TEST1: val1 + register: env_3 + +- name: env (more environment variables) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + env: + TEST1: val1 + TEST3: val3 + stop_timeout: 1 + register: env_4 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - env_1 is changed + - env_2 is not changed + - env_3 is not changed + - env_4 is changed + +#################################################################### +## env_file ######################################################### +#################################################################### + +- name: env_file + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + env_file: "{{ role_path }}/files/env-file" + register: env_file_1 + +- name: env_file (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + env_file: "{{ role_path }}/files/env-file" + register: env_file_2 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - env_file_1 is changed + - env_file_2 is not changed + +#################################################################### +## etc_hosts ####################################################### +#################################################################### + +- name: etc_hosts + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + etc_hosts: + example.com: 1.2.3.4 + example.org: 4.3.2.1 + register: etc_hosts_1 + +- name: etc_hosts (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + etc_hosts: + example.org: 4.3.2.1 + example.com: 1.2.3.4 + register: etc_hosts_2 + +- name: etc_hosts (less hosts) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + etc_hosts: + example.com: 1.2.3.4 + register: etc_hosts_3 + +- name: etc_hosts (more hosts) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + etc_hosts: + example.com: 1.2.3.4 + example.us: 1.2.3.5 + stop_timeout: 1 + register: etc_hosts_4 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - etc_hosts_1 is changed + - etc_hosts_2 is not changed + - etc_hosts_3 is not changed + - etc_hosts_4 is changed + +#################################################################### +## exposed_ports ################################################### +#################################################################### + +- name: exposed_ports + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + exposed_ports: + - 1234 + - 5678 + register: exposed_ports_1 + +- name: exposed_ports (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + exposed_ports: + - 5678 + - 1234 + register: exposed_ports_2 + +- name: exposed_ports (less ports) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + exposed_ports: + - 1234 + register: exposed_ports_3 + +- name: exposed_ports (more ports) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + exposed_ports: + - 1234 + - 1235 + stop_timeout: 1 + register: exposed_ports_4 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - exposed_ports_1 is changed + - exposed_ports_2 is not changed + - exposed_ports_3 is not changed + - exposed_ports_4 is changed + +#################################################################### +## force_kill ###################################################### +#################################################################### + +# TODO: - force_kill + +#################################################################### +## groups ########################################################## +#################################################################### + +- name: groups + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + groups: + - 1234 + - 5678 + register: groups_1 + +- name: groups (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + groups: + - 5678 + - 1234 + register: groups_2 + +- name: groups (less groups) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + groups: + - 1234 + register: groups_3 + +- name: groups (more groups) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + groups: + - 1234 + - 2345 + stop_timeout: 1 + register: groups_4 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - groups_1 is changed + - groups_2 is not changed + - groups_3 is not changed + - groups_4 is changed + +#################################################################### +## hostname ######################################################## +#################################################################### + +- name: hostname + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + hostname: me.example.com + state: started + register: hostname_1 + +- name: hostname (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + hostname: me.example.com + state: started + register: hostname_2 + +- name: hostname (change) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + hostname: me.example.org + state: started + stop_timeout: 1 + register: hostname_3 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - hostname_1 is changed + - hostname_2 is not changed + - hostname_3 is changed + +#################################################################### +## init ############################################################ +#################################################################### + +- name: init + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + init: yes + state: started + register: init_1 + +- name: init (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + init: yes + state: started + register: init_2 + +- name: init (change) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + init: no + state: started + stop_timeout: 1 + register: init_3 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - init_1 is changed + - init_2 is not changed + - init_3 is changed + +#################################################################### +## interactive ##################################################### +#################################################################### + +- name: interactive + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + interactive: yes + state: started + register: interactive_1 + +- name: interactive (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + interactive: yes + state: started + register: interactive_2 + +- name: interactive (change) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + interactive: no + state: started + stop_timeout: 1 + register: interactive_3 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - interactive_1 is changed + - interactive_2 is not changed + - interactive_3 is changed + +#################################################################### +## image / ignore_image ############################################ +#################################################################### + +- name: Pull hello-world image to make sure ignore_image test succeeds + # If the image isn't there, it will pull it and return 'changed'. + docker_image: + name: hello-world + pull: true + +- name: image + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + register: image_1 + +- name: image (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + register: image_2 + +- name: ignore_image + docker_container: + image: hello-world + ignore_image: yes + name: "{{ cname }}" + state: started + register: ignore_image + +- name: image change + docker_container: + image: hello-world + name: "{{ cname }}" + state: started + stop_timeout: 1 + register: image_change + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - image_1 is changed + - image_2 is not changed + - ignore_image is not changed + - image_change is changed + +#################################################################### +## ipc_mode ######################################################## +#################################################################### + +- name: start helpers + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ container_name }}" + state: started + loop: + - "{{ cname_h1 }}" + loop_control: + loop_var: container_name + +- name: ipc_mode + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + #ipc_mode: "container:{{ cname_h1 }}" + ipc_mode: shareable + register: ipc_mode_1 + +- name: ipc_mode (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + # THIS IS CURRENTLY NOT IDEMPOTENT! SEE https://github.com/ansible/ansible/issues/45829 + # ipc_mode: "container:{{ cname_h1 }}" + ipc_mode: shareable + register: ipc_mode_2 + +- name: ipc_mode (change) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + ipc_mode: private + stop_timeout: 1 + register: ipc_mode_3 + +- name: cleanup + docker_container: + name: "{{ container_name }}" + state: absent + stop_timeout: 1 + loop: + - "{{ cname }}" + - "{{ cname_h1 }}" + loop_control: + loop_var: container_name + +- assert: + that: + - ipc_mode_1 is changed + - ipc_mode_2 is not changed + - ipc_mode_3 is changed + +#################################################################### +## kernel_memory ################################################### +#################################################################### + +- name: kernel_memory + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + kernel_memory: 8M + state: started + register: kernel_memory_1 + +- name: kernel_memory (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + kernel_memory: 8M + state: started + register: kernel_memory_2 + +- name: kernel_memory (change) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + kernel_memory: 6M + state: started + stop_timeout: 1 + register: kernel_memory_3 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - kernel_memory_1 is changed + - kernel_memory_2 is not changed + - kernel_memory_3 is changed + +#################################################################### +## kill_signal ##################################################### +#################################################################### + +# TODO: - kill_signal + +#################################################################### +## labels ########################################################## +#################################################################### + +- name: labels + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + labels: + ansible.test.1: hello + ansible.test.2: world + register: labels_1 + +- name: labels (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + labels: + ansible.test.2: world + ansible.test.1: hello + register: labels_2 + +- name: labels (less labels) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + labels: + ansible.test.1: hello + register: labels_3 + +- name: labels (more labels) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + labels: + ansible.test.1: hello + ansible.test.3: ansible + stop_timeout: 1 + register: labels_4 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - labels_1 is changed + - labels_2 is not changed + - labels_3 is not changed + - labels_4 is changed + +#################################################################### +## links ########################################################### +#################################################################### + +- name: start helpers + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ container_name }}" + state: started + loop: + - "{{ cname_h1 }}" + - "{{ cname_h2 }}" + - "{{ cname_h3 }}" + loop_control: + loop_var: container_name + +- name: links + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + links: + - "{{ cname_h1 }}:test1" + - "{{ cname_h2 }}:test2" + register: links_1 + +- name: links (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + links: + - "{{ cname_h2 }}:test2" + - "{{ cname_h1 }}:test1" + register: links_2 + +- name: links (less links) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + links: + - "{{ cname_h1 }}:test1" + register: links_3 + +- name: links (more links) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + links: + - "{{ cname_h1 }}:test1" + - "{{ cname_h3 }}:test3" + stop_timeout: 1 + register: links_4 + +- name: cleanup + docker_container: + name: "{{ container_name }}" + state: absent + stop_timeout: 1 + loop: + - "{{ cname }}" + - "{{ cname_h1 }}" + - "{{ cname_h2 }}" + - "{{ cname_h3 }}" + loop_control: + loop_var: container_name + +- assert: + that: + - links_1 is changed + - links_2 is not changed + - links_3 is not changed + - links_4 is changed + +#################################################################### +## log_driver ###################################################### +#################################################################### + +- name: log_driver + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + log_driver: json-file + register: log_driver_1 + +- name: log_driver (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + log_driver: json-file + register: log_driver_2 + +- name: log_driver (change) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + log_driver: syslog + stop_timeout: 1 + register: log_driver_3 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - log_driver_1 is changed + - log_driver_2 is not changed + - log_driver_3 is changed + +#################################################################### +## log_options ##################################################### +#################################################################### + +- name: log_options + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + log_driver: json-file + log_options: + labels: production_status + env: os,customer + register: log_options_1 + +- name: log_options (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + log_driver: json-file + log_options: + env: os,customer + labels: production_status + register: log_options_2 + +- name: log_options (less log options) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + log_driver: json-file + log_options: + labels: production_status + register: log_options_3 + +- name: log_options (more log options) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + log_driver: json-file + log_options: + labels: production_status + max-file: 1 + stop_timeout: 1 + register: log_options_4 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - log_options_1 is changed + - log_options_2 is not changed + - log_options_3 is not changed + - log_options_4 is changed + +#################################################################### +## mac_address ##################################################### +#################################################################### + +- name: mac_address + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + mac_address: 92:d0:c6:0a:29:33 + state: started + register: mac_address_1 + +- name: mac_address (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + mac_address: 92:d0:c6:0a:29:33 + state: started + register: mac_address_2 + +- name: mac_address (change) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + mac_address: 92:d0:c6:0a:29:44 + state: started + stop_timeout: 1 + register: mac_address_3 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - mac_address_1 is changed + - mac_address_2 is not changed + - mac_address_3 is changed + +#################################################################### +## memory ########################################################## +#################################################################### + +- name: memory + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + memory: 64M + state: started + register: memory_1 + +- name: memory (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + memory: 64M + state: started + register: memory_2 + +- name: memory (change) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + memory: 48M + state: started + stop_timeout: 1 + register: memory_3 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - memory_1 is changed + - memory_2 is not changed + - memory_3 is changed + +#################################################################### +## memory_reservation ############################################## +#################################################################### + +- name: memory_reservation + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + memory_reservation: 64M + state: started + register: memory_reservation_1 + +- name: memory_reservation (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + memory_reservation: 64M + state: started + register: memory_reservation_2 + +- name: memory_reservation (change) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + memory_reservation: 48M + state: started + stop_timeout: 1 + register: memory_reservation_3 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - memory_reservation_1 is changed + - memory_reservation_2 is not changed + - memory_reservation_3 is changed + +#################################################################### +## memory_swap ##################################################### +#################################################################### + +- name: memory_swap + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + # Docker daemon does not accept memory_swap if memory is not specified + memory: 32M + memory_swap: 64M + state: started + debug: yes + register: memory_swap_1 + +- name: memory_swap (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + # Docker daemon does not accept memory_swap if memory is not specified + memory: 32M + memory_swap: 64M + state: started + debug: yes + register: memory_swap_2 + +- name: memory_swap (change) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + # Docker daemon does not accept memory_swap if memory is not specified + memory: 32M + memory_swap: 48M + state: started + stop_timeout: 1 + debug: yes + register: memory_swap_3 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - memory_swap_1 is changed + # Sometimes (in particular during integration tests, maybe when not running + # on a proper VM), memory_swap cannot be set and will be -1 afterwards. + - memory_swap_2 is not changed or memory_swap_2.ansible_facts.docker_container.HostConfig.MemorySwap == -1 + - memory_swap_3 is changed + +- debug: var=memory_swap_1 + when: memory_swap_2 is changed +- debug: var=memory_swap_2 + when: memory_swap_2 is changed +- debug: var=memory_swap_3 + when: memory_swap_2 is changed + +#################################################################### +## memory_swappiness ############################################### +#################################################################### + +- name: memory_swappiness + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + memory_swappiness: 40 + state: started + register: memory_swappiness_1 + +- name: memory_swappiness (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + memory_swappiness: 40 + state: started + register: memory_swappiness_2 + +- name: memory_swappiness (change) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + memory_swappiness: 60 + state: started + stop_timeout: 1 + register: memory_swappiness_3 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - memory_swappiness_1 is changed + - memory_swappiness_2 is not changed + - memory_swappiness_3 is changed + +#################################################################### +## network_mode #################################################### +#################################################################### + +- name: network_mode + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + network_mode: host + register: network_mode_1 + +- name: network_mode (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + network_mode: host + register: network_mode_2 + +- name: network_mode (change) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + network_mode: none + stop_timeout: 1 + register: network_mode_3 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - network_mode_1 is changed + - network_mode_2 is not changed + - network_mode_3 is changed + +#################################################################### +## networks, purge_networks ######################################## +#################################################################### + +- name: networks, purge_networks + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + purge_networks: yes + networks: + - name: bridge + - name: "{{ nname_1 }}" + register: networks_1 + +- name: networks, purge_networks (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + purge_networks: yes + networks: + - name: "{{ nname_1 }}" + - name: bridge + register: networks_2 + +- name: networks (less networks) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + networks: + - name: bridge + register: networks_3 + +- name: networks, purge_networks (less networks) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + purge_networks: yes + networks: + - name: bridge + register: networks_4 + +- name: networks, purge_networks (more networks) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + purge_networks: yes + networks: + - name: bridge + - name: "{{ nname_2 }}" + stop_timeout: 1 + register: networks_5 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - networks_1 is changed + - networks_2 is not changed + - networks_3 is not changed + - networks_4 is changed + - networks_5 is changed + +#################################################################### +## oom_killer ###################################################### +#################################################################### + +- name: oom_killer + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + oom_killer: yes + state: started + register: oom_killer_1 + +- name: oom_killer (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + oom_killer: yes + state: started + register: oom_killer_2 + +- name: oom_killer (change) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + oom_killer: no + state: started + stop_timeout: 1 + register: oom_killer_3 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - oom_killer_1 is changed + - oom_killer_2 is not changed + - oom_killer_3 is changed + +#################################################################### +## oom_score_adj ################################################### +#################################################################### + +- name: oom_score_adj + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + oom_score_adj: 5 + state: started + register: oom_score_adj_1 + +- name: oom_score_adj (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + oom_score_adj: 5 + state: started + register: oom_score_adj_2 + +- name: oom_score_adj (change) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + oom_score_adj: 7 + state: started + stop_timeout: 1 + register: oom_score_adj_3 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - oom_score_adj_1 is changed + - oom_score_adj_2 is not changed + - oom_score_adj_3 is changed + +#################################################################### +## output_logs ##################################################### +#################################################################### + +# TODO: - output_logs + +#################################################################### +## paused ########################################################## +#################################################################### + +# TODO: - paused + +#################################################################### +## pid_mode ######################################################## +#################################################################### + +- name: start helpers + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname_h1 }}" + state: started + register: pid_mode_helper + +- name: pid_mode + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + pid_mode: "container:{{ pid_mode_helper.ansible_facts.docker_container.Id }}" + register: pid_mode_1 + +- name: pid_mode (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + pid_mode: "container:{{ pid_mode_helper.ansible_facts.docker_container.Id }}" + register: pid_mode_2 + +- name: pid_mode (change) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + pid_mode: host + stop_timeout: 1 + register: pid_mode_3 + +- name: cleanup + docker_container: + name: "{{ container_name }}" + state: absent + stop_timeout: 1 + loop: + - "{{ cname }}" + - "{{ cname_h1 }}" + loop_control: + loop_var: container_name + +- assert: + that: + - pid_mode_1 is changed + - pid_mode_2 is not changed + - pid_mode_3 is changed + +#################################################################### +## privileged ###################################################### +#################################################################### + +- name: privileged + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + privileged: yes + state: started + register: privileged_1 + +- name: privileged (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + privileged: yes + state: started + register: privileged_2 + +- name: privileged (change) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + privileged: no + state: started + stop_timeout: 1 + register: privileged_3 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - privileged_1 is changed + - privileged_2 is not changed + - privileged_3 is changed + +#################################################################### +## published_ports ################################################# +#################################################################### + +- name: published_ports + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + published_ports: + - 1234 + - 5678 + register: published_ports_1 + +- name: published_ports (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + published_ports: + - 5678 + - 1234 + register: published_ports_2 + +- name: published_ports (less published_ports) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + published_ports: + - 1234 + register: published_ports_3 + +- name: published_ports (more published_ports) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + published_ports: + - 1234 + - 2345 + stop_timeout: 1 + register: published_ports_4 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - published_ports_1 is changed + - published_ports_2 is not changed + - published_ports_3 is not changed + - published_ports_4 is changed + +#################################################################### +## pull ############################################################ +#################################################################### + +# TODO: - pull + +#################################################################### +## read_only ####################################################### +#################################################################### + +- name: read_only + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + read_only: yes + state: started + register: read_only_1 + +- name: read_only (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + read_only: yes + state: started + register: read_only_2 + +- name: read_only (change) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + read_only: no + state: started + stop_timeout: 1 + register: read_only_3 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - read_only_1 is changed + - read_only_2 is not changed + - read_only_3 is changed + +#################################################################### +## recreate ######################################################## +#################################################################### + +# TODO: - recreate + +#################################################################### +## restart ######################################################### +#################################################################### + +# TODO: - restart + +#################################################################### +## restart_policy ################################################## +#################################################################### + +- name: restart_policy + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + restart_policy: always + state: started + register: restart_policy_1 + +- name: restart_policy (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + restart_policy: always + state: started + register: restart_policy_2 + +- name: restart_policy (change) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + restart_policy: unless-stopped + state: started + stop_timeout: 1 + register: restart_policy_3 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - restart_policy_1 is changed + - restart_policy_2 is not changed + - restart_policy_3 is changed + +#################################################################### +## restart_retries ################################################# +#################################################################### + +- name: restart_retries + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + restart_policy: on-failure + restart_retries: 5 + state: started + register: restart_retries_1 + +- name: restart_retries (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + restart_policy: on-failure + restart_retries: 5 + state: started + register: restart_retries_2 + +- name: restart_retries (change) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + restart_policy: on-failure + restart_retries: 2 + state: started + stop_timeout: 1 + register: restart_retries_3 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - restart_retries_1 is changed + - restart_retries_2 is not changed + - restart_retries_3 is changed + +#################################################################### +## security_opts ################################################### +#################################################################### + +# In case some of the options stop working, here are some more +# options which *currently* work with all integration test targets: +# no-new-privileges +# label:disable +# label=disable +# label:level:s0:c100,c200 +# label=level:s0:c100,c200 +# label:type:svirt_apache_t +# label=type:svirt_apache_t +# label:user:root +# label=user:root +# seccomp:unconfined +# seccomp=unconfined +# apparmor:docker-default +# apparmor=docker-default + +- name: security_opts + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + security_opts: + - "label:level:s0:c100,c200" + - "no-new-privileges" + register: security_opts_1 + +- name: security_opts (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + security_opts: + - "no-new-privileges" + - "label:level:s0:c100,c200" + register: security_opts_2 + +- name: security_opts (less security options) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + security_opts: + - "no-new-privileges" + register: security_opts_3 + +- name: security_opts (more security options) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + security_opts: + - "label:disable" + - "no-new-privileges" + stop_timeout: 1 + register: security_opts_4 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - security_opts_1 is changed + - security_opts_2 is not changed + - security_opts_3 is not changed + - security_opts_4 is changed + +#################################################################### +## shm_size ######################################################## +#################################################################### + +- name: shm_size + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + shm_size: 96M + state: started + register: shm_size_1 + +- name: shm_size (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + shm_size: 96M + state: started + register: shm_size_2 + +- name: shm_size (change) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + shm_size: 75M + state: started + stop_timeout: 1 + register: shm_size_3 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - shm_size_1 is changed + - shm_size_2 is not changed + - shm_size_3 is changed + +#################################################################### +## stop_signal ##################################################### +#################################################################### + +- name: stop_signal + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + stop_signal: 30 + state: started + register: stop_signal_1 + +- name: stop_signal (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + stop_signal: 30 + state: started + register: stop_signal_2 + +- name: stop_signal (change) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + stop_signal: 9 + state: started + stop_timeout: 1 + register: stop_signal_3 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - stop_signal_1 is changed + - stop_signal_2 is not changed + - stop_signal_3 is changed + +#################################################################### +## stop_timeout #################################################### +#################################################################### + +# TODO: - stop_timeout + +#################################################################### +## sysctls ######################################################### +#################################################################### + +# In case some of the options stop working, here are some more +# options which *currently* work with all integration test targets: +# net.ipv4.conf.default.log_martians: 1 +# net.ipv4.conf.default.secure_redirects: 0 +# net.ipv4.conf.default.send_redirects: 0 +# net.ipv4.conf.all.log_martians: 1 +# net.ipv4.conf.all.accept_redirects: 0 +# net.ipv4.conf.all.secure_redirects: 0 +# net.ipv4.conf.all.send_redirects: 0 + +- name: sysctls + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + sysctls: + net.ipv4.icmp_echo_ignore_all: 1 + net.ipv4.ip_forward: 1 + register: sysctls_1 + +- name: sysctls (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + sysctls: + net.ipv4.ip_forward: 1 + net.ipv4.icmp_echo_ignore_all: 1 + register: sysctls_2 + +- name: sysctls (less sysctls) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + sysctls: + net.ipv4.icmp_echo_ignore_all: 1 + register: sysctls_3 + +- name: sysctls (more sysctls) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + sysctls: + net.ipv4.icmp_echo_ignore_all: 1 + net.ipv6.conf.default.accept_redirects: 0 + stop_timeout: 1 + register: sysctls_4 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - sysctls_1 is changed + - sysctls_2 is not changed + - sysctls_3 is not changed + - sysctls_4 is changed + +#################################################################### +## timeout ######################################################### +#################################################################### + +# TODO: - timeout + +#################################################################### +## tmpfs ########################################################### +#################################################################### + +- name: tmpfs + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + tmpfs: + - "/test1:rw,noexec,nosuid,size=65536k" + - "/test2:rw,noexec,nosuid,size=65536k" + register: tmpfs_1 + +- name: tmpfs (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + tmpfs: + - "/test2:rw,noexec,nosuid,size=65536k" + - "/test1:rw,noexec,nosuid,size=65536k" + register: tmpfs_2 + +- name: tmpfs (less tmpfs) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + tmpfs: + - "/test1:rw,noexec,nosuid,size=65536k" + register: tmpfs_3 + +- name: tmpfs (more tmpfs) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + tmpfs: + - "/test1:rw,noexec,nosuid,size=65536k" + - "/test3:rw,noexec,nosuid,size=65536k" + stop_timeout: 1 + register: tmpfs_4 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - tmpfs_1 is changed + - tmpfs_2 is not changed + - tmpfs_3 is not changed + - tmpfs_4 is changed + +#################################################################### +## trust_image_content ############################################# +#################################################################### + +# TODO: - trust_image_content + +#################################################################### +## tty ############################################################# +#################################################################### + +- name: tty + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + tty: yes + state: started + register: tty_1 + +- name: tty (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + tty: yes + state: started + register: tty_2 + +- name: tty (change) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + tty: no + state: started + stop_timeout: 1 + register: tty_3 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - tty_1 is changed + - tty_2 is not changed + - tty_3 is changed + +#################################################################### +## ulimits ######################################################### +#################################################################### + +- name: ulimits + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + ulimits: + - "nofile:1234:1234" + - "nproc:3:6" + register: ulimits_1 + +- name: ulimits (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + ulimits: + - "nproc:3:6" + - "nofile:1234:1234" + register: ulimits_2 + +- name: ulimits (less ulimits) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + ulimits: + - "nofile:1234:1234" + register: ulimits_3 + +- name: ulimits (more ulimits) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + ulimits: + - "nofile:1234:1234" + - "sigpending:100:200" + stop_timeout: 1 + register: ulimits_4 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - ulimits_1 is changed + - ulimits_2 is not changed + - ulimits_3 is not changed + - ulimits_4 is changed + +#################################################################### +## user ############################################################ +#################################################################### + +- name: user + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + user: nobody + state: started + register: user_1 + +- name: user (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + user: nobody + state: started + register: user_2 + +- name: user (change) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + user: root + state: started + stop_timeout: 1 + register: user_3 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - user_1 is changed + - user_2 is not changed + - user_3 is changed + +#################################################################### +## userns_mode ##################################################### +#################################################################### + +- name: userns_mode + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + userns_mode: host + state: started + register: userns_mode_1 + +- name: userns_mode (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + userns_mode: host + state: started + register: userns_mode_2 + +- name: userns_mode (change) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + userns_mode: "" + state: started + stop_timeout: 1 + register: userns_mode_3 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - userns_mode_1 is changed + - userns_mode_2 is not changed + - userns_mode_3 is changed + +#################################################################### +## uts ############################################################# +#################################################################### + +- name: uts + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + uts: host + state: started + register: uts_1 + +- name: uts (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + uts: host + state: started + register: uts_2 + +- name: uts (change) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + uts: "" + state: started + stop_timeout: 1 + register: uts_3 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - uts_1 is changed + - uts_2 is not changed + - uts_3 is changed + +#################################################################### +## keep_volumes #################################################### +#################################################################### + +# TODO: - keep_volumes + +#################################################################### +## volume_driver ################################################### +#################################################################### + +- name: volume_driver + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + volume_driver: local + state: started + register: volume_driver_1 + +- name: volume_driver (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + volume_driver: local + state: started + register: volume_driver_2 + +- name: volume_driver (change) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + volume_driver: / + state: started + stop_timeout: 1 + register: volume_driver_3 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - volume_driver_1 is changed + - volume_driver_2 is not changed + - volume_driver_3 is changed + +#################################################################### +## volumes ######################################################### +#################################################################### + +- name: volumes + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + volumes: + - "/tmp:/tmp" + - "/:/whatever" + register: volumes_1 + +- name: volumes (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + volumes: + - "/:/whatever" + - "/tmp:/tmp" + register: volumes_2 + +- name: volumes (less volumes) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + volumes: + - "/tmp:/tmp" + register: volumes_3 + +- name: volumes (more volumes) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + volumes: + - "/tmp:/tmp" + - "/tmp:/somewhereelse:ro" + stop_timeout: 1 + register: volumes_4 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - volumes_1 is changed + - volumes_2 is not changed + - volumes_3 is not changed + - volumes_4 is changed + +#################################################################### +## volumes_from #################################################### +#################################################################### + +- name: start helpers + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ container_name }}" + state: started + volumes: + - "{{ '/tmp:/tmp' if container_name == cname_h1 else '/:/whatever:ro' }}" + loop: + - "{{ cname_h1 }}" + - "{{ cname_h2 }}" + loop_control: + loop_var: container_name + +- name: volumes_from + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + volumes_from: "{{ cname_h1 }}" + register: volumes_from_1 + +- name: volumes_from (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + volumes_from: "{{ cname_h1 }}" + register: volumes_from_2 + +- name: volumes_from (change) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + state: started + volumes_from: "{{ cname_h2 }}" + stop_timeout: 1 + register: volumes_from_3 + +- name: cleanup + docker_container: + name: "{{ container_name }}" + state: absent + stop_timeout: 1 + loop: + - "{{ cname }}" + - "{{ cname_h1 }}" + - "{{ cname_h2 }}" + loop_control: + loop_var: container_name + +- assert: + that: + - volumes_from_1 is changed + - volumes_from_2 is not changed + - volumes_from_3 is changed + +#################################################################### +## working_dir ##################################################### +#################################################################### + +- name: working_dir + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + working_dir: /tmp + state: started + register: working_dir_1 + +- name: working_dir (idempotency) + docker_container: + image: alpine:3.8 + command: '/bin/sh -v -c "sleep 10m"' + name: "{{ cname }}" + working_dir: /tmp + state: started + register: working_dir_2 + +- name: working_dir (change) + docker_container: + image: alpine:3.8 + command: '/bin/sh -c "sleep 10m"' + name: "{{ cname }}" + working_dir: / + state: started + stop_timeout: 1 + register: working_dir_3 + +- name: cleanup + docker_container: + name: "{{ cname }}" + state: absent + stop_timeout: 1 + +- assert: + that: + - working_dir_1 is changed + - working_dir_2 is not changed + - working_dir_3 is changed + +#################################################################### +#################################################################### +#################################################################### + +- name: Delete networks + docker_network: + name: "{{ network_name }}" + state: absent + force: yes + loop: + - "{{ nname_1 }}" + - "{{ nname_2 }}" + loop_control: + loop_var: network_name diff --git a/test/integration/targets/docker_container/tasks/tests/regression-45700-dont-parse-on-absent.yml b/test/integration/targets/docker_container/tasks/tests/regression-45700-dont-parse-on-absent.yml index 85ce6f035e..f5267e13f3 100644 --- a/test/integration/targets/docker_container/tasks/tests/regression-45700-dont-parse-on-absent.yml +++ b/test/integration/targets/docker_container/tasks/tests/regression-45700-dont-parse-on-absent.yml @@ -10,7 +10,7 @@ - name: Start container docker_container: image: alpine:3.8 - command: '/bin/sh -c "sleep 1h"' + command: '/bin/sh -c "sleep 10m"' name: "{{ cname }}" state: started diff --git a/test/integration/targets/docker_container/tasks/tests/start-stop.yml b/test/integration/targets/docker_container/tasks/tests/start-stop.yml index a479cb1fe0..0457e26eaf 100644 --- a/test/integration/targets/docker_container/tasks/tests/start-stop.yml +++ b/test/integration/targets/docker_container/tasks/tests/start-stop.yml @@ -13,7 +13,7 @@ - name: Create container (check) docker_container: image: alpine:3.8 - command: '/bin/sh -c "sleep 1h"' + command: '/bin/sh -c "sleep 10m"' name: "{{ cname }}" state: present check_mode: yes @@ -22,7 +22,7 @@ - name: Create container docker_container: image: alpine:3.8 - command: '/bin/sh -c "sleep 1h"' + command: '/bin/sh -c "sleep 10m"' name: "{{ cname }}" state: present register: create_2 @@ -30,7 +30,7 @@ - name: Create container (idempotent) docker_container: image: alpine:3.8 - command: '/bin/sh -c "sleep 1h"' + command: '/bin/sh -c "sleep 10m"' name: "{{ cname }}" state: present register: create_3 @@ -38,7 +38,7 @@ - name: Create container (idempotent check) docker_container: image: alpine:3.8 - command: '/bin/sh -c "sleep 1h"' + command: '/bin/sh -c "sleep 10m"' name: "{{ cname }}" state: present check_mode: yes @@ -95,7 +95,7 @@ - name: Present check for running container (check) docker_container: image: alpine:3.8 - command: '/bin/sh -c "sleep 1h"' + command: '/bin/sh -c "sleep 10m"' name: "{{ cname }}" state: present check_mode: yes @@ -104,7 +104,7 @@ - name: Present check for running container docker_container: image: alpine:3.8 - command: '/bin/sh -c "sleep 1h"' + command: '/bin/sh -c "sleep 10m"' name: "{{ cname }}" state: present register: present_check_2 @@ -127,7 +127,7 @@ - name: Start container from scratch (check) docker_container: image: alpine:3.8 - command: '/bin/sh -c "sleep 1h"' + command: '/bin/sh -c "sleep 10m"' name: "{{ cname }}" state: started check_mode: yes @@ -136,7 +136,7 @@ - name: Start container from scratch docker_container: image: alpine:3.8 - command: '/bin/sh -c "sleep 1h"' + command: '/bin/sh -c "sleep 10m"' name: "{{ cname }}" state: started register: start_scratch_2 @@ -144,7 +144,7 @@ - name: Start container from scratch (idempotent) docker_container: image: alpine:3.8 - command: '/bin/sh -c "sleep 1h"' + command: '/bin/sh -c "sleep 10m"' name: "{{ cname }}" state: started register: start_scratch_3 @@ -152,7 +152,7 @@ - name: Start container from scratch (idempotent check) docker_container: image: alpine:3.8 - command: '/bin/sh -c "sleep 1h"' + command: '/bin/sh -c "sleep 10m"' name: "{{ cname }}" state: started check_mode: yes @@ -254,7 +254,7 @@ - name: Start container (setup for removing from running) docker_container: image: alpine:3.8 - command: '/bin/sh -c "sleep 1h"' + command: '/bin/sh -c "sleep 10m"' name: "{{ cname }}" state: started