add docker examples

This commit is contained in:
Dany LE
2025-04-11 10:11:27 +00:00
parent 453233a25b
commit f135dcc118
704 changed files with 101445 additions and 21 deletions

View File

@ -0,0 +1,5 @@
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
hidden

View File

@ -0,0 +1,16 @@
#!/usr/bin/env bash
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
set -eux
[ -f "${INVENTORY}" ]
# Run connection tests with both the default and C locale.
ansible-playbook test_connection.yml -i "${INVENTORY}" "$@"
if ansible --version | grep ansible | grep -E ' 2\.(9|10|11|12|13)\.'; then
LC_ALL=C LANG=C ansible-playbook test_connection.yml -i "${INVENTORY}" "$@"
fi

View File

@ -0,0 +1,48 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
- hosts: "{{ target_hosts }}"
gather_facts: false
serial: 1
tasks:
### raw with unicode arg and output
- name: raw with unicode arg and output
raw: echo 汉语
register: command
- name: check output of raw with unicode arg and output
assert:
that:
- "'汉语' in command.stdout"
- command is changed # as of 2.2, raw should default to changed: true for consistency w/ shell/command/script modules
### copy local file with unicode filename and content
- name: create local file with unicode filename and content
local_action: lineinfile dest={{ local_tmp }}-汉语/汉语.txt create=true line=汉语
- name: remove remote file with unicode filename and content
action: "{{ action_prefix }}file path={{ remote_tmp }}-汉语/汉语.txt state=absent"
- name: create remote directory with unicode name
action: "{{ action_prefix }}file path={{ remote_tmp }}-汉语 state=directory"
- name: copy local file with unicode filename and content
action: "{{ action_prefix }}copy src={{ local_tmp }}-汉语/汉语.txt dest={{ remote_tmp }}-汉语/汉语.txt"
### fetch remote file with unicode filename and content
- name: remove local file with unicode filename and content
local_action: file path={{ local_tmp }}-汉语/汉语.txt state=absent
- name: fetch remote file with unicode filename and content
fetch: src={{ remote_tmp }}-汉语/汉语.txt dest={{ local_tmp }}-汉语/汉语.txt fail_on_missing=true validate_checksum=true flat=true
### remove local and remote temp files
- name: remove local temp file
local_action: file path={{ local_tmp }}-汉语 state=absent
- name: remove remote temp file
action: "{{ action_prefix }}file path={{ remote_tmp }}-汉语 state=absent"
### test wait_for_connection plugin
- ansible.builtin.wait_for_connection:

View File

@ -0,0 +1,7 @@
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
azp/4
skip/docker # coverage does not work if we're inside a docker container, since we cannot access this container's /tmp dir from the new container; also privileged doesn't work
destructive

View File

@ -0,0 +1,7 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
dependencies:
- setup_docker

View File

@ -0,0 +1,67 @@
#!/usr/bin/env bash
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
# If you use another image, you possibly also need to adjust
# ansible_python_interpreter in test_connection.inventory.
source ../setup_docker/vars/main.env
IMAGE="${DOCKER_TEST_IMAGE_PYTHON3}"
# Setup phase
echo "Setup"
ANSIBLE_ROLES_PATH=.. ansible-playbook setup.yml
# If docker wasn't installed, don't run the tests
if [ "$(command -v docker)" == "" ]; then
exit
fi
# Test phase
CONTAINER_SUFFIX=-${RANDOM}
DOCKER_CONTAINERS="docker-connection-test-container${CONTAINER_SUFFIX}"
[[ -n "$DEBUG" || -n "$ANSIBLE_DEBUG" ]] && set -x
set -euo pipefail
cleanup() {
echo "Cleanup"
docker rm -f ${DOCKER_CONTAINERS}
echo "Shutdown"
ANSIBLE_ROLES_PATH=.. ansible-playbook shutdown.yml
echo "Done"
}
trap cleanup INT TERM EXIT
echo "Start containers"
for CONTAINER in ${DOCKER_CONTAINERS}; do
if [ "${ANSIBLE_TEST_COVERAGE:-}" == "" ]; then
docker run --rm --name "${CONTAINER}" --detach "${IMAGE}" /bin/sh -c 'sleep 10m'
else
docker run --rm --name "${CONTAINER}" --detach -v /tmp:/tmp "${IMAGE}" /bin/sh -c 'sleep 10m'
docker exec "${CONTAINER}" pip3 install coverage
fi
echo "${CONTAINER}"
done
cat > test_connection.inventory << EOF
[docker]
docker-no-pipelining ansible_pipelining=false
docker-pipelining ansible_pipelining=true
docker-working-dir ansible_docker_working_dir=/home
docker-privileged ansible_docker_privileged=true
[docker:vars]
ansible_host=docker-connection-test-container${CONTAINER_SUFFIX}
ansible_connection=community.docker.docker
ansible_python_interpreter=/usr/local/bin/python3
EOF
echo "Run tests"
./runme-connection.sh "$@"

View File

@ -0,0 +1,14 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
- hosts: localhost
connection: local
vars:
docker_skip_cleanup: true
tasks:
- name: Setup docker
import_role:
name: setup_docker

View File

@ -0,0 +1,20 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
- hosts: localhost
connection: local
vars:
docker_skip_cleanup: true
tasks:
- name: Remove docker packages
action: "{{ ansible_facts.pkg_mgr }}"
args:
name:
- docker
- docker-ce
- docker-ce-cli
state: absent
when: not docker_skip_cleanup

View File

@ -0,0 +1,7 @@
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
azp/4
skip/docker # coverage does not work if we're inside a docker container, since we cannot access this container's /tmp dir from the new container; also privileged doesn't work
destructive

View File

@ -0,0 +1,8 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
dependencies:
- setup_docker
- setup_docker_python_deps

View File

@ -0,0 +1,67 @@
#!/usr/bin/env bash
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
# If you use another image, you possibly also need to adjust
# ansible_python_interpreter in test_connection.inventory.
source ../setup_docker/vars/main.env
IMAGE="${DOCKER_TEST_IMAGE_PYTHON3}"
# Setup phase
echo "Setup"
ANSIBLE_ROLES_PATH=.. ansible-playbook setup.yml
# If docker wasn't installed, don't run the tests
if [ "$(command -v docker)" == "" ]; then
exit
fi
# Test phase
CONTAINER_SUFFIX=-${RANDOM}
DOCKER_CONTAINERS="docker-connection-test-container${CONTAINER_SUFFIX}"
[[ -n "$DEBUG" || -n "$ANSIBLE_DEBUG" ]] && set -x
set -euo pipefail
cleanup() {
echo "Cleanup"
docker rm -f ${DOCKER_CONTAINERS}
echo "Shutdown"
ANSIBLE_ROLES_PATH=.. ansible-playbook shutdown.yml
echo "Done"
}
trap cleanup INT TERM EXIT
echo "Start containers"
for CONTAINER in ${DOCKER_CONTAINERS}; do
if [ "${ANSIBLE_TEST_COVERAGE:-}" == "" ]; then
docker run --rm --name "${CONTAINER}" --detach "${IMAGE}" /bin/sh -c 'sleep 10m'
else
docker run --rm --name "${CONTAINER}" --detach -v /tmp:/tmp "${IMAGE}" /bin/sh -c 'sleep 10m'
docker exec "${CONTAINER}" pip3 install coverage
fi
echo "${CONTAINER}"
done
cat > test_connection.inventory << EOF
[docker_api]
docker_api-no-pipelining ansible_pipelining=false
docker_api-pipelining ansible_pipelining=true
docker_api-working-dir ansible_docker_working_dir=/home
docker_api-privileged ansible_docker_privileged=true
[docker_api:vars]
ansible_host=docker-connection-test-container${CONTAINER_SUFFIX}
ansible_connection=community.docker.docker_api
ansible_python_interpreter=/usr/local/bin/python3
EOF
echo "Run tests"
./runme-connection.sh "$@"

View File

@ -0,0 +1,18 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
- hosts: localhost
connection: local
vars:
docker_skip_cleanup: true
tasks:
- name: Setup docker
import_role:
name: setup_docker
- name: Setup docker Python deps
import_role:
name: setup_docker_python_deps

View File

@ -0,0 +1,20 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
- hosts: localhost
connection: local
vars:
docker_skip_cleanup: true
tasks:
- name: Remove docker packages
action: "{{ ansible_facts.pkg_mgr }}"
args:
name:
- docker
- docker-ce
- docker-ce-cli
state: absent
when: not docker_skip_cleanup

View File

@ -0,0 +1,8 @@
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
azp/5
skip/docker # this requires unfettered access to the container host
skip/rhel7.9 # nsenter does not work out of the box
destructive

View File

@ -0,0 +1,7 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
dependencies:
- setup_docker

View File

@ -0,0 +1,75 @@
#!/usr/bin/env bash
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
set -euo pipefail
[[ -n "${DEBUG:-}" || -n "${ANSIBLE_DEBUG:-}" ]] && set -x
readonly IMAGE="quay.io/ansible/ansible-runner:devel"
# shellcheck disable=SC2155
readonly PYTHON="$(command -v python3 python | head -n1)"
# Determine collection root
COLLECTION_ROOT=./
while true; do
if [ -e ${COLLECTION_ROOT}galaxy.yml ] || [ -e ${COLLECTION_ROOT}MANIFEST.json ]; then
break
fi
COLLECTION_ROOT="${COLLECTION_ROOT}../"
done
# shellcheck disable=SC2155
readonly COLLECTION_ROOT="$(cd ${COLLECTION_ROOT} ; pwd)"
# Setup phase
echo "Setup"
ANSIBLE_ROLES_PATH=.. ansible-playbook setup.yml
# If docker wasn't installed, don't run the tests
if [ "$(command -v docker)" == "" ]; then
exit
fi
cleanup() {
echo "Cleanup"
echo "Shutdown"
ANSIBLE_ROLES_PATH=.. ansible-playbook shutdown.yml
echo "Done"
}
envs=(--env "HOME=${HOME:-}")
while IFS=$'\0' read -d '' -r line; do
key="$(echo "$line" | cut -d= -f1)"
value="$(echo "$line" | cut -d= -f2-)"
if [[ "${key}" =~ ^(ANSIBLE_|JUNIT_OUTPUT_DIR$|OUTPUT_DIR$|PYTHONPATH$) ]]; then
envs+=(--env "${key}=${value}")
fi
done < <(printenv -0)
# Test phase
cat > test_connection.inventory << EOF
[nsenter]
nsenter-no-pipelining ansible_pipelining=false
nsenter-pipelining ansible_pipelining=true
[nsenter:vars]
ansible_host=localhost
ansible_connection=community.docker.nsenter
ansible_host_volume_mount=/host
ansible_nsenter_pid=1
ansible_python_interpreter=${PYTHON}
EOF
echo "Run tests"
set -x
docker run \
-i \
--rm \
--privileged \
--pid host \
"${envs[@]}" \
--volume "${COLLECTION_ROOT}:${COLLECTION_ROOT}" \
--workdir "$(pwd)" \
"${IMAGE}" \
./runme-connection.sh "$@"

View File

@ -0,0 +1,14 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
- hosts: localhost
connection: local
vars:
docker_skip_cleanup: true
tasks:
- name: Setup docker
import_role:
name: setup_docker

View File

@ -0,0 +1,20 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
- hosts: localhost
connection: local
vars:
docker_skip_cleanup: true
tasks:
- name: Remove docker packages
action: "{{ ansible_facts.pkg_mgr }}"
args:
name:
- docker
- docker-ce
- docker-ce-cli
state: absent
when: not docker_skip_cleanup

View File

@ -0,0 +1,6 @@
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
needs/target/connection
hidden

View File

@ -0,0 +1,23 @@
#!/usr/bin/env bash
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
set -eux
# Connection tests for POSIX platforms use this script by linking to it from the appropriate 'connection_' target dir.
# The name of the inventory group to test is extracted from the directory name following the 'connection_' prefix.
PYTHON="$(command -v python3 python | head -n1)"
group=$(${PYTHON} -c \
"from os import path; print(path.basename(path.abspath(path.dirname('$0'))).replace('connection_', ''))")
cd ../connection
INVENTORY="../connection_${group}/test_connection.inventory" ./test.sh \
-e target_hosts="${group}" \
-e action_prefix= \
-e local_tmp=/tmp/ansible-local \
-e remote_tmp=/tmp/ansible-remote \
"$@"

View File

@ -0,0 +1,6 @@
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
azp/4
skip/rhel

View File

