This commit is contained in:
Gary Kwok
2024-02-23 18:13:31 +08:00
commit 0530779609
3215 changed files with 455593 additions and 0 deletions

View File

@@ -0,0 +1,10 @@
#!/usr/bin/env bash
set -eux
[ -f "${INVENTORY}" ]
# Run connection tests with both the default and C locale.
ansible-playbook test_connection.yml -i "${INVENTORY}" "$@"
LC_ALL=C LANG=C ansible-playbook test_connection.yml -i "${INVENTORY}" "$@"

View File

@@ -0,0 +1,43 @@
- hosts: "{{ target_hosts }}"
gather_facts: no
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,3 @@
shippable/posix/group4
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
destructive

View File

@@ -0,0 +1,3 @@
---
dependencies:
- setup_docker

View File

@@ -0,0 +1,20 @@
#!/usr/bin/env bash
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,62 @@
#!/usr/bin/env bash
# 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: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,10 @@
---
- hosts: localhost
connection: local
vars:
docker_skip_cleanup: yes
tasks:
- name: Setup docker
import_role:
name: setup_docker

View File

@@ -0,0 +1,15 @@
---
- hosts: localhost
connection: local
vars:
docker_skip_cleanup: yes
tasks:
- name: Remove docker packages
action: "{{ ansible_facts.pkg_mgr }}"
args:
name:
- docker
- docker-ce
- docker-ce-cli
state: absent

View File

@@ -0,0 +1,3 @@
shippable/posix/group4
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
destructive

View File

@@ -0,0 +1,3 @@
---
dependencies:
- setup_docker

View File

@@ -0,0 +1,20 @@
#!/usr/bin/env bash
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,62 @@
#!/usr/bin/env bash
# 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: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,10 @@
---
- hosts: localhost
connection: local
vars:
docker_skip_cleanup: yes
tasks:
- name: Setup docker
import_role:
name: setup_docker

View File

@@ -0,0 +1,15 @@
---
- hosts: localhost
connection: local
vars:
docker_skip_cleanup: yes
tasks:
- name: Remove docker packages
action: "{{ ansible_facts.pkg_mgr }}"
args:
name:
- docker
- docker-ce
- docker-ce-cli
state: absent

View File

@@ -0,0 +1,4 @@
shippable/posix/group5
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,3 @@
---
dependencies:
- setup_docker

View File

@@ -0,0 +1,20 @@
#!/usr/bin/env bash
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,70 @@
#!/usr/bin/env bash
set -euo pipefail
[[ -n "${DEBUG:-}" || -n "${ANSIBLE_DEBUG:-}" ]] && set -x
readonly IMAGE="quay.io/ansible/ansible-runner:devel"
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
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,10 @@
---
- hosts: localhost
connection: local
vars:
docker_skip_cleanup: yes
tasks:
- name: Setup docker
import_role:
name: setup_docker

View File

@@ -0,0 +1,15 @@
---
- hosts: localhost
connection: local
vars:
docker_skip_cleanup: yes
tasks:
- name: Remove docker packages
action: "{{ ansible_facts.pkg_mgr }}"
args:
name:
- docker
- docker-ce
- docker-ce-cli
state: absent

View File

@@ -0,0 +1,2 @@
needs/target/connection
hidden

View File

@@ -0,0 +1,20 @@
#!/usr/bin/env bash
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,2 @@
shippable/posix/group4
destructive

View File

@@ -0,0 +1,4 @@
---
dependencies:
- setup_docker_compose
- setup_remote_tmp_dir

View File

@@ -0,0 +1,43 @@
---
####################################################################
# 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: []
dnetworks: []
- debug:
msg: "Using container name prefix {{ cname_prefix }}"
# Run the tests
- block:
- include_tasks: run-test.yml
with_fileglob:
- "tests/*.yml"
always:
- name: "Make sure all containers are removed"
docker_container:
name: "{{ item }}"
state: absent
force_kill: yes
with_items: "{{ cnames }}"
diff: no
- name: "Make sure all networks are removed"
docker_network:
name: "{{ item }}"
state: absent
force: yes
with_items: "{{ dnetworks }}"
when: docker_py_version is version('1.10.0', '>=')
diff: no
when: has_docker_compose and docker_py_version is version('1.8.0', '>=') and docker_api_version is version('1.20', '>=')
- fail: msg="Too old docker / docker-py version to run all docker_container tests!"
when: has_docker_compose and not(docker_py_version is version('3.5.0', '>=') and docker_api_version is version('1.25', '>=')) and (ansible_distribution != 'CentOS' or ansible_distribution_major_version|int > 6)

View File

@@ -0,0 +1,3 @@
---
- name: "Loading tasks from {{ item }}"
include_tasks: "{{ item }}"

View File

@@ -0,0 +1,239 @@
---
- name: Registering container name
set_fact:
pname: "{{ cname_prefix }}"
cname_1: "{{ cname_prefix ~ '1' }}"
cname_2: "{{ cname_prefix ~ '2' }}"
####################################################################
## Profiles ########################################################
####################################################################
- block:
- name: Define service
set_fact:
test_service: |
version: '3'
services:
{{ cname_1 }}:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
profiles:
- profile_1
- profile_all
stop_grace_period: 1s
{{ cname_2 }}:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
profiles:
- profile_2
- profile_all
stop_grace_period: 1s
test_cases:
- test_name: no services enabled
- test_name: enable 1
profiles_value:
- profile_1
- test_name: stop all services
profiles_value:
- profile_1
stopped_value: true
- test_name: enable 2
profiles_value:
- profile_2
- test_name: stop all services
profiles_value:
- profile_2
stopped_value: true
- test_name: enable both
profiles_value:
- profile_1
- profile_2
- test_name: stop all services
profiles_value:
- profile_1
- profile_2
stopped_value: true
- test_name: enable all
profiles_value:
- profile_all
- name: Profiles ({{ test_case.test_name }})
docker_compose:
project_name: "{{ pname }}"
definition: "{{ test_service | from_yaml }}"
profiles: "{{ test_case.profiles_value | default(omit) }}"
stopped: "{{ test_case.stopped_value | default(omit) }}"
state: present
register: profiles_outputs
loop: "{{ test_cases }}"
loop_control:
loop_var: test_case
- name: Cleanup
docker_compose:
project_name: "{{ pname }}"
state: absent
definition: "{{ test_service | from_yaml }}"
- assert:
that:
- profiles_outputs.results[0] is not changed
- profiles_outputs.results[1].services[cname_1][cname_1_name].state.running
- profiles_outputs.results[1].services[cname_2] == {}
- not profiles_outputs.results[2].services[cname_1][cname_1_name].state.running
- profiles_outputs.results[2].services[cname_2] == {}
- not profiles_outputs.results[3].services[cname_1][cname_1_name].state.running
- profiles_outputs.results[3].services[cname_2][cname_2_name].state.running
- not profiles_outputs.results[4].services[cname_1][cname_1_name].state.running
- not profiles_outputs.results[4].services[cname_2][cname_2_name].state.running
- profiles_outputs.results[5].services[cname_1][cname_1_name].state.running
- profiles_outputs.results[5].services[cname_2][cname_2_name].state.running
- not profiles_outputs.results[6].services[cname_1][cname_1_name].state.running
- not profiles_outputs.results[6].services[cname_2][cname_2_name].state.running
- profiles_outputs.results[7].services[cname_1][cname_1_name].state.running
- profiles_outputs.results[7].services[cname_2][cname_2_name].state.running
vars:
cname_1_name: "{{ pname + '_' + cname_1 + '_1' }}"
cname_2_name: "{{ pname + '_' + cname_2 + '_1' }}"
when: docker_compose_version is version('1.28.0', '>=')
####################################################################
## Env_file ########################################################
####################################################################
- block:
- name: Define service and files
set_fact:
compose_file: "{{ remote_tmp_dir }}/docker-compose.yml"
env_file: "{{ remote_tmp_dir }}/.env"
env_sleep_cmd: sleep 10m
new_env_file: "{{ remote_tmp_dir }}/new.env"
new_env_sleep_cmd: sleep 20m
test_service: |
version: '3'
services:
{{ cname_1 }}:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "${SLEEP_CMD}"'
stop_grace_period: 1s
- name: Define testcases
set_fact:
test_cases:
- test_name: Without env_file option
- test_name: With env_file option
env_file: "{{ new_env_file }}"
- name: Generate compose file
ansible.builtin.copy:
content: "{{ test_service }}"
dest: "{{ compose_file }}"
- name: Generate .env file
ansible.builtin.copy:
content: |
SLEEP_CMD="{{ env_sleep_cmd }}"
dest: "{{ env_file }}"
- name: Generate new.env file
ansible.builtin.copy:
content: |
SLEEP_CMD="{{ new_env_sleep_cmd }}"
dest: "{{ new_env_file }}"
- name: Env_file
docker_compose:
project_name: "{{ pname }}"
project_src: "{{ remote_tmp_dir }}"
env_file: "{{ test_case.env_file | default(omit) }}"
register: env_file_outputs
loop: "{{ test_cases }}"
loop_control:
loop_var: test_case
- name: Cleanup
docker_compose:
project_name: "{{ pname }}"
state: absent
definition: "{{ test_service | from_yaml }}"
- assert:
that:
- "env_sleep_cmd is in (env_file_outputs.results[0].services[cname_1][cname_1_name].cmd | join(' '))"
- "new_env_sleep_cmd is in (env_file_outputs.results[1].services[cname_1][cname_1_name].cmd | join(' '))"
vars:
cname_1_name: "{{ pname + '_' + cname_1 + '_1' }}"
cname_2_name: "{{ pname + '_' + cname_2 + '_1' }}"
- name: Remove files
ansible.builtin.file:
path: "{{ file_path }}"
state: absent
loop_control:
loop_var: file_path
loop:
- "{{ compose_file }}"
- "{{ env_file }}"
- "{{ new_env_file }}"
when: docker_compose_version is version('1.25.0', '>=')
####################################################################
## Project_src #####################################################
####################################################################
- name: Define service and files
set_fact:
compose_file: "{{ remote_tmp_dir }}/docker-compose.yml"
env_sleep_cmd: sleep 10m
new_env_sleep_cmd: sleep 20m
test_service: |
version: '3'
services:
{{ cname_1 }}:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c 10m'
stop_grace_period: 1s
- name: Generate compose file
ansible.builtin.copy:
content: "{{ test_service }}"
dest: "{{ compose_file }}"
- name: Start with project_src
docker_compose:
project_src: "{{ remote_tmp_dir }}"
register: project_src_1
- name: Start with project_src (idempotent)
docker_compose:
project_src: "{{ remote_tmp_dir }}"
register: project_src_2
- name: Stop with project_src
docker_compose:
project_src: "{{ remote_tmp_dir }}"
state: absent
register: project_src_3
- name: Stop with project_src (idempotent)
docker_compose:
project_src: "{{ remote_tmp_dir }}"
state: absent
register: project_src_4
- name: Remove files
ansible.builtin.file:
path: "{{ file_path }}"
state: absent
loop_control:
loop_var: file_path
loop:
- "{{ compose_file }}"
- assert:
that:
- project_src_1 is changed
# - project_src_2 is not changed -- for some reason, this currently fails!
- project_src_3 is changed
- project_src_4 is not changed

