diff --git a/changelogs/fragments/1118-docker_login-config-store.yml b/changelogs/fragments/1118-docker_login-config-store.yml new file mode 100644 index 0000000000..4106d675df --- /dev/null +++ b/changelogs/fragments/1118-docker_login-config-store.yml @@ -0,0 +1,2 @@ +bugfixes: +- "docker_login - fix internal config file storage to handle credentials for more than one registry (https://github.com/ansible-collections/community.general/issues/1117)." \ No newline at end of file diff --git a/plugins/modules/cloud/docker/docker_login.py b/plugins/modules/cloud/docker/docker_login.py index 58eb03236d..6522e64241 100644 --- a/plugins/modules/cloud/docker/docker_login.py +++ b/plugins/modules/cloud/docker/docker_login.py @@ -257,14 +257,13 @@ class DockerFileStore(object): auth = to_text(b64auth) # build up the auth structure - new_auth = dict( - auths=dict() - ) - new_auth['auths'][server] = dict( + if 'auths' not in self._config: + self._config['auths'] = dict() + + self._config['auths'][server] = dict( auth=auth ) - self._config.update(new_auth) self._write() def erase(self, server): @@ -272,8 +271,9 @@ class DockerFileStore(object): Remove credentials for the given server from the configuration. ''' - self._config['auths'].pop(server) - self._write() + if 'auths' in self._config and server in self._config['auths']: + self._config['auths'].pop(server) + self._write() class LoginManager(DockerBaseClass): diff --git a/tests/integration/targets/docker_login/tasks/main.yml b/tests/integration/targets/docker_login/tasks/main.yml index 2be493eb14..115c31e6c9 100644 --- a/tests/integration/targets/docker_login/tasks/main.yml +++ b/tests/integration/targets/docker_login/tasks/main.yml @@ -1,3 +1,4 @@ +--- #################################################################### # WARNING: These are designed specifically for Ansible tests # # and should not be used as examples of how to write Ansible roles # diff --git a/tests/integration/targets/docker_login/tasks/test.yml b/tests/integration/targets/docker_login/tasks/test.yml index e1b584a392..5a6f15fab9 100644 --- a/tests/integration/targets/docker_login/tasks/test.yml +++ b/tests/integration/targets/docker_login/tasks/test.yml @@ -1,3 +1,4 @@ +--- - block: - include_tasks: run-test.yml with_fileglob: diff --git a/tests/integration/targets/setup_docker_registry/handlers/cleanup.yml b/tests/integration/targets/setup_docker_registry/handlers/cleanup.yml index 8353038038..6b5001d419 100644 --- a/tests/integration/targets/setup_docker_registry/handlers/cleanup.yml +++ b/tests/integration/targets/setup_docker_registry/handlers/cleanup.yml @@ -1,10 +1,11 @@ +--- - name: "Make sure all images are removed" docker_image: name: "{{ item }}" state: absent - with_items: "{{ inames }}" + with_items: "{{ docker_registry_setup_inames }}" - name: "Get registry logs" - command: "docker logs {{ registry_name }}" + command: "docker logs {{ docker_registry_container_name_registry }}" register: registry_logs no_log: yes ignore_errors: yes @@ -12,26 +13,35 @@ debug: var: registry_logs.stdout_lines when: registry_logs is not failed -- name: "Get nginx logs" - command: "docker logs {{ nginx_name }}" +- name: "Get nginx logs for first instance" + command: "docker logs {{ docker_registry_container_name_nginx }}" register: nginx_logs no_log: yes ignore_errors: yes -- name: "Printing nginx logs" +- name: "Get nginx logs for second instance" + command: "docker logs {{ docker_registry_container_name_nginx2 }}" + register: nginx2_logs + no_log: yes + ignore_errors: yes +- name: "Printing nginx logs for first instance" debug: var: nginx_logs.stdout_lines when: nginx_logs is not failed +- name: "Printing nginx logs for second instance" + debug: + var: nginx2_logs.stdout_lines + when: nginx_logs is not failed - name: "Make sure all containers are removed" docker_container: name: "{{ item }}" state: absent force_kill: yes - with_items: "{{ cnames }}" + with_items: "{{ docker_registry_setup_cnames }}" register: result retries: 3 delay: 3 until: result is success - name: "Make sure all volumes are removed" command: "docker rm -f {{ item }}" - with_items: "{{ vnames }}" + with_items: "{{ docker_registry_setup_vnames }}" ignore_errors: yes diff --git a/tests/integration/targets/setup_docker_registry/handlers/main.yml b/tests/integration/targets/setup_docker_registry/handlers/main.yml index b2b858a624..23030182ae 100644 --- a/tests/integration/targets/setup_docker_registry/handlers/main.yml +++ b/tests/integration/targets/setup_docker_registry/handlers/main.yml @@ -1,2 +1,3 @@ +--- - name: Remove test registry include_tasks: ../handlers/cleanup.yml diff --git a/tests/integration/targets/setup_docker_registry/meta/main.yml b/tests/integration/targets/setup_docker_registry/meta/main.yml new file mode 100644 index 0000000000..b252b0e7a9 --- /dev/null +++ b/tests/integration/targets/setup_docker_registry/meta/main.yml @@ -0,0 +1,3 @@ +dependencies: + #- setup_docker -- done in setup.yml, to work around cleanup problems! + - setup_openssl diff --git a/tests/integration/targets/setup_docker_registry/tasks/main.yml b/tests/integration/targets/setup_docker_registry/tasks/main.yml index 4017827447..320df2467c 100644 --- a/tests/integration/targets/setup_docker_registry/tasks/main.yml +++ b/tests/integration/targets/setup_docker_registry/tasks/main.yml @@ -1,3 +1,4 @@ +--- #################################################################### # WARNING: These are designed specifically for Ansible tests # # and should not be used as examples of how to write Ansible roles # diff --git a/tests/integration/targets/setup_docker_registry/tasks/setup.yml b/tests/integration/targets/setup_docker_registry/tasks/setup.yml index f42bc592b5..e5287f46d1 100644 --- a/tests/integration/targets/setup_docker_registry/tasks/setup.yml +++ b/tests/integration/targets/setup_docker_registry/tasks/setup.yml @@ -1,54 +1,60 @@ -- name: Setup OpenSSL - include_role: - name: setup_openssl +--- - name: Register registry cleanup command: 'true' notify: Remove test registry - name: Setup Docker + # Please note that we do setup_docker here and not via meta/main.yml to avoid the problem that + # our cleanup is called **after** setup_docker's cleanup has been called! include_role: name: setup_docker - name: Create random name prefix and test registry name set_fact: - name_prefix: '{{ ''ansible-test-%0x'' % ((2**32) | random) }}' - registry_name: '{{ ''ansible-test-registry-%0x'' % ((2**32) | random) }}' - nginx_name: '{{ ''ansible-test-registry-frontend-%0x'' % ((2**32) | random) }}' + docker_registry_container_name_registry: '{{ ''ansible-test-registry-%0x'' % ((2**32) | random) }}' + docker_registry_container_name_nginx: '{{ ''ansible-test-registry-frontend-%0x'' % ((2**32) | random) }}' + docker_registry_container_name_nginx2: '{{ ''ansible-test-registry-frontend2-%0x'' % ((2**32) | random) }}' - name: Create image and container list set_fact: - inames: [] - cnames: - - '{{ registry_name }}' - - '{{ nginx_name }}' - vnames: - - '{{ nginx_name }}' + docker_registry_setup_inames: [] + docker_registry_setup_cnames: + - '{{ docker_registry_container_name_registry }}' + - '{{ docker_registry_container_name_nginx }}' + - '{{ docker_registry_container_name_nginx2 }}' + docker_registry_setup_vnames: + - '{{ docker_registry_container_name_nginx }}' + - '{{ docker_registry_container_name_nginx2 }}' - debug: - msg: Using name prefix {{ name_prefix }} and test registry name {{ registry_name }} + msg: Using test registry name {{ docker_registry_container_name_registry }} and nginx frontend name {{ docker_registry_container_name_nginx }} - block: + + # Set up registry container - name: Start test registry docker_container: - name: '{{ registry_name }}' + name: '{{ docker_registry_container_name_registry }}' image: registry:2.6.1 ports: 5000 register: registry_container - name: Get registry URL set_fact: registry_address: localhost:{{ registry_container.container.NetworkSettings.Ports['5000/tcp'].0.HostPort }} + + # Set up first nginx frontend for registry - name: Start nginx frontend for registry docker_volume: - name: '{{ nginx_name }}' + name: '{{ docker_registry_container_name_nginx }}' state: present - name: Create container for nginx frontend for registry docker_container: state: stopped - name: '{{ nginx_name }}' + name: '{{ docker_registry_container_name_nginx }}' image: nginx:alpine ports: 5000 links: - - '{{ registry_name }}:real-registry' + - '{{ docker_registry_container_name_registry }}:real-registry' volumes: - - '{{ nginx_name }}:/etc/nginx/' + - '{{ docker_registry_container_name_nginx }}:/etc/nginx/' register: nginx_container - name: Copy static files into volume - command: docker cp {{ role_path }}/files/{{ item }} {{ nginx_name }}:/etc/nginx/{{ item }} + command: docker cp {{ role_path }}/files/{{ item }} {{ docker_registry_container_name_nginx }}:/etc/nginx/{{ item }} loop: - nginx.conf - nginx.htpasswd @@ -73,13 +79,13 @@ privatekey_path: '{{ output_dir }}/cert.key' provider: selfsigned - name: Copy dynamic files into volume - command: docker cp {{ output_dir }}/{{ item }} {{ nginx_name }}:/etc/nginx/{{ item }} + command: docker cp {{ output_dir }}/{{ item }} {{ docker_registry_container_name_nginx }}:/etc/nginx/{{ item }} loop: - cert.pem - cert.key - name: Start nginx frontend for registry docker_container: - name: '{{ nginx_name }}' + name: '{{ docker_registry_container_name_nginx }}' state: started register: nginx_container - debug: var=nginx_container.container.NetworkSettings @@ -100,7 +106,78 @@ - set_fact: registry_frontend_address: 'n/a' when: can_copy_files is failed - - debug: msg="Registry available under {{ registry_address }}, NGINX frontend available under {{ registry_frontend_address }}" + + # Set up second nginx frontend for registry + - name: Start nginx frontend for registry + docker_volume: + name: '{{ docker_registry_container_name_nginx2 }}' + state: present + - name: Create container for nginx frontend for registry + docker_container: + state: stopped + name: '{{ docker_registry_container_name_nginx2 }}' + image: nginx:alpine + ports: 5000 + links: + - '{{ docker_registry_container_name_registry }}:real-registry' + volumes: + - '{{ docker_registry_container_name_nginx2 }}:/etc/nginx/' + register: nginx_container + - name: Copy static files into volume + command: docker cp {{ role_path }}/files/{{ item }} {{ docker_registry_container_name_nginx2 }}:/etc/nginx/{{ item }} + loop: + - nginx.conf + - nginx.htpasswd + register: can_copy_files + ignore_errors: yes + - block: + - name: Create private key for frontend certificate + community.crypto.openssl_privatekey: + path: '{{ output_dir }}/cert.key' + type: ECC + curve: secp256r1 + - name: Create CSR for frontend certificate + community.crypto.openssl_csr: + path: '{{ output_dir }}/cert.csr' + privatekey_path: '{{ output_dir }}/cert.key' + subject_alt_name: + - DNS:test-registry.ansible.com + - name: Create frontend certificate + community.crypto.openssl_certificate: + path: '{{ output_dir }}/cert.pem' + csr_path: '{{ output_dir }}/cert.csr' + privatekey_path: '{{ output_dir }}/cert.key' + provider: selfsigned + - name: Copy dynamic files into volume + command: docker cp {{ output_dir }}/{{ item }} {{ docker_registry_container_name_nginx2 }}:/etc/nginx/{{ item }} + loop: + - cert.pem + - cert.key + - name: Start nginx frontend for registry + docker_container: + name: '{{ docker_registry_container_name_nginx2 }}' + state: started + register: nginx_container + - debug: var=nginx_container.container.NetworkSettings + - name: Wait for registry frontend + uri: + url: https://{{ nginx_container.container.NetworkSettings.IPAddress }}:5000/v2/ + url_username: testuser + url_password: hunter2 + validate_certs: false + register: result + until: result is success + retries: 5 + delay: 1 + - name: Get registry URL + set_fact: + registry_frontend2_address: localhost:{{ nginx_container.container.NetworkSettings.Ports['5000/tcp'].0.HostPort }} + when: can_copy_files is not failed + - set_fact: + registry_frontend2_address: 'n/a' + when: can_copy_files is failed + + - debug: msg="Registry available under {{ registry_address }}, NGINX frontends available under {{ registry_frontend_address }} and {{ registry_frontend2_address }}" 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)