@ -0,0 +1,41 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
####################################################################
# WARNING: These are designed specifically for Ansible tests #
# and should not be used as examples of how to write Ansible roles #
####################################################################
- name: Get facts
current_container_facts:
register: result
# WARNING: This is not a proper test as it won't fail when the module does not work!
# To make this a proper test, we need to know the environment in which this
# test runs, which we do not know in general...
- name: Print facts
ansible.builtin.debug:
var: result.ansible_facts
- name: Read files
ansible.builtin.slurp:
src: '{{ item }}'
loop:
- /proc/self/cgroup
- /proc/self/cpuset
- /proc/self/mountinfo
register: slurp
ignore_errors: true
- name: Print files
ansible.builtin.debug:
msg: |-
{{ item.content | ansible.builtin.b64decode | split('
') }}
loop: '{{ slurp.results }}'
loop_control:
label: '{{ item.source | default(item.item) }}'
when: item is not failed

View File

@ -0,0 +1,6 @@
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
azp/4
destructive

View File

@ -0,0 +1,10 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
dependencies:
- setup_docker_cli_compose
# The Python dependencies are needed for the other modules
- setup_docker_python_deps
- setup_remote_tmp_dir

View File

@ -0,0 +1,56 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
####################################################################
# WARNING: These are designed specifically for Ansible tests #
# and should not be used as examples of how to write Ansible roles #
####################################################################
# Create random name prefix (for services, ...)
- name: Create random container name prefix
set_fact:
name_prefix: "{{ 'ansible-docker-test-%0x' % ((2**32) | random) }}"
cnames: []
dnetworks: []
images: []
- debug:
msg: "Using name prefix {{ name_prefix }}"
# Run the tests
- block:
- name: Show docker compose --help output
command: docker compose --help
- include_tasks: run-test.yml
with_fileglob:
- "tests/*.yml"
loop_control:
loop_var: test_name
always:
- name: "Make sure all containers are removed"
docker_container:
name: "{{ item }}"
state: absent
force_kill: true
loop: "{{ cnames }}"
diff: false
- name: "Make sure all networks are removed"
docker_network:
name: "{{ item }}"
state: absent
force: true
loop: "{{ dnetworks }}"
diff: false
- name: "Make sure all images are removed"
docker_image_remove:
name: "{{ item }}"
loop: "{{ images }}"
diff: false
when: docker_has_compose and docker_compose_version is version('2.18.0', '>=')

View File

@ -0,0 +1,7 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
- name: "Loading tasks from {{ test_name }}"
include_tasks: "{{ test_name }}"

View File

@ -0,0 +1,135 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
- vars:
pname: "{{ name_prefix }}-build"
cname: "{{ name_prefix }}-container"
iname: "{{ name_prefix }}-image"
project_src: "{{ remote_tmp_dir }}/{{ pname }}"
test_service: |
services:
{{ cname }}:
build: ./build
image: "{{ iname }}"
pull_policy: never
stop_grace_period: 1s
block:
- name: Registering container name
set_fact:
cnames: "{{ cnames + [pname ~ '-' ~ cname ~ '-1'] }}"
dnetworks: "{{ dnetworks + [pname ~ '_default'] }}"
images: "{{ images + [iname] }}"
- name: Create project directory
file:
path: '{{ item }}'
state: directory
loop:
- '{{ project_src }}'
- '{{ project_src }}/build'
- name: Template default project file
copy:
dest: '{{ project_src }}/docker-compose.yml'
content: '{{ test_service }}'
- name: Template Dockerfile
copy:
dest: '{{ project_src }}/build/Dockerfile'
content: |
FROM {{ docker_test_image_alpine }}
ENTRYPOINT ["/bin/sh", "-c", "sleep 10m"]
- name: Present (check)
docker_compose_v2:
project_src: '{{ project_src }}'
state: present
check_mode: true
register: present_1_check
- name: Present
docker_compose_v2:
project_src: '{{ project_src }}'
state: present
register: present_1
- name: Present (idempotent check)
docker_compose_v2:
project_src: '{{ project_src }}'
state: present
check_mode: true
register: present_2_check
- name: Present (idempotent)
docker_compose_v2:
project_src: '{{ project_src }}'
state: present
register: present_2
- name: Present (idempotent check, build=always, ignore_build_events=false)
docker_compose_v2:
project_src: '{{ project_src }}'
state: present
build: always
ignore_build_events: false
check_mode: true
register: present_3_check
- name: Present (idempotent, build=always, ignore_build_events=false)
docker_compose_v2:
project_src: '{{ project_src }}'
state: present
build: always
ignore_build_events: false
register: present_3
- name: Present (idempotent check, build=always, ignore_build_events=true)
docker_compose_v2:
project_src: '{{ project_src }}'
state: present
build: always
ignore_build_events: true
check_mode: true
register: present_4_check
- name: Present (idempotent, build=always, ignore_build_events=true)
docker_compose_v2:
project_src: '{{ project_src }}'
state: present
build: always
ignore_build_events: true
register: present_4
- assert:
that:
- present_1_check is changed
- present_1_check.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_1 is changed
- present_1.containers | length == 1
- present_1.containers[0].Name == (pname ~ '-' ~ cname ~ '-1')
- present_1.images | length == 1
- present_1.images[0].ContainerName == (pname ~ '-' ~ cname ~ '-1')
- present_1.images[0].Repository == iname
- present_1.images[0].Tag == "latest"
- present_1.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_2_check is not changed
- present_2_check.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_2 is not changed
- present_2.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_3_check is changed
- present_3_check.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- ((present_3 is changed) if docker_compose_version is version('2.31.0', '>=') and docker_compose_version is version('2.32.2', '<') else (present_3 is not changed))
- present_3.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_4_check is changed
- present_4_check.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_4 is not changed
- present_4.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
always:
- name: Cleanup
docker_compose_v2:
project_src: '{{ project_src }}'
state: absent

View File

@ -0,0 +1,70 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
- vars:
pname: "{{ name_prefix }}-exit"
cname: "{{ name_prefix }}-container"
project_src: "{{ remote_tmp_dir }}/{{ pname }}"
test_service: |
services:
{{ cname }}:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "exit 0"'
stop_grace_period: 1s
block:
- name: Registering container name
set_fact:
cnames: "{{ cnames + [pname ~ '-' ~ cname ~ '-1'] }}"
dnetworks: "{{ dnetworks + [pname ~ '_default'] }}"
- name: Create project directory
file:
path: '{{ project_src }}'
state: directory
- name: Template default project file
copy:
dest: '{{ project_src }}/docker-compose.yml'
content: '{{ test_service }}'
- name: Present (check)
docker_compose_v2:
project_src: '{{ project_src }}'
state: present
wait: true
check_mode: true
register: present_1_check
- name: Present
docker_compose_v2:
project_src: '{{ project_src }}'
state: present
wait: true
register: present_1
ignore_errors: true
- name: Cleanup
docker_compose_v2:
project_src: '{{ project_src }}'
state: absent
- assert:
that:
- present_1_check is changed
- present_1_check.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_1 is failed
- present_1.containers | length == 1
- present_1.containers[0].Name == (pname ~ '-' ~ cname ~ '-1')
- present_1.containers[0].Image == docker_test_image_alpine
- present_1.containers[0].State == 'exited'
- present_1.containers[0].ExitCode == 0
- present_1.images | length == 1
- present_1.images[0].ContainerName == (pname ~ '-' ~ cname ~ '-1')
- present_1.images[0].Repository == (docker_test_image_alpine | split(':') | first)
- present_1.images[0].Tag == (docker_test_image_alpine | split(':') | last)
- present_1.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- >-
("container " ~ pname ~ '-' ~ cname ~ "-1 exited (0)") in present_1.msg

View File

@ -0,0 +1,288 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
- vars:
pname: "{{ name_prefix }}-definition"
cname: "{{ name_prefix }}-container"
test_service: |
services:
{{ cname }}:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
stop_grace_period: 1s
test_service_mod: |
services:
{{ cname }}:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 15m"'
stop_grace_period: 1s
block:
- name: Registering container name
set_fact:
cnames: "{{ cnames + [pname ~ '-' ~ cname ~ '-1'] }}"
dnetworks: "{{ dnetworks + [pname ~ '_default'] }}"
####################################################################
## Present #########################################################
####################################################################
- name: Present (check)
docker_compose_v2:
project_name: '{{ pname }}'
definition: '{{ test_service | from_yaml }}'
state: present
check_mode: true
register: present_1_check
- name: Present
docker_compose_v2:
project_name: '{{ pname }}'
definition: '{{ test_service | from_yaml }}'
state: present
register: present_1
- name: Present (idempotent check)
docker_compose_v2:
project_name: '{{ pname }}'
definition: '{{ test_service | from_yaml }}'
state: present
check_mode: true
register: present_2_check
- name: Present (idempotent)
docker_compose_v2:
project_name: '{{ pname }}'
definition: '{{ test_service | from_yaml }}'
state: present
register: present_2
- name: Present (changed check)
docker_compose_v2:
project_name: '{{ pname }}'
definition: '{{ test_service_mod | from_yaml }}'
state: present
check_mode: true
register: present_3_check
- name: Present (changed)
docker_compose_v2:
project_name: '{{ pname }}'
definition: '{{ test_service_mod | from_yaml }}'
state: present
register: present_3
- assert:
that:
- present_1_check is changed
- present_1_check.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_1 is changed
- present_1.containers | length == 1
- present_1.containers[0].Name == (pname ~ '-' ~ cname ~ '-1')
- present_1.containers[0].Image == docker_test_image_alpine
- present_1.images | length == 1
- present_1.images[0].ContainerName == (pname ~ '-' ~ cname ~ '-1')
- present_1.images[0].Repository == (docker_test_image_alpine | split(':') | first)
- present_1.images[0].Tag == (docker_test_image_alpine | split(':') | last)
- present_1.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_2_check is not changed
- present_2_check.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_2 is not changed
- present_2.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_3_check is changed
- present_3_check.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_3 is changed
- present_3.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
####################################################################
## Absent ##########################################################
####################################################################
- name: Absent (check)
docker_compose_v2:
project_name: '{{ pname }}'
definition: '{{ test_service_mod | from_yaml }}'
state: absent
check_mode: true
register: absent_1_check
- name: Absent
docker_compose_v2:
project_name: '{{ pname }}'
definition: '{{ test_service_mod | from_yaml }}'
state: absent
register: absent_1
- name: Absent (idempotent check)
docker_compose_v2:
project_name: '{{ pname }}'
definition: '{{ test_service_mod | from_yaml }}'
state: absent
check_mode: true
register: absent_2_check
- name: Absent (idempotent)
docker_compose_v2:
project_name: '{{ pname }}'
definition: '{{ test_service_mod | from_yaml }}'
state: absent
register: absent_2
- assert:
that:
- absent_1_check is changed
- absent_1_check.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- absent_1 is changed
- absent_1.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- absent_2_check is not changed
- absent_2_check.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- absent_2 is not changed
- absent_2.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
####################################################################
## Stopping and starting ###########################################
####################################################################
- name: Present stopped (check)
docker_compose_v2:
project_name: '{{ pname }}'
definition: '{{ test_service | from_yaml }}'
state: stopped
check_mode: true
register: present_1_check
- name: Present stopped
docker_compose_v2:
project_name: '{{ pname }}'
definition: '{{ test_service | from_yaml }}'
state: stopped
register: present_1
- name: Present stopped (idempotent check)
docker_compose_v2:
project_name: '{{ pname }}'
definition: '{{ test_service | from_yaml }}'
state: stopped
check_mode: true
register: present_2_check
- name: Present stopped (idempotent)
docker_compose_v2:
project_name: '{{ pname }}'
definition: '{{ test_service | from_yaml }}'
state: stopped
register: present_2
- name: Started (check)
docker_compose_v2:
project_name: '{{ pname }}'
definition: '{{ test_service | from_yaml }}'
state: present
check_mode: true
register: present_3_check
- name: Started
docker_compose_v2:
project_name: '{{ pname }}'
definition: '{{ test_service | from_yaml }}'
state: present
register: present_3
- name: Started (idempotent check)
docker_compose_v2:
project_name: '{{ pname }}'
definition: '{{ test_service | from_yaml }}'
state: present
check_mode: true
register: present_4_check
- name: Started (idempotent)
docker_compose_v2:
project_name: '{{ pname }}'
definition: '{{ test_service | from_yaml }}'
state: present
register: present_4
- name: Restarted (check)
docker_compose_v2:
project_name: '{{ pname }}'
definition: '{{ test_service | from_yaml }}'
state: restarted
check_mode: true
register: present_5_check
- name: Restarted
docker_compose_v2:
project_name: '{{ pname }}'
definition: '{{ test_service | from_yaml }}'
state: restarted
register: present_5
- name: Stopped (check)
docker_compose_v2:
project_name: '{{ pname }}'
definition: '{{ test_service | from_yaml }}'
state: stopped
check_mode: true
register: present_6_check
- name: Stopped
docker_compose_v2:
project_name: '{{ pname }}'
definition: '{{ test_service | from_yaml }}'
state: stopped
register: present_6
- name: Restarted (check)
docker_compose_v2:
project_name: '{{ pname }}'
definition: '{{ test_service | from_yaml }}'
state: restarted
check_mode: true
register: present_7_check
- name: Restarted
docker_compose_v2:
project_name: '{{ pname }}'
definition: '{{ test_service | from_yaml }}'
state: restarted
register: present_7
- name: Cleanup
docker_compose_v2:
project_name: '{{ pname }}'
definition: '{{ test_service | from_yaml }}'
state: absent
- assert:
that:
- present_1_check is changed
- present_1_check.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_1 is changed
- present_1.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_2_check is not changed
- present_2_check.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_2 is not changed
- present_2.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_3_check is changed
- present_3_check.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_3 is changed
- present_3.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_4_check is not changed
- present_4_check.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_4 is not changed
- present_4.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_5_check is changed
- present_5_check.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_5 is changed
- present_5.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_6_check is changed
- present_6_check.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_6 is changed
- present_6.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_7_check is changed
- present_7_check.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_7 is changed
- present_7.warnings | default([]) | select('regex', ' Please report this at ') | length == 0

View File

@ -0,0 +1,223 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
- vars:
pname: "{{ name_prefix }}-pull"
cname: "{{ name_prefix }}-cont"
non_existing_image: does-not-exist:latest
project_src: "{{ remote_tmp_dir }}/{{ pname }}"
test_service_non_existing: |
services:
{{ cname }}:
image: {{ non_existing_image }}
test_service_simple: |
services:
{{ cname }}:
image: {{ docker_test_image_simple_1 }}
command: 10m
stop_grace_period: 1s
block:
- name: Registering container name
set_fact:
cnames: "{{ cnames + [pname ~ '-' ~ cname ~ '-1'] }}"
dnetworks: "{{ dnetworks + [pname ~ '_default'] }}"
- name: Create project directory
file:
path: '{{ project_src }}'
state: directory
- name: Make sure images are not around
docker_image_remove:
name: '{{ item }}'
loop:
- '{{ non_existing_image }}'
- '{{ docker_test_image_simple_1 }}'
####################################################################
## Missing image ###################################################
####################################################################
- name: Template project file with non-existing image
copy:
dest: '{{ project_src }}/docker-compose.yml'
content: '{{ test_service_non_existing }}'
- name: Present with pull=never (check)
docker_compose_v2:
project_src: '{{ project_src }}'
state: present
pull: never
check_mode: true
register: present_1_check
ignore_errors: true
- name: Present with pull=never
docker_compose_v2:
project_src: '{{ project_src }}'
state: present
pull: never
register: present_1
ignore_errors: true
- name: Present without explicit pull (check)
docker_compose_v2:
project_src: '{{ project_src }}'
state: present
check_mode: true
register: present_2_check
ignore_errors: true
- name: Present without explicit pull
docker_compose_v2:
project_src: '{{ project_src }}'
state: present
register: present_2
ignore_errors: true
- assert:
that:
- present_1_check is failed or present_1_check is changed
- present_1_check is changed or present_1_check.msg.startswith('General error:')
- present_1_check.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_1 is failed
- present_1.msg.startswith('General error:')
- present_1.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_2_check is failed
- present_2_check.msg.startswith('Error when processing ' ~ cname ~ ':')
- present_2_check.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_2 is failed
- present_2.msg.startswith('Error when processing ' ~ cname ~ ':')
- present_2.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
####################################################################
## Regular image ###################################################
####################################################################
- name: Template project file with simple image
copy:
dest: '{{ project_src }}/docker-compose.yml'
content: '{{ test_service_simple }}'
- name: Present with pull=missing (check)
docker_compose_v2:
project_src: '{{ project_src }}'
state: present
pull: missing
check_mode: true
register: present_1_check
- name: Present with pull=missing
docker_compose_v2:
project_src: '{{ project_src }}'
state: present
pull: missing
register: present_1
- name: Present with pull=missing (idempotent, check)
docker_compose_v2:
project_src: '{{ project_src }}'
state: present
pull: missing
check_mode: true
register: present_2_check
- name: Present with pull=missing (idempotent)
docker_compose_v2:
project_src: '{{ project_src }}'
state: present
pull: missing
register: present_2
- name: Present with pull=always (check)
docker_compose_v2:
project_src: '{{ project_src }}'
state: present
pull: always
check_mode: true
register: present_3_check
- name: Present with pull=always
docker_compose_v2:
project_src: '{{ project_src }}'
state: present
pull: always
register: present_3
- name: Stopping service
docker_compose_v2:
project_src: '{{ project_src }}'
state: absent
- name: Present with pull=never (check)
docker_compose_v2:
project_src: '{{ project_src }}'
state: present
pull: missing
check_mode: true
register: present_4_check
- name: Present with pull=never
docker_compose_v2:
project_src: '{{ project_src }}'
state: present
pull: missing
register: present_4
- name: Present with pull=never (idempotent, check)
docker_compose_v2:
project_src: '{{ project_src }}'
state: present
pull: missing
check_mode: true
register: present_5_check
- name: Present with pull=never (idempotent)
docker_compose_v2:
project_src: '{{ project_src }}'
state: present
pull: missing
register: present_5
- name: Cleanup
docker_compose_v2:
project_src: '{{ project_src }}'
state: absent
- assert:
that:
- present_1_check is changed
- (present_1_check.actions | selectattr('status', 'eq', 'Pulling') | first) is truthy
- (present_1_check.actions | selectattr('status', 'eq', 'Creating') | first) is truthy
- present_1_check.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_1 is changed
- (present_1.actions | selectattr('status', 'eq', 'Pulling') | first) is truthy
- (present_1.actions | selectattr('status', 'eq', 'Creating') | first) is truthy
- present_1.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_2_check is not changed
- present_2_check.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_2 is not changed
- present_2.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_3_check is changed
- (present_3_check.actions | selectattr('status', 'eq', 'Pulling') | first) is truthy
- present_3_check.actions | selectattr('status', 'eq', 'Creating') | length == 0
- present_3_check.actions | selectattr('status', 'eq', 'Recreating') | length == 0
- present_3_check.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_3 is not changed
- (present_3.actions | selectattr('status', 'eq', 'Pulling') | first) is truthy
- present_3.actions | selectattr('status', 'eq', 'Creating') | length == 0
- present_3.actions | selectattr('status', 'eq', 'Recreating') | length == 0
- present_3.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_4_check is changed
- present_4_check.actions | selectattr('status', 'eq', 'Pulling') | length == 0
- present_4_check.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_4 is changed
- present_4.actions | selectattr('status', 'eq', 'Pulling') | length == 0
- present_4.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_5_check is not changed
- present_5_check.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_5 is not changed
- present_5.warnings | default([]) | select('regex', ' Please report this at ') | length == 0

View File

@ -0,0 +1,291 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
- vars:
pname: "{{ name_prefix }}-start-stop"
cname: "{{ name_prefix }}-container"
project_src: "{{ remote_tmp_dir }}/{{ pname }}"
test_service: |
services:
{{ cname }}:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
stop_grace_period: 1s
test_service_mod: |
services:
{{ cname }}:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 15m"'
stop_grace_period: 1s
block:
- name: Registering container name
set_fact:
cnames: "{{ cnames + [pname ~ '-' ~ cname ~ '-1'] }}"
dnetworks: "{{ dnetworks + [pname ~ '_default'] }}"
- name: Create project directory
file:
path: '{{ project_src }}'
state: directory
####################################################################
## Present #########################################################
####################################################################
- name: Template default project file
copy:
dest: '{{ project_src }}/docker-compose.yml'
content: '{{ test_service }}'
- name: Present (check)
docker_compose_v2:
project_src: '{{ project_src }}'
state: present
check_mode: true
register: present_1_check
- name: Present
docker_compose_v2:
project_src: '{{ project_src }}'
state: present
register: present_1
- name: Present (idempotent check)
docker_compose_v2:
project_src: '{{ project_src }}'
state: present
check_mode: true
register: present_2_check
- name: Present (idempotent)
docker_compose_v2:
project_src: '{{ project_src }}'
state: present
register: present_2
- name: Template modified project file
copy:
dest: '{{ project_src }}/docker-compose.yml'
content: '{{ test_service_mod }}'
- name: Present (changed check)
docker_compose_v2:
project_src: '{{ project_src }}'
state: present
check_mode: true
register: present_3_check
- name: Present (changed)
docker_compose_v2:
project_src: '{{ project_src }}'
state: present
register: present_3
- name: Present with --yes
docker_compose_v2:
project_src: '{{ project_src }}'
state: present
assume_yes: true
when: docker_compose_version is version('2.32.0', '>=')
- assert:
that:
- present_1_check is changed
- present_1_check.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_1 is changed
- present_1.containers | length == 1
- present_1.containers[0].Name == (pname ~ '-' ~ cname ~ '-1')
- present_1.containers[0].Image == docker_test_image_alpine
- present_1.images | length == 1
- present_1.images[0].ContainerName == (pname ~ '-' ~ cname ~ '-1')
- present_1.images[0].Repository == (docker_test_image_alpine | split(':') | first)
- present_1.images[0].Tag == (docker_test_image_alpine | split(':') | last)
- present_1.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_2_check is not changed
- present_2_check.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_2 is not changed
- present_2.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_3_check is changed
- present_3_check.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_3 is changed
- present_3.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
####################################################################
## Absent ##########################################################
####################################################################
- name: Absent (check)
docker_compose_v2:
project_src: '{{ project_src }}'
state: absent
check_mode: true
register: absent_1_check
- name: Absent
docker_compose_v2:
project_src: '{{ project_src }}'
state: absent
register: absent_1
- name: Absent (idempotent check)
docker_compose_v2:
project_src: '{{ project_src }}'
state: absent
check_mode: true
register: absent_2_check
- name: Absent (idempotent)
docker_compose_v2:
project_src: '{{ project_src }}'
state: absent
register: absent_2
- assert:
that:
- absent_1_check is changed
- absent_1_check.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- absent_1 is changed
- absent_1.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- absent_2_check is not changed
- absent_2_check.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- absent_2 is not changed
- absent_2.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
####################################################################
## Stopping and starting ###########################################
####################################################################
- name: Template default project file
copy:
dest: '{{ project_src }}/docker-compose.yml'
content: '{{ test_service }}'
- name: Present stopped (check)
docker_compose_v2:
project_src: '{{ project_src }}'
state: stopped
check_mode: true
register: present_1_check
- name: Present stopped
docker_compose_v2:
project_src: '{{ project_src }}'
state: stopped
register: present_1
- name: Present stopped (idempotent check)
docker_compose_v2:
project_src: '{{ project_src }}'
state: stopped
check_mode: true
register: present_2_check
- name: Present stopped (idempotent)
docker_compose_v2:
project_src: '{{ project_src }}'
state: stopped
register: present_2
- name: Started (check)
docker_compose_v2:
project_src: '{{ project_src }}'
state: present
check_mode: true
register: present_3_check
- name: Started
docker_compose_v2:
project_src: '{{ project_src }}'
state: present
register: present_3
- name: Started (idempotent check)
docker_compose_v2:
project_src: '{{ project_src }}'
state: present
check_mode: true
register: present_4_check
- name: Started (idempotent)
docker_compose_v2:
project_src: '{{ project_src }}'
state: present
register: present_4
- name: Restarted (check)
docker_compose_v2:
project_src: '{{ project_src }}'
state: restarted
check_mode: true
register: present_5_check
- name: Restarted
docker_compose_v2:
project_src: '{{ project_src }}'
state: restarted
register: present_5
- name: Stopped (check)
docker_compose_v2:
project_src: '{{ project_src }}'
state: stopped
check_mode: true
register: present_6_check
- name: Stopped
docker_compose_v2:
project_src: '{{ project_src }}'
state: stopped
register: present_6
- name: Restarted (check)
docker_compose_v2:
project_src: '{{ project_src }}'
state: restarted
check_mode: true
register: present_7_check
- name: Restarted
docker_compose_v2:
project_src: '{{ project_src }}'
state: restarted
register: present_7
- name: Cleanup
docker_compose_v2:
project_src: '{{ project_src }}'
state: absent
- assert:
that:
- present_1_check is changed
- present_1_check.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_1 is changed
- present_1.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_2_check is not changed
- present_2_check.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_2 is not changed
- present_2.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_3_check is changed
- present_3_check.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_3 is changed
- present_3.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_4_check is not changed
- present_4_check.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_4 is not changed
- present_4.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_5_check is changed
- present_5_check.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_5 is changed
- present_5.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_6_check is changed
- present_6_check.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_6 is changed
- present_6.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_7_check is changed
- present_7_check.warnings | default([]) | select('regex', ' Please report this at ') | length == 0
- present_7 is changed
- present_7.warnings | default([]) | select('regex', ' Please report this at ') | length == 0

View File

@ -0,0 +1,6 @@
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
azp/4
destructive

View File

@ -0,0 +1,10 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
dependencies:
- setup_docker_cli_compose
# The Python dependencies are needed for the other modules
- setup_docker_python_deps
- setup_remote_tmp_dir

View File

@ -0,0 +1,49 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
####################################################################
# WARNING: These are designed specifically for Ansible tests #
# and should not be used as examples of how to write Ansible roles #
####################################################################
# Create random name prefix (for services, ...)
- name: Create random container name prefix
set_fact:
name_prefix: "{{ 'ansible-docker-test-%0x' % ((2**32) | random) }}"
cnames: []
dnetworks: []
- debug:
msg: "Using name prefix {{ name_prefix }}"
# Run the tests
- block:
- name: Show docker compose --help output
command: docker compose --help
- include_tasks: run-test.yml
with_fileglob:
- "tests/*.yml"
loop_control:
loop_var: test_name
always:
- name: "Make sure all containers are removed"
docker_container:
name: "{{ item }}"
state: absent
force_kill: true
with_items: "{{ cnames }}"
diff: false
- name: "Make sure all networks are removed"
docker_network:
name: "{{ item }}"
state: absent
force: true
with_items: "{{ dnetworks }}"
diff: false
when: docker_has_compose and docker_compose_version is version('2.18.0', '>=')

View File

@ -0,0 +1,7 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
- name: "Loading tasks from {{ test_name }}"
include_tasks: "{{ test_name }}"

View File

@ -0,0 +1,97 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
- vars:
pname: "{{ name_prefix }}-start-stop"
cname: "{{ name_prefix }}-container"
project_src: "{{ remote_tmp_dir }}/{{ pname }}"
test_service: |
services:
{{ cname }}:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
stop_grace_period: 1s
block:
- name: Registering container name
set_fact:
cnames: "{{ cnames + [pname ~ '-' ~ cname ~ '-1'] }}"
dnetworks: "{{ dnetworks + [pname ~ '_default'] }}"
- name: Create project directory
file:
path: '{{ project_src }}'
state: directory
- name: Template default project file
copy:
dest: '{{ project_src }}/docker-compose.yml'
content: '{{ test_service }}'
- block:
- name: Start services
docker_compose_v2:
project_src: '{{ project_src }}'
state: present
- name: Run command with command
docker_compose_v2_exec:
project_src: '{{ project_src }}'
service: '{{ cname }}'
command: /bin/sh -c "ls /"
register: result_1
- name: Run command with argv
docker_compose_v2_exec:
project_src: '{{ project_src }}'
service: '{{ cname }}'
argv:
- /bin/sh
- "-c"
- whoami
user: "1234"
register: result_2
failed_when: result_2.rc != 1
- name: Run detached command
docker_compose_v2_exec:
project_src: '{{ project_src }}'
service: '{{ cname }}'
command: /bin/sh -c "sleep 1"
detach: true
register: result_3
- name: Run command with input
docker_compose_v2_exec:
project_src: '{{ project_src }}'
service: '{{ cname }}'
command: /bin/sh -c "cat"
stdin: This is a test
register: result_4
- assert:
that:
- result_1.rc == 0
- result_1.stderr == ""
- >-
"usr" in result_1.stdout_lines
and
"etc" in result_1.stdout_lines
- result_2.rc == 1
- >-
"whoami: unknown uid 1234" in result_2.stderr
- result_2.stdout == ""
- result_3.rc is not defined
- result_3.stdout is not defined
- result_3.stderr is not defined
- result_4.rc == 0
- result_4.stdout == "This is a test"
- result_4.stderr == ""
always:
- name: Cleanup
docker_compose_v2:
project_src: '{{ project_src }}'
state: absent

View File

@ -0,0 +1,6 @@
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
azp/4
destructive

View File

@ -0,0 +1,10 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
dependencies:
- setup_docker_cli_compose
# The Python dependencies are needed for the other modules
- setup_docker_python_deps
- setup_remote_tmp_dir

View File

@ -0,0 +1,52 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
####################################################################
# WARNING: These are designed specifically for Ansible tests #
# and should not be used as examples of how to write Ansible roles #
####################################################################
# Create random name prefix (for services, ...)
- name: Create random container name prefix
set_fact:
name_prefix: "{{ 'ansible-docker-test-%0x' % ((2**32) | random) }}"
cnames: []
dnetworks: []
- debug:
msg: "Using name prefix {{ name_prefix }}"
- name: Show images
command: docker images --all --digests
# Run the tests
- block:
- name: Show docker compose --help output
command: docker compose --help
- include_tasks: run-test.yml
with_fileglob:
- "tests/*.yml"
loop_control:
loop_var: test_name
always:
- name: "Make sure all containers are removed"
docker_container:
name: "{{ item }}"
state: absent
force_kill: true
with_items: "{{ cnames }}"
diff: false
- name: "Make sure all networks are removed"
docker_network:
name: "{{ item }}"
state: absent
force: true
with_items: "{{ dnetworks }}"
diff: false
when: docker_has_compose and docker_compose_version is version('2.18.0', '>=')

View File

@ -0,0 +1,7 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
- name: "Loading tasks from {{ test_name }}"
include_tasks: "{{ test_name }}"

View File

@ -0,0 +1,206 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
- vars:
pname: "{{ name_prefix }}-pull"
cname: "{{ name_prefix }}-cont"
non_existing_image: does-not-exist:latest
project_src: "{{ remote_tmp_dir }}/{{ pname }}"
test_service_non_existing: |
version: '3'
services:
{{ cname }}:
image: {{ non_existing_image }}
test_service_simple: |
version: '3'
services:
{{ cname }}:
image: {{ docker_test_image_simple_1 }}
command: 10m
stop_grace_period: 1s
block:
- name: Registering container name
set_fact:
cnames: "{{ cnames + [pname ~ '-' ~ cname ~ '-1'] }}"
dnetworks: "{{ dnetworks + [pname ~ '_default'] }}"
- name: Create project directory
file:
path: '{{ project_src }}'
state: directory
- name: Make sure images are not around
docker_image_remove:
name: '{{ item }}'
loop:
- '{{ non_existing_image }}'
- '{{ docker_test_image_simple_1 }}'
####################################################################
## Missing image ###################################################
####################################################################
- name: Template project file with non-existing image
copy:
dest: '{{ project_src }}/docker-compose.yml'
content: '{{ test_service_non_existing }}'
- name: Pull (check)
docker_compose_v2_pull:
project_src: '{{ project_src }}'
check_mode: true
register: pull_1_check
ignore_errors: true
- name: Pull
docker_compose_v2_pull:
project_src: '{{ project_src }}'
register: pull_1
ignore_errors: true
- assert:
that:
- pull_1_check is failed or pull_1_check is changed
- pull_1_check is changed or pull_1_check.msg.startswith('Error when processing ')
- pull_1_check.warnings | default([]) | select('regex', 'Cannot parse event from ') | length == 0
- pull_1 is failed
- pull_1.msg.startswith('Error when processing ')
- pull_1.warnings | default([]) | select('regex', 'Cannot parse event from ') | length == 0
####################################################################
## Regular image ###################################################
####################################################################
- name: Template project file with simple image
copy:
dest: '{{ project_src }}/docker-compose.yml'
content: '{{ test_service_simple }}'
- when: docker_compose_version is version('2.22.0', '>=')
block:
- name: Pull with policy=missing (check)
docker_compose_v2_pull:
project_src: '{{ project_src }}'
policy: missing
check_mode: true
register: pull_1_check
- name: Pull with policy=missing
docker_compose_v2_pull:
project_src: '{{ project_src }}'
policy: missing
register: pull_1
- name: Pull with policy=missing (idempotent, check)
docker_compose_v2_pull:
project_src: '{{ project_src }}'
policy: missing
check_mode: true
register: pull_2_check
- name: Pull with policy=missing (idempotent)
docker_compose_v2_pull:
project_src: '{{ project_src }}'
policy: missing
register: pull_2
- name: Make sure image is not around
docker_image_remove:
name: '{{ docker_test_image_simple_1 }}'
- name: Pull with policy=always (check)
docker_compose_v2_pull:
project_src: '{{ project_src }}'
policy: always
check_mode: true
register: pull_3_check
- name: Pull with policy=always
docker_compose_v2_pull:
project_src: '{{ project_src }}'
policy: always
register: pull_3
- name: Pull with policy=always (check, idempotent)
docker_compose_v2_pull:
project_src: '{{ project_src }}'
policy: always
check_mode: true
register: pull_4_check
- name: Pull with policy=always (idempotent)
docker_compose_v2_pull:
project_src: '{{ project_src }}'
policy: always
register: pull_4
- assert:
that:
- pull_1_check is changed
- (pull_1_check.actions | selectattr('status', 'eq', 'Pulling') | first) is truthy
- pull_1_check.warnings | default([]) | select('regex', 'Cannot parse event from ') | length == 0
- pull_1 is changed
- (pull_1.actions | selectattr('status', 'eq', 'Pulling') | first) is truthy
- pull_1.warnings | default([]) | select('regex', 'Cannot parse event from ') | length == 0
- pull_2_check is not changed
- pull_2_check.warnings | default([]) | select('regex', 'Cannot parse event from ') | length == 0
- pull_2 is not changed
- pull_2.warnings | default([]) | select('regex', 'Cannot parse event from ') | length == 0
- pull_3_check is changed
- (pull_3_check.actions | selectattr('status', 'eq', 'Pulling') | first) is truthy
- pull_3_check.warnings | default([]) | select('regex', 'Cannot parse event from ') | length == 0
- pull_3 is changed
- (pull_3.actions | selectattr('status', 'eq', 'Pulling') | first) is truthy
- pull_3.warnings | default([]) | select('regex', 'Cannot parse event from ') | length == 0
- pull_4_check is changed
- (pull_4_check.actions | selectattr('status', 'eq', 'Pulling') | first) is truthy
- pull_4_check.warnings | default([]) | select('regex', 'Cannot parse event from ') | length == 0
- pull_4 is not changed
- (pull_4.actions | selectattr('status', 'eq', 'Pulling') | first) is truthy
- pull_4.warnings | default([]) | select('regex', 'Cannot parse event from ') | length == 0
- when: docker_compose_version is version('2.22.0', '<')
block:
- name: Pull with policy=always (check)
docker_compose_v2_pull:
project_src: '{{ project_src }}'
policy: always
check_mode: true
register: pull_1_check
- name: Pull with policy=always
docker_compose_v2_pull:
project_src: '{{ project_src }}'
policy: always
register: pull_1
- name: Pull with policy=always (again, check)
docker_compose_v2_pull:
project_src: '{{ project_src }}'
policy: always
check_mode: true
register: pull_2_check
- name: Pull with policy=always (again)
docker_compose_v2_pull:
project_src: '{{ project_src }}'
policy: always
register: pull_2
- assert:
that:
- pull_1_check is changed
- (pull_1_check.actions | selectattr('status', 'eq', 'Pulling') | first) is truthy
- pull_1_check.warnings | default([]) | select('regex', 'Cannot parse event from ') | length == 0
- pull_1 is changed
- (pull_1.actions | selectattr('status', 'eq', 'Pulling') | first) is truthy
- pull_1.warnings | default([]) | select('regex', 'Cannot parse event from ') | length == 0
- pull_2_check is changed
- (pull_2_check.actions | selectattr('status', 'eq', 'Pulling') | first) is truthy
- pull_2_check.warnings | default([]) | select('regex', 'Cannot parse event from ') | length == 0
- pull_2 is not changed
- (pull_2.actions | selectattr('status', 'eq', 'Pulling') | first) is truthy
- pull_2.warnings | default([]) | select('regex', 'Cannot parse event from ') | length == 0

View File

@ -0,0 +1,6 @@
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
azp/4
destructive

View File

@ -0,0 +1,10 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
dependencies:
- setup_docker_cli_compose
# The Python dependencies are needed for the other modules
- setup_docker_python_deps
- setup_remote_tmp_dir

View File

@ -0,0 +1,49 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
####################################################################
# WARNING: These are designed specifically for Ansible tests #
# and should not be used as examples of how to write Ansible roles #
####################################################################
# Create random name prefix (for services, ...)
- name: Create random container name prefix
set_fact:
name_prefix: "{{ 'ansible-docker-test-%0x' % ((2**32) | random) }}"
cnames: []
dnetworks: []
- debug:
msg: "Using name prefix {{ name_prefix }}"
# Run the tests
- block:
- name: Show docker compose --help output
command: docker compose --help
- include_tasks: run-test.yml
with_fileglob:
- "tests/*.yml"
loop_control:
loop_var: test_name
always:
- name: "Make sure all containers are removed"
docker_container:
name: "{{ item }}"
state: absent
force_kill: true
with_items: "{{ cnames }}"
diff: false
- name: "Make sure all networks are removed"
docker_network:
name: "{{ item }}"
state: absent
force: true
with_items: "{{ dnetworks }}"
diff: false
when: docker_has_compose and docker_compose_version is version('2.18.0', '>=')

View File

@ -0,0 +1,7 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
- name: "Loading tasks from {{ test_name }}"
include_tasks: "{{ test_name }}"

View File

@ -0,0 +1,104 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
- vars:
pname: "{{ name_prefix }}-start-stop"
cname: "{{ name_prefix }}-container"
project_src: "{{ remote_tmp_dir }}/{{ pname }}"
test_service: |
services:
{{ cname }}:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
stop_grace_period: 1s
block:
- name: Registering container name
set_fact:
cnames: "{{ cnames + [pname ~ '-' ~ cname ~ '-1'] }}"
dnetworks: "{{ dnetworks + [pname ~ '_default'] }}"
- name: Create project directory
file:
path: '{{ project_src }}'
state: directory
- name: Template default project file
copy:
dest: '{{ project_src }}/docker-compose.yml'
content: '{{ test_service }}'
- block:
- name: Start services
docker_compose_v2:
project_src: '{{ project_src }}'
state: present
- name: Run command with command
docker_compose_v2_run:
project_src: '{{ project_src }}'
service: '{{ cname }}'
command: /bin/sh -c "ls /"
cleanup: true
register: result_1
- name: Run command with argv
docker_compose_v2_run:
project_src: '{{ project_src }}'
service: '{{ cname }}'
argv:
- /bin/sh
- "-c"
- whoami
user: "1234"
cleanup: true
register: result_2
failed_when: result_2.rc != 1
- name: Run detached command
docker_compose_v2_run:
project_src: '{{ project_src }}'
service: '{{ cname }}'
command: /bin/sh -c "sleep 1"
detach: true
cleanup: true
register: result_3
- name: Run command with input
docker_compose_v2_run:
project_src: '{{ project_src }}'
service: '{{ cname }}'
command: /bin/sh -c "cat"
stdin: This is a test
register: result_4
- assert:
that:
- result_1.rc == 0
- result_1.stderr == ""
- >-
"usr" in result_1.stdout_lines
and
"etc" in result_1.stdout_lines
- result_1.container_id is not defined
- result_2.rc == 1
- >-
"whoami: unknown uid 1234" in result_2.stderr
- result_2.stdout == ""
- result_2.container_id is not defined
- result_3.rc is not defined
- result_3.stdout is not defined
- result_3.stderr is not defined
- result_3.container_id is string
- result_4.rc == 0
- result_4.stdout == "This is a test"
- result_4.stderr is string
- result_4.container_id is not defined
always:
- name: Cleanup
docker_compose_v2:
project_src: '{{ project_src }}'
state: absent

View File

@ -0,0 +1,6 @@
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
azp/3
destructive

View File

@ -0,0 +1,9 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
dependencies:
- setup_docker
- setup_docker_sdk_for_python
- setup_remote_tmp_dir

View File

@ -0,0 +1,15 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
####################################################################
# WARNING: These are designed specifically for Ansible tests #
# and should not be used as examples of how to write Ansible roles #
####################################################################
- include_tasks: test_docker_config.yml
when: docker_py_version is version('2.6.0', '>=') and docker_api_version is version('1.30', '>=')
- fail: msg="Too old docker / docker-py version to run docker_config tests!"
when: not(docker_py_version is version('2.6.0', '>=') and docker_api_version is version('1.30', '>=')) and (ansible_distribution != 'CentOS' or ansible_distribution_major_version|int > 6)

View File

@ -0,0 +1,334 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
- block:
- shell: "docker info --format '{% raw %}{{json .}}{% endraw %}' | python -m json.tool"
- name: Make sure we're not already using Docker swarm
docker_swarm:
state: absent
force: true
- shell: "docker info --format '{% raw %}{{json .}}{% endraw %}' | python -m json.tool"
- name: Create a Swarm cluster
docker_swarm:
name: default
state: present
advertise_addr: "{{ ansible_default_ipv4.address | default('127.0.0.1') }}"
- name: Parameter name should be required
docker_config:
state: present
ignore_errors: true
register: output
- name: Assert failure when called with no name
assert:
that:
- 'output is failed'
- 'output.msg == "missing required arguments: name"'
- name: Test parameters
docker_config:
name: foo
state: present
ignore_errors: true
register: output
- name: Assert failure when called with no data
assert:
that:
- 'output is failed'
- 'output.msg == "state is present but any of the following are missing: data, data_src"'
- name: Create config
docker_config:
name: db_password
data: opensesame!
state: present
register: output
- name: Create variable config_id
set_fact:
config_id: "{{ output.config_id }}"
- name: Inspect config
command: "docker config inspect {{ config_id }}"
register: inspect
ignore_errors: true
- debug:
var: inspect
- name: Assert config creation succeeded
assert:
that:
- "'db_password' in inspect.stdout"
- "'ansible_key' in inspect.stdout"
when: inspect is not failed
- assert:
that:
- "'is too new. Maximum supported API version is' in inspect.stderr"
when: inspect is failed
- name: Create config again
docker_config:
name: db_password
data: opensesame!
state: present
register: output
- name: Assert create config is idempotent
assert:
that:
- output is not changed
- name: Write config into file
copy:
dest: "{{ remote_tmp_dir }}/data"
content: |-
opensesame!
- name: Create config again (from file)
docker_config:
name: db_password
data_src: "{{ remote_tmp_dir }}/data"
state: present
register: output
- name: Assert create config is idempotent
assert:
that:
- output is not changed
- name: Create config again (base64)
docker_config:
name: db_password
data: b3BlbnNlc2FtZSE=
data_is_b64: true
state: present
register: output
- name: Assert create config (base64) is idempotent
assert:
that:
- output is not changed
- name: Update config
docker_config:
name: db_password
data: newpassword!
state: present
register: output
- name: Assert config was updated
assert:
that:
- output is changed
- output.config_id != config_id
- name: Remove config
docker_config:
name: db_password
state: absent
- name: Check that config is removed
command: "docker config inspect {{ config_id }}"
register: output
ignore_errors: true
- name: Assert config was removed
assert:
that:
- output is failed
- name: Remove config
docker_config:
name: db_password
state: absent
register: output
- name: Assert remove config is idempotent
assert:
that:
- output is not changed
# Rolling update
- name: Create rolling config
docker_config:
name: rolling_password
data: opensesame!
rolling_versions: true
state: present
register: original_output
- name: Create variable config_id
set_fact:
config_id: "{{ original_output.config_id }}"
- name: Inspect config
command: "docker config inspect {{ config_id }}"
register: inspect
ignore_errors: true
- debug:
var: inspect
- name: Assert config creation succeeded
assert:
that:
- "'rolling_password' in inspect.stdout"
- "'ansible_key' in inspect.stdout"
- "'ansible_version' in inspect.stdout"
- original_output.config_name == 'rolling_password_v1'
when: inspect is not failed
- assert:
that:
- "'is too new. Maximum supported API version is' in inspect.stderr"
when: inspect is failed
- name: Create config again
docker_config:
name: rolling_password
data: newpassword!
rolling_versions: true
state: present
register: new_output
- name: Assert that new version is created
assert:
that:
- new_output is changed
- new_output.config_id != original_output.config_id
- new_output.config_name != original_output.config_name
- new_output.config_name == 'rolling_password_v2'
- name: Remove rolling configs
docker_config:
name: rolling_password
rolling_versions: true
state: absent
- name: Check that config is removed
command: "docker config inspect {{ original_output.config_id }}"
register: output
ignore_errors: true
- name: Assert config was removed
assert:
that:
- output is failed
- name: Check that config is removed
command: "docker config inspect {{ new_output.config_id }}"
register: output
ignore_errors: true
- name: Assert config was removed
assert:
that:
- output is failed
# template_driver tests
- when: docker_py_version is version('5.0.3', '>=') and docker_api_version is version('1.37', '>=')
block:
- name: Create regular config
docker_config:
name: db_password
data: opensesame!
state: present
- name: Update config with template_driver
docker_config:
name: db_password
data: opensesame!
template_driver: golang
state: present
register: output
- name: Assert config was updated
assert:
that:
- output is changed
- name: Invalid template_driver
docker_config:
name: db_password
data: opensesame!
template_driver: "not a template driver"
state: present
ignore_errors: true
register: output
- name: Assert failure when called with invalid template_driver
assert:
that:
- 'output is failed'
- 'output.msg == "value of template_driver must be one of: golang, got: not a template driver"'
- name: Create config again
docker_config:
name: db_password
data: opensesame!
template_driver: golang
state: present
register: output
- name: Assert create config is idempotent
assert:
that:
- output is not changed
# data is the docker swarm's name
- name: Update config with template data
docker_config:
name: db_password
data: "{{ '{{' }} .Service.Name {{ '}}' }}"
template_driver: golang
state: present
register: output
- name: Inspect config
command: "docker config inspect {{ output.config_id }}"
register: inspect
- name: Show inspection result
debug:
var: inspect
- name: Assert config creation succeeded
assert:
that:
- "'db_password' in inspect.stdout"
- "'ansible_key' in inspect.stdout"
# According to the API docs, 'Data' is "Base64-url-safe-encoded (RFC 4648) config data."
- "'\"Data\": \"e3sgLlNlcnZpY2UuTmFtZSB9fQ==\"' in inspect.stdout"
- "'Templating' in inspect.stdout"
- "'\"Name\": \"golang\"' in inspect.stdout"
- name: Remove config
docker_config:
name: db_password
state: absent
- name: Check that config is removed
command: "docker config inspect {{ output.config_id }}"
register: output
ignore_errors: true
- name: Assert config was removed
assert:
that:
- output is failed
always:
- name: Remove a Swarm cluster
docker_swarm:
state: absent
force: true

View File

@ -0,0 +1,6 @@
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
azp/5
destructive

View File

@ -0,0 +1,6 @@
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
TEST3=val3
TEST4=val4

View File

@ -0,0 +1,21 @@
# Copyright (c) 2020, Felix Fontein <felix@fontein.de>
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
from __future__ import absolute_import, division, print_function
__metaclass__ = type
def _normalize_ipaddr(ipaddr):
# Import when needed, to allow installation of that module in the test setup
import ipaddress
return ipaddress.ip_address(ipaddr).compressed
class FilterModule(object):
""" IP address and network manipulation filters """
def filters(self):
return {
'normalize_ipaddr': _normalize_ipaddr,
}

View File

@ -0,0 +1,8 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
dependencies:
- setup_docker
- setup_docker_python_deps

View File

@ -0,0 +1,70 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
####################################################################
# WARNING: These are designed specifically for Ansible tests #
# and should not be used as examples of how to write Ansible roles #
####################################################################
- name: Gather facts on controller
setup:
gather_subset: '!all'
delegate_to: localhost
delegate_facts: true
run_once: true
- name: Make sure ipaddress is available on controller
pip:
name: ipaddress
delegate_to: localhost
when: hostvars['localhost'].ansible_facts.python.version.major < 3
# Create random name prefix (for containers, networks, ...)
- name: Create random container name prefix
set_fact:
cname_prefix: "{{ 'ansible-docker-test-%0x' % ((2**32) | random) }}"
cnames: []
inames: []
dnetworks: []
- debug:
msg: "Using container name prefix {{ cname_prefix }}"
- name: Retrieve docker host info
docker_host_info:
register: docker_host_info
# Run the tests
- block:
- include_tasks: run-test.yml
with_fileglob:
- "tests/*.yml"
loop_control:
loop_var: test_name
always:
- name: "Make sure all containers are removed"
docker_container:
name: "{{ item }}"
state: absent
force_kill: true
with_items: "{{ cnames }}"
diff: false
- name: "Make sure all images are removed"
docker_image_remove:
name: "{{ item }}"
with_items: "{{ inames }}"
- name: "Make sure all networks are removed"
docker_network:
name: "{{ item }}"
state: absent
force: true
with_items: "{{ dnetworks }}"
diff: false
when: docker_api_version is version('1.25', '>=')
- fail: msg="Too old docker / docker-py version to run all docker_container tests!"
when: not(docker_api_version is version('1.25', '>=')) and (ansible_distribution != 'CentOS' or ansible_distribution_major_version|int > 6)

View File

@ -0,0 +1,7 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
- name: "Loading tasks from {{ test_name }}"
include_tasks: "{{ test_name }}"

View File

@ -0,0 +1,466 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
- name: Registering container name
set_fact:
cname: "{{ cname_prefix ~ '-comparisons' }}"
- name: Registering container name
set_fact:
cnames: "{{ cnames + [cname] }}"
####################################################################
## value ###########################################################
####################################################################
- name: value
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
hostname: example.com
register: value_1
- name: value (change, ignore)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
hostname: example.org
force_kill: true
comparisons:
hostname: ignore
register: value_2
- name: value (change, strict)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
hostname: example.org
force_kill: true
comparisons:
hostname: strict
register: value_3
- name: cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: true
diff: false
- assert:
that:
- value_1 is changed
- value_2 is not changed
- value_3 is changed
####################################################################
## list ############################################################
####################################################################
- name: list
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
dns_servers:
- 1.1.1.1
- 8.8.8.8
register: list_1
- name: list (change, ignore)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
dns_servers:
- 9.9.9.9
force_kill: true
comparisons:
dns_servers: ignore
register: list_2
- name: list (change, strict)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
dns_servers:
- 9.9.9.9
force_kill: true
comparisons:
dns_servers: strict
register: list_3
- name: cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: true
diff: false
- assert:
that:
- list_1 is changed
- list_2 is not changed
- list_3 is changed
####################################################################
## set #############################################################
####################################################################
- name: set
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
groups:
- "1010"
- "1011"
register: set_1
- name: set (change, ignore)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
groups:
- "1010"
- "1011"
- "1012"
force_kill: true
comparisons:
groups: ignore
register: set_2
- name: set (change, allow_more_present)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
groups:
- "1010"
- "1011"
- "1012"
force_kill: true
comparisons:
groups: allow_more_present
register: set_3
- name: set (change, allow_more_present)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
groups:
- "1010"
- "1012"
force_kill: true
comparisons:
groups: allow_more_present
register: set_4
- name: set (change, strict)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
groups:
- "1010"
- "1012"
force_kill: true
comparisons:
groups: strict
register: set_5
- name: cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: true
diff: false
- assert:
that:
- set_1 is changed
- set_2 is not changed
- set_3 is changed
- set_4 is not changed
- set_5 is changed
####################################################################
## set(dict) #######################################################
####################################################################
- name: set(dict)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
devices:
- "/dev/random:/dev/virt-random:rwm"
- "/dev/urandom:/dev/virt-urandom:rwm"
register: set_dict_1
- name: set(dict) (change, ignore)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
devices:
- "/dev/random:/dev/virt-random:rwm"
- "/dev/urandom:/dev/virt-urandom:rwm"
- "/dev/null:/dev/virt-null:rwm"
force_kill: true
comparisons:
devices: ignore
register: set_dict_2
- name: set(dict) (change, allow_more_present)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
devices:
- "/dev/random:/dev/virt-random:rwm"
- "/dev/urandom:/dev/virt-urandom:rwm"
- "/dev/null:/dev/virt-null:rwm"
force_kill: true
comparisons:
devices: allow_more_present
register: set_dict_3
- name: set(dict) (change, allow_more_present)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
devices:
- "/dev/random:/dev/virt-random:rwm"
- "/dev/null:/dev/virt-null:rwm"
force_kill: true
comparisons:
devices: allow_more_present
register: set_dict_4
- name: set(dict) (change, strict)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
devices:
- "/dev/random:/dev/virt-random:rwm"
- "/dev/null:/dev/virt-null:rwm"
force_kill: true
comparisons:
devices: strict
register: set_dict_5
- name: cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: true
diff: false
- assert:
that:
- set_dict_1 is changed
- set_dict_2 is not changed
- set_dict_3 is changed
- set_dict_4 is not changed
- set_dict_5 is changed
####################################################################
## dict ############################################################
####################################################################
- name: dict
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
labels:
ansible.test.1: hello
ansible.test.2: world
register: dict_1
- name: dict (change, ignore)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
labels:
ansible.test.1: hello
ansible.test.2: world
ansible.test.3: ansible
force_kill: true
comparisons:
labels: ignore
register: dict_2
- name: dict (change, allow_more_present)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
labels:
ansible.test.1: hello
ansible.test.2: world
ansible.test.3: ansible
force_kill: true
comparisons:
labels: allow_more_present
register: dict_3
- name: dict (change, allow_more_present)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
labels:
ansible.test.1: hello
ansible.test.3: ansible
force_kill: true
comparisons:
labels: allow_more_present
register: dict_4
- name: dict (change, strict)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
labels:
ansible.test.1: hello
ansible.test.3: ansible
force_kill: true
comparisons:
labels: strict
register: dict_5
- name: cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: true
diff: false
- assert:
that:
- dict_1 is changed
- dict_2 is not changed
- dict_3 is changed
- dict_4 is not changed
- dict_5 is changed
####################################################################
## wildcard ########################################################
####################################################################
- name: Pull {{ docker_test_image_hello_world }} image to make sure wildcard_2 test succeeds
# If the image isn't there, it will pull it and return 'changed'.
docker_image_pull:
name: "{{ docker_test_image_hello_world }}"
- name: wildcard
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
hostname: example.com
stop_timeout: 1
labels:
ansible.test.1: hello
ansible.test.2: world
ansible.test.3: ansible
register: wildcard_1
- name: wildcard (change, ignore)
docker_container:
image: "{{ docker_test_image_hello_world }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
hostname: example.org
stop_timeout: 2
labels:
ansible.test.1: hello
ansible.test.4: ignore
force_kill: true
comparisons:
'*': ignore
register: wildcard_2
- name: wildcard (change, strict)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
hostname: example.org
stop_timeout: 1
labels:
ansible.test.1: hello
ansible.test.2: world
ansible.test.3: ansible
force_kill: true
comparisons:
'*': strict
register: wildcard_3
- name: wildcard (no change, strict)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
hostname: example.org
stop_timeout: 1
labels:
ansible.test.1: hello
ansible.test.2: world
ansible.test.3: ansible
force_kill: true
comparisons:
'*': strict
register: wildcard_4
- name: cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: true
diff: false
- assert:
that:
- wildcard_1 is changed
- wildcard_2 is not changed
- wildcard_3 is changed
- wildcard_4 is not changed

View File

@ -0,0 +1,122 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
- name: Registering container name
set_fact:
cname: "{{ cname_prefix ~ '-hi' }}"
- name: Registering container name
set_fact:
cnames: "{{ cnames + [cname] }}"
####################################################################
## container_default_behavior: compatibility #######################
####################################################################
- name: Start container (check)
docker_container:
name: "{{ cname }}"
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
state: started
container_default_behavior: compatibility
check_mode: true
register: start_1
- name: Start container
docker_container:
name: "{{ cname }}"
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
state: started
container_default_behavior: compatibility
register: start_2
- name: Start container (idempotent)
docker_container:
name: "{{ cname }}"
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
state: started
container_default_behavior: compatibility
register: start_3
- name: Start container (idempotent check)
docker_container:
name: "{{ cname }}"
image: "{{ docker_test_image_alpine }}"
state: started
container_default_behavior: compatibility
check_mode: true
register: start_4
- name: cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: true
diff: false
- assert:
that:
- start_1 is changed
- start_2 is changed
- start_3 is not changed
- start_4 is not changed
####################################################################
## container_default_behavior: no_defaults #########################
####################################################################
- name: Start container (check)
docker_container:
name: "{{ cname }}"
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
state: started
container_default_behavior: no_defaults
check_mode: true
register: start_1
- name: Start container
docker_container:
name: "{{ cname }}"
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
state: started
container_default_behavior: no_defaults
register: start_2
- name: Start container (idempotent)
docker_container:
name: "{{ cname }}"
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
state: started
container_default_behavior: no_defaults
register: start_3
- name: Start container (idempotent check)
docker_container:
name: "{{ cname }}"
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
state: started
container_default_behavior: no_defaults
check_mode: true
register: start_4
- name: cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: true
diff: false
- assert:
that:
- start_1 is changed
- start_2 is changed
- start_3 is not changed
- start_4 is not changed

View File

@ -0,0 +1,64 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
- name: Registering container name
set_fact:
cname: "{{ cname_prefix ~ '-hi' }}"
- name: Registering container name
set_fact:
cnames: "{{ cnames + [cname] }}"
- name: Prepare container
docker_container:
name: "{{ cname }}"
image: "{{ docker_test_image_healthcheck }}"
command: '10m'
state: stopped
register: healthy_1
- debug: var=healthy_1.container.State
- name: Start container (not healthy in time)
docker_container:
name: "{{ cname }}"
state: healthy
healthy_wait_timeout: 1
register: healthy_2
ignore_errors: true
- debug: var=healthy_2.container.State
- name: Prepare container
docker_container:
name: "{{ cname }}"
image: "{{ docker_test_image_healthcheck }}"
command: '10m 5s'
state: stopped
force_kill: true
register: healthy_3
- debug: var=healthy_3.container.State
- name: Start container (healthy in time)
docker_container:
name: "{{ cname }}"
state: healthy
healthy_wait_timeout: 10
register: healthy_4
- debug: var=healthy_4.container.State
- name: Cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: true
- assert:
that:
- healthy_2 is failed
- healthy_2.container.State.Health.Status == "starting"
- healthy_2.msg.startswith("Timeout of 1.0 seconds exceeded while waiting for container ")
- healthy_4 is changed
- healthy_4.container.State.Health.Status == "healthy"

View File

@ -0,0 +1,155 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
- name: Registering container name
set_fact:
cname: "{{ cname_prefix ~ '-iid' }}"
- name: Registering container name
set_fact:
cnames: "{{ cnames + [cname] }}"
- name: Pull images
docker_image_pull:
name: "{{ image }}"
loop:
- "{{ docker_test_image_hello_world }}"
- "{{ docker_test_image_alpine }}"
loop_control:
loop_var: image
- name: Get image ID of {{ docker_test_image_hello_world }} and {{ docker_test_image_alpine }} images
docker_image_info:
name:
- "{{ docker_test_image_hello_world }}"
- "{{ docker_test_image_alpine }}"
register: image_info
- assert:
that:
- image_info.images | length == 2
- name: Print image IDs
debug:
msg: "{{ docker_test_image_hello_world }}: {{ image_info.images[0].Id }}; {{ docker_test_image_alpine }}: {{ image_info.images[1].Id }}"
- name: Create container with {{ docker_test_image_hello_world }} image via ID
docker_container:
image: "{{ image_info.images[0].Id }}"
name: "{{ cname }}"
state: present
force_kill: true
register: create_1
- name: Create container with {{ docker_test_image_hello_world }} image via ID (idempotent)
docker_container:
image: "{{ image_info.images[0].Id }}"
name: "{{ cname }}"
state: present
force_kill: true
register: create_2
- name: Create container with {{ docker_test_image_alpine }} image via ID
docker_container:
image: "{{ image_info.images[1].Id }}"
name: "{{ cname }}"
state: present
force_kill: true
register: create_3
- name: Create container with {{ docker_test_image_alpine }} image via ID (idempotent)
docker_container:
image: "{{ image_info.images[1].Id }}"
name: "{{ cname }}"
state: present
force_kill: true
register: create_4
- name: Untag image
# Image will not be deleted since the container still uses it
docker_image_remove:
name: "{{ docker_test_image_alpine }}"
force: true
- name: Create container with {{ docker_test_image_alpine }} image via name (check mode, will pull, same image)
docker_container:
image: "{{ docker_test_image_alpine }}"
name: "{{ cname }}"
state: present
image_name_mismatch: ignore
register: create_5
check_mode: true
- name: Create container with {{ docker_test_image_alpine }} image via name (will pull, same image)
docker_container:
image: "{{ docker_test_image_alpine }}"
name: "{{ cname }}"
state: present
image_name_mismatch: ignore
register: create_6
- name: Cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: true
diff: false
- assert:
that:
- create_1 is changed
- create_2 is not changed
- create_3 is changed
- create_4 is not changed
- create_5 is changed
- create_6 is changed
- create_6.container.Image == image_info.images[1].Id
- create_6.container.Id == create_4.container.Id # make sure container wasn't recreated
- name: Create container with {{ docker_test_image_digest_base }} image via old digest
docker_container:
image: "{{ docker_test_image_digest_base }}@sha256:{{ docker_test_image_digest_v1 }}"
name: "{{ cname }}"
state: present
force_kill: true
register: digest_1
- name: Create container with {{ docker_test_image_digest_base }} image via old digest (idempotent)
docker_container:
image: "{{ docker_test_image_digest_base }}@sha256:{{ docker_test_image_digest_v1 }}"
name: "{{ cname }}"
state: present
force_kill: true
register: digest_2
- name: Create container with {{ docker_test_image_digest_base }} image via old digest (idempotent, pull)
docker_container:
image: "{{ docker_test_image_digest_base }}@sha256:{{ docker_test_image_digest_v1 }}"
name: "{{ cname }}"
pull: true
state: present
force_kill: true
register: digest_3
- name: Update container with {{ docker_test_image_digest_base }} image via new digest
docker_container:
image: "{{ docker_test_image_digest_base }}@sha256:{{ docker_test_image_digest_v2 }}"
name: "{{ cname }}"
state: present
force_kill: true
register: digest_4
- name: Cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: true
diff: false
- assert:
that:
- digest_1 is changed
- digest_2 is not changed
- digest_3 is not changed
- digest_4 is changed

View File

@ -0,0 +1,558 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
- name: Registering container name
set_fact:
cname: "{{ cname_prefix ~ '-mounts' }}"
cname_h1: "{{ cname_prefix ~ '-mounts-h1' }}"
cname_h2: "{{ cname_prefix ~ '-mounts-h2' }}"
- name: Registering container name
set_fact:
cnames: "{{ cnames + [cname, cname_h1, cname_h2] }}"
####################################################################
## keep_volumes ####################################################
####################################################################
# TODO: - keep_volumes
####################################################################
## mounts ##########################################################
####################################################################
- name: mounts
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
mounts:
- source: /tmp
target: /tmp
type: bind
- source: /
target: /whatever
type: bind
read_only: false
register: mounts_1
- name: mounts (idempotency)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
mounts:
- source: /
target: /whatever
type: bind
read_only: false
- source: /tmp
target: /tmp
type: bind
register: mounts_2
- name: mounts (less mounts)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
mounts:
- source: /tmp
target: /tmp
type: bind
register: mounts_3
- name: mounts (more mounts)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
mounts:
- source: /tmp
target: /tmp
type: bind
- source: /tmp
target: /somewhereelse
type: bind
read_only: true
force_kill: true
register: mounts_4
- name: mounts (different modes)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
mounts:
- source: /tmp
target: /tmp
type: bind
- source: /tmp
target: /somewhereelse
type: bind
read_only: false
force_kill: true
register: mounts_5
- name: mounts (endpoint collision)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
mounts:
- source: /home
target: /x
type: bind
- source: /etc
target: /x
type: bind
read_only: false
force_kill: true
register: mounts_6
ignore_errors: true
- name: mounts (anonymous volume)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
mounts:
- target: /tmp
type: volume
force_kill: true
register: mounts_7
- name: mounts (anonymous volume idempotency)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
mounts:
- target: /tmp
type: volume
force_kill: true
register: mounts_8
- name: cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: true
diff: false
- assert:
that:
- mounts_1 is changed
- mounts_2 is not changed
- mounts_3 is not changed
- mounts_4 is changed
- mounts_5 is changed
- mounts_6 is failed
- "'The mount point \"/x\" appears twice in the mounts option' == mounts_6.msg"
- mounts_7 is changed
- mounts_8 is not changed
####################################################################
## tmpfs ###########################################################
####################################################################
- name: tmpfs
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
mounts:
- target: /cache1
type: tmpfs
tmpfs_mode: "1777"
tmpfs_size: "1GB"
- target: /cache2
type: tmpfs
tmpfs_mode: "1777"
tmpfs_size: "1GB"
force_kill: true
register: tmpfs_1
- name: tmpfs (idempotency)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
mounts:
- target: /cache2
type: tmpfs
tmpfs_mode: "1777"
tmpfs_size: "1GB"
- target: /cache1
type: tmpfs
tmpfs_mode: "1777"
tmpfs_size: "1GB"
force_kill: true
register: tmpfs_2
- name: tmpfs (more mounts)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
mounts:
- target: /cache1
type: tmpfs
tmpfs_mode: "1777"
tmpfs_size: "1GB"
- target: /cache2
type: tmpfs
tmpfs_mode: "1777"
tmpfs_size: "1GB"
- target: /cache3
type: tmpfs
tmpfs_mode: "1777"
tmpfs_size: "1GB"
force_kill: true
register: tmpfs_3
- name: tmpfs (change mode)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
mounts:
- target: /cache1
type: tmpfs
tmpfs_mode: "1700"
tmpfs_size: "1GB"
force_kill: true
register: tmpfs_4
- name: tmpfs (change size)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
mounts:
- target: /cache1
type: tmpfs
tmpfs_mode: "1700"
tmpfs_size: "2GB"
force_kill: true
register: tmpfs_5
- name: cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: true
diff: false
- assert:
that:
- tmpfs_1 is changed
- tmpfs_2 is not changed
- tmpfs_3 is changed
- tmpfs_4 is changed
- tmpfs_5 is changed
####################################################################
## mounts + volumes ################################################
####################################################################
- name: mounts + volumes
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
mounts:
- source: /
target: /whatever
type: bind
read_only: true
volumes:
- /tmp:/tmp
register: mounts_volumes_1
- name: mounts + volumes (idempotency)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
mounts:
- source: /
target: /whatever
type: bind
read_only: true
volumes:
- /tmp:/tmp
register: mounts_volumes_2
- name: mounts + volumes (switching)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
mounts:
- source: /tmp
target: /tmp
type: bind
read_only: false
volumes:
- /:/whatever:ro
force_kill: true
register: mounts_volumes_3
- name: mounts + volumes (collision, should fail)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
mounts:
- source: /tmp
target: /tmp
type: bind
read_only: false
volumes:
- /tmp:/tmp
force_kill: true
register: mounts_volumes_4
ignore_errors: true
- name: cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: true
diff: false
- assert:
that:
- mounts_volumes_1 is changed
- mounts_volumes_2 is not changed
- mounts_volumes_3 is changed
- mounts_volumes_4 is failed
- "'The mount point \"/tmp\" appears both in the volumes and mounts option' in mounts_volumes_4.msg"
####################################################################
## volume_driver ###################################################
####################################################################
- name: volume_driver
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
volume_driver: local
state: started
register: volume_driver_1
- name: volume_driver (idempotency)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
volume_driver: local
state: started
register: volume_driver_2
- name: volume_driver (change)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
volume_driver: /
state: started
force_kill: true
register: volume_driver_3
- name: cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: true
diff: false
- assert:
that:
- volume_driver_1 is changed
- volume_driver_2 is not changed
- volume_driver_3 is changed
####################################################################
## volumes #########################################################
####################################################################
- name: volumes
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
volumes:
- "/tmp:/tmp"
- "/:/whatever:rw,z"
- "/anon:rw"
register: volumes_1
- name: volumes (idempotency)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
volumes:
- "/:/whatever:rw,z"
- "/tmp:/tmp"
- "/anon:rw"
register: volumes_2
- name: volumes (less volumes)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
volumes:
- "/tmp:/tmp"
register: volumes_3
- name: volumes (more volumes)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
volumes:
- "/tmp:/tmp"
- "/tmp:/somewhereelse:ro,Z"
force_kill: true
register: volumes_4
- name: volumes (different modes)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
volumes:
- "/tmp:/tmp"
- "/tmp:/somewhereelse:ro"
force_kill: true
register: volumes_5
- name: volumes (collision)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
volumes:
- "/etc:/tmp"
- "/home:/tmp:ro"
force_kill: true
register: volumes_6
ignore_errors: true
- name: cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: true
diff: false
- assert:
that:
- volumes_1 is changed
- volumes_1.container.Config.Volumes | length == 1
- volumes_1.container.Config.Volumes['/anon:rw'] | length == 0
- volumes_2 is not changed
- volumes_3 is not changed
- volumes_4 is changed
- not volumes_4.container.Config.Volumes
- volumes_5 is changed
- volumes_6 is failed
- "'The mount point \"/tmp\" appears twice in the volumes option' in volumes_6.msg"
####################################################################
## volumes_from ####################################################
####################################################################
- name: start helpers
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -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: "{{ docker_test_image_alpine }}"
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: "{{ docker_test_image_alpine }}"
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: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
volumes_from: "{{ cname_h2 }}"
force_kill: true
register: volumes_from_3
- name: cleanup
docker_container:
name: "{{ container_name }}"
state: absent
force_kill: true
loop:
- "{{ cname }}"
- "{{ cname_h1 }}"
- "{{ cname_h2 }}"
loop_control:
loop_var: container_name
diff: false
- assert:
that:
- volumes_from_1 is changed
- volumes_from_2 is not changed
- volumes_from_3 is changed
####################################################################
####################################################################
####################################################################

View File

@ -0,0 +1,745 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
- name: Registering container name
set_fact:
cname: "{{ cname_prefix ~ '-network' }}"
cname_h1: "{{ cname_prefix ~ '-network-h1' }}"
nname_1: "{{ cname_prefix ~ '-network-1' }}"
nname_2: "{{ cname_prefix ~ '-network-2' }}"
nname_3: "{{ cname_prefix ~ '-network-3' }}"
- name: Registering container name
set_fact:
cnames: "{{ cnames + [cname, cname_h1] }}"
dnetworks: "{{ dnetworks + [nname_1, nname_2, nname_3] }}"
- name: Create networks
docker_network:
name: "{{ network_name }}"
state: present
loop:
- "{{ nname_1 }}"
- "{{ nname_2 }}"
loop_control:
loop_var: network_name
- set_fact:
subnet_ipv4_base: 10.{{ 16 + (240 | random) }}.{{ 16 + (240 | random) }}
subnet_ipv6_base: fdb6:feea:{{ '%0.4x:%0.4x' | format(65536 | random, 65536 | random) }}
# If netaddr would be installed on the controller, one could do:
# subnet_ipv4: "10.{{ 16 + (240 | random) }}.{{ 16 + (240 | random) }}.0/24"
# subnet_ipv6: "fdb6:feea:{{ '%0.4x:%0.4x' | format(65536 | random, 65536 | random) }}::/64"
- set_fact:
subnet_ipv4: "{{ subnet_ipv4_base }}.0/24"
subnet_ipv6: "{{ subnet_ipv6_base }}::/64"
nname_3_ipv4_2: "{{ subnet_ipv4_base }}.2"
nname_3_ipv4_3: "{{ subnet_ipv4_base }}.3"
nname_3_ipv4_4: "{{ subnet_ipv4_base }}.4"
nname_3_ipv6_2: "{{ subnet_ipv6_base }}::2"
nname_3_ipv6_3: "{{ subnet_ipv6_base }}::3"
nname_3_ipv6_4: "{{ subnet_ipv6_base }}::4"
# If netaddr would be installed on the controller, one could do:
# nname_3_ipv4_2: "{{ subnet_ipv4 | ansible.netcommon.next_nth_usable(2) }}"
# nname_3_ipv4_3: "{{ subnet_ipv4 | ansible.netcommon.next_nth_usable(3) }}"
# nname_3_ipv4_4: "{{ subnet_ipv4 | ansible.netcommon.next_nth_usable(4) }}"
# nname_3_ipv6_2: "{{ subnet_ipv6 | ansible.netcommon.next_nth_usable(2) }}"
# nname_3_ipv6_3: "{{ subnet_ipv6 | ansible.netcommon.next_nth_usable(3) }}"
# nname_3_ipv6_4: "{{ subnet_ipv6 | ansible.netcommon.next_nth_usable(4) }}"
- debug:
msg: "Chose random IPv4 subnet {{ subnet_ipv4 }} and random IPv6 subnet {{ subnet_ipv6 }}"
- name: Create network with fixed IPv4 and IPv6 subnets
docker_network:
name: "{{ nname_3 }}"
enable_ipv6: true
ipam_config:
- subnet: "{{ subnet_ipv4 }}"
- subnet: "{{ subnet_ipv6 }}"
state: present
####################################################################
## network_mode ####################################################
####################################################################
- name: network_mode
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
network_mode: host
register: network_mode_1
- name: network_mode (idempotency)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
network_mode: host
register: network_mode_2
- name: network_mode (change)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
network_mode: none
force_kill: true
register: network_mode_3
- name: network_mode (container mode setup)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname_h1 }}"
state: started
register: cname_h1_id
- name: network_mode (container mode)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
network_mode: "container:{{ cname_h1_id.container.Id }}"
force_kill: true
register: network_mode_4
- name: network_mode (container mode idempotency)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
network_mode: "container:{{ cname_h1 }}"
register: network_mode_5
- name: cleanup
docker_container:
name: "{{ container_name }}"
state: absent
force_kill: true
loop:
- "{{ cname }}"
- "{{ cname_h1 }}"
loop_control:
loop_var: container_name
diff: false
- assert:
that:
- network_mode_1 is changed
- network_mode_1.container.HostConfig.NetworkMode == 'host'
- network_mode_2 is not changed
- network_mode_2.container.HostConfig.NetworkMode == 'host'
- network_mode_3 is changed
- network_mode_3.container.HostConfig.NetworkMode == 'none'
- network_mode_4 is changed
- network_mode_4.container.HostConfig.NetworkMode == ('container:' ~ cname_h1_id.container.Id)
- network_mode_5 is not changed
- network_mode_5.container.HostConfig.NetworkMode == ('container:' ~ cname_h1_id.container.Id)
####################################################################
## networks, purge_networks for networks_cli_compatible=no #########
####################################################################
- name: networks_cli_compatible=no, networks w/o purge_networks
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
networks:
- name: "{{ nname_1 }}"
- name: "{{ nname_2 }}"
networks_cli_compatible: false
register: networks_1
- name: networks_cli_compatible=no, networks w/o purge_networks
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
networks:
- name: "{{ nname_1 }}"
- name: "{{ nname_2 }}"
networks_cli_compatible: false
register: networks_2
- name: networks_cli_compatible=no, networks, purge_networks
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
comparisons:
networks: strict
networks:
- name: bridge
- name: "{{ nname_1 }}"
networks_cli_compatible: false
force_kill: true
register: networks_3
- name: networks_cli_compatible=no, networks, purge_networks (idempotency)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
comparisons:
networks: strict
networks:
- name: "{{ nname_1 }}"
- name: bridge
networks_cli_compatible: false
register: networks_4
- name: networks_cli_compatible=no, networks (less networks)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
networks:
- name: bridge
networks_cli_compatible: false
register: networks_5
- name: networks_cli_compatible=no, networks, purge_networks (less networks)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
comparisons:
networks: strict
networks:
- name: bridge
networks_cli_compatible: false
force_kill: true
register: networks_6
- name: networks_cli_compatible=no, networks, purge_networks (more networks)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
comparisons:
networks: strict
networks:
- name: bridge
- name: "{{ nname_2 }}"
networks_cli_compatible: false
force_kill: true
register: networks_7
- name: cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: true
diff: false
- assert:
that:
# networks_1 has networks default, 'bridge', nname_1
- networks_1 is changed
- networks_1.container.NetworkSettings.Networks | length == 3
- nname_1 in networks_1.container.NetworkSettings.Networks
- nname_2 in networks_1.container.NetworkSettings.Networks
- "'default' in networks_1.container.NetworkSettings.Networks or 'bridge' in networks_1.container.NetworkSettings.Networks"
# networks_2 has networks default, 'bridge', nname_1
- networks_2 is not changed
- networks_2.container.NetworkSettings.Networks | length == 3
- nname_1 in networks_2.container.NetworkSettings.Networks
- nname_2 in networks_1.container.NetworkSettings.Networks
- "'default' in networks_1.container.NetworkSettings.Networks or 'bridge' in networks_1.container.NetworkSettings.Networks"
# networks_3 has networks 'bridge', nname_1
- networks_3 is changed
- networks_3.container.NetworkSettings.Networks | length == 2
- nname_1 in networks_3.container.NetworkSettings.Networks
- "'default' in networks_3.container.NetworkSettings.Networks or 'bridge' in networks_3.container.NetworkSettings.Networks"
# networks_4 has networks 'bridge', nname_1
- networks_4 is not changed
- networks_4.container.NetworkSettings.Networks | length == 2
- nname_1 in networks_4.container.NetworkSettings.Networks
- "'default' in networks_4.container.NetworkSettings.Networks or 'bridge' in networks_4.container.NetworkSettings.Networks"
# networks_5 has networks 'bridge', nname_1
- networks_5 is not changed
- networks_5.container.NetworkSettings.Networks | length == 2
- nname_1 in networks_5.container.NetworkSettings.Networks
- "'default' in networks_5.container.NetworkSettings.Networks or 'bridge' in networks_5.container.NetworkSettings.Networks"
# networks_6 has networks 'bridge'
- networks_6 is changed
- networks_6.container.NetworkSettings.Networks | length == 1
- "'default' in networks_6.container.NetworkSettings.Networks or 'bridge' in networks_6.container.NetworkSettings.Networks"
# networks_7 has networks 'bridge', nname_2
- networks_7 is changed
- networks_7.container.NetworkSettings.Networks | length == 2
- nname_2 in networks_7.container.NetworkSettings.Networks
- "'default' in networks_7.container.NetworkSettings.Networks or 'bridge' in networks_7.container.NetworkSettings.Networks"
####################################################################
## networks for networks_cli_compatible=yes ########################
####################################################################
- name: networks_cli_compatible=yes, networks specified
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
networks:
- name: "{{ nname_1 }}"
aliases:
- alias1
- alias2
- name: "{{ nname_2 }}"
networks_cli_compatible: true
register: networks_1
- name: networks_cli_compatible=yes, networks specified
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
networks:
- name: "{{ nname_1 }}"
- name: "{{ nname_2 }}"
networks_cli_compatible: true
register: networks_2
- name: cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: true
diff: false
- name: networks_cli_compatible=yes, empty networks list specified
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
networks: []
networks_cli_compatible: true
register: networks_3
- name: networks_cli_compatible=yes, empty networks list specified
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
networks: []
networks_cli_compatible: true
register: networks_4
- name: networks_cli_compatible=yes, empty networks list specified, purge_networks
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
networks: []
networks_cli_compatible: true
comparisons:
networks: strict
force_kill: true
register: networks_5
- name: cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: true
diff: false
- name: networks_cli_compatible=yes, networks not specified
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
networks_cli_compatible: true
force_kill: true
register: networks_6
- name: networks_cli_compatible=yes, networks not specified
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
networks_cli_compatible: true
register: networks_7
- name: networks_cli_compatible=yes, networks empty, purge_networks
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
networks_cli_compatible: true
comparisons:
networks: strict
networks: []
force_kill: true
register: networks_8
- name: cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: true
diff: false
- debug: var=networks_3
- assert:
that:
# networks_1 has networks nname_1, nname_2
- networks_1 is changed
- networks_1.container.NetworkSettings.Networks | length == 2
- nname_1 in networks_1.container.NetworkSettings.Networks
- nname_2 in networks_1.container.NetworkSettings.Networks
# networks_2 has networks nname_1, nname_2
- networks_2 is not changed
- networks_2.container.NetworkSettings.Networks | length == 2
- nname_1 in networks_2.container.NetworkSettings.Networks
- nname_2 in networks_1.container.NetworkSettings.Networks
# networks_3 has networks 'bridge'
- networks_3 is changed
- networks_3.container.NetworkSettings.Networks | length == 1
- "'default' in networks_3.container.NetworkSettings.Networks or 'bridge' in networks_3.container.NetworkSettings.Networks"
# networks_4 has networks 'bridge'
- networks_4 is not changed
- networks_4.container.NetworkSettings.Networks | length == 1
- "'default' in networks_4.container.NetworkSettings.Networks or 'bridge' in networks_4.container.NetworkSettings.Networks"
# networks_5 has no networks
- networks_5 is changed
- networks_5.container.NetworkSettings.Networks | length == 0
# networks_6 has networks 'bridge'
- networks_6 is changed
- networks_6.container.NetworkSettings.Networks | length == 1
- "'default' in networks_6.container.NetworkSettings.Networks or 'bridge' in networks_6.container.NetworkSettings.Networks"
# networks_7 has networks 'bridge'
- networks_7 is not changed
- networks_7.container.NetworkSettings.Networks | length == 1
- "'default' in networks_7.container.NetworkSettings.Networks or 'bridge' in networks_7.container.NetworkSettings.Networks"
# networks_8 has no networks
- networks_8 is changed
- networks_8.container.NetworkSettings.Networks | length == 0
####################################################################
## networks with comparisons #######################################
####################################################################
- name: create container with one network
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
networks:
- name: "{{ nname_1 }}"
networks_cli_compatible: true
register: networks_1
- name: different networks, comparisons=ignore
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
networks:
- name: "{{ nname_2 }}"
networks_cli_compatible: true
comparisons:
network_mode: ignore # otherwise we'd have to set network_mode to nname_1
networks: ignore
register: networks_2
- name: less networks, comparisons=ignore
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
networks: []
networks_cli_compatible: true
comparisons:
networks: ignore
register: networks_3
- name: less networks, comparisons=allow_more_present
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
networks: []
networks_cli_compatible: true
comparisons:
networks: allow_more_present
register: networks_4
- name: different networks, comparisons=allow_more_present
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
networks:
- name: "{{ nname_2 }}"
networks_cli_compatible: true
comparisons:
network_mode: ignore # otherwise we'd have to set network_mode to nname_1
networks: allow_more_present
force_kill: true
register: networks_5
- name: different networks, comparisons=strict
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
networks:
- name: "{{ nname_2 }}"
networks_cli_compatible: true
comparisons:
networks: strict
force_kill: true
register: networks_6
- name: less networks, comparisons=strict
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
networks: []
networks_cli_compatible: true
comparisons:
networks: strict
force_kill: true
register: networks_7
- name: cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: true
diff: false
- assert:
that:
# networks_1 has networks nname_1
- networks_1 is changed
- networks_1.container.NetworkSettings.Networks | length == 1
- nname_1 in networks_1.container.NetworkSettings.Networks
# networks_2 has networks nname_1
- networks_2 is not changed
- networks_2.container.NetworkSettings.Networks | length == 1
- nname_1 in networks_2.container.NetworkSettings.Networks
# networks_3 has networks nname_1
- networks_3 is not changed
- networks_3.container.NetworkSettings.Networks | length == 1
- nname_1 in networks_3.container.NetworkSettings.Networks
# networks_4 has networks nname_1
- networks_4 is not changed
- networks_4.container.NetworkSettings.Networks | length == 1
- nname_1 in networks_4.container.NetworkSettings.Networks
# networks_5 has networks nname_1, nname_2
- networks_5 is changed
- networks_5.container.NetworkSettings.Networks | length == 2
- nname_1 in networks_5.container.NetworkSettings.Networks
- nname_2 in networks_5.container.NetworkSettings.Networks
# networks_6 has networks nname_2
- networks_6 is changed
- networks_6.container.NetworkSettings.Networks | length == 1
- nname_2 in networks_6.container.NetworkSettings.Networks
# networks_7 has no networks
- networks_7 is changed
- networks_7.container.NetworkSettings.Networks | length == 0
####################################################################
## networks with IP address ########################################
####################################################################
- name: create container (stopped) with one network and fixed IP
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: stopped
networks:
- name: "{{ nname_3 }}"
ipv4_address: "{{ nname_3_ipv4_2 }}"
ipv6_address: "{{ nname_3_ipv6_2 }}"
networks_cli_compatible: true
register: networks_1
- name: create container (stopped) with one network and fixed IP (idempotent)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: stopped
networks:
- name: "{{ nname_3 }}"
ipv4_address: "{{ nname_3_ipv4_2 }}"
ipv6_address: "{{ nname_3_ipv6_2 }}"
networks_cli_compatible: true
register: networks_2
- name: create container (stopped) with one network and fixed IP (different IPv4)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: stopped
networks:
- name: "{{ nname_3 }}"
ipv4_address: "{{ nname_3_ipv4_3 }}"
ipv6_address: "{{ nname_3_ipv6_2 }}"
networks_cli_compatible: true
register: networks_3
- name: create container (stopped) with one network and fixed IP (different IPv6)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: stopped
networks:
- name: "{{ nname_3 }}"
ipv4_address: "{{ nname_3_ipv4_3 }}"
ipv6_address: "{{ nname_3_ipv6_3 }}"
networks_cli_compatible: true
register: networks_4
- name: create container (started) with one network and fixed IP
docker_container:
name: "{{ cname }}"
state: started
register: networks_5
- name: create container (started) with one network and fixed IP (different IPv4)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
networks:
- name: "{{ nname_3 }}"
ipv4_address: "{{ nname_3_ipv4_4 }}"
ipv6_address: "{{ nname_3_ipv6_3 }}"
networks_cli_compatible: true
force_kill: true
register: networks_6
- name: create container (started) with one network and fixed IP (different IPv6)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
networks:
- name: "{{ nname_3 }}"
ipv4_address: "{{ nname_3_ipv4_4 }}"
ipv6_address: "{{ nname_3_ipv6_4 }}"
networks_cli_compatible: true
force_kill: true
register: networks_7
- name: create container (started) with one network and fixed IP (idempotent)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
networks:
- name: "{{ nname_3 }}"
ipv4_address: "{{ nname_3_ipv4_4 }}"
ipv6_address: "{{ nname_3_ipv6_4 }}"
networks_cli_compatible: true
register: networks_8
- name: cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: true
diff: false
- assert:
that:
- networks_1 is changed
- networks_1.container.NetworkSettings.Networks[nname_3].IPAMConfig.IPv4Address == nname_3_ipv4_2
- networks_1.container.NetworkSettings.Networks[nname_3].IPAMConfig.IPv6Address | normalize_ipaddr == nname_3_ipv6_2 | normalize_ipaddr
- networks_1.container.NetworkSettings.Networks[nname_3].IPAddress == ""
- networks_1.container.NetworkSettings.Networks[nname_3].GlobalIPv6Address == ""
- networks_2 is not changed
- networks_2.container.NetworkSettings.Networks[nname_3].IPAMConfig.IPv4Address == nname_3_ipv4_2
- networks_2.container.NetworkSettings.Networks[nname_3].IPAMConfig.IPv6Address | normalize_ipaddr == nname_3_ipv6_2 | normalize_ipaddr
- networks_2.container.NetworkSettings.Networks[nname_3].IPAddress == ""
- networks_2.container.NetworkSettings.Networks[nname_3].GlobalIPv6Address == ""
- networks_3 is changed
- networks_3.container.NetworkSettings.Networks[nname_3].IPAMConfig.IPv4Address == nname_3_ipv4_3
- networks_3.container.NetworkSettings.Networks[nname_3].IPAMConfig.IPv6Address | normalize_ipaddr == nname_3_ipv6_2 | normalize_ipaddr
- networks_3.container.NetworkSettings.Networks[nname_3].IPAddress == ""
- networks_3.container.NetworkSettings.Networks[nname_3].GlobalIPv6Address == ""
- networks_4 is changed
- networks_4.container.NetworkSettings.Networks[nname_3].IPAMConfig.IPv4Address == nname_3_ipv4_3
- networks_4.container.NetworkSettings.Networks[nname_3].IPAMConfig.IPv6Address | normalize_ipaddr == nname_3_ipv6_3 | normalize_ipaddr
- networks_4.container.NetworkSettings.Networks[nname_3].IPAddress == ""
- networks_4.container.NetworkSettings.Networks[nname_3].GlobalIPv6Address == ""
- networks_5 is changed
- networks_5.container.NetworkSettings.Networks[nname_3].IPAMConfig.IPv4Address == nname_3_ipv4_3
- networks_5.container.NetworkSettings.Networks[nname_3].IPAMConfig.IPv6Address | normalize_ipaddr == nname_3_ipv6_3 | normalize_ipaddr
- networks_5.container.NetworkSettings.Networks[nname_3].IPAddress == nname_3_ipv4_3
- networks_5.container.NetworkSettings.Networks[nname_3].GlobalIPv6Address | normalize_ipaddr == nname_3_ipv6_3 | normalize_ipaddr
- networks_6 is changed
- networks_6.container.NetworkSettings.Networks[nname_3].IPAMConfig.IPv4Address == nname_3_ipv4_4
- networks_6.container.NetworkSettings.Networks[nname_3].IPAMConfig.IPv6Address | normalize_ipaddr == nname_3_ipv6_3 | normalize_ipaddr
- networks_6.container.NetworkSettings.Networks[nname_3].IPAddress == nname_3_ipv4_4
- networks_6.container.NetworkSettings.Networks[nname_3].GlobalIPv6Address | normalize_ipaddr == nname_3_ipv6_3 | normalize_ipaddr
- networks_7 is changed
- networks_7.container.NetworkSettings.Networks[nname_3].IPAMConfig.IPv4Address == nname_3_ipv4_4
- networks_7.container.NetworkSettings.Networks[nname_3].IPAMConfig.IPv6Address | normalize_ipaddr == nname_3_ipv6_4 | normalize_ipaddr
- networks_7.container.NetworkSettings.Networks[nname_3].IPAddress == nname_3_ipv4_4
- networks_7.container.NetworkSettings.Networks[nname_3].GlobalIPv6Address | normalize_ipaddr == nname_3_ipv6_4 | normalize_ipaddr
- networks_8 is not changed
- networks_8.container.NetworkSettings.Networks[nname_3].IPAMConfig.IPv4Address == nname_3_ipv4_4
- networks_8.container.NetworkSettings.Networks[nname_3].IPAMConfig.IPv6Address | normalize_ipaddr == nname_3_ipv6_4 | normalize_ipaddr
- networks_8.container.NetworkSettings.Networks[nname_3].IPAddress == nname_3_ipv4_4
- networks_8.container.NetworkSettings.Networks[nname_3].GlobalIPv6Address | normalize_ipaddr == nname_3_ipv6_4 | normalize_ipaddr
####################################################################
####################################################################
####################################################################
- name: Delete networks
docker_network:
name: "{{ network_name }}"
state: absent
force: true
loop:
- "{{ nname_1 }}"
- "{{ nname_2 }}"
- "{{ nname_3 }}"
loop_control:
loop_var: network_name

View File

@ -0,0 +1,328 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
- name: Registering container name
set_fact:
cname: "{{ cname_prefix ~ '-options' }}"
cname2: "{{ cname_prefix ~ '-options-h1' }}"
- name: Registering container name
set_fact:
cnames: "{{ cnames + [cname, cname2] }}"
####################################################################
## published_ports: error handling #################################
####################################################################
- name: published_ports -- non-closing square bracket
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
published_ports:
- "[::1:2000:3000"
register: published_ports_1
ignore_errors: true
- name: published_ports -- forgot square brackets for IPv6
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
published_ports:
- "::1:2000:3000"
register: published_ports_2
ignore_errors: true
- name: published_ports -- disallow hostnames
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
published_ports:
- "foo:2000:3000"
register: published_ports_3
ignore_errors: true
- assert:
that:
- published_ports_1 is failed
- published_ports_1.msg == 'Cannot find closing "]" in input "[::1:2000:3000" for opening "[" at index 1!'
- published_ports_2 is failed
- published_ports_2.msg == 'Invalid port description "::1:2000:3000" - expected 1 to 3 colon-separated parts, but got 5. Maybe you forgot to use square brackets ([...]) around an IPv6 address?'
- published_ports_3 is failed
- "published_ports_3.msg == 'Bind addresses for published ports must be IPv4 or IPv6 addresses, not hostnames. Use the dig lookup to resolve hostnames. (Found hostname: foo)'"
####################################################################
## published_ports: port range #####################################
####################################################################
- name: published_ports -- port range
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
exposed_ports:
- "9001"
- "9010-9050"
published_ports:
- "9001:9001"
- "9010-9050:9010-9050"
force_kill: true
register: published_ports_1
- name: published_ports -- port range (idempotency)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
exposed_ports:
- "9001"
- "9010-9050"
published_ports:
- "9001:9001"
- "9010-9050:9010-9050"
force_kill: true
register: published_ports_2
- name: published_ports -- port range (different range)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
exposed_ports:
- "9001"
- "9010-9050"
published_ports:
- "9001:9001"
- "9020-9060:9020-9060"
force_kill: true
register: published_ports_3
- name: cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: true
diff: false
- assert:
that:
- published_ports_1 is changed
- published_ports_2 is not changed
- published_ports_3 is changed
####################################################################
## published_ports: one-element container port range ###############
####################################################################
- name: published_ports -- one-element container port range
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ item }}"
state: started
published_ports:
- "9010-9050:9010"
force_kill: true
loop:
- '{{ cname }}'
- '{{ cname2 }}'
register: published_ports_1
- name: published_ports -- one-element container port range (idempotency)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ item }}"
state: started
published_ports:
- "9010-9050:9010"
force_kill: true
loop:
- '{{ cname }}'
- '{{ cname2 }}'
register: published_ports_2
- name: published_ports -- one-element container port range (different range)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ item }}"
state: started
published_ports:
- "9010-9051:9010"
force_kill: true
loop:
- '{{ cname }}'
- '{{ cname2 }}'
register: published_ports_3
- name: cleanup
docker_container:
name: "{{ item }}"
state: absent
force_kill: true
loop:
- '{{ cname }}'
- '{{ cname2 }}'
diff: false
- assert:
that:
- published_ports_1 is changed
- published_ports_2 is not changed
- published_ports_3 is changed
####################################################################
## published_ports: IPv6 addresses #################################
####################################################################
- when: docker_host_info.host_info.ServerVersion is version('27.0.0', '<')
block:
- name: published_ports -- IPv6
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
published_ports:
- "[::1]:9001:9001"
force_kill: true
register: published_ports_1
- name: published_ports -- IPv6 (idempotency)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
published_ports:
- "[::1]:9001:9001"
force_kill: true
register: published_ports_2
- name: published_ports -- IPv6 (different IP)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
published_ports:
- "127.0.0.1:9001:9001"
force_kill: true
register: published_ports_3
- name: published_ports -- IPv6 (hostname)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
published_ports:
- "localhost:9001:9001"
force_kill: true
register: published_ports_4
ignore_errors: true
- name: cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: true
diff: false
- assert:
that:
- published_ports_1 is changed
- published_ports_2 is not changed
- published_ports_3 is changed
- published_ports_4 is failed
####################################################################
## publish_all_ports ###############################################
####################################################################
- set_fact:
publish_all_ports_test_cases:
- test_name: no_options
changed: true
- test_name: null_to_true
publish_all_ports_value: true
changed: true
- test_name: true_idempotency
publish_all_ports_value: true
changed: false
- test_name: true_to_null
changed: false
- test_name: null_to_true_2
publish_all_ports_value: true
changed: false
- test_name: true_to_false
publish_all_ports_value: false
changed: true
- test_name: false_idempotency
publish_all_ports_value: false
changed: false
- test_name: false_to_null
changed: false
- test_name: null_with_published_ports
published_ports_value: &ports
- "9001:9001"
- "9010-9050:9010-9050"
changed: true
- test_name: null_to_true_with_published_ports
publish_all_ports_value: true
published_ports_value: *ports
changed: true
- test_name: true_idempotency_with_published_ports
publish_all_ports_value: true
published_ports_value: *ports
changed: false
- test_name: true_to_null_with_published_ports
published_ports_value: *ports
changed: false
- test_name: null_to_true_2_with_published_ports
publish_all_ports_value: true
published_ports_value: *ports
changed: false
- test_name: true_to_false_with_published_ports
publish_all_ports_value: false
published_ports_value: *ports
changed: true
- test_name: false_idempotency_with_published_ports
publish_all_ports_value: false
published_ports_value: *ports
changed: false
- test_name: false_to_null_with_published_ports
published_ports_value: *ports
changed: false
- name: publish_all_ports ({{ test_case.test_name }})
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
publish_all_ports: "{{ test_case.publish_all_ports_value | default(omit) }}"
published_ports: "{{ test_case.published_ports_value | default(omit) }}"
force_kill: true
register: publish_all_ports
loop_control:
loop_var: test_case
loop: "{{ publish_all_ports_test_cases }}"
- assert:
that:
- publish_all_ports.results[index].changed == test_case.changed
loop: "{{ publish_all_ports_test_cases }}"
loop_control:
index_var: index
loop_var: test_case