View File

@@ -0,0 +1,229 @@
---
- name: Registering container name
set_fact:
pname: "{{ cname_prefix }}"
cname: "{{ cname_prefix ~ '-hi' }}"
- name: Registering container name
set_fact:
cnames: "{{ cnames + [pname ~ '-' ~ cname] }}"
dnetworks: "{{ dnetworks + [pname ~ '_default'] }}"
- name: Define service
set_fact:
test_service: |
version: '3'
services:
{{ cname }}:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
stop_grace_period: 1s
test_service_mod: |
version: '3'
services:
{{ cname }}:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 15m"'
stop_grace_period: 1s
####################################################################
## Present #########################################################
####################################################################
- name: Present (check)
docker_compose:
project_name: "{{ pname }}"
state: present
definition: "{{ test_service | from_yaml }}"
check_mode: yes
register: present_1
- name: Present
docker_compose:
project_name: "{{ pname }}"
state: present
definition: "{{ test_service | from_yaml }}"
register: present_2
- name: Present (idempotent)
docker_compose:
project_name: "{{ pname }}"
state: present
definition: "{{ test_service | from_yaml }}"
register: present_3
- name: Present (idempotent check)
docker_compose:
project_name: "{{ pname }}"
state: present
definition: "{{ test_service | from_yaml }}"
check_mode: yes
register: present_4
- name: Present (changed check)
docker_compose:
project_name: "{{ pname }}"
state: present
definition: "{{ test_service_mod | from_yaml }}"
check_mode: yes
register: present_5
- name: Present (changed)
docker_compose:
project_name: "{{ pname }}"
state: present
definition: "{{ test_service_mod | from_yaml }}"
register: present_6
- assert:
that:
- present_1 is changed
- present_2 is changed
- present_3 is not changed
- present_4 is not changed
- present_5 is changed
- present_6 is changed
####################################################################
## Absent ##########################################################
####################################################################
- name: Absent (check)
docker_compose:
project_name: "{{ pname }}"
state: absent
definition: "{{ test_service_mod | from_yaml }}"
check_mode: yes
register: absent_1
- name: Absent
docker_compose:
project_name: "{{ pname }}"
state: absent
definition: "{{ test_service_mod | from_yaml }}"
register: absent_2
- name: Absent (idempotent)
docker_compose:
project_name: "{{ pname }}"
state: absent
definition: "{{ test_service_mod | from_yaml }}"
register: absent_3
- name: Absent (idempotent check)
docker_compose:
project_name: "{{ pname }}"
state: absent
definition: "{{ test_service_mod | from_yaml }}"
check_mode: yes
register: absent_4
- assert:
that:
- absent_1 is changed
- absent_2 is changed
- absent_3 is not changed
- absent_4 is not changed
####################################################################
## Stopping and starting ###########################################
####################################################################
- name: Present stopped (check)
docker_compose:
project_name: "{{ pname }}"
state: present
definition: "{{ test_service | from_yaml }}"
stopped: true
check_mode: yes
register: present_1
- name: Present stopped
docker_compose:
project_name: "{{ pname }}"
state: present
definition: "{{ test_service | from_yaml }}"
stopped: true
register: present_2
- name: Present stopped (idempotent)
docker_compose:
project_name: "{{ pname }}"
state: present
definition: "{{ test_service | from_yaml }}"
stopped: true
register: present_3
- name: Present stopped (idempotent check)
docker_compose:
project_name: "{{ pname }}"
state: present
definition: "{{ test_service | from_yaml }}"
stopped: true
check_mode: yes
register: present_4
- name: Started (check)
docker_compose:
project_name: "{{ pname }}"
state: present
definition: "{{ test_service | from_yaml }}"
check_mode: yes
register: started_1
- name: Started
docker_compose:
project_name: "{{ pname }}"
state: present
definition: "{{ test_service | from_yaml }}"
register: started_2
- name: Started (idempotent)
docker_compose:
project_name: "{{ pname }}"
state: present
definition: "{{ test_service | from_yaml }}"
register: started_3
- name: Started (idempotent check)
docker_compose:
project_name: "{{ pname }}"
state: present
definition: "{{ test_service | from_yaml }}"
check_mode: yes
register: started_4
- name: Stopped (check)
docker_compose:
project_name: "{{ pname }}"
state: present
definition: "{{ test_service | from_yaml }}"
stopped: true
check_mode: yes
register: stopped_1
- name: Stopped
docker_compose:
project_name: "{{ pname }}"
state: present
definition: "{{ test_service | from_yaml }}"
stopped: true
register: stopped_2
- name: Cleanup
docker_compose:
project_name: "{{ pname }}"
state: absent
definition: "{{ test_service | from_yaml }}"
- assert:
that:
- present_1 is changed
- present_2 is changed
- present_3 is not changed
- present_4 is not changed
- started_1 is changed
- started_2 is changed
- started_3 is not changed
- started_4 is not changed
- stopped_1 is changed
- stopped_2 is changed

View File

@@ -0,0 +1,2 @@
shippable/posix/group3
destructive

View File

@@ -0,0 +1,4 @@
---
dependencies:
- setup_docker
- setup_remote_tmp_dir

View File

@@ -0,0 +1,11 @@
---
####################################################################
# 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,330 @@
---
- 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}}"
- name: Parameter name should be required
docker_config:
state: present
ignore_errors: yes
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: yes
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: yes
- 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: yes
- 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: yes
- 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: yes
- 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: yes
- 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: yes
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: yes
- 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,2 @@
shippable/posix/group5
destructive

View File

@@ -0,0 +1,34 @@
# (c) 2020, Felix Fontein <felix@fontein.de>
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
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,3 @@
---
dependencies:
- setup_docker

View File

@@ -0,0 +1,62 @@
---
####################################################################
# 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 }}"
# Run the tests
- block:
- include_tasks: run-test.yml
with_fileglob:
- "tests/*.yml"
always:
- name: "Make sure all containers are removed"
docker_container:
name: "{{ item }}"
state: absent
force_kill: yes
with_items: "{{ cnames }}"
diff: no
- name: "Make sure all images are removed"
docker_image:
name: "{{ item }}"
state: absent
with_items: "{{ inames }}"
- name: "Make sure all networks are removed"
docker_network:
name: "{{ item }}"
state: absent
force: yes
with_items: "{{ dnetworks }}"
when: docker_py_version is version('1.10.0', '>=')
diff: no
when: docker_py_version is version('1.8.0', '>=') and docker_api_version is version('1.20', '>=')
- fail: msg="Too old docker / docker-py version to run all docker_container tests!"
when: not(docker_py_version is version('3.5.0', '>=') and docker_api_version is version('1.25', '>=')) and (ansible_distribution != 'CentOS' or ansible_distribution_major_version|int > 6)

View File

@@ -0,0 +1,3 @@
---
- name: "Loading tasks from {{ item }}"
include_tasks: "{{ item }}"

View File

