From a16164cb722044e66fe1ab716a4b149f90621fe4 Mon Sep 17 00:00:00 2001 From: Felix Fontein Date: Tue, 15 Dec 2020 21:04:09 +0100 Subject: [PATCH] Prepare docker tests for AZP. (#1482) Backport of important parts of https://github.com/ansible-collections/community.docker/pull/48 to stable-1. --- .../docker_container/tasks/tests/network.yml | 4 +- .../library/current_container_facts.py | 101 ++++++++++++++++++ .../targets/setup_docker/tasks/RedHat-7.yml | 2 +- .../targets/setup_docker/tasks/RedHat-8.yml | 2 +- .../targets/setup_docker/tasks/main.yml | 13 +++ .../tasks/setup-frontend.yml | 22 +++- .../setup_docker_registry/tasks/setup.yml | 9 ++ 7 files changed, 144 insertions(+), 9 deletions(-) create mode 100644 tests/integration/targets/setup_docker/library/current_container_facts.py diff --git a/tests/integration/targets/docker_container/tasks/tests/network.yml b/tests/integration/targets/docker_container/tasks/tests/network.yml index 0ca341d99e..9ef33643a2 100644 --- a/tests/integration/targets/docker_container/tasks/tests/network.yml +++ b/tests/integration/targets/docker_container/tasks/tests/network.yml @@ -23,10 +23,10 @@ when: docker_py_version is version('1.10.0', '>=') - set_fact: - subnet_ipv4_base: 192.168.{{ 64 + (192 | random) }} + 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: "192.168.{{ 64 + (192 | random) }}.0/24" + # 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: diff --git a/tests/integration/targets/setup_docker/library/current_container_facts.py b/tests/integration/targets/setup_docker/library/current_container_facts.py new file mode 100644 index 0000000000..b1fea1b256 --- /dev/null +++ b/tests/integration/targets/setup_docker/library/current_container_facts.py @@ -0,0 +1,101 @@ +#!/usr/bin/python +# +# (c) 2020 Matt Clay +# (c) 2020 Felix Fontein +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +# This module properly lives in community.docker; it has been vendored here +# to support the 1.x.y docker integration tests. + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: current_container_facts +short_description: Return facts about whether the module runs in a Docker container +description: + - Return facts about whether the module runs in a Docker container. +author: + - Felix Fontein (@felixfontein) +''' + +EXAMPLES = ''' +- name: Get facts on current container + community.docker.current_container_facts: +- name: Print information on current container when running in a container + ansible.builtin.debug: + msg: "Container ID is {{ ansible_module_container_id }}" + when: ansible_module_running_in_container +''' + +RETURN = ''' +ansible_facts: + description: Ansible facts returned by the module + type: dict + returned: always + contains: + ansible_module_running_in_container: + description: + - Whether the module was able to detect that it runs in a container or not. + returned: always + type: bool + ansible_module_container_id: + description: + - The detected container ID. + - Contains an empty string if no container was detected. + returned: always + type: str + ansible_module_container_type: + description: + - The detected container environment. + - Contains an empty string if no container was detected. + - Otherwise, will be one of C(docker) or C(azure_pipelines). + returned: always + type: str + # choices: + # - docker + # - azure_pipelines +''' + +import os + +from ansible.module_utils.basic import AnsibleModule + + +def main(): + module = AnsibleModule(dict(), supports_check_mode=True) + + path = '/proc/self/cpuset' + container_id = '' + container_type = '' + + if os.path.exists(path): + # File content varies based on the environment: + # No Container: / + # Docker: /docker/c86f3732b5ba3d28bb83b6e14af767ab96abbc52de31313dcb1176a62d91a507 + # Azure Pipelines (Docker): /azpl_job/0f2edfed602dd6ec9f2e42c867f4d5ee640ebf4c058e6d3196d4393bb8fd0891 + # Podman: /../../../../../.. + with open(path, 'rb') as f: + contents = f.read().decode('utf-8') + + cgroup_path, cgroup_name = os.path.split(contents.strip()) + + if cgroup_path == '/docker': + container_id = cgroup_name + container_type = 'docker' + + if cgroup_path == '/azpl_job': + container_id = cgroup_name + container_type = 'azure_pipelines' + + module.exit_json(ansible_facts=dict( + ansible_module_running_in_container=container_id != '', + ansible_module_container_id=container_id, + ansible_module_container_type=container_type, + )) + + +if __name__ == '__main__': + main() diff --git a/tests/integration/targets/setup_docker/tasks/RedHat-7.yml b/tests/integration/targets/setup_docker/tasks/RedHat-7.yml index 4fa28b74db..6e798ce27d 100644 --- a/tests/integration/targets/setup_docker/tasks/RedHat-7.yml +++ b/tests/integration/targets/setup_docker/tasks/RedHat-7.yml @@ -42,4 +42,4 @@ service: name: docker state: started - ignore_errors: "{{ ansible_virtualization_type == 'docker' }}" + ignore_errors: "{{ ansible_virtualization_type in ['docker', 'container', 'containerd'] }}" diff --git a/tests/integration/targets/setup_docker/tasks/RedHat-8.yml b/tests/integration/targets/setup_docker/tasks/RedHat-8.yml index 5e8334835c..c207f4ab0b 100644 --- a/tests/integration/targets/setup_docker/tasks/RedHat-8.yml +++ b/tests/integration/targets/setup_docker/tasks/RedHat-8.yml @@ -31,4 +31,4 @@ service: name: docker state: started - ignore_errors: "{{ ansible_virtualization_type == 'docker' }}" + ignore_errors: "{{ ansible_virtualization_type in ['docker', 'container', 'containerd'] }}" diff --git a/tests/integration/targets/setup_docker/tasks/main.yml b/tests/integration/targets/setup_docker/tasks/main.yml index a9c8a7c51b..e1b25dc869 100644 --- a/tests/integration/targets/setup_docker/tasks/main.yml +++ b/tests/integration/targets/setup_docker/tasks/main.yml @@ -135,3 +135,16 @@ images: "{{ docker_images.stdout_lines | default([]) }}" when: docker_cli_version is version('0.0', '>') + + - name: Detect whether we are running inside a container + current_container_facts: + + - name: Inspect current container + docker_container_info: + name: "{{ ansible_module_container_id }}" + register: current_container_info + when: ansible_module_running_in_container + + - name: Determine network name + set_fact: + current_container_network_ip: "{{ (current_container_info.container.NetworkSettings.Networks | dictsort)[0].0 | default('') if ansible_module_running_in_container else '' }}" diff --git a/tests/integration/targets/setup_docker_registry/tasks/setup-frontend.yml b/tests/integration/targets/setup_docker_registry/tasks/setup-frontend.yml index b52a13f866..f1055ea3d3 100644 --- a/tests/integration/targets/setup_docker_registry/tasks/setup-frontend.yml +++ b/tests/integration/targets/setup_docker_registry/tasks/setup-frontend.yml @@ -11,10 +11,18 @@ name: '{{ docker_registry_container_name_frontend }}' image: "{{ docker_test_image_registry_nginx }}" ports: 5000 + # `links` does not work when using a network. That's why the docker_container task + # in setup.yml specifies `aliases` so we get the same effect. links: - '{{ docker_registry_container_name_registry }}:real-registry' volumes: - '{{ docker_registry_container_name_frontend }}:/etc/nginx/' + network_mode: '{{ current_container_network_ip | default(omit, true) }}' + networks: >- + {{ + [dict([['name', current_container_network_ip]])] + if current_container_network_ip not in ['', 'bridge'] else omit + }} register: nginx_container - name: Copy static files into volume @@ -65,9 +73,17 @@ debug: var: nginx_container.container.NetworkSettings + - name: Get registry URL + set_fact: + # Note that this host/port combination is used by the Docker daemon, that's why `localhost` is appropriate! + # This host/port combination cannot be used if the tests are running inside a docker container. + docker_registry_frontend_address: localhost:{{ nginx_container.container.NetworkSettings.Ports['5000/tcp'].0.HostPort }} + # The following host/port combination can be used from inside the docker container. + docker_registry_frontend_address_internal: "{{ nginx_container.container.NetworkSettings.Networks[current_container_network_ip].IPAddress if current_container_network_ip else nginx_container.container.NetworkSettings.IPAddress }}:5000" + - name: Wait for registry frontend uri: - url: https://{{ nginx_container.container.NetworkSettings.IPAddress }}:5000/v2/ + url: https://{{ docker_registry_frontend_address_internal }}/v2/ url_username: testuser url_password: hunter2 validate_certs: false @@ -76,10 +92,6 @@ retries: 5 delay: 1 - - name: Get registry URL - set_fact: - docker_registry_frontend_address: localhost:{{ nginx_container.container.NetworkSettings.Ports['5000/tcp'].0.HostPort }} - - set_fact: docker_registry_frontend_address: 'n/a' when: can_copy_files is failed diff --git a/tests/integration/targets/setup_docker_registry/tasks/setup.yml b/tests/integration/targets/setup_docker_registry/tasks/setup.yml index 9d2b52b95a..6782da9d12 100644 --- a/tests/integration/targets/setup_docker_registry/tasks/setup.yml +++ b/tests/integration/targets/setup_docker_registry/tasks/setup.yml @@ -44,6 +44,15 @@ name: '{{ docker_registry_container_name_registry }}' image: "{{ docker_test_image_registry }}" ports: 5000 + network_mode: '{{ current_container_network_ip | default(omit, true) }}' + # We need to define the alias `real-registry` here because the global `links` + # option for the NGINX containers (see setup-frontend.yml) does not work when + # using networks. + networks: >- + {{ + [dict([['name', current_container_network_ip], ['aliases', ['real-registry']]])] + if current_container_network_ip not in ['', 'bridge'] else omit + }} register: registry_container - name: Get registry URL