View File

@ -0,0 +1,38 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
# Regression test for https://github.com/ansible/ansible/pull/45700
- name: Registering container name
set_fact:
cname: "{{ cname_prefix ~ '-45700' }}"
- name: Registering container name
set_fact:
cnames: "{{ cnames + [cname] }}"
- name: Start container
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
- name: Stop container with a lot of invalid options
docker_container:
name: "{{ cname }}"
force_kill: true
# Some options with "invalid" values, which would
# have to be parsed. The values are "invalid" because
# the containers and networks listed here do not exist.
# This can happen because the networks are removed
# before the container is stopped (see
# https://github.com/ansible/ansible/issues/45486).
networks:
- name: "nonexistant-network-{{ (2**32) | random }}"
published_ports:
- '1:2'
- '3'
links:
- "nonexistant-container-{{ (2**32) | random }}:test"
state: absent

View File

@ -0,0 +1,459 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
- name: Registering container name
set_fact:
cname: "{{ cname_prefix ~ '-hi' }}"
- name: Registering container name
set_fact:
cnames: "{{ cnames + [cname] }}"
####################################################################
## Creation ########################################################
####################################################################
- name: Create container (check)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: present
check_mode: true
register: create_1
- name: Create container
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: present
register: create_2
- name: Create container (idempotent)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: present
register: create_3
- name: Create container (idempotent check)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: present
check_mode: true
register: create_4
- assert:
that:
- create_1 is changed
- create_2 is changed
- create_3 is not changed
- create_4 is not changed
####################################################################
## Starting (after creation) #######################################
####################################################################
- name: Start container (check)
docker_container:
name: "{{ cname }}"
state: started
check_mode: true
register: start_1
- name: Start container
docker_container:
name: "{{ cname }}"
state: started
register: start_2
- name: Start container (idempotent)
docker_container:
name: "{{ cname }}"
state: started
register: start_3
- name: Start container (idempotent check)
docker_container:
name: "{{ cname }}"
state: started
check_mode: true
register: start_4
- assert:
that:
- start_1 is changed
- start_2 is changed
- start_3 is not changed
- start_4 is not changed
####################################################################
## Present check for running container #############################
####################################################################
- name: Present check for running container (check)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: present
check_mode: true
register: present_check_1
- name: Present check for running container
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: present
register: present_check_2
- assert:
that:
- present_check_1 is not changed
- present_check_2 is not changed
####################################################################
## Starting (from scratch) #########################################
####################################################################
- name: Remove container (setup for starting from scratch)
docker_container:
name: "{{ cname }}"
state: absent
force_kill: true
- name: Start container from scratch (check)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
stop_timeout: 1
name: "{{ cname }}"
state: started
check_mode: true
register: start_scratch_1
- name: Start container from scratch
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
stop_timeout: 1
name: "{{ cname }}"
state: started
register: start_scratch_2
- name: Start container from scratch (idempotent)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
stop_timeout: 1
name: "{{ cname }}"
state: started
register: start_scratch_3
- name: Start container from scratch (idempotent check)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
stop_timeout: 1
name: "{{ cname }}"
state: started
check_mode: true
register: start_scratch_4
- assert:
that:
- start_scratch_1 is changed
- start_scratch_2 is changed
- start_scratch_3 is not changed
- start_scratch_4 is not changed
####################################################################
## Recreating ######################################################
####################################################################
- name: Recreating container (created)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: present
force_kill: true
register: recreate_1
- name: Recreating container (created, recreate, check mode)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
recreate: true
state: present
force_kill: true
register: recreate_2
check_mode: true
- name: Recreating container (created, recreate)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
recreate: true
state: present
force_kill: true
register: recreate_3
- name: Recreating container (started)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
force_kill: true
register: recreate_4
- name: Recreating container (started, recreate, check mode)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
recreate: true
removal_wait_timeout: 10
state: started
force_kill: true
register: recreate_5
check_mode: true
- name: Recreating container (started, recreate)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
recreate: true
removal_wait_timeout: 10
state: started
force_kill: true
register: recreate_6
- name: cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: true
diff: false
- debug: var=recreate_1
- debug: var=recreate_3
- debug: var=recreate_4
- debug: var=recreate_6
- assert:
that:
- recreate_2 is changed
- recreate_3 is changed
- recreate_4 is changed
- recreate_5 is changed
- recreate_6 is changed
- recreate_1.container.Id == recreate_2.container.Id
- recreate_1.container.Id != recreate_3.container.Id
- recreate_3.container.Id == recreate_4.container.Id
- recreate_4.container.Id == recreate_5.container.Id
- recreate_4.container.Id != recreate_6.container.Id
####################################################################
## Restarting ######################################################
####################################################################
- name: Restarting
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
stop_timeout: 1
volumes:
- /tmp/tmp
register: restart_1
- name: Restarting (restart, check mode)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
restart: true
state: started
stop_timeout: 1
force_kill: true
register: restart_2
check_mode: true
- name: Restarting (restart)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
restart: true
state: started
stop_timeout: 1
force_kill: true
register: restart_3
- name: Restarting (verify volumes)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
stop_timeout: 1
volumes:
- /tmp/tmp
register: restart_4
- name: cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: true
diff: false
- assert:
that:
- restart_1 is changed
- restart_2 is changed
- restart_3 is changed
- restart_1.container.Id == restart_3.container.Id
- restart_4 is not changed
####################################################################
## Stopping ########################################################
####################################################################
- name: Stop container (check)
docker_container:
image: "{{ docker_test_image_alpine }}"
name: "{{ cname }}"
state: stopped
stop_timeout: 1
check_mode: true
register: stop_1
- name: Stop container
docker_container:
image: "{{ docker_test_image_alpine }}"
name: "{{ cname }}"
state: stopped
stop_timeout: 1
register: stop_2
- name: Stop container (idempotent)
docker_container:
image: "{{ docker_test_image_alpine }}"
name: "{{ cname }}"
state: stopped
stop_timeout: 1
register: stop_3
- name: Stop container (idempotent check)
docker_container:
image: "{{ docker_test_image_alpine }}"
name: "{{ cname }}"
state: stopped
stop_timeout: 1
check_mode: true
register: stop_4
- assert:
that:
- stop_1 is changed
- stop_2 is changed
- stop_3 is not changed
- stop_4 is not changed
####################################################################
## Removing ########################################################
####################################################################
- name: Remove container (check)
docker_container:
name: "{{ cname }}"
state: absent
check_mode: true
register: remove_1
- name: Remove container
docker_container:
name: "{{ cname }}"
state: absent
register: remove_2
- name: Remove container (idempotent)
docker_container:
name: "{{ cname }}"
state: absent
register: remove_3
- name: Remove container (idempotent check)
docker_container:
name: "{{ cname }}"
state: absent
check_mode: true
register: remove_4
- assert:
that:
- remove_1 is changed
- remove_2 is changed
- remove_3 is not changed
- remove_4 is not changed
####################################################################
## Removing (from running) #########################################
####################################################################
- name: Start container (setup for removing from running)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
- name: Remove container from running (check)
docker_container:
name: "{{ cname }}"
state: absent
force_kill: true
check_mode: true
register: remove_from_running_1
- name: Remove container from running
docker_container:
name: "{{ cname }}"
state: absent
force_kill: true
register: remove_from_running_2
- name: Remove container from running (idempotent)
docker_container:
name: "{{ cname }}"
state: absent
force_kill: true
register: remove_from_running_3
- name: Remove container from running (idempotent check)
docker_container:
name: "{{ cname }}"
state: absent
force_kill: true
check_mode: true
register: remove_from_running_4
- assert:
that:
- remove_from_running_1 is changed
- remove_from_running_2 is changed
- remove_from_running_3 is not changed
- remove_from_running_4 is not changed