@@ -0,0 +1,463 @@
---
- 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: yes
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: yes
comparisons:
hostname: strict
register: value_3
- name: cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: yes
diff: no
- 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: yes
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: yes
comparisons:
dns_servers: strict
register: list_3
- name: cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: yes
diff: no
- 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: yes
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: yes
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: yes
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: yes
comparisons:
groups: strict
register: set_5
- name: cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: yes
diff: no
- 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: yes
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: yes
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: yes
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: yes
comparisons:
devices: strict
register: set_dict_5
- name: cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: yes
diff: no
- 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: yes
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: yes
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: yes
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: yes
comparisons:
labels: strict
register: dict_5
- name: cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: yes
diff: no
- 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:
name: "{{ docker_test_image_hello_world }}"
source: pull
- 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: yes
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: yes
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: yes
comparisons:
'*': strict
register: wildcard_4
- name: cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: yes
diff: no
- 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,118 @@
---
- 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: yes
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: yes
register: start_4
- name: cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: yes
diff: no
- 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: yes
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: yes
register: start_4
- name: cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: yes
diff: no
- 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,151 @@
---
- name: Registering container name
set_fact:
cname: "{{ cname_prefix ~ '-iid' }}"
- name: Registering container name
set_fact:
cnames: "{{ cnames + [cname] }}"
- name: Pull images
docker_image:
name: "{{ image }}"
source: pull
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: yes
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: yes
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: yes
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: yes
register: create_4
- name: Untag image
# Image will not be deleted since the container still uses it
docker_image:
name: "{{ docker_test_image_alpine }}"
force_absent: yes
state: absent
- 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
register: create_5
check_mode: yes
- 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
register: create_6
- name: Cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: yes
diff: no
- 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: yes
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: yes
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: yes
state: present
force_kill: yes
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: yes
register: digest_4
- name: Cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: yes
diff: no
- 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,471 @@
---
- 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: no
register: mounts_1
ignore_errors: yes
- 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: no
- source: /tmp
target: /tmp
type: bind
register: mounts_2
ignore_errors: yes
- 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
ignore_errors: yes
- 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: yes
force_kill: yes
register: mounts_4
ignore_errors: yes
- 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: no
force_kill: yes
register: mounts_5
ignore_errors: yes
- 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: no
force_kill: yes
register: mounts_6
ignore_errors: yes
- 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: yes
diff: no
- 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
when: docker_py_version is version('2.6.0', '>=')
- assert:
that:
- mounts_1 is failed
- "('version is ' ~ docker_py_version ~ ' ') in mounts_1.msg"
- "'Minimum version required is 2.6.0 ' in mounts_1.msg"
when: docker_py_version is version('2.6.0', '<')
####################################################################
## 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: yes
volumes:
- /tmp:/tmp
register: mounts_volumes_1
ignore_errors: yes
- 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: yes
volumes:
- /tmp:/tmp
register: mounts_volumes_2
ignore_errors: yes
- 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: no
volumes:
- /:/whatever:ro
force_kill: yes
register: mounts_volumes_3
ignore_errors: yes
- 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: no
volumes:
- /tmp:/tmp
force_kill: yes
register: mounts_volumes_4
ignore_errors: yes
- name: cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: yes
diff: no
- 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"
when: docker_py_version is version('2.6.0', '>=')
- assert:
that:
- mounts_volumes_1 is failed
- "('version is ' ~ docker_py_version ~ ' ') in mounts_1.msg"
- "'Minimum version required is 2.6.0 ' in mounts_1.msg"
when: docker_py_version is version('2.6.0', '<')
####################################################################
## 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: yes
register: volume_driver_3
- name: cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: yes
diff: no
- 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: yes
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: yes
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: yes
register: volumes_6
ignore_errors: yes
- name: cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: yes
diff: no
- 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: yes
register: volumes_from_3
- name: cleanup
docker_container:
name: "{{ container_name }}"
state: absent
force_kill: yes
loop:
- "{{ cname }}"
- "{{ cname_h1 }}"
- "{{ cname_h2 }}"
loop_control:
loop_var: container_name
diff: no
- assert:
that:
- volumes_from_1 is changed
- volumes_from_2 is not changed
- volumes_from_3 is changed
####################################################################
####################################################################
####################################################################

View File

@@ -0,0 +1,749 @@
---
- 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
when: docker_py_version is version('1.10.0', '>=')
- 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: yes
ipam_config:
- subnet: "{{ subnet_ipv4 }}"
- subnet: "{{ subnet_ipv6 }}"
state: present
when: docker_py_version is version('1.10.0', '>=')
####################################################################
## 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: yes
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: yes
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: yes
loop:
- "{{ cname }}"
- "{{ cname_h1 }}"
loop_control:
loop_var: container_name
diff: no
- 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 #########
####################################################################
- block:
- 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: no
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: no
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
purge_networks: yes
networks:
- name: bridge
- name: "{{ nname_1 }}"
networks_cli_compatible: no
force_kill: yes
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
purge_networks: yes
networks:
- name: "{{ nname_1 }}"
- name: bridge
networks_cli_compatible: no
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: no
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
purge_networks: yes
networks:
- name: bridge
networks_cli_compatible: no
force_kill: yes
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
purge_networks: yes
networks:
- name: bridge
- name: "{{ nname_2 }}"
networks_cli_compatible: no
force_kill: yes
register: networks_7
- name: cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: yes
diff: no
- 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"
when: docker_py_version is version('1.10.0', '>=')
####################################################################
## networks for networks_cli_compatible=yes ########################
####################################################################
- block:
- 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: yes
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: yes
register: networks_2
- name: cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: yes
diff: no
- 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: yes
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: yes
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: yes
purge_networks: yes
force_kill: yes
register: networks_5
- name: cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: yes
diff: no
- 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: yes
force_kill: yes
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: yes
register: networks_7
- name: networks_cli_compatible=yes, networks not specified, purge_networks
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
networks_cli_compatible: yes
purge_networks: yes
force_kill: yes
register: networks_8
- name: cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: yes
diff: no
- 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
when: docker_py_version is version('1.10.0', '>=')
####################################################################
## networks with comparisons #######################################
####################################################################
- block:
- 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: yes
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: yes
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: yes
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: yes
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: yes
comparisons:
network_mode: ignore # otherwise we'd have to set network_mode to nname_1
networks: allow_more_present
force_kill: yes
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: yes
comparisons:
networks: strict
force_kill: yes
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: yes
comparisons:
networks: strict
force_kill: yes
register: networks_7
- name: cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: yes
diff: no
- 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
when: docker_py_version is version('1.10.0', '>=')
####################################################################
## networks with IP address ########################################
####################################################################
- block:
- 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: yes
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: yes
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: yes
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: yes
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: yes
force_kill: yes
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: yes
force_kill: yes
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: yes
register: networks_8
- name: cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: yes
diff: no
- 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
when: docker_py_version is version('1.10.0', '>=')
####################################################################
####################################################################
####################################################################
- name: Delete networks
docker_network:
name: "{{ network_name }}"
state: absent
force: yes
loop:
- "{{ nname_1 }}"
- "{{ nname_2 }}"
- "{{ nname_3 }}"
loop_control:
loop_var: network_name
when: docker_py_version is version('1.10.0', '>=')

View File

@@ -0,0 +1,427 @@
---
- 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: all ############################################
####################################################################
- name: published_ports -- all
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
exposed_ports:
- "9001"
- "9002"
published_ports:
- all
force_kill: yes
register: published_ports_1
- name: published_ports -- all (idempotency)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
exposed_ports:
- "9001"
- "9002"
published_ports:
- all
force_kill: yes
register: published_ports_2
- name: published_ports -- all (writing out 'all')
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
exposed_ports:
- "9001"
- "9002"
published_ports:
- "9001"
- "9002"
force_kill: yes
register: published_ports_3
- name: published_ports -- all (idempotency 2)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
exposed_ports:
- "9001"
- "9002"
published_ports:
- "9002"
- "9001"
force_kill: yes
register: published_ports_4
- name: published_ports -- all (switching back to 'all')
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
exposed_ports:
- "9001"
- "9002"
published_ports:
- all
force_kill: yes
register: published_ports_5
- name: published_ports -- all equivalence with publish_all_ports
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
state: started
exposed_ports:
- "9001"
- "9002"
publish_all_ports: true
force_kill: yes
register: published_ports_6
- name: cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: yes
diff: no
- assert:
that:
- published_ports_1 is changed
- published_ports_2 is not changed
- published_ports_3 is changed
- published_ports_4 is not changed
- published_ports_5 is changed
- published_ports_6 is not changed
####################################################################
## 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: yes
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: yes
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: yes
register: published_ports_3
- name: cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: yes
diff: no
- 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: yes
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: yes
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: yes
loop:
- '{{ cname }}'
- '{{ cname2 }}'
register: published_ports_3
- name: cleanup
docker_container:
name: "{{ item }}"
state: absent
force_kill: yes
loop:
- '{{ cname }}'
- '{{ cname2 }}'
diff: no
- assert:
that:
- published_ports_1 is changed
- published_ports_2 is not changed
- published_ports_3 is changed
####################################################################
## published_ports: IPv6 addresses #################################
####################################################################
- 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: yes
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: yes
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: yes
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: yes
register: published_ports_4
ignore_errors: yes
- name: cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: yes
diff: no
- 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: yes
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,34 @@
---
# 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: yes
# 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,455 @@
---
- 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: yes
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: yes
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: yes
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: yes
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: yes
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: yes
- 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: yes
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: yes
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: yes
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: yes
state: present
force_kill: yes
register: recreate_2
check_mode: yes
- name: Recreating container (created, recreate)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
recreate: yes
state: present
force_kill: yes
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: yes
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: yes
removal_wait_timeout: 10
state: started
force_kill: yes
register: recreate_5
check_mode: yes
- name: Recreating container (started, recreate)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
recreate: yes
removal_wait_timeout: 10
state: started
force_kill: yes
register: recreate_6
- name: cleanup
docker_container:
name: "{{ cname }}"
state: absent
force_kill: yes
diff: no
- 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: yes
state: started
stop_timeout: 1
force_kill: yes
register: restart_2
check_mode: yes
- name: Restarting (restart)
docker_container:
image: "{{ docker_test_image_alpine }}"
command: '/bin/sh -c "sleep 10m"'
name: "{{ cname }}"
restart: yes
state: started
stop_timeout: 1
force_kill: yes
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: yes
diff: no
- 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: yes
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: yes
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: yes
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: yes
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: yes
check_mode: yes
register: remove_from_running_1
- name: Remove container from running
docker_container:
name: "{{ cname }}"
state: absent
force_kill: yes
register: remove_from_running_2
- name: Remove container from running (idempotent)
docker_container:
name: "{{ cname }}"
state: absent
force_kill: yes
register: remove_from_running_3
- name: Remove container from running (idempotent check)
docker_container:
name: "{{ cname }}"
state: absent
force_kill: yes
check_mode: yes
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,2 @@
shippable/posix/group4
destructive

View File

@@ -0,0 +1,3 @@
---
dependencies:
- setup_docker

View File

@@ -0,0 +1,226 @@
---
####################################################################
# 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: yes
- 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: yes
- 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
- when: docker_py_version is version('2.3.0', '>=') and docker_api_version is version('1.25', '>=')
block:
- 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: yes
when: docker_py_version is version('1.8.0', '>=') and docker_api_version is version('1.20', '>=')
- fail: msg="Too old docker / docker-py version to run docker_container_exec tests!"
when: not(docker_py_version is version('1.8.0', '>=') and docker_api_version is version('1.20', '>=')) and (ansible_distribution != 'CentOS' or ansible_distribution_major_version|int > 6)

View File

@@ -0,0 +1,2 @@
shippable/posix/group5
destructive

View File

@@ -0,0 +1,3 @@
---
dependencies:
- setup_docker

View File

@@ -0,0 +1,80 @@
---
####################################################################
# 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: yes
- 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: yes
- 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: yes
- 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"
- 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: yes
when: docker_py_version is version('1.8.0', '>=') and docker_api_version is version('1.20', '>=')
- fail: msg="Too old docker / docker-py version to run docker_container_info tests!"
when: not(docker_py_version is version('1.8.0', '>=') and docker_api_version is version('1.20', '>=')) and (ansible_distribution != 'CentOS' or ansible_distribution_major_version|int > 6)

View File

@@ -0,0 +1,2 @@
shippable/posix/group4
destructive

View File

@@ -0,0 +1,3 @@
---
dependencies:
- setup_docker

View File

@@ -0,0 +1,10 @@
####################################################################
# 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_py_version is version('1.10.0', '>=') and docker_api_version is version('1.21', '>=')
- fail: msg="Too old docker / docker-py version to run docker_host_info tests!"
when: not(docker_py_version is version('1.10.0', '>=') and docker_api_version is version('1.21', '>=')) and (ansible_distribution != 'CentOS' or ansible_distribution_major_version|int > 6)

View File

@@ -0,0 +1,337 @@
---
- name: Create random container/volume name
set_fact:
cname: "{{ 'ansible-docker-test-%0x' % ((2**32) | random) }}"
vname: "{{ 'ansible-docker-test-%0x' % ((2**32) | random) }}"
- debug:
msg: "Using container name '{{ cname }}' 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'
# 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 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
- assert:
that:
- container_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: yes
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: yes
containers_filters:
label: key1=value1
register: output
- name: assert container is returned when filters are matched (single label)
assert:
that: "{{ output.containers | length }} == 1"
- name: Get info on Docker host and list containers matching filters (multiple labels)
docker_host_info:
containers: yes
containers_filters:
label:
- key1=value1
- key2=value2
register: output
- name: assert container is returned when filters are matched (multiple labels)
assert:
that: "{{ output.containers | length }} == 1"
- name: Get info on Docker host and do not list containers which do not match filters
docker_host_info:
containers: yes
containers_filters:
label:
- key1=value1
- key2=value2
- key3=value3
register: output
- name: assert no container is returned when filters are not matched
assert:
that: "{{ output.containers | length }} == 0"
- name: Get info on Docker host and list containers with verbose output
docker_host_info:
containers: yes
verbose_output: yes
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: yes
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: yes
verbose_output: yes
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: yes
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: yes
verbose_output: yes
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: yes
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: yes
verbose_output: yes
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: yes
register: output
ignore_errors: yes
- 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.BuilderSize is not defined'
when: docker_py_version is version('2.2.0', '>=')
- assert:
that:
- output is failed
- "('version is ' ~ docker_py_version ~ ' ') in output.msg"
- "'Minimum version required is 2.2.0 ' in output.msg"
when: docker_py_version is version('2.2.0', '<')
- name: Get info on Docker host and get disk usage with verbose output
docker_host_info:
disk_usage: yes
verbose_output: yes
register: output
ignore_errors: yes
- 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.BuilderSize is number'
when: docker_py_version is version('2.2.0', '>=')
- assert:
that:
- output is failed
- "('version is ' ~ docker_py_version ~ ' ') in output.msg"
- "'Minimum version required is 2.2.0 ' in output.msg"
when: docker_py_version is version('2.2.0', '<')
- name: Get info on Docker host, disk usage and get all lists together
docker_host_info:
volumes: yes
containers: yes
networks: yes
images: yes
disk_usage: "{{ docker_py_version is version('2.2.0', '>=') }}"
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'
- assert:
that:
- 'output.disk_usage.LayersSize is number'
- 'output.disk_usage.BuilderSize is not defined'
when: docker_py_version is version('2.2.0', '>=')
- name: Get info on Docker host, disk usage and get all lists together with verbose output
docker_host_info:
volumes: yes
containers: yes
networks: yes
images: yes
disk_usage: "{{ docker_py_version is version('2.2.0', '>=') }}"
verbose_output: yes
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'
- assert:
that:
- 'output.disk_usage.LayersSize is number'
- 'output.disk_usage.BuilderSize is number'
when: docker_py_version is version('2.2.0', '>=')
always:
- name: Delete container
docker_container:
name: "{{ cname }}"
state: absent
force_kill: yes
- name: Delete volume
docker_volume:
name: "{{ vname }}"
state: absent

View File

@@ -0,0 +1,2 @@
shippable/posix/group4
destructive

View File

@@ -0,0 +1,4 @@
---
dependencies:
- setup_docker_registry
- setup_remote_tmp_dir

View File

@@ -0,0 +1,8 @@
####################################################################
# 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,3 @@
---
- name: "Loading tasks from {{ item }}"
include_tasks: "{{ item }}"

View File

@@ -0,0 +1,49 @@
---
- 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:
- Dockerfile
- EtcHostsDockerfile
- MyDockerfile
- StagedDockerfile
- block:
- include_tasks: run-test.yml
with_fileglob:
- "tests/*.yml"
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: yes
with_items: "{{ cnames }}"
when: docker_py_version is version('1.8.0', '>=') and docker_api_version is version('1.20', '>=')
- fail: msg="Too old docker / docker-py version to run docker_image tests!"
when: not(docker_py_version is version('1.8.0', '>=') and docker_api_version is version('1.20', '>=')) and (ansible_distribution != 'CentOS' or ansible_distribution_major_version|int > 6)

View File

@@ -0,0 +1,135 @@
---
####################################################################
## basic ###########################################################
####################################################################
- name: Make sure image is not there
docker_image:
name: "{{ docker_test_image_hello_world }}"
state: absent
force_absent: yes
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: yes
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: buildargs
docker_image:
source: build
name: "{{ present_1.image.Id }}"
build:
path: "{{ remote_tmp_dir }}/files"
force_source: true
register: fail_4
ignore_errors: yes
- 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,255 @@
---
- name: Registering image name
set_fact:
iname: "{{ name_prefix ~ '-options' }}"
- name: Determining pushed image names
set_fact:
hello_world_image_base: "{{ registry_address }}/test/hello-world"
test_image_base: "{{ registry_address }}/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: Make sure image is not there
docker_image:
name: "{{ hello_world_image_base }}:latest"
state: absent
force_absent: yes
- 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: yes
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: yes
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: yes
source: local
force_tag: yes
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: yes
- 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: "{{ facts_3.images[0].RepoDigests[0] }}"
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: no
source: pull
- name: Push different image with new tag
docker_image:
name: "{{ hello_world_image_base }}"
repository: "{{ hello_world_image_base }}"
tag: newtag
push: yes
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: yes
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: no
source: pull
- name: Push same image with new tag
docker_image:
name: "{{ hello_world_image_base }}"
repository: "{{ hello_world_image_base }}"
tag: newtag2
push: yes
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: yes
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: yes
- name: repository
docker_image:
name: "{{ iname }}"
build:
path: "{{ remote_tmp_dir }}/files"
pull: no
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: yes
- assert:
that:
- facts_1.images | length == 1

View File