View File

@ -0,0 +1,221 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
- name: Registering container name
set_fact:
cname: "{{ cname_prefix ~ '-update' }}"
- name: Registering container name
set_fact:
cnames: "{{ cnames + [cname] }}"
# We do not test cpuset_cpus and cpuset_mems since changing it fails if the system does
# not have 'enough' CPUs. We do not test kernel_memory since it is deprecated and fails.
- set_fact:
has_blkio_weight: true
- name: Create container
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
blkio_weight: "{{ 123 if has_blkio_weight else omit }}"
cpu_period: 90000
cpu_quota: 150000
cpu_shares: 900
memory: 64M
memory_reservation: 64M
memory_swap: 64M
restart_policy: on-failure
restart_retries: 5
register: create
ignore_errors: true
- when: create is failed
block:
- name: Make sure container is not there
docker_container:
name: "{{ cname }}"
state: absent
- when: "'setting cgroup config for procHooks process caused: failed to write' in create.msg and 'io.bfq.weight' in create.msg"
set_fact:
has_blkio_weight: false
- name: Create container again
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
blkio_weight: "{{ 123 if has_blkio_weight else omit }}"
cpu_period: 90000
cpu_quota: 150000
cpu_shares: 900
memory: 64M
memory_reservation: 64M
memory_swap: 64M
restart_policy: on-failure
restart_retries: 5
register: create_2
- when: "'setting cgroup config for procHooks process caused: failed to write' in create.msg and 'io.bfq.weight' in create.msg"
set_fact:
create: "{{ create_2 }}"
- name: Update values
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
blkio_weight: "{{ 234 if has_blkio_weight else omit }}"
cpu_period: 50000
cpu_quota: 50000
cpu_shares: 1100
memory: 48M
memory_reservation: 48M
memory_swap: unlimited
restart_policy: on-failure # only on-failure can have restart_retries, so don't change it here
restart_retries: 2
register: update
diff: true
- name: Update values again
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
blkio_weight: "{{ 135 if has_blkio_weight else omit }}"
cpu_period: 30000
cpu_quota: 40000
cpu_shares: 1000
memory: 32M
memory_reservation: 30M
memory_swap: 128M
restart_policy: always
restart_retries: 0
register: update2
diff: true
- name: Recreate container
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 20m"' # this will force re-creation
name: "{{ cname }}"
state: started
blkio_weight: "{{ 234 if has_blkio_weight else omit }}"
cpu_period: 50000
cpu_quota: 50000
cpu_shares: 1100
memory: 48M
memory_reservation: 48M
memory_swap: unlimited
restart_policy: on-failure
restart_retries: 2
force_kill: true
register: recreate
diff: true
- name: cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: true
diff: false
- name: Check general things
assert:
that:
- create is changed
- update is changed
- update2 is changed
- recreate is changed
# Make sure the container was *not* recreated when it should not be
- create.container.Id == update.container.Id
- create.container.Id == update2.container.Id
# Make sure that the container was recreated when it should be
- create.container.Id != recreate.container.Id
- name: Check diff for first update
assert:
that:
# blkio_weight sometimes cannot be set, then we end up with 0 instead of the value we had
- >-
not has_blkio_weight or update.diff.before.blkio_weight == 123 or ('Docker warning: Your kernel does not support Block I/O weight or the cgroup is not mounted. Weight discarded.' in (create.warnings | default([])))
- not has_blkio_weight or update.diff.after.blkio_weight == 234
- update.diff.before.cpu_period == 90000
- update.diff.after.cpu_period == 50000
- update.diff.before.cpu_quota == 150000
- update.diff.after.cpu_quota == 50000
- update.diff.before.cpu_shares == 900
- update.diff.after.cpu_shares == 1100
- update.diff.before.memory == 67108864
- update.diff.after.memory == 50331648
- update.diff.before.memory_reservation == 67108864
- update.diff.after.memory_reservation == 50331648
- >-
(update.diff.before.memory_swap | default(0)) == 67108864 or ('Docker warning: Your kernel does not support swap limit capabilities or the cgroup is not mounted. Memory limited without swap.' in (create.warnings | default([])))
- >-
(update.diff.after.memory_swap | default(0)) == -1 or ('Docker warning: Your kernel does not support swap limit capabilities or the cgroup is not mounted. Memory limited without swap.' in (create.warnings | default([])))
- "'restart_policy' not in update.diff.before"
- update.diff.before.restart_retries == 5
- update.diff.after.restart_retries == 2
- name: Check diff for second update
assert:
that:
- >-
not has_blkio_weight or update2.diff.before.blkio_weight == 234 or ('Docker warning: Your kernel does not support Block I/O weight or the cgroup is not mounted. Weight discarded.' in (create.warnings | default([])))
- not has_blkio_weight or update2.diff.after.blkio_weight == 135
- update2.diff.before.cpu_period == 50000
- update2.diff.after.cpu_period == 30000
- update2.diff.before.cpu_quota == 50000
- update2.diff.after.cpu_quota == 40000
- update2.diff.before.cpu_shares == 1100
- update2.diff.after.cpu_shares == 1000
- update2.diff.before.memory == 50331648
- update2.diff.after.memory == 33554432
- update2.diff.before.memory_reservation == 50331648
- update2.diff.after.memory_reservation == 31457280
- >-
(update2.diff.before.memory_swap | default(0)) == -1 or ('Docker warning: Your kernel does not support swap limit capabilities or the cgroup is not mounted. Memory limited without swap.' in (create.warnings | default([])))
- >-
(update2.diff.after.memory_swap | default(0)) == 134217728 or ('Docker warning: Your kernel does not support swap limit capabilities or the cgroup is not mounted. Memory limited without swap.' in (create.warnings | default([])))
- update2.diff.before.restart_policy == 'on-failure'
- update2.diff.after.restart_policy == 'always'
- update2.diff.before.restart_retries == 2
- update2.diff.after.restart_retries == 0
- name: Check diff for recreation
assert:
that:
- >-
not has_blkio_weight or recreate.diff.before.blkio_weight == 135 or ('Docker warning: Your kernel does not support Block I/O weight or the cgroup is not mounted. Weight discarded.' in (create.warnings | default([])))
- not has_blkio_weight or recreate.diff.after.blkio_weight == 234
- recreate.diff.before.cpu_period == 30000
- recreate.diff.after.cpu_period == 50000
- recreate.diff.before.cpu_quota == 40000
- recreate.diff.after.cpu_quota == 50000
- recreate.diff.before.cpu_shares == 1000
- recreate.diff.after.cpu_shares == 1100
- recreate.diff.before.memory == 33554432
- recreate.diff.after.memory == 50331648
- recreate.diff.before.memory_reservation == 31457280
- recreate.diff.after.memory_reservation == 50331648
- >-
(recreate.diff.before.memory_swap | default(0)) == 134217728 or ('Docker warning: Your kernel does not support swap limit capabilities or the cgroup is not mounted. Memory limited without swap.' in (create.warnings | default([])))
- >-
(recreate.diff.after.memory_swap | default(0)) == -1 or ('Docker warning: Your kernel does not support swap limit capabilities or the cgroup is not mounted. Memory limited without swap.' in (create.warnings | default([])))
- recreate.diff.before.restart_policy == 'always'
- recreate.diff.after.restart_policy == 'on-failure'
- recreate.diff.before.restart_retries == 0
- recreate.diff.after.restart_retries == 2
- recreate.diff.before.command == ['/bin/sh', '-c', 'sleep 10m']
- recreate.diff.after.command == ['/bin/sh', '-c', 'sleep 20m']