@@ -0,0 +1,404 @@
---
- name: Registering image name
set_fact:
iname: "{{ name_prefix ~ '-options' }}"
iname_1: "{{ name_prefix ~ '-options-1' }}"
- name: Registering image name
set_fact:
inames: "{{ inames + [iname, iname_1] }}"
####################################################################
## build.args ######################################################
####################################################################
- name: cleanup
docker_image:
name: "{{ iname }}"
state: absent
force_absent: yes
- name: buildargs
docker_image:
name: "{{ iname }}"
build:
path: "{{ remote_tmp_dir }}/files"
args:
TEST1: val1
TEST2: val2
TEST3: "True"
pull: no
source: build
register: buildargs_1
ignore_errors: yes
- name: buildargs (idempotency)
docker_image:
name: "{{ iname }}"
build:
path: "{{ remote_tmp_dir }}/files"
args:
TEST1: val1
TEST2: val2
TEST3: "True"
pull: no
source: build
register: buildargs_2
ignore_errors: yes
- name: cleanup
docker_image:
name: "{{ iname }}"
state: absent
force_absent: yes
- assert:
that:
- buildargs_1 is changed
- buildargs_2 is not failed and buildargs_2 is not changed
when: docker_py_version is version('1.6.0', '>=')
- assert:
that:
- buildargs_1 is failed
- buildargs_2 is failed
when: docker_py_version is version('1.6.0', '<')
####################################################################
## 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: 4000
pull: no
source: build
ignore_errors: yes
register: container_limits_1
- name: container_limits
docker_image:
name: "{{ iname }}"
build:
path: "{{ remote_tmp_dir }}/files"
container_limits:
memory: 7000000
memswap: 8000000
pull: no
source: build
register: container_limits_2
- name: cleanup
docker_image:
name: "{{ iname }}"
state: absent
force_absent: yes
- 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: no
source: build
register: dockerfile_1
- name: cleanup
docker_image:
name: "{{ iname }}"
state: absent
force_absent: yes
- 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: yes
- name: build.platform
docker_image:
name: "{{ iname }}"
build:
path: "{{ remote_tmp_dir }}/files"
platform: linux
pull: no
source: build
register: platform_1
ignore_errors: yes
- name: build.platform (idempotency)
docker_image:
name: "{{ iname }}"
build:
path: "{{ remote_tmp_dir }}/files"
platform: linux
pull: no
source: build
register: platform_2
ignore_errors: yes
- name: cleanup
docker_image:
name: "{{ iname }}"
state: absent
force_absent: yes
- assert:
that:
- platform_1 is changed
- platform_2 is not failed and platform_2 is not changed
when: docker_py_version is version('3.0.0', '>=')
- assert:
that:
- platform_1 is failed
- platform_2 is failed
when: docker_py_version is version('3.0.0', '<')
####################################################################
## force ###########################################################
####################################################################
- name: Build an image
docker_image:
name: "{{ iname }}"
build:
path: "{{ remote_tmp_dir }}/files"
pull: no
source: build
- name: force (changed)
docker_image:
name: "{{ iname }}"
build:
path: "{{ remote_tmp_dir }}/files"
dockerfile: "MyDockerfile"
pull: no
source: build
force_source: yes
register: force_1
- name: force (unchanged)
docker_image:
name: "{{ iname }}"
build:
path: "{{ remote_tmp_dir }}/files"
dockerfile: "MyDockerfile"
pull: no
source: build
force_source: yes
register: force_2
- name: cleanup
docker_image:
name: "{{ iname }}"
state: absent
force_absent: yes
- 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
- 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: yes
- 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 (invalid image, old API version)
docker_image:
name: foo:bar
load_path: "{{ remote_tmp_dir }}/image-invalid.tar"
source: load
api_version: "1.22"
register: load_image_4
- 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_5
- 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 changed
- "'The API version of your Docker daemon is < 1.23, which does not return the image loading result from the Docker daemon. Therefore, we cannot verify whether the expected image was loaded, whether multiple images where loaded, or whether the load actually succeeded. You should consider upgrading your Docker daemon.' in load_image_4.warnings"
- load_image_5 is not changed
####################################################################
## build.path ######################################################
####################################################################
- name: Build image
docker_image:
name: "{{ iname }}"
build:
path: "{{ remote_tmp_dir }}/files"
pull: no
source: build
register: path_1
- name: Build image (idempotency)
docker_image:
name: "{{ iname }}"
build:
path: "{{ remote_tmp_dir }}/files"
pull: no
source: build
register: path_2
- name: cleanup
docker_image:
name: "{{ iname }}"
state: absent
force_absent: yes
- 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: no
source: build
register: dockerfile_2
- name: cleanup
docker_image:
name: "{{ iname }}"
state: absent
force_absent: yes
- 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: no
etc_hosts:
some-custom-host: "127.0.0.1"
source: build
register: path_1
- name: cleanup
docker_image:
name: "{{ iname }}"
state: absent
force_absent: yes
- assert:
that:
- path_1 is changed

View File

@@ -0,0 +1,3 @@
FROM {{ docker_test_image_busybox }}
ENV foo /bar
WORKDIR ${foo}

View File

@@ -0,0 +1,3 @@
FROM {{ docker_test_image_busybox }}
# This should fail building if docker cannot resolve some-custom-host
RUN ping -c1 some-custom-host

View File

@@ -0,0 +1,5 @@
FROM {{ docker_test_image_alpine }}
ENV INSTALL_PATH /newdata
RUN mkdir -p $INSTALL_PATH
WORKDIR $INSTALL_PATH

View File

@@ -0,0 +1,7 @@
FROM {{ docker_test_image_busybox }} AS first
ENV dir /first
WORKDIR ${dir}
FROM {{ docker_test_image_busybox }} AS second
ENV dir /second
WORKDIR ${dir}

View File

@@ -0,0 +1,2 @@
shippable/posix/group4
destructive

View File

@@ -0,0 +1,3 @@
---
dependencies:
- setup_docker

View File

@@ -0,0 +1,59 @@
---
####################################################################
# WARNING: These are designed specifically for Ansible tests #
# and should not be used as examples of how to write Ansible roles #
####################################################################
- block:
- name: Make sure image is not there
docker_image:
name: "{{ docker_test_image_alpine_different }}"
state: absent
- name: Inspect a non-available image
docker_image_info:
name: "{{ docker_test_image_alpine_different }}"
register: result
- assert:
that:
- "result.images|length == 0"
- name: Make sure images are there
docker_image:
name: "{{ item }}"
source: pull
state: present
loop:
- "{{ docker_test_image_hello_world }}"
- "{{ docker_test_image_alpine }}"
- name: Inspect an available image
docker_image_info:
name: "{{ docker_test_image_hello_world }}"
register: result
- assert:
that:
- "result.images|length == 1"
- "docker_test_image_hello_world in result.images[0].RepoTags"
- name: Inspect multiple images
docker_image_info:
name:
- "{{ docker_test_image_hello_world }}"
- "{{ docker_test_image_alpine }}"
register: result
- debug: var=result
- assert:
that:
- "result.images|length == 2"
- "docker_test_image_hello_world in result.images[0].RepoTags"
- "docker_test_image_alpine in result.images[1].RepoTags"
when: docker_py_version is version('1.8.0', '>=') and docker_api_version is version('1.20', '>=')
- fail: msg="Too old docker / docker-py version to run docker_image_info tests!"
when: not(docker_py_version is version('1.8.0', '>=') and docker_api_version is version('1.20', '>=')) and (ansible_distribution != 'CentOS' or ansible_distribution_major_version|int > 6)

View File

@@ -0,0 +1,2 @@
shippable/posix/group4
destructive

View File

@@ -0,0 +1,4 @@
---
dependencies:
- setup_docker
- setup_remote_tmp_dir

View File

@@ -0,0 +1,8 @@
####################################################################
# 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,3 @@
---
- name: "Loading tasks from {{ item }}"
include_tasks: "{{ item }}"

View File

@@ -0,0 +1,34 @@
---
- 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 }}"
- block:
- include_tasks: run-test.yml
with_fileglob:
- "tests/*.yml"
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: yes
with_items: "{{ cnames }}"
when: docker_py_version is version('2.5.0', '>=') and docker_api_version is version('1.23', '>=')
- fail: msg="Too old docker / docker-py version to run docker_image tests!"
when: not(docker_py_version is version('2.5.0', '>=') and docker_api_version is version('1.23', '>=')) and (ansible_distribution != 'CentOS' or ansible_distribution_major_version|int > 6)

View File

@@ -0,0 +1,213 @@
---
- set_fact:
image_names:
- "{{ docker_test_image_hello_world }}"
- "{{ docker_test_image_alpine_different }}"
- "{{ docker_test_image_alpine }}"
- name: Make sure images are there
docker_image:
name: "{{ item }}"
source: pull
register: images
loop: "{{ image_names }}"
- name: Compile list of all image names and IDs
set_fact:
image_ids: "{{ images.results | map(attribute='image') | map(attribute='Id') | list }}"
all_images: "{{ image_names + (images.results | map(attribute='image') | map(attribute='Id') | list) }}"
- name: Create archives
command: docker save {{ item.images | join(' ') }} -o {{ remote_tmp_dir }}/{{ item.file }}
loop:
- file: archive-1.tar
images: "{{ image_names }}"
- file: archive-2.tar
images: "{{ image_ids }}"
- file: archive-3.tar
images:
- "{{ image_names[0] }}"
- "{{ image_ids[1] }}"
- file: archive-4.tar
images:
- "{{ image_ids[0] }}"
- "{{ image_names[0] }}"
- file: archive-5.tar
images:
- "{{ image_ids[0] }}"
# All images by IDs
- name: Remove all images
docker_image:
name: "{{ item }}"
state: absent
force_absent: true
loop: "{{ all_images }}"
ignore_errors: true
register: remove_all_images
- name: Prune all containers (if removing failed)
docker_prune:
containers: true
when: remove_all_images is failed
- name: Obtain all docker containers and images (if removing failed)
shell: docker ps -a ; docker images -a
when: remove_all_images is failed
register: docker_container_image_list
- name: Show all docker containers and images (if removing failed)
debug:
var: docker_container_image_list.stdout_lines
when: remove_all_images is failed
- name: Remove all images (after pruning)
docker_image:
name: "{{ item }}"
state: absent
force_absent: true
loop: "{{ all_images }}"
when: remove_all_images is failed
- name: Load all images (IDs)
docker_image_load:
path: "{{ remote_tmp_dir }}/archive-2.tar"
register: result
- name: Print loaded image names
debug:
var: result.image_names
- assert:
that:
- result is changed
- result.image_names | sort == image_ids | sort
- result.image_names | length == result.images | length
- name: Load all images (IDs, should be same result)
docker_image_load:
path: "{{ remote_tmp_dir }}/archive-2.tar"
register: result_2
- name: Print loaded image names
debug:
var: result_2.image_names
- assert:
that:
- result_2 is changed
- result_2.image_names | sort == image_ids | sort
- result_2.image_names | length == result_2.images | length
# Mixed images and IDs
- name: Remove all images
docker_image:
name: "{{ item }}"
state: absent
loop: "{{ all_images }}"
- name: Load all images (mixed images and IDs)
docker_image_load:
path: "{{ remote_tmp_dir }}/archive-3.tar"
register: result
- name: Print loading log
debug:
var: result.stdout_lines
- name: Print loaded image names
debug:
var: result.image_names
- assert:
that:
- result is changed
# For some reason, *sometimes* only the named image is found; in fact, in that case, the log only mentions that image and nothing else
- "result.images | length == 3 or ('Loaded image: ' ~ docker_test_image_hello_world) == result.stdout"
- (result.image_names | sort) in [[image_names[0], image_ids[0], image_ids[1]] | sort, [image_names[0]]]
- result.images | length in [1, 3]
- (result.images | map(attribute='Id') | sort) in [[image_ids[0], image_ids[0], image_ids[1]] | sort, [image_ids[0]]]
# Same image twice
- name: Remove all images
docker_image:
name: "{{ item }}"
state: absent
loop: "{{ all_images }}"
- name: Load all images (same image twice)
docker_image_load:
path: "{{ remote_tmp_dir }}/archive-4.tar"
register: result
- name: Print loaded image names
debug:
var: result.image_names
- assert:
that:
- result is changed
- result.image_names | length == 1
- result.image_names[0] == image_names[0]
- result.images | length == 1
- result.images[0].Id == image_ids[0]
# Single image by ID
- name: Remove all images
docker_image:
name: "{{ item }}"
state: absent
loop: "{{ all_images }}"
- name: Load all images (single image by ID)
docker_image_load:
path: "{{ remote_tmp_dir }}/archive-5.tar"
register: result
- name: Print loaded image names
debug:
var: result.image_names
- assert:
that:
- result is changed
- result.image_names | length == 1
- result.image_names[0] == image_ids[0]
- result.images | length == 1
- result.images[0].Id == image_ids[0]
- name: Try to get image info by name
docker_image_info:
name: "{{ image_names[0] }}"
register: result
- name: Make sure that image does not exist by name
assert:
that:
- result.images | length == 0
# All images by names
- name: Remove all images
docker_image:
name: "{{ item }}"
state: absent
loop: "{{ all_images }}"
- name: Load all images (names)
docker_image_load:
path: "{{ remote_tmp_dir }}/archive-1.tar"
register: result
- name: Print loaded image names
debug:
var: result.image_names
- assert:
that:
- result.image_names | sort == image_names | sort
- result.image_names | length == result.images | length

View File

@@ -0,0 +1,2 @@
shippable/posix/group4
destructive

View File

@@ -0,0 +1,3 @@
---
dependencies:
- setup_docker_registry

View File

@@ -0,0 +1,9 @@
---
####################################################################
# 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,3 @@
---
- name: "Loading tasks from {{ item }}"
include_tasks: "{{ item }}"

View File

@@ -0,0 +1,9 @@
---
- block:
- include_tasks: run-test.yml
with_fileglob:
- "tests/*.yml"
when: docker_py_version is version('1.8.0', '>=') and docker_api_version is version('1.20', '>=')
- fail: msg="Too old docker / docker-py version to run docker_image tests!"
when: not(docker_py_version is version('1.8.0', '>=') and docker_api_version is version('1.20', '>=')) and (ansible_distribution != 'CentOS' or ansible_distribution_major_version|int > 6)

View File

@@ -0,0 +1,146 @@
---
- block:
- name: Log out server
docker_login:
registry_url: "{{ registry_frontend_address }}"
username: testuser
password: hunter2
state: absent
- name: Log in with wrong password (check mode)
docker_login:
registry_url: "{{ registry_frontend_address }}"
username: testuser
password: "1234"
state: present
register: login_failed_check
ignore_errors: yes
check_mode: yes
- name: Log in with wrong password
docker_login:
registry_url: "{{ registry_frontend_address }}"
username: testuser
password: "1234"
state: present
register: login_failed
ignore_errors: yes
- name: Make sure that login failed
assert:
that:
- login_failed_check is failed
- "('login attempt to http://' ~ registry_frontend_address ~ '/v2/ failed') in login_failed_check.msg"
- login_failed is failed
- "('login attempt to http://' ~ registry_frontend_address ~ '/v2/ failed') in login_failed.msg"
- name: Log in (check mode)
docker_login:
registry_url: "{{ registry_frontend_address }}"
username: testuser
password: hunter2
state: present
register: login_1
check_mode: yes
- name: Log in
docker_login:
registry_url: "{{ registry_frontend_address }}"
username: testuser
password: hunter2
state: present
register: login_2
- name: Get permissions of ~/.docker/config.json
stat:
path: ~/.docker/config.json
register: login_2_stat
- name: Log in (idempotent)
docker_login:
registry_url: "{{ registry_frontend_address }}"
username: testuser
password: hunter2
state: present
register: login_3
- name: Log in (idempotent, check mode)
docker_login:
registry_url: "{{ registry_frontend_address }}"
username: testuser
password: hunter2
state: present
register: login_4
check_mode: yes
- name: Make sure that login worked
assert:
that:
- login_1 is changed
- login_2 is changed
- login_3 is not changed
- login_4 is not changed
- login_2_stat.stat.mode == '0600'
- name: Log in again with wrong password (check mode)
docker_login:
registry_url: "{{ registry_frontend_address }}"
username: testuser
password: "1234"
state: present
register: login_failed_check
ignore_errors: yes
check_mode: yes
- name: Log in again with wrong password
docker_login:
registry_url: "{{ registry_frontend_address }}"
username: testuser
password: "1234"
state: present
register: login_failed
ignore_errors: yes
- name: Make sure that login failed again
assert:
that:
- login_failed_check is failed
- "('login attempt to http://' ~ registry_frontend_address ~ '/v2/ failed') in login_failed_check.msg"
- login_failed is failed
- "('login attempt to http://' ~ registry_frontend_address ~ '/v2/ failed') in login_failed.msg"
- name: Log out (check mode)
docker_login:
registry_url: "{{ registry_frontend_address }}"
state: absent
register: logout_1
check_mode: yes
- name: Log out
docker_login:
registry_url: "{{ registry_frontend_address }}"
state: absent
register: logout_2
- name: Log out (idempotent)
docker_login:
registry_url: "{{ registry_frontend_address }}"
state: absent
register: logout_3
- name: Log out (idempotent, check mode)
docker_login:
registry_url: "{{ registry_frontend_address }}"
state: absent
register: logout_4
check_mode: yes
- name: Make sure that login worked
assert:
that:
- logout_1 is changed
- logout_2 is changed
- logout_3 is not changed
- logout_4 is not changed
when: registry_frontend_address != 'n/a'

View File

@@ -0,0 +1,57 @@
---
- block:
- name: Log out server 1
docker_login:
registry_url: "{{ registry_frontend_address }}"
username: testuser
password: hunter2
state: absent
- name: Log out server 2
docker_login:
registry_url: "{{ registry_frontend2_address }}"
username: testuser
password: hunter2
state: absent
- name: Log in server 1
docker_login:
registry_url: "{{ registry_frontend_address }}"
username: testuser
password: hunter2
state: present
register: login_1
- name: Log in server 2
docker_login:
registry_url: "{{ registry_frontend2_address }}"
username: testuser
password: hunter2
state: present
register: login_2
- name: Log in server 1 (idempotent)
docker_login:
registry_url: "{{ registry_frontend_address }}"
username: testuser
password: hunter2
state: present
register: login_1_2
- name: Log in server 2 (idempotent)
docker_login:
registry_url: "{{ registry_frontend2_address }}"
username: testuser
password: hunter2
state: present
register: login_2_2
- name: Make sure that login worked
assert:
that:
- login_1 is changed
- login_2 is changed
- login_1_2 is not changed
- login_2_2 is not changed
when: registry_frontend_address != 'n/a' and registry_frontend2_address != 'n/a'

View File

@@ -0,0 +1,2 @@
shippable/posix/group4
destructive

View File

@@ -0,0 +1,3 @@
---
dependencies:
- setup_docker

View File

@@ -0,0 +1,48 @@
---
####################################################################
# WARNING: These are designed specifically for Ansible tests #
# and should not be used as examples of how to write Ansible roles #
####################################################################
- name: List inspection results for all docker networks
docker_host_info:
networks: true
verbose_output: true
register: all_networks
- name: Show inspection results for all docker networks
debug:
var: all_networks.networks
- name: Create random name prefix
set_fact:
name_prefix: "{{ 'ansible-docker-test-%0x' % ((2**32) | random) }}"
cnames: []
dnetworks: []
- debug:
msg: "Using name prefix {{ name_prefix }}"
- block:
- include_tasks: run-test.yml
with_fileglob:
- "tests/*.yml"
always:
- name: "Make sure all containers are removed"
docker_container:
name: "{{ item }}"
state: absent
force_kill: yes
loop: "{{ cnames }}"
- name: "Make sure all networks are removed"
docker_network:
name: "{{ item }}"
state: absent
force: yes
loop: "{{ dnetworks }}"
when: docker_py_version is version('1.10.0', '>=') and docker_api_version is version('1.20', '>=') # FIXME: find out API version!
- fail: msg="Too old docker / docker-py version to run docker_network tests!"
when: not(docker_py_version is version('1.10.0', '>=') and docker_api_version is version('1.20', '>=')) and (ansible_distribution != 'CentOS' or ansible_distribution_major_version|int > 6)

View File

@@ -0,0 +1,3 @@
---
- name: "Loading tasks from {{ item }}"
include_tasks: "{{ item }}"

View File