View File

@ -0,0 +1,6 @@
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
azp/4
destructive

View File

@ -0,0 +1,9 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
dependencies:
- setup_docker
- setup_docker_python_deps
- setup_remote_tmp_dir

View File

@ -0,0 +1,47 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
####################################################################
# WARNING: These are designed specifically for Ansible tests #
# and should not be used as examples of how to write Ansible roles #
####################################################################
- name: Gather facts on controller
setup:
gather_subset: '!all'
delegate_to: localhost
delegate_facts: true
run_once: true
# Create random name prefix (for containers)
- name: Create random container name prefix
set_fact:
cname_prefix: "{{ 'ansible-docker-test-%0x' % ((2**32) | random) }}"
cnames: []
- debug:
msg: "Using container name prefix {{ cname_prefix }}"
# Run the tests
- block:
- include_tasks: run-test.yml
with_fileglob:
- "tests/*.yml"
loop_control:
loop_var: test_name
always:
- name: "Make sure all containers are removed"
docker_container:
name: "{{ item }}"
state: absent
force_kill: true
with_items: "{{ cnames }}"
diff: false
when: docker_api_version is version('1.25', '>=')
- fail: msg="Too old Docker API version to run all docker_container_copy_into tests!"
when: not(docker_api_version is version('1.25', '>=')) and (ansible_distribution != 'CentOS' or ansible_distribution_major_version|int > 6)

View File

@ -0,0 +1,7 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
- name: "Loading tasks from {{ test_name }}"
include_tasks: "{{ test_name }}"

View File

@ -0,0 +1,6 @@
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
azp/4
destructive

View File

@ -0,0 +1,8 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
dependencies:
- setup_docker
- setup_docker_python_deps

View File

@ -0,0 +1,228 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
####################################################################
# WARNING: These are designed specifically for Ansible tests #
# and should not be used as examples of how to write Ansible roles #
####################################################################
- block:
- name: Create random container name
set_fact:
cname: "{{ 'ansible-docker-test-%0x' % ((2**32) | random) }}"
- name: Make sure container is not there
docker_container:
name: "{{ cname }}"
state: absent
force_kill: true
- name: Execute in a non-present container
docker_container_exec:
container: "{{ cname }}"
command: "/bin/bash -c 'ls -a'"
register: result
ignore_errors: true
- assert:
that:
- result is failed
- "'Could not find container' in result.msg"
- name: Make sure container exists
docker_container:
name: "{{ cname }}"
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
state: started
force_kill: true
- name: Execute in a present container (command)
docker_container_exec:
container: "{{ cname }}"
command: "/bin/sh -c 'ls -a'"
register: result_cmd
- assert:
that:
- result_cmd.rc == 0
- "'stdout' in result_cmd"
- "'stdout_lines' in result_cmd"
- "'stderr' in result_cmd"
- "'stderr_lines' in result_cmd"
- name: Execute in a present container (argv)
docker_container_exec:
container: "{{ cname }}"
argv:
- /bin/sh
- '-c'
- ls -a
register: result_argv
- assert:
that:
- result_argv.rc == 0
- "'stdout' in result_argv"
- "'stdout_lines' in result_argv"
- "'stderr' in result_argv"
- "'stderr_lines' in result_argv"
- result_cmd.stdout == result_argv.stdout
- name: Execute in a present container (cat without stdin)
docker_container_exec:
container: "{{ cname }}"
argv:
- /bin/sh
- '-c'
- cat
register: result
- assert:
that:
- result.rc == 0
- result.stdout == ''
- result.stdout_lines == []
- result.stderr == ''
- result.stderr_lines == []
- name: Execute in a present container (cat with stdin)
docker_container_exec:
container: "{{ cname }}"
argv:
- /bin/sh
- '-c'
- cat
stdin: Hello world!
strip_empty_ends: false
register: result
- assert:
that:
- result.rc == 0
- result.stdout == 'Hello world!\n'
- result.stdout_lines == ['Hello world!']
- result.stderr == ''
- result.stderr_lines == []
- name: Execute in a present container (cat with stdin, no newline)
docker_container_exec:
container: "{{ cname }}"
argv:
- /bin/sh
- '-c'
- cat
stdin: Hello world!
stdin_add_newline: false
strip_empty_ends: false
register: result
- assert:
that:
- result.rc == 0
- result.stdout == 'Hello world!'
- result.stdout_lines == ['Hello world!']
- result.stderr == ''
- result.stderr_lines == []
- name: Execute in a present container (cat with stdin, newline but stripping)
docker_container_exec:
container: "{{ cname }}"
argv:
- /bin/sh
- '-c'
- cat
stdin: Hello world!
stdin_add_newline: true
strip_empty_ends: true
register: result
- assert:
that:
- result.rc == 0
- result.stdout == 'Hello world!'
- result.stdout_lines == ['Hello world!']
- result.stderr == ''
- result.stderr_lines == []
- name: Prepare long string
set_fact:
very_long_string: "{{ 'something long ' * 10000 }}"
very_long_string2: "{{ 'something else ' * 5000 }}"
- name: Execute in a present container (long stdin)
docker_container_exec:
container: "{{ cname }}"
argv:
- /bin/sh
- '-c'
- cat
stdin: |-
{{ very_long_string }}
{{ very_long_string2 }}
register: result
- assert:
that:
- result is changed
- result.rc == 0
- result.stdout == (very_long_string ~ '\n' ~ very_long_string2)
- result.stdout_lines == [very_long_string, very_long_string2]
- result.stderr == ''
- result.stderr_lines == []
- "'exec_id' not in result"
- name: Execute in a present container (detached)
docker_container_exec:
container: "{{ cname }}"
argv:
- /bin/sh
- '-c'
- sleep 1m
detach: true
register: result
- debug: var=result
- assert:
that:
- result is changed
- "'rc' not in result"
- "'stdout' not in result"
- "'stderr' not in result"
- result.exec_id is string
- name: Execute in a present container (environment variable)
docker_container_exec:
container: "{{ cname }}"
argv:
- /bin/sh
- '-c'
- 'echo "$FOO" ; echo $FOO > /dev/stderr'
env:
FOO: |-
bar
baz
register: result
- assert:
that:
- result.rc == 0
- result.stdout == 'bar\nbaz'
- result.stdout_lines == ['bar', 'baz']
- result.stderr == 'bar baz'
- result.stderr_lines == ['bar baz']
always:
- name: Cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: true
when: docker_api_version is version('1.25', '>=')
- fail: msg="Too old docker / docker-py version to run docker_container_exec tests!"
when: not(docker_api_version is version('1.25', '>=')) and (ansible_distribution != 'CentOS' or ansible_distribution_major_version|int > 6)