@@ -0,0 +1,134 @@
---
- name: Registering container and network names
set_fact:
cname_1: "{{ name_prefix ~ '-container-1' }}"
cname_2: "{{ name_prefix ~ '-container-2' }}"
cname_3: "{{ name_prefix ~ '-container-3' }}"
nname_1: "{{ name_prefix ~ '-network-1' }}"
nname_2: "{{ name_prefix ~ '-network-2' }}"
- name: Registering container and network names
set_fact:
cnames: "{{ cnames + [cname_1, cname_2, cname_3] }}"
dnetworks: "{{ dnetworks + [nname_1, nname_2] }}"
- name: Create containers
docker_container:
name: "{{ container_name }}"
image: "{{ docker_test_image_alpine }}"
command: /bin/sleep 10m
state: started
loop:
- "{{ cname_1 }}"
- "{{ cname_2 }}"
- "{{ cname_3 }}"
loop_control:
loop_var: container_name
####################################################################
- name: Create network
docker_network:
name: "{{ nname_1 }}"
state: present
register: networks_1
- name: Connect network to containers 1
docker_network:
name: "{{ nname_1 }}"
state: present
connected:
- "{{ cname_1 }}"
register: networks_2
- name: Connect network to containers 1 (idempotency)
docker_network:
name: "{{ nname_1 }}"
state: present
connected:
- "{{ cname_1 }}"
register: networks_2_idem
- name: Connect network to containers 1 and 2
docker_network:
name: "{{ nname_1 }}"
state: present
connected:
- "{{ cname_1 }}"
- "{{ cname_2 }}"
register: networks_3
- name: Connect network to containers 1 and 2 (idempotency)
docker_network:
name: "{{ nname_1 }}"
state: present
connected:
- "{{ cname_1 }}"
- "{{ cname_2 }}"
register: networks_3_idem
- name: Connect network to container 3
docker_network:
name: "{{ nname_1 }}"
state: present
connected:
- "{{ cname_3 }}"
appends: yes
register: networks_4
- name: Connect network to container 3 (idempotency)
docker_network:
name: "{{ nname_1 }}"
state: present
connected:
- "{{ cname_3 }}"
appends: yes
register: networks_4_idem
- name: Disconnect network from container 1
docker_network:
name: "{{ nname_1 }}"
state: present
connected:
- "{{ cname_2 }}"
- "{{ cname_3 }}"
register: networks_5
- name: Disconnect network from container 1 (idempotency)
docker_network:
name: "{{ nname_1 }}"
state: present
connected:
- "{{ cname_2 }}"
- "{{ cname_3 }}"
register: networks_5_idem
- name: Cleanup
docker_network:
name: "{{ nname_1 }}"
state: absent
- assert:
that:
- networks_1 is changed
- networks_2 is changed
- networks_2_idem is not changed
- networks_3 is changed
- networks_3_idem is not changed
- networks_4 is changed
- networks_4_idem is not changed
- networks_5 is changed
- networks_5_idem is not changed
####################################################################
- name: Delete containers
docker_container:
name: "{{ container_name }}"
state: absent
force_kill: yes
loop:
- "{{ cname_1 }}"
- "{{ cname_2 }}"
- "{{ cname_3 }}"
loop_control:
loop_var: container_name

View File

@@ -0,0 +1,312 @@
---
- name: Registering network names
set_fact:
nname_ipam_0: "{{ name_prefix ~ '-network-ipam-0' }}"
nname_ipam_1: "{{ name_prefix ~ '-network-ipam-1' }}"
nname_ipam_2: "{{ name_prefix ~ '-network-ipam-2' }}"
nname_ipam_3: "{{ name_prefix ~ '-network-ipam-3' }}"
- name: Registering network names
set_fact:
dnetworks: "{{ dnetworks + [nname_ipam_0, nname_ipam_1, nname_ipam_2, nname_ipam_3] }}"
#################### IPv4 IPAM config ####################
- name: Create network with custom IPAM config
docker_network:
name: "{{ nname_ipam_1 }}"
ipam_config:
- subnet: 10.25.120.0/24
gateway: 10.25.120.2
iprange: 10.25.120.0/26
aux_addresses:
host1: 10.25.120.3
host2: 10.25.120.4
register: network
- assert:
that:
- network is changed
- name: Create network with custom IPAM config (idempotence)
docker_network:
name: "{{ nname_ipam_1 }}"
ipam_config:
- subnet: 10.25.120.0/24
gateway: 10.25.120.2
iprange: 10.25.120.0/26
aux_addresses:
host1: 10.25.120.3
host2: 10.25.120.4
register: network
- assert:
that:
- network is not changed
- name: Change of network created with custom IPAM config
docker_network:
name: "{{ nname_ipam_1 }}"
ipam_config:
- subnet: 10.25.121.0/24
gateway: 10.25.121.2
iprange: 10.25.121.0/26
aux_addresses:
host1: 10.25.121.3
register: network
diff: yes
- assert:
that:
- network is changed
- network.diff.differences | length == 4
- '"ipam_config[0].subnet" in network.diff.differences'
- '"ipam_config[0].gateway" in network.diff.differences'
- '"ipam_config[0].iprange" in network.diff.differences'
- '"ipam_config[0].aux_addresses" in network.diff.differences'
- name: Remove gateway and iprange of network with custom IPAM config
docker_network:
name: "{{ nname_ipam_1 }}"
ipam_config:
- subnet: 10.25.121.0/24
register: network
- assert:
that:
- network is not changed
- name: Cleanup network with custom IPAM config
docker_network:
name: "{{ nname_ipam_1 }}"
state: absent
#################### IPv6 IPAM config ####################
- name: Create network with IPv6 IPAM config
docker_network:
name: "{{ nname_ipam_2 }}"
enable_ipv6: yes
ipam_config:
- subnet: fdd1:ac8c:0557:7ce0::/64
register: network
- assert:
that:
- network is changed
- name: Create network with IPv6 IPAM config (idempotence)
docker_network:
name: "{{ nname_ipam_2 }}"
enable_ipv6: yes
ipam_config:
- subnet: fdd1:ac8c:0557:7ce0::/64
register: network
- assert:
that:
- network is not changed
- name: Change subnet of network with IPv6 IPAM config
docker_network:
name: "{{ nname_ipam_2 }}"
enable_ipv6: yes
ipam_config:
- subnet: fdd1:ac8c:0557:7ce1::/64
register: network
diff: yes
- assert:
that:
- network is changed
- network.diff.differences | length == 1
- network.diff.differences[0] == "ipam_config[0].subnet"
- name: Change subnet of network with IPv6 IPAM config
docker_network:
name: "{{ nname_ipam_2 }}"
enable_ipv6: yes
ipam_config:
- subnet: "fdd1:ac8c:0557:7ce1::"
register: network
ignore_errors: yes
- assert:
that:
- network is failed
- "network.msg == '\"fdd1:ac8c:0557:7ce1::\" is not a valid CIDR'"
- name: Cleanup network with IPv6 IPAM config
docker_network:
name: "{{ nname_ipam_2 }}"
state: absent
#################### IPv4 and IPv6 network ####################
- name: Create network with IPv6 and custom IPv4 IPAM config
docker_network:
name: "{{ nname_ipam_3 }}"
enable_ipv6: yes
ipam_config:
- subnet: 10.26.120.0/24
- subnet: fdd1:ac8c:0557:7ce2::/64
register: network
- assert:
that:
- network is changed
- name: Change subnet order of network with IPv6 and custom IPv4 IPAM config (idempotence)
docker_network:
name: "{{ nname_ipam_3 }}"
enable_ipv6: yes
ipam_config:
- subnet: fdd1:ac8c:0557:7ce2::/64
- subnet: 10.26.120.0/24
register: network
- assert:
that:
- network is not changed
- name: Remove IPv6 from network with custom IPv4 and IPv6 IPAM config (change)
docker_network:
name: "{{ nname_ipam_3 }}"
enable_ipv6: no
ipam_config:
- subnet: 10.26.120.0/24
register: network
diff: yes
- assert:
that:
- network is changed
- network.diff.differences | length == 1
- network.diff.differences[0] == "enable_ipv6"
- name: Cleanup network with IPv6 and custom IPv4 IPAM config
docker_network:
name: "{{ nname_ipam_3 }}"
state: absent
#################### multiple IPv4 networks ####################
- block:
- name: Create network with two IPv4 IPAM configs
docker_network:
name: "{{ nname_ipam_3 }}"
driver: "macvlan"
driver_options:
parent: "{{ ansible_default_ipv4.alias }}"
ipam_config:
- subnet: 10.26.120.0/24
- subnet: 10.26.121.0/24
register: network
- assert:
that:
- network is changed
- name: Create network with two IPv4 IPAM configs (idempotence)
docker_network:
name: "{{ nname_ipam_3 }}"
driver: "macvlan"
driver_options:
parent: "{{ ansible_default_ipv4.alias }}"
ipam_config:
- subnet: 10.26.121.0/24
- subnet: 10.26.120.0/24
register: network
- assert:
that:
- network is not changed
- name: Create network with two IPv4 IPAM configs (change)
docker_network:
name: "{{ nname_ipam_3 }}"
driver: "macvlan"
driver_options:
parent: "{{ ansible_default_ipv4.alias }}"
ipam_config:
- subnet: 10.26.120.0/24
- subnet: 10.26.122.0/24
register: network
diff: yes
- assert:
that:
- network is changed
- network.diff.differences | length == 1
- name: Create network with one IPv4 IPAM config (no change)
docker_network:
name: "{{ nname_ipam_3 }}"
driver: "macvlan"
driver_options:
parent: "{{ ansible_default_ipv4.alias }}"
ipam_config:
- subnet: 10.26.122.0/24
register: network
- assert:
that:
- network is not changed
- name: Cleanup network
docker_network:
name: "{{ nname_ipam_3 }}"
state: absent
when: ansible_facts.virtualization_type != 'docker'
#################### IPAM driver options ####################
- name: Create network with IPAM driver options
docker_network:
name: "{{ nname_ipam_3 }}"
ipam_driver: default
ipam_driver_options:
a: b
register: network_1
ignore_errors: yes
- name: Create network with IPAM driver options (idempotence)
docker_network:
name: "{{ nname_ipam_3 }}"
ipam_driver: default
ipam_driver_options:
a: b
diff: yes
register: network_2
ignore_errors: yes
- name: Create network with IPAM driver options (change)
docker_network:
name: "{{ nname_ipam_3 }}"
ipam_driver: default
ipam_driver_options:
a: c
diff: yes
register: network_3
ignore_errors: yes
- name: Cleanup network
docker_network:
name: "{{ nname_ipam_3 }}"
state: absent
- assert:
that:
- network_1 is changed
- network_2 is not changed
- network_3 is changed
when: docker_py_version is version('2.0.0', '>=')
- assert:
that:
- network_1 is failed
- "('version is ' ~ docker_py_version ~ ' ') in network_1.msg"
- "'Minimum version required is 2.0.0 ' in network_1.msg"
when: docker_py_version is version('2.0.0', '<')