View File

@ -0,0 +1,6 @@
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
azp/5
destructive

View File

@ -0,0 +1,8 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
dependencies:
- setup_docker
- setup_docker_python_deps

View File

@ -0,0 +1,84 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
####################################################################
# WARNING: These are designed specifically for Ansible tests #
# and should not be used as examples of how to write Ansible roles #
####################################################################
- block:
- name: Create random container name
set_fact:
cname: "{{ 'ansible-docker-test-%0x' % ((2**32) | random) }}"
- name: Make sure container is not there
docker_container:
name: "{{ cname }}"
state: absent
force_kill: true
- name: Inspect a non-present container
docker_container_info:
name: "{{ cname }}"
register: result
- assert:
that:
- "not result.exists"
- "'container' in result"
- "result.container is none"
- name: Make sure container exists
docker_container:
name: "{{ cname }}"
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
state: started
force_kill: true
- name: Inspect a present container
docker_container_info:
name: "{{ cname }}"
register: result
- name: Dump docker_container_info result
debug: var=result
- name: "Comparison: use 'docker inspect'"
command: docker inspect "{{ cname }}"
register: docker_inspect
ignore_errors: true
- block:
- set_fact:
docker_inspect_result: "{{ docker_inspect.stdout | from_json }}"
- name: Dump docker inspect result
debug: var=docker_inspect_result
when: docker_inspect is not failed
- assert:
that:
- result.exists
- "'container' in result"
- "result.container is truthy"
- assert:
that:
- "result.container == docker_inspect_result[0]"
when: docker_inspect is not failed
- assert:
that:
- "'is too new. Maximum supported API version is' in docker_inspect.stderr"
when: docker_inspect is failed
always:
- name: Cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: true
when: docker_api_version is version('1.25', '>=')
- fail: msg="Too old docker / docker-py version to run docker_container_info tests!"
when: not(docker_api_version is version('1.25', '>=')) and (ansible_distribution != 'CentOS' or ansible_distribution_major_version|int > 6)

View File

@ -0,0 +1,6 @@
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
azp/5
destructive

View File

@ -0,0 +1,9 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
dependencies:
- setup_docker
- setup_docker_python_deps
- setup_podman

View File

@ -0,0 +1,40 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
####################################################################
# WARNING: These are designed specifically for Ansible tests #
# and should not be used as examples of how to write Ansible roles #
####################################################################
# Create random name prefix (for containers, networks, ...)
- name: Create random container name prefix
set_fact:
cname_prefix: "{{ 'ansible-docker-test-%0x' % ((2**32) | random) }}"
cnames: []
- debug:
msg: "Using container name prefix {{ cname_prefix }}"
# Run the tests
- block:
- include_tasks: run-test.yml
with_fileglob:
- "tests/*.yml"
loop_control:
loop_var: test_name
always:
- name: "Make sure all containers are removed"
docker_container:
name: "{{ item }}"
state: absent
force_kill: true
with_items: "{{ cnames }}"
diff: false
when: docker_api_version is version('1.25', '>=')
- fail: msg="Too old docker / docker-py version to run all docker_container tests!"
when: not(docker_api_version is version('1.25', '>=')) and (ansible_distribution != 'CentOS' or ansible_distribution_major_version|int > 6)

View File

@ -0,0 +1,7 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
- name: "Loading tasks from {{ test_name }}"
include_tasks: "{{ test_name }}"

View File

@ -0,0 +1,121 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
- name: Registering container name
set_fact:
cname: "{{ cname_prefix ~ '-hi' }}"
- name: Registering container name
set_fact:
cnames: "{{ cnames + [cname] }}"
- name: Get current context
community.docker.docker_context_info:
only_current: true
register: docker_current_context
- assert:
that:
- docker_current_context is not changed
# Some of the following tests will not be true on all machines, but they should be in CI:
- docker_current_context.current_context_name == 'default'
- docker_current_context.contexts | length == 1
- docker_current_context.contexts[0].name == 'default'
- docker_current_context.contexts[0].current == true
- docker_current_context.contexts[0].description == 'Current DOCKER_HOST based configuration'
- docker_current_context.contexts[0].meta_path is none
- docker_current_context.contexts[0].tls_path is none
- docker_current_context.contexts[0].config.docker_host == 'unix:///var/run/docker.sock'
- docker_current_context.contexts[0].config.tls == false
- name: Run community.docker modules with current context
module_defaults:
group/community.docker.docker: "{{ docker_current_context.contexts[0].config }}"
block:
- name: Create container
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: present
register: create_1
- name: Create container (idempotent)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: present
register: create_2
- assert:
that:
- create_1 is changed
- create_2 is not changed
- name: Inspect container with CLI tool
ansible.builtin.command:
cmd: docker inspect {{ cname }}
register: result
- assert:
that:
- (result.stdout | from_json) | length == 1
- (result.stdout | from_json)[0].State.Status == "created"
- name: Start container
docker_container:
name: "{{ cname }}"
state: started
register: start_1
- name: Start container (idempotent)
docker_container:
name: "{{ cname }}"
state: started
register: start_2
- assert:
that:
- start_1 is changed
- start_2 is not changed
- name: Inspect container with CLI tool
ansible.builtin.command:
cmd: docker inspect {{ cname }}
register: result
- assert:
that:
- (result.stdout | from_json) | length == 1
- (result.stdout | from_json)[0].State.Status == "running"
- name: Remove container
docker_container:
name: "{{ cname }}"
state: absent
force_kill: true
register: remove_1
- name: Remove container (idempotent)
docker_container:
name: "{{ cname }}"
state: absent
force_kill: true
register: remove_2
- assert:
that:
- remove_1 is changed
- remove_2 is not changed
- name: Inspect container with CLI tool
ansible.builtin.command:
cmd: docker inspect {{ cname }}
register: result
failed_when: result.rc != 1
- assert:
that:
- (result.stdout | from_json) | length == 0

View File

@ -0,0 +1,49 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
- when: podman_cli_version is version('1.0.0', '>=')
block:
# The setup_podman role created a 'podman' context that we can use here.
- name: Get all contexts
community.docker.docker_context_info:
register: docker_contexts
- name: Ensure that there are at least two contexts
assert:
that:
- docker_contexts.contexts | length >= 2
- name: Get Podman context
community.docker.docker_context_info:
name: podman
register: docker_podman_context
- assert:
that:
- docker_podman_context.contexts | length == 1
- docker_podman_context.contexts[0].name == 'podman'
- docker_podman_context.contexts[0].current == false
- docker_podman_context.contexts[0].description == 'Podman'
- docker_podman_context.contexts[0].meta_path is string
- docker_podman_context.contexts[0].tls_path is string
- docker_podman_context.contexts[0].config.docker_host is string
- docker_podman_context.contexts[0].config.tls == false
- name: Run basic test with Podman context
module_defaults:
group/community.docker.docker: "{{ docker_podman_context.contexts[0].config }}"
block:
- name: Get info on Podman host
docker_host_info:
register: output
- name: Check for some Podman specific values
assert:
that:
- output.host_info.ProductLicense == 'Apache-2.0'
- >-
"Rootless" in output.host_info

View File

@ -0,0 +1,6 @@
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
azp/4
destructive

View File

@ -0,0 +1,9 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
dependencies:
- setup_docker
- setup_docker_python_deps
- setup_podman

View File

@ -0,0 +1,38 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
####################################################################
# WARNING: These are designed specifically for Ansible tests #
# and should not be used as examples of how to write Ansible roles #
####################################################################
- include_tasks: test_host_info.yml
when: docker_api_version is version('1.25', '>=')
- fail: msg="Too old docker / docker-py version to run docker_host_info tests!"
when: not(docker_api_version is version('1.25', '>=')) and (ansible_distribution != 'CentOS' or ansible_distribution_major_version|int > 6)
- when: podman_cli_version is version('1.0.0', '>=')
block:
- name: Get Podman context
community.docker.docker_context_info:
name: podman
register: docker_podman_context
- name: Run tests with Podman context
module_defaults:
group/community.docker.docker: "{{ docker_podman_context.contexts[0].config }}"
block:
- name: Get info on Podman host
docker_host_info:
register: output
- name: Check for some Podman specific values
assert:
that:
- output.host_info.ProductLicense == 'Apache-2.0'
- >-
"Rootless" in output.host_info

View File

@ -0,0 +1,391 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
- name: Create random container/volume name
set_fact:
cname: "{{ 'ansible-docker-test-%0x' % ((2**32) | random) }}"
cname2: "{{ 'ansible-docker-test-%0x' % ((2**32) | random) }}"
vname: "{{ 'ansible-docker-test-%0x' % ((2**32) | random) }}"
- debug:
msg: "Using container names '{{ cname }}' and '{{ cname2 }}', and volume name '{{ vname }}'"
- block:
- name: Get info on Docker host
docker_host_info:
register: output
- name: assert reading docker host facts when docker is running
assert:
that:
- output.host_info.Name is string
- output.containers is not defined
- output.networks is not defined
- output.volumes is not defined
- output.images is not defined
- output.disk_usage is not defined
- output.can_talk_to_docker is true
- block:
- name: Get info on Docker host with invalid api_version
docker_host_info:
api_version: 1.999.999
register: output
ignore_errors: true
- name: assert can_talk_is_docker is false
assert:
that:
- output is failed
- output.can_talk_to_docker is false
- block:
- name: Get info on Docker host with invalid docker_host
docker_host_info:
docker_host: tcp://127.0.0.1:80
register: output
ignore_errors: true
- name: assert can_talk_is_docker is false
assert:
that:
- output is failed
- output.can_talk_to_docker is false
# Container and volume are created so that all lists are non-empty:
# * container and volume lists are non-emtpy because of the created objects;
# * image list is non-empty because the image of the container is there;
# * network list is always non-empty (default networks).
- name: Create running container
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
labels:
key1: value1
key2: value2
state: started
register: container_output
- name: Create running container
docker_container:
image: "{{ docker_test_image_alpine }}"
name: "{{ cname2 }}"
labels:
key2: value2
key3: value3
state: stopped
register: container2_output
- assert:
that:
- container_output is changed
- container2_output is changed
- name: Create a volume
docker_volume:
name: "{{ vname }}"
register: volume_output
- assert:
that:
- volume_output is changed
- name: Get info on Docker host and list containers
docker_host_info:
containers: true
register: output
- name: assert reading docker host facts when docker is running and list containers
assert:
that:
- 'output.host_info.Name is string'
- 'output.networks is not defined'
- 'output.volumes is not defined'
- 'output.images is not defined'
- 'output.disk_usage is not defined'
- 'output.containers[0].Image is string'
- 'output.containers[0].ImageID is not defined'
- name: Get info on Docker host and list containers matching filters (single label)
docker_host_info:
containers: true
containers_filters:
label: key1=value1
register: output
- name: assert container is returned when filters are matched (single label)
assert:
that: "output.containers | length == 1"
- name: Get info on Docker host and list containers matching filters (multiple labels)
docker_host_info:
containers: true
containers_filters:
label:
- key1=value1
- key2=value2
register: output
- name: assert container is returned when filters are matched (multiple labels)
assert:
that: "output.containers | length == 1"
- name: Get info on Docker host and do not list containers which do not match filters
docker_host_info:
containers: true
containers_filters:
label:
- key1=value1
- key2=value2
- key3=value3
register: output
- name: assert no container is returned when filters are not matched
assert:
that: "output.containers | length == 0"
- name: Get info on Docker host and list containers matching filters (single label, not all containers)
docker_host_info:
containers: true
containers_all: false
containers_filters:
label: key2=value2
register: output
- name: Get info on Docker host and list containers matching filters (single label, all containers)
docker_host_info:
containers: true
containers_all: true
containers_filters:
label: key2=value2
register: output_all
- name: assert one resp. two container is returned
assert:
that:
- "output.containers | length == 1"
- "output_all.containers | length == 2"
- name: Get info on Docker host and list containers with verbose output
docker_host_info:
containers: true
verbose_output: true
register: output
- name: assert reading docker host facts when docker is running and list containers with verbose output
assert:
that:
- 'output.host_info.Name is string'
- 'output.networks is not defined'
- 'output.volumes is not defined'
- 'output.images is not defined'
- 'output.disk_usage is not defined'
- 'output.containers[0].Image is string'
- 'output.containers[0].ImageID is string'
- name: Get info on Docker host and list images
docker_host_info:
images: true
register: output
- name: assert reading docker host facts when docker is running and list images
assert:
that:
- 'output.host_info.Name is string'
- 'output.containers is not defined'
- 'output.networks is not defined'
- 'output.volumes is not defined'
- 'output.images[0].Id is string'
- 'output.images[0].ParentId is not defined'
- 'output.disk_usage is not defined'
- name: Get info on Docker host and list images with verbose output
docker_host_info:
images: true
verbose_output: true
register: output
- name: assert reading docker host facts when docker is running and list images with verbose output
assert:
that:
- 'output.host_info.Name is string'
- 'output.containers is not defined'
- 'output.networks is not defined'
- 'output.volumes is not defined'
- 'output.images[0].Id is string'
- 'output.images[0].ParentId is string'
- 'output.disk_usage is not defined'
- name: Get info on Docker host and list networks
docker_host_info:
networks: true
register: output
- name: assert reading docker host facts when docker is running and list networks
assert:
that:
- 'output.host_info.Name is string'
- 'output.containers is not defined'
- 'output.networks[0].Id is string'
- 'output.networks[0].Created is not defined'
- 'output.volumes is not defined'
- 'output.images is not defined'
- 'output.disk_usage is not defined'
- name: Get info on Docker host and list networks with verbose output
docker_host_info:
networks: true
verbose_output: true
register: output
- name: assert reading docker host facts when docker is running and list networks with verbose output
assert:
that:
- 'output.host_info.Name is string'
- 'output.containers is not defined'
- 'output.networks[0].Id is string'
- 'output.networks[0].Created is string'
- 'output.volumes is not defined'
- 'output.images is not defined'
- 'output.disk_usage is not defined'
- name: Get info on Docker host and list volumes
docker_host_info:
volumes: true
register: output
- name: assert reading docker host facts when docker is running and list volumes
assert:
that:
- 'output.host_info.Name is string'
- 'output.containers is not defined'
- 'output.networks is not defined'
- 'output.volumes[0].Name is string'
- 'output.volumes[0].Mountpoint is not defined'
- 'output.images is not defined'
- 'output.disk_usage is not defined'
- name: Get info on Docker host and list volumes with verbose output
docker_host_info:
volumes: true
verbose_output: true
register: output
- name: assert reading docker host facts when docker is running and list volumes with verbose output
assert:
that:
- 'output.host_info.Name is string'
- 'output.containers is not defined'
- 'output.networks is not defined'
- 'output.volumes[0].Name is string'
- 'output.volumes[0].Mountpoint is string'
- 'output.images is not defined'
- 'output.disk_usage is not defined'
- name: Get info on Docker host and get disk usage
docker_host_info:
disk_usage: true
register: output
- name: assert reading docker host facts when docker is running and get disk usage
assert:
that:
- 'output.host_info.Name is string'
- 'output.containers is not defined'
- 'output.networks is not defined'
- 'output.volumes is not defined'
- 'output.images is not defined'
- 'output.disk_usage.LayersSize is number'
- 'output.disk_usage.Images is not defined'
- 'output.disk_usage.Containers is not defined'
- 'output.disk_usage.Volumes is not defined'
- name: Get info on Docker host and get disk usage with verbose output
docker_host_info:
disk_usage: true
verbose_output: true
register: output
- name: assert reading docker host facts when docker is running and get disk usage with verbose output
assert:
that:
- 'output.host_info.Name is string'
- 'output.containers is not defined'
- 'output.networks is not defined'
- 'output.volumes is not defined'
- 'output.images is not defined'
- 'output.disk_usage.LayersSize is number'
- 'output.disk_usage.Images is sequence'
- 'output.disk_usage.Containers is sequence'
- 'output.disk_usage.Volumes is sequence'
- name: Get info on Docker host, disk usage and get all lists together
docker_host_info:
volumes: true
containers: true
networks: true
images: true
disk_usage: true
register: output
- name: assert reading docker host facts when docker is running, disk usage and get lists together
assert:
that:
- 'output.host_info.Name is string'
- 'output.containers[0].Image is string'
- 'output.containers[0].ImageID is not defined'
- 'output.networks[0].Id is string'
- 'output.networks[0].Created is not defined'
- 'output.volumes[0].Name is string'
- 'output.volumes[0].Mountpoint is not defined'
- 'output.images[0].Id is string'
- 'output.images[0].ParentId is not defined'
- 'output.disk_usage.LayersSize is number'
- 'output.disk_usage.Images is not defined'
- 'output.disk_usage.Containers is not defined'
- 'output.disk_usage.Volumes is not defined'
- name: Get info on Docker host, disk usage and get all lists together with verbose output
docker_host_info:
volumes: true
containers: true
networks: true
images: true
disk_usage: true
verbose_output: true
register: output
- name: assert reading docker host facts when docker is running and get disk usage with verbose output
assert:
that:
- 'output.host_info.Name is string'
- 'output.containers[0].Image is string'
- 'output.containers[0].ImageID is string'
- 'output.networks[0].Id is string'
- 'output.networks[0].Created is string'
- 'output.volumes[0].Name is string'
- 'output.volumes[0].Mountpoint is string'
- 'output.images[0].Id is string'
- 'output.images[0].ParentId is string'
- 'output.disk_usage.LayersSize is number'
- 'output.disk_usage.Images is sequence'
- 'output.disk_usage.Containers is sequence'
- 'output.disk_usage.Volumes is sequence'
always:
- name: Delete containers
docker_container:
name: "{{ item }}"
state: absent
force_kill: true
loop:
- "{{ cname }}"
- "{{ cname2 }}"
- name: Delete volume
docker_volume:
name: "{{ vname }}"
state: absent

View File

@ -0,0 +1,6 @@
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
azp/4
destructive

View File

@ -0,0 +1,9 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
dependencies:
- setup_docker_registry
- setup_docker_python_deps
- setup_remote_tmp_dir

View File

@ -0,0 +1,13 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
####################################################################
# WARNING: These are designed specifically for Ansible tests #
# and should not be used as examples of how to write Ansible roles #
####################################################################
- when: ansible_facts.distribution ~ ansible_facts.distribution_major_version not in ['CentOS6', 'RedHat6']
include_tasks:
file: test.yml

View File

@ -0,0 +1,7 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
- name: "Loading tasks from {{ test_name }}"
include_tasks: "{{ test_name }}"

View File

@ -0,0 +1,56 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
- name: Create random name prefix
set_fact:
name_prefix: "{{ 'ansible-docker-test-%0x' % ((2**32) | random) }}"
- name: Create image and container list
set_fact:
inames: []
cnames: []
- debug:
msg: "Using name prefix {{ name_prefix }}"
- name: Create files directory
file:
path: '{{ remote_tmp_dir }}/files'
state: directory
- name: Template files
template:
src: '{{ item }}'
dest: '{{ remote_tmp_dir }}/files/{{ item }}'
loop:
- ArgsDockerfile
- Dockerfile
- EtcHostsDockerfile
- MyDockerfile
- StagedDockerfile
- block:
- include_tasks: run-test.yml
with_fileglob:
- "tests/*.yml"
loop_control:
loop_var: test_name
always:
- name: "Make sure all images are removed"
docker_image:
name: "{{ item }}"
state: absent
with_items: "{{ inames }}"
- name: "Make sure all containers are removed"
docker_container:
name: "{{ item }}"
state: absent
force_kill: true
with_items: "{{ cnames }}"
when: docker_api_version is version('1.25', '>=')
- fail: msg="Too old docker / docker-py version to run docker_image tests!"
when: not(docker_api_version is version('1.25', '>=')) and (ansible_distribution != 'CentOS' or ansible_distribution_major_version|int > 6)

View File

@ -0,0 +1,139 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
####################################################################
## basic ###########################################################
####################################################################
- name: Make sure image is not there
docker_image:
name: "{{ docker_test_image_hello_world }}"
state: absent
force_absent: true
register: absent_1
- name: Make sure image is not there (idempotency)
docker_image:
name: "{{ docker_test_image_hello_world }}"
state: absent
register: absent_2
- assert:
that:
- absent_2 is not changed
- name: Make sure image is there
docker_image:
name: "{{ docker_test_image_hello_world }}"
state: present
source: pull
pull:
platform: amd64
register: present_1
- name: Make sure image is there (idempotent)
docker_image:
name: "{{ docker_test_image_hello_world }}"
state: present
source: pull
pull:
platform: amd64
register: present_2
- assert:
that:
- present_1 is changed
- present_2 is not changed
- name: Make sure tag is not there
docker_image:
name: "{{ docker_test_image_hello_world_base }}:alias"
state: absent
- name: Tag image with alias
docker_image:
source: local
name: "{{ docker_test_image_hello_world }}"
repository: "{{ docker_test_image_hello_world_base }}:alias"
register: tag_1
- name: Tag image with alias (idempotent)
docker_image:
source: local
name: "{{ docker_test_image_hello_world }}"
repository: "{{ docker_test_image_hello_world_base }}:alias"
register: tag_2
- name: Tag image with alias (force, still idempotent)
docker_image:
source: local
name: "{{ docker_test_image_hello_world }}"
repository: "{{ docker_test_image_hello_world_base }}:alias"
force_tag: true
register: tag_3
- name: Tag image with ID instead of name
docker_image:
source: local
name: "{{ present_1.image.Id }}"
repository: "{{ docker_test_image_hello_world_base }}:alias"
register: tag_4
- assert:
that:
- tag_1 is changed
- tag_2 is not changed
- tag_3 is not changed
- tag_4 is not changed
- name: Cleanup alias tag
docker_image:
name: "{{ docker_test_image_hello_world_base }}:alias"
state: absent
- name: Tag image with ID instead of name (use ID for repository, must fail)
docker_image:
source: local
name: "{{ docker_test_image_hello_world }}"
repository: "{{ present_1.image.Id }}"
register: fail_1
ignore_errors: true
- name: Push image with ID (must fail)
docker_image:
source: local
name: "{{ present_1.image.Id }}"
push: true
register: fail_2
ignore_errors: true
- name: Pull image ID (must fail)
docker_image:
source: pull
name: "{{ present_1.image.Id }}"
force_source: true
register: fail_3
ignore_errors: true
- name: Build image ID (must fail)
docker_image:
source: build
name: "{{ present_1.image.Id }}"
build:
path: "{{ remote_tmp_dir }}/files"
force_source: true
register: fail_4
ignore_errors: true
- assert:
that:
- fail_1 is failed
- "'`repository` must not be an image ID' in fail_1.msg"
- fail_2 is failed
- "'Cannot push an image by ID' in fail_2.msg"
- fail_3 is failed
- "'Image name must not be an image ID for source=pull' in fail_3.msg"
- fail_4 is failed
- "'Image name must not be an image ID for source=build' in fail_4.msg"

View File

@ -0,0 +1,262 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
- name: Registering image name
set_fact:
iname: "{{ name_prefix ~ '-options' }}"
- name: Determining pushed image names
set_fact:
hello_world_image_base: "{{ registry_address | default('localhost') }}/test/hello-world"
test_image_base: "{{ registry_address | default('localhost') }}/test/{{ iname }}"
- name: Registering image name
set_fact:
inames: "{{ inames + [iname, test_image_base ~ ':latest', test_image_base ~ ':other', hello_world_image_base ~ ':latest', hello_world_image_base ~ ':newtag', hello_world_image_base ~ ':newtag2'] }}"
####################################################################
## interact with test registry #####################################
####################################################################
- name: Run registry tests only when registry is present
when: registry_address is defined
block:
- name: Make sure image is not there
docker_image:
name: "{{ hello_world_image_base }}:latest"
state: absent
force_absent: true
- name: Make sure we have {{ docker_test_image_hello_world }}
docker_image:
name: "{{ docker_test_image_hello_world }}"
source: pull
- name: Push image to test registry
docker_image:
name: "{{ docker_test_image_hello_world }}"
repository: "{{ hello_world_image_base }}:latest"
push: true
source: local
register: push_1
- name: Push image to test registry (idempotent)
docker_image:
name: "{{ docker_test_image_hello_world }}"
repository: "{{ hello_world_image_base }}:latest"
push: true
source: local
register: push_2
- name: Push image to test registry (force, still idempotent)
docker_image:
name: "{{ docker_test_image_hello_world }}"
repository: "{{ hello_world_image_base }}:latest"
push: true
source: local
force_tag: true
register: push_3
- assert:
that:
- push_1 is changed
- push_2 is not changed
- push_3 is not changed
- name: Get facts of local image
docker_image_info:
name: "{{ hello_world_image_base }}:latest"
register: facts_1
- name: Make sure image is not there
docker_image:
name: "{{ hello_world_image_base }}:latest"
state: absent
force_absent: true
- name: Get facts of local image (absent)
docker_image_info:
name: "{{ hello_world_image_base }}:latest"
register: facts_2
- name: Pull image from test registry
docker_image:
name: "{{ hello_world_image_base }}:latest"
state: present
source: pull
register: pull_1
- name: Pull image from test registry (idempotency)
docker_image:
name: "{{ hello_world_image_base }}:latest"
state: present
source: pull
register: pull_2
- name: Get facts of local image (present)
docker_image_info:
name: "{{ hello_world_image_base }}:latest"
register: facts_3
- assert:
that:
- pull_1 is changed
- pull_2 is not changed
- facts_1.images | length == 1
- facts_2.images | length == 0
- facts_3.images | length == 1
- name: Pull image from test registry (with digest)
docker_image:
name: "{{ hello_world_image_base }}@{{ facts_3.images[0].RepoDigests[0] | regex_replace('.*@', '') }}"
state: present
source: pull
force_source: true
register: pull_digest
- name: Make sure that changed is still false
assert:
that:
- pull_digest is not changed
- name: Tag different image with new tag
docker_image:
name: "{{ docker_test_image_alpine_different }}"
repository: "{{ hello_world_image_base }}:newtag"
push: false
source: pull
- name: Push different image with new tag
docker_image:
name: "{{ hello_world_image_base }}"
repository: "{{ hello_world_image_base }}"
tag: newtag
push: true
source: local
register: push_1_different
- name: Push different image with new tag (idempotent)
docker_image:
name: "{{ hello_world_image_base }}"
repository: "{{ hello_world_image_base }}"
tag: newtag
push: true
source: local
register: push_2_different
- assert:
that:
- push_1_different is changed
- push_2_different is not changed
- name: Tag same image with new tag
docker_image:
name: "{{ docker_test_image_alpine_different }}"
repository: "{{ hello_world_image_base }}:newtag2"
push: false
source: pull
- name: Push same image with new tag
docker_image:
name: "{{ hello_world_image_base }}"
repository: "{{ hello_world_image_base }}"
tag: newtag2
push: true
source: local
register: push_1_same
- name: Push same image with new tag (idempotent)
docker_image:
name: "{{ hello_world_image_base }}"
repository: "{{ hello_world_image_base }}"
tag: newtag2
push: true
source: local
register: push_2_same
- assert:
that:
# NOTE: This should be:
# - push_1_same is changed
# Unfortunately docker does *NOT* report whether the tag already existed or not.
# Here are the logs returned by client.push() for both tasks (which are exactly the same):
# push_1_same:
# {"status": "The push refers to repository [localhost:32796/test/hello-world]"},
# {"id": "3fc64803ca2d", "progressDetail": {}, "status": "Preparing"},
# {"id": "3fc64803ca2d", "progressDetail": {}, "status": "Layer already exists"},
# {"status": "newtag2: digest: sha256:92251458088c638061cda8fd8b403b76d661a4dc6b7ee71b6affcf1872557b2b size: 528"},
# {"aux": {"Digest": "sha256:92251458088c638061cda8fd8b403b76d661a4dc6b7ee71b6affcf1872557b2b", "Size": 528, "Tag": "newtag2"}, "progressDetail": {}}
# push_2_same:
# {"status": "The push refers to repository [localhost:32796/test/hello-world]"},
# {"id": "3fc64803ca2d", "progressDetail": {}, "status": "Preparing"},
# {"id": "3fc64803ca2d", "progressDetail": {}, "status": "Layer already exists"},
# {"status": "newtag2: digest: sha256:92251458088c638061cda8fd8b403b76d661a4dc6b7ee71b6affcf1872557b2b size: 528"},
# {"aux": {"Digest": "sha256:92251458088c638061cda8fd8b403b76d661a4dc6b7ee71b6affcf1872557b2b", "Size": 528, "Tag": "newtag2"}, "progressDetail": {}}
- push_1_same is not changed
- push_2_same is not changed
####################################################################
## repository ######################################################
####################################################################
- name: Make sure image is not there
docker_image:
name: "{{ test_image_base }}:latest"
state: absent
force_absent: true
- name: repository
docker_image:
name: "{{ iname }}"
build:
path: "{{ remote_tmp_dir }}/files"
pull: false
repository: "{{ test_image_base }}"
source: build
register: repository_1
- name: repository (idempotent)
docker_image:
name: "{{ iname }}"
repository: "{{ test_image_base }}"
source: local
register: repository_2
- name: repository, tag with ID
docker_image:
name: "{{ repository_1.image.Id }}"
repository: "{{ test_image_base }}:other"
source: local
register: repository_3
- name: repository, tag with ID (idempotent)
docker_image:
name: "{{ repository_1.image.Id }}"
repository: "{{ test_image_base }}:other"
source: local
force_tag: true
register: repository_4
- assert:
that:
- repository_1 is changed
- repository_2 is not changed
- repository_3 is changed
- repository_4 is not changed
- name: Get facts of image
docker_image_info:
name: "{{ test_image_base }}:latest"
register: facts_1
- name: cleanup
docker_image:
name: "{{ test_image_base }}:latest"
state: absent
force_absent: true
- assert:
that:
- facts_1.images | length == 1

View File

@ -0,0 +1,504 @@
---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
- name: Registering image name
set_fact:
iname: "{{ name_prefix ~ '-options' }}"
iname_1: "{{ name_prefix ~ '-options-1' }}"
hello_world_alt: "{{ name_prefix }}-hello-world-alt:v1.2.3-foo"
- name: Registering image name
set_fact:
inames: "{{ inames + [iname, iname_1, hello_world_alt] }}"
####################################################################
## build.args ######################################################
####################################################################
- name: cleanup
docker_image:
name: "{{ iname }}"
state: absent
force_absent: true
- name: buildargs
docker_image:
name: "{{ iname }}"
build:
path: "{{ remote_tmp_dir }}/files"
dockerfile: "ArgsDockerfile"
args:
IMAGE: "{{ docker_test_image_busybox }}"
TEST1: val1
TEST2: val2
TEST3: "True"
pull: false
source: build
register: buildargs_1
ignore_errors: true
- name: buildargs (idempotency)
docker_image:
name: "{{ iname }}"
build:
path: "{{ remote_tmp_dir }}/files"
dockerfile: "ArgsDockerfile"
args:
IMAGE: "{{ docker_test_image_busybox }}"
TEST1: val1
TEST2: val2
TEST3: "True"
pull: false
source: build
register: buildargs_2
ignore_errors: true
- name: cleanup
docker_image:
name: "{{ iname }}"
state: absent
force_absent: true
- assert:
that:
- buildargs_1 is changed
- buildargs_2 is not failed and buildargs_2 is not changed
####################################################################
## build.container_limits ##########################################
####################################################################
- name: container_limits (Failed due to min memory limit)
docker_image:
name: "{{ iname }}"
build:
path: "{{ remote_tmp_dir }}/files"
container_limits:
memory: 4KB
pull: false
source: build
ignore_errors: true
register: container_limits_1
- name: container_limits
docker_image:
name: "{{ iname }}"
build:
path: "{{ remote_tmp_dir }}/files"
container_limits:
memory: 7MB
memswap: 8MB
pull: false
source: build
register: container_limits_2
- name: cleanup
docker_image:
name: "{{ iname }}"
state: absent
force_absent: true
- assert:
that:
# It *sometimes* happens that the first task does not fail.
# For now, we work around this by
# a) requiring that if it fails, the message must
# contain 'Minimum memory limit allowed is (4|6)MB', and
# b) requiring that either the first task, or the second
# task is changed, but not both.
- "not container_limits_1 is failed or ('Minimum memory limit allowed is ') in container_limits_1.msg"
- "container_limits_1 is changed or container_limits_2 is changed and not (container_limits_1 is changed and container_limits_2 is changed)"
####################################################################
## build.dockerfile ################################################
####################################################################
- name: dockerfile
docker_image:
name: "{{ iname }}"
build:
path: "{{ remote_tmp_dir }}/files"
dockerfile: "MyDockerfile"
pull: false
source: build
register: dockerfile_1
- name: cleanup
docker_image:
name: "{{ iname }}"
state: absent
force_absent: true
- assert:
that:
- dockerfile_1 is changed
- "('FROM ' ~ docker_test_image_alpine) in dockerfile_1.stdout"
- dockerfile_1['image']['Config']['WorkingDir'] == '/newdata'
####################################################################
## build.platform ##################################################
####################################################################
- name: cleanup
docker_image:
name: "{{ iname }}"
state: absent
force_absent: true
- name: build.platform
docker_image:
name: "{{ iname }}"
build:
path: "{{ remote_tmp_dir }}/files"
platform: linux
pull: false
source: build
register: platform_1
ignore_errors: true
- name: build.platform (idempotency)
docker_image:
name: "{{ iname }}"
build:
path: "{{ remote_tmp_dir }}/files"
platform: linux
pull: false
source: build
register: platform_2
ignore_errors: true
- name: cleanup
docker_image:
name: "{{ iname }}"
state: absent
force_absent: true
- assert:
that:
- platform_1 is changed
- platform_2 is not failed and platform_2 is not changed
####################################################################
## force ###########################################################
####################################################################
- name: Build an image
docker_image:
name: "{{ iname }}"
build:
path: "{{ remote_tmp_dir }}/files"
pull: false
source: build
- name: force (changed)
docker_image:
name: "{{ iname }}"
build:
path: "{{ remote_tmp_dir }}/files"
dockerfile: "MyDockerfile"
pull: false
source: build
force_source: true
register: force_1
- name: force (unchanged)
docker_image:
name: "{{ iname }}"
build:
path: "{{ remote_tmp_dir }}/files"
dockerfile: "MyDockerfile"
pull: false
source: build
force_source: true
register: force_2
- name: cleanup
docker_image:
name: "{{ iname }}"
state: absent
force_absent: true
- assert:
that:
- force_1 is changed
- force_2 is not changed
####################################################################
## load path #######################################################
####################################################################
- name: Archive image
docker_image:
name: "{{ docker_test_image_hello_world }}"
archive_path: "{{ remote_tmp_dir }}/image.tar"
source: pull
register: archive_image
- assert:
that:
- archive_image is changed
- name: Copy archive because we will mutate it but other tests need the original
copy:
remote_src: true
src: "{{ remote_tmp_dir }}/image.tar"
dest: "{{ remote_tmp_dir }}/image_mutated.tar"
- name: Archive image again (idempotent)
docker_image:
name: "{{ docker_test_image_hello_world }}"
archive_path: "{{ remote_tmp_dir }}/image_mutated.tar"
source: local
register: archive_image_2
- assert:
that:
- archive_image_2 is not changed
- name: Archive image 3rd time, should overwrite due to different id
docker_image:
name: "{{ docker_test_image_alpine_different }}"
archive_path: "{{ remote_tmp_dir }}/image_mutated.tar"
source: pull
register: archive_image_3
- assert:
that:
- archive_image_3 is changed
- name: Reset archive
copy:
remote_src: true
src: "{{ remote_tmp_dir }}/image.tar"
dest: "{{ remote_tmp_dir }}/image_mutated.tar"
- name: Tag image with different name
docker_image:
name: "{{ docker_test_image_hello_world }}"
repository: "{{ hello_world_alt }}"
source: local
- name: Archive image 4th time, should overwrite due to different name even when ID is same
docker_image:
name: "{{ hello_world_alt }}"
# Tagged as docker_test_image_hello_world but has same hash/id (before this task overwrites it)
archive_path: "{{ remote_tmp_dir }}/image_mutated.tar"
source: local
register: archive_image_4
- assert:
that:
- archive_image_4 is changed
# This is the test that needs the original, non-mutated archive
- name: Archive image by ID
docker_image:
name: "{{ archive_image.image.Id }}"
archive_path: "{{ remote_tmp_dir }}/image_id.tar"
source: local
register: archive_image_id
- name: Create invalid archive
copy:
dest: "{{ remote_tmp_dir }}/image-invalid.tar"
content: "this is not a valid image"
- name: remove image
docker_image:
name: "{{ docker_test_image_hello_world }}"
state: absent
force_absent: true
- name: load image (changed)
docker_image:
name: "{{ docker_test_image_hello_world }}"
load_path: "{{ remote_tmp_dir }}/image.tar"
source: load
register: load_image
- name: load image (idempotency)
docker_image:
name: "{{ docker_test_image_hello_world }}"
load_path: "{{ remote_tmp_dir }}/image.tar"
source: load
register: load_image_1
- name: load image (wrong name)
docker_image:
name: foo:bar
load_path: "{{ remote_tmp_dir }}/image.tar"
source: load
register: load_image_2
ignore_errors: true
- name: load image (invalid image)
docker_image:
name: foo:bar
load_path: "{{ remote_tmp_dir }}/image-invalid.tar"
source: load
register: load_image_3
ignore_errors: true
- name: load image (ID, idempotency)
docker_image:
name: "{{ archive_image.image.Id }}"
load_path: "{{ remote_tmp_dir }}/image_id.tar"
source: load
register: load_image_4
- assert:
that:
- load_image is changed
- archive_image['image']['Id'] == load_image['image']['Id']
- load_image_1 is not changed
- load_image_2 is failed
- >-
("The archive did not contain image 'foo:bar'. Instead, found '" ~ docker_test_image_hello_world ~ "'.") == load_image_2.msg
- load_image_3 is failed
- '"Detected no loaded images. Archive potentially corrupt?" == load_image_3.msg'
- load_image_4 is not changed
####################################################################
## build.path ######################################################
####################################################################
- name: Build image
docker_image:
name: "{{ iname }}"
build:
path: "{{ remote_tmp_dir }}/files"
pull: false
source: build
register: path_1
- name: Build image (idempotency)
docker_image:
name: "{{ iname }}"
build:
path: "{{ remote_tmp_dir }}/files"
pull: false
source: build
register: path_2
- name: cleanup
docker_image:
name: "{{ iname }}"
state: absent
force_absent: true
- assert:
that:
- path_1 is changed
- path_2 is not changed
####################################################################
## build.target ####################################################
####################################################################
- name: Build multi-stage image
docker_image:
name: "{{ iname }}"
build:
path: "{{ remote_tmp_dir }}/files"
dockerfile: "StagedDockerfile"
target: first
pull: false
source: build
register: dockerfile_2
- name: cleanup
docker_image:
name: "{{ iname }}"
state: absent
force_absent: true
- assert:
that:
- dockerfile_2 is changed
- dockerfile_2.image.Config.WorkingDir == '/first'
####################################################################
## build.etc_hosts #################################################
####################################################################
- name: Build image with custom etc_hosts
docker_image:
name: "{{ iname }}"
build:
path: "{{ remote_tmp_dir }}/files"
dockerfile: "EtcHostsDockerfile"
pull: false
etc_hosts:
some-custom-host: "127.0.0.1"
source: build
register: path_1
- name: cleanup
docker_image:
name: "{{ iname }}"
state: absent
force_absent: true
- assert:
that:
- path_1 is changed
####################################################################
## build.shm_size ##################################################
####################################################################
- name: Build image with custom shm_size
docker_image:
name: "{{ iname }}"
build:
path: "{{ remote_tmp_dir }}/files"
dockerfile: "MyDockerfile"
pull: false
shm_size: 128MB
source: build
register: path_1
- name: cleanup
docker_image:
name: "{{ iname }}"
state: absent
force_absent: true
- assert:
that:
- path_1 is changed
####################################################################
## build.labels ####################################################
####################################################################
- name: Build image with labels
docker_image:
name: "{{ iname }}"
build:
path: "{{ remote_tmp_dir }}/files"
dockerfile: "MyDockerfile"
pull: false
labels:
FOO: BAR
this is a label: this is the label's value
source: build
register: labels_1
- name: cleanup
docker_image:
name: "{{ iname }}"
state: absent
force_absent: true
- name: Show image information
debug:
var: labels_1.image
- assert:
that:
- labels_1 is changed
- labels_1.image.Config.Labels.FOO == 'BAR'
- labels_1.image.Config.Labels["this is a label"] == "this is the label's value"

Some files were not shown because too many files have changed in this diff Show More