View File

@@ -0,0 +1,240 @@
---
- name: Registering network name
set_fact:
nname_1: "{{ name_prefix ~ '-network-1' }}"
- name: Registering network name
set_fact:
dnetworks: "{{ dnetworks + [nname_1] }}"
####################################################################
## internal ########################################################
####################################################################
- name: internal
docker_network:
name: "{{ nname_1 }}"
internal: yes
register: internal_1
- name: internal (idempotency)
docker_network:
name: "{{ nname_1 }}"
internal: yes
register: internal_2
- name: internal (change)
docker_network:
name: "{{ nname_1 }}"
internal: no
register: internal_3
- name: cleanup
docker_network:
name: "{{ nname_1 }}"
state: absent
force: yes
- assert:
that:
- internal_1 is changed
- internal_2 is not changed
- internal_3 is changed
####################################################################
## driver_options ##################################################
####################################################################
- name: driver_options
docker_network:
name: "{{ nname_1 }}"
driver_options:
com.docker.network.bridge.enable_icc: 'false'
register: driver_options_1
- name: driver_options (idempotency)
docker_network:
name: "{{ nname_1 }}"
driver_options:
com.docker.network.bridge.enable_icc: 'false'
register: driver_options_2
- name: driver_options (idempotency with string translation)
docker_network:
name: "{{ nname_1 }}"
driver_options:
com.docker.network.bridge.enable_icc: False
register: driver_options_3
- name: driver_options (change)
docker_network:
name: "{{ nname_1 }}"
driver_options:
com.docker.network.bridge.enable_icc: 'true'
register: driver_options_4
- name: driver_options (idempotency with string translation)
docker_network:
name: "{{ nname_1 }}"
driver_options:
com.docker.network.bridge.enable_icc: True
register: driver_options_5
- name: cleanup
docker_network:
name: "{{ nname_1 }}"
state: absent
force: yes
- assert:
that:
- driver_options_1 is changed
- driver_options_2 is not changed
- driver_options_3 is not changed
- driver_options_4 is changed
- driver_options_5 is not changed
####################################################################
## scope ###########################################################
####################################################################
- block:
- name: scope
docker_network:
name: "{{ nname_1 }}"
driver: bridge
scope: local
register: scope_1
- name: scope (idempotency)
docker_network:
name: "{{ nname_1 }}"
driver: bridge
scope: local
register: scope_2
- name: swarm
docker_swarm:
state: present
advertise_addr: "{{ansible_default_ipv4.address}}"
# Driver change alongside scope is intentional - bridge doesn't appear to support anything but local, and overlay can't downgrade to local. Additionally, overlay reports as swarm for swarm OR global, so no change is reported in that case.
# Test output indicates that the scope is altered, at least, so manual inspection will be required to verify this going forward, unless we come up with a test driver that supports multiple scopes.
- name: scope (change)
docker_network:
name: "{{ nname_1 }}"
driver: overlay
scope: swarm
register: scope_3
- name: cleanup network
docker_network:
name: "{{ nname_1 }}"
state: absent
force: yes
- assert:
that:
- scope_1 is changed
- scope_2 is not changed
- scope_3 is changed
always:
- name: cleanup swarm
docker_swarm:
state: absent
force: yes
# Requirements for docker_swarm
when: docker_py_version is version('2.6.0', '>=') and docker_api_version is version('1.25', '>=')
####################################################################
## attachable ######################################################
####################################################################
- name: attachable
docker_network:
name: "{{ nname_1 }}"
attachable: true
register: attachable_1
ignore_errors: yes
- name: attachable (idempotency)
docker_network:
name: "{{ nname_1 }}"
attachable: true
register: attachable_2
ignore_errors: yes
- name: attachable (change)
docker_network:
name: "{{ nname_1 }}"
attachable: false
register: attachable_3
ignore_errors: yes
- name: cleanup
docker_network:
name: "{{ nname_1 }}"
state: absent
force: yes
- assert:
that:
- attachable_1 is changed
- attachable_2 is not changed
- attachable_3 is changed
when: docker_py_version is version('2.0.0', '>=')
- assert:
that:
- attachable_1 is failed
- "('version is ' ~ docker_py_version ~ ' ') in attachable_1.msg"
- "'Minimum version required is 2.0.0 ' in attachable_1.msg"
when: docker_py_version is version('2.0.0', '<')
####################################################################
## labels ##########################################################
####################################################################
- name: labels
docker_network:
name: "{{ nname_1 }}"
labels:
ansible.test.1: hello
ansible.test.2: world
register: labels_1
- name: labels (idempotency)
docker_network:
name: "{{ nname_1 }}"
labels:
ansible.test.2: world
ansible.test.1: hello
register: labels_2
- name: labels (less labels)
docker_network:
name: "{{ nname_1 }}"
labels:
ansible.test.1: hello
register: labels_3
- name: labels (more labels)
docker_network:
name: "{{ nname_1 }}"
labels:
ansible.test.1: hello
ansible.test.3: ansible
register: labels_4
- name: cleanup
docker_network:
name: "{{ nname_1 }}"
state: absent
force: yes
- assert:
that:
- labels_1 is changed
- labels_2 is not changed
- labels_3 is not changed
- labels_4 is changed

View File

@@ -0,0 +1,61 @@
---
- name: Registering network name
set_fact:
nname_1: "{{ name_prefix ~ '-network-1' }}"
- name: Registering network name
set_fact:
dnetworks: "{{ dnetworks + [nname_1] }}"
####################################################################
## overlay #########################################################
####################################################################
- block:
# Overlay networks require swarm initialization before they'll work
- name: swarm
docker_swarm:
state: present
advertise_addr: "{{ansible_default_ipv4.address}}"
- name: overlay
docker_network:
name: "{{ nname_1 }}"
driver: overlay
driver_options:
com.docker.network.driver.overlay.vxlanid_list: "257"
register: overlay_1
- name: overlay (idempotency)
docker_network:
name: "{{ nname_1 }}"
driver: overlay
driver_options:
com.docker.network.driver.overlay.vxlanid_list: "257"
register: overlay_2
- name: overlay (change)
docker_network:
name: "{{ nname_1 }}"
driver: bridge
register: overlay_3
- name: cleanup network
docker_network:
name: "{{ nname_1 }}"
state: absent
force: yes
- assert:
that:
- overlay_1 is changed
- overlay_2 is not changed
- overlay_3 is changed
always:
- name: cleanup swarm
docker_swarm:
state: absent
force: yes
# Requirements for docker_swarm
when: docker_py_version is version('2.6.0', '>=') and docker_api_version is version('1.25', '>=')

View File

@@ -0,0 +1,37 @@
---
- name: Registering container and network names
set_fact:
nname_1: "{{ name_prefix ~ '-network-foo' }}"
nname_2: "{{ name_prefix ~ '-network-foobar' }}"
- name: Registering container and network names
set_fact:
dnetworks: "{{ dnetworks + [nname_1, nname_2] }}"
####################################################################
- name: Create network (superstring)
docker_network:
name: "{{ nname_2 }}"
state: present
register: networks_1
- name: Create network (substring)
docker_network:
name: "{{ nname_1 }}"
state: present
register: networks_2
- name: Cleanup
docker_network:
name: "{{ network_name }}"
state: absent
loop:
- "{{ nname_1 }}"
- "{{ nname_2 }}"
loop_control:
loop_var: network_name
- assert:
that:
- networks_1 is changed
- networks_2 is changed

View File

@@ -0,0 +1,2 @@
shippable/posix/group4
destructive

View File

@@ -0,0 +1,3 @@
---
dependencies:
- setup_docker

View File

@@ -0,0 +1,76 @@
---
####################################################################
# 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 network name
set_fact:
nname: "{{ 'ansible-docker-test-%0x' % ((2**32) | random) }}"
- name: Make sure network is not there
docker_network:
name: "{{ nname }}"
state: absent
force: yes
- name: Inspect a non-present network
docker_network_info:
name: "{{ nname }}"
register: result
- assert:
that:
- "not result.exists"
- "'network' in result"
- "result.network is none"
- name: Make sure network exists
docker_network:
name: "{{ nname }}"
state: present
- name: Inspect a present network
docker_network_info:
name: "{{ nname }}"
register: result
- name: Dump docker_network_info result
debug: var=result
- name: "Comparison: use 'docker network inspect'"
command: docker network inspect "{{ nname }}"
register: docker_inspect
ignore_errors: yes
- 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
- name: Cleanup
docker_network:
name: "{{ nname }}"
state: absent
force: yes
- assert:
that:
- result.exists
- "'network' in result"
- "result.network"
- assert:
that:
- "result.network == 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
when: docker_py_version is version('1.8.0', '>=') and docker_api_version is version('1.21', '>=')
- fail: msg="Too old docker / docker-py version to run docker_network_info tests!"
when: not(docker_py_version is version('1.8.0', '>=') and docker_api_version is version('1.21', '>=')) and (ansible_distribution != 'CentOS' or ansible_distribution_major_version|int > 6)

View File

@@ -0,0 +1,3 @@
shippable/posix/group2
destructive
needs/root

View File

@@ -0,0 +1,3 @@
---
dependencies:
- setup_docker

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