Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docker_network state:absent destroys networks with containers still attached, contrary to the documentation #1014

Closed
sonotley opened this issue Dec 18, 2024 · 2 comments · Fixed by #1016
Labels
docker-plain plain Docker (no swarm, no compose, no stack) documentation Improvements or additions to documentation

Comments

@sonotley
Copy link

SUMMARY

When I run a playbook which declares the state of an existing docker_network with connected containers to be absent, I expect the deletion to fail as documented here

If a network has connected containers, it cannot be deleted.

Instead the network is deleted leaving the container running but without the network.

ISSUE TYPE
  • Bug Report
COMPONENT NAME

docker_network

ANSIBLE VERSION
$ ansible --version
ansible [core 2.18.1]
  config file = None
  configured module search path = ['/Users/simon/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /opt/homebrew/Cellar/ansible/11.1.0/libexec/lib/python3.13/site-packages/ansible
  ansible collection location = /Users/simon/.ansible/collections:/usr/share/ansible/collections
  executable location = /opt/homebrew/bin/ansible
  python version = 3.13.1 (main, Dec  3 2024, 17:59:52) [Clang 16.0.0 (clang-1600.0.26.4)] (/opt/homebrew/Cellar/ansible/11.1.0/libexec/bin/python)
  jinja version = 3.1.4
  libyaml = True
COLLECTION VERSION
# /opt/homebrew/Cellar/ansible/11.1.0/libexec/lib/python3.13/site-packages/ansible_collections
Collection       Version
---------------- -------
community.docker 4.1.0
CONFIGURATION
$ ansible-config dump --only-changed -t all
CONFIG_FILE() = None

GALAXY_SERVERS:
OS / ENVIRONMENT

MacOS 14.7.1

STEPS TO REPRODUCE

Playbook 1

---
- name: Deploy Nginx in a Docker container
  hosts: localhost
  become: true
  tasks:
    - name: Create a user-defined Docker network
      community.docker.docker_network:
        name: custom_network
        state: present

    - name: Deploy an Nginx container
      community.docker.docker_container:
        name: nginx_container
        image: nginx:latest
        state: started
        networks:
          - name: custom_network
        ports:
          - "8080:80"

    - name: Verify the Nginx container is running
      ansible.builtin.shell: "docker ps | grep nginx_container"
      register: nginx_status

    - name: Display the status of the Nginx container
      ansible.builtin.debug:
        msg: "{{ nginx_status.stdout_lines }}"

    - name: Verify the network exists
      ansible.builtin.shell: "docker network list | grep custom_network"
      register: network_list

    - name: Display the network list
      ansible.builtin.debug:
        msg: "{{ network_list.stdout_lines }}"

Playbook 2

- name: Deploy Nginx in a Docker container
  hosts: localhost
  become: true
  tasks:
    - name: Create a user-defined Docker network
      community.docker.docker_network:
        name: custom_network
        state: absent

    - name: Verify the Nginx container is running
      ansible.builtin.shell: "docker ps | grep nginx_container"
      register: nginx_status

    - name: Display the status of the Nginx container
      ansible.builtin.debug:
        msg: "{{ nginx_status.stdout_lines }}"

    - name: Verify the network exists
      ansible.builtin.shell: "docker network list | grep custom_network"
      register: network_list
      failed_when: network_list.rc not in [0,1]

    - name: Display the network list
      ansible.builtin.debug:
        msg: "{{ network_list.stdout_lines }}"
EXPECTED RESULTS

I expected custom_network to remain in existence after running playbook2, but in fact it is gone.

ACTUAL RESULTS

Output below is from playbook 2 only showing it disconnecting the container and deleting the network contrary to the docs.

ansible-playbook [core 2.18.1]
  config file = None
  configured module search path = ['/Users/simon/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /opt/homebrew/Cellar/ansible/11.1.0/libexec/lib/python3.13/site-packages/ansible
  ansible collection location = /Users/simon/.ansible/collections:/usr/share/ansible/collections
  executable location = /opt/homebrew/bin/ansible-playbook
  python version = 3.13.1 (main, Dec  3 2024, 17:59:52) [Clang 16.0.0 (clang-1600.0.26.4)] (/opt/homebrew/Cellar/ansible/11.1.0/libexec/bin/python)
  jinja version = 3.1.4
  libyaml = True
No config file found; using defaults
BECOME password:
setting up inventory plugins
Loading collection ansible.builtin from
host_list declined parsing /etc/ansible/hosts as it did not pass its verify_file() method
Skipping due to inventory source not existing or not being readable by the current user
script declined parsing /etc/ansible/hosts as it did not pass its verify_file() method
auto declined parsing /etc/ansible/hosts as it did not pass its verify_file() method
Skipping due to inventory source not existing or not being readable by the current user
yaml declined parsing /etc/ansible/hosts as it did not pass its verify_file() method
Skipping due to inventory source not existing or not being readable by the current user
ini declined parsing /etc/ansible/hosts as it did not pass its verify_file() method
Skipping due to inventory source not existing or not being readable by the current user
toml declined parsing /etc/ansible/hosts as it did not pass its verify_file() method
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'
Loading collection community.docker from /opt/homebrew/Cellar/ansible/11.1.0/libexec/lib/python3.13/site-packages/ansible_collections/community/docker
Loading callback plugin default of type stdout, v2.0 from /opt/homebrew/Cellar/ansible/11.1.0/libexec/lib/python3.13/site-packages/ansible/plugins/callback/default.py
Skipping callback 'default', as we already have a stdout callback.
Skipping callback 'minimal', as we already have a stdout callback.
Skipping callback 'oneline', as we already have a stdout callback.

PLAYBOOK: playbook2.yml **************************************************************************************************************************************************************
Positional arguments: playbook2.yml
verbosity: 4
connection: ssh
become_method: sudo
become_ask_pass: True
tags: ('all',)
inventory: ('/etc/ansible/hosts',)
forks: 5
1 plays in playbook2.yml

PLAY [Deploy Nginx in a Docker container] ********************************************************************************************************************************************

TASK [Gathering Facts] ***************************************************************************************************************************************************************
task path: /Users/simon/source/docker-net-test/playbook2.yml:1
<127.0.0.1> ESTABLISH LOCAL CONNECTION FOR USER: simon
<127.0.0.1> EXEC /bin/sh -c 'echo ~simon && sleep 0'
<127.0.0.1> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /Users/simon/.ansible/tmp `"&& mkdir "` echo /Users/simon/.ansible/tmp/ansible-tmp-1734524728.427339-80135-269737139249987 `" && echo ansible-tmp-1734524728.427339-80135-269737139249987="` echo /Users/simon/.ansible/tmp/ansible-tmp-1734524728.427339-80135-269737139249987 `" ) && sleep 0'
Using module file /opt/homebrew/Cellar/ansible/11.1.0/libexec/lib/python3.13/site-packages/ansible/modules/setup.py
<127.0.0.1> PUT /Users/simon/.ansible/tmp/ansible-local-80114wwv6suld/tmp6_rh6wfo TO /Users/simon/.ansible/tmp/ansible-tmp-1734524728.427339-80135-269737139249987/AnsiballZ_setup.py
<127.0.0.1> EXEC /bin/sh -c 'chmod u+x /Users/simon/.ansible/tmp/ansible-tmp-1734524728.427339-80135-269737139249987/ /Users/simon/.ansible/tmp/ansible-tmp-1734524728.427339-80135-269737139249987/AnsiballZ_setup.py && sleep 0'
<127.0.0.1> EXEC /bin/sh -c 'sudo -H -S -p "[sudo via ansible, key=voprbglpsmdpzxuuqzxmnvrkiilabelz] password:" -u root /bin/sh -c '"'"'echo BECOME-SUCCESS-voprbglpsmdpzxuuqzxmnvrkiilabelz ; /opt/homebrew/Cellar/ansible/11.1.0/libexec/bin/python /Users/simon/.ansible/tmp/ansible-tmp-1734524728.427339-80135-269737139249987/AnsiballZ_setup.py'"'"' && sleep 0'
<127.0.0.1> EXEC /bin/sh -c 'rm -f -r /Users/simon/.ansible/tmp/ansible-tmp-1734524728.427339-80135-269737139249987/ > /dev/null 2>&1 && sleep 0'
ok: [localhost]

TASK [Create a user-defined Docker network] ******************************************************************************************************************************************
task path: /Users/simon/source/docker-net-test/playbook2.yml:5
<127.0.0.1> ESTABLISH LOCAL CONNECTION FOR USER: simon
<127.0.0.1> EXEC /bin/sh -c 'echo ~simon && sleep 0'
<127.0.0.1> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /Users/simon/.ansible/tmp `"&& mkdir "` echo /Users/simon/.ansible/tmp/ansible-tmp-1734524731.379621-80176-130326662296446 `" && echo ansible-tmp-1734524731.379621-80176-130326662296446="` echo /Users/simon/.ansible/tmp/ansible-tmp-1734524731.379621-80176-130326662296446 `" ) && sleep 0'
Using module file /opt/homebrew/Cellar/ansible/11.1.0/libexec/lib/python3.13/site-packages/ansible_collections/community/docker/plugins/modules/docker_network.py
<127.0.0.1> PUT /Users/simon/.ansible/tmp/ansible-local-80114wwv6suld/tmp1pa1la08 TO /Users/simon/.ansible/tmp/ansible-tmp-1734524731.379621-80176-130326662296446/AnsiballZ_docker_network.py
<127.0.0.1> EXEC /bin/sh -c 'chmod u+x /Users/simon/.ansible/tmp/ansible-tmp-1734524731.379621-80176-130326662296446/ /Users/simon/.ansible/tmp/ansible-tmp-1734524731.379621-80176-130326662296446/AnsiballZ_docker_network.py && sleep 0'
<127.0.0.1> EXEC /bin/sh -c 'sudo -H -S -p "[sudo via ansible, key=abwuehlmpshpuexxxxkrpipbnvllrqge] password:" -u root /bin/sh -c '"'"'echo BECOME-SUCCESS-abwuehlmpshpuexxxxkrpipbnvllrqge ; /opt/homebrew/Cellar/ansible/11.1.0/libexec/bin/python /Users/simon/.ansible/tmp/ansible-tmp-1734524731.379621-80176-130326662296446/AnsiballZ_docker_network.py'"'"' && sleep 0'
<127.0.0.1> EXEC /bin/sh -c 'rm -f -r /Users/simon/.ansible/tmp/ansible-tmp-1734524731.379621-80176-130326662296446/ > /dev/null 2>&1 && sleep 0'
changed: [localhost] => {
    "actions": [
        "Disconnected container nginx_container",
        "Removed network custom_network"
    ],
    "changed": true,
    "invocation": {
        "module_args": {
            "api_version": "auto",
            "appends": false,
            "attachable": null,
            "ca_path": null,
            "client_cert": null,
            "client_key": null,
            "config_from": null,
            "config_only": null,
            "connected": [],
            "debug": false,
            "docker_host": "unix:///var/run/docker.sock",
            "driver": "bridge",
            "driver_options": {},
            "enable_ipv6": null,
            "force": false,
            "internal": null,
            "ipam_config": null,
            "ipam_driver": null,
            "ipam_driver_options": null,
            "labels": {},
            "name": "custom_network",
            "scope": null,
            "state": "absent",
            "timeout": 60,
            "tls": false,
            "tls_hostname": null,
            "use_ssh_client": false,
            "validate_certs": false
        }
    }
}

TASK [Verify the Nginx container is running] *****************************************************************************************************************************************
task path: /Users/simon/source/docker-net-test/playbook2.yml:10
<127.0.0.1> ESTABLISH LOCAL CONNECTION FOR USER: simon
<127.0.0.1> EXEC /bin/sh -c 'echo ~simon && sleep 0'
<127.0.0.1> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /Users/simon/.ansible/tmp `"&& mkdir "` echo /Users/simon/.ansible/tmp/ansible-tmp-1734524732.229014-80201-42969956857922 `" && echo ansible-tmp-1734524732.229014-80201-42969956857922="` echo /Users/simon/.ansible/tmp/ansible-tmp-1734524732.229014-80201-42969956857922 `" ) && sleep 0'
Using module file /opt/homebrew/Cellar/ansible/11.1.0/libexec/lib/python3.13/site-packages/ansible/modules/command.py
<127.0.0.1> PUT /Users/simon/.ansible/tmp/ansible-local-80114wwv6suld/tmpq8absk6k TO /Users/simon/.ansible/tmp/ansible-tmp-1734524732.229014-80201-42969956857922/AnsiballZ_command.py
<127.0.0.1> EXEC /bin/sh -c 'chmod u+x /Users/simon/.ansible/tmp/ansible-tmp-1734524732.229014-80201-42969956857922/ /Users/simon/.ansible/tmp/ansible-tmp-1734524732.229014-80201-42969956857922/AnsiballZ_command.py && sleep 0'
<127.0.0.1> EXEC /bin/sh -c 'sudo -H -S -p "[sudo via ansible, key=ddgjsezyvpqdwfppjqtpwvsrdjslddel] password:" -u root /bin/sh -c '"'"'echo BECOME-SUCCESS-ddgjsezyvpqdwfppjqtpwvsrdjslddel ; /opt/homebrew/Cellar/ansible/11.1.0/libexec/bin/python /Users/simon/.ansible/tmp/ansible-tmp-1734524732.229014-80201-42969956857922/AnsiballZ_command.py'"'"' && sleep 0'
<127.0.0.1> EXEC /bin/sh -c 'rm -f -r /Users/simon/.ansible/tmp/ansible-tmp-1734524732.229014-80201-42969956857922/ > /dev/null 2>&1 && sleep 0'
changed: [localhost] => {
    "changed": true,
    "cmd": "docker ps | grep nginx_container",
    "delta": "0:00:00.055873",
    "end": "2024-12-18 12:25:32.658854",
    "invocation": {
        "module_args": {
            "_raw_params": "docker ps | grep nginx_container",
            "_uses_shell": true,
            "argv": null,
            "chdir": null,
            "creates": null,
            "executable": null,
            "expand_argument_vars": true,
            "removes": null,
            "stdin": null,
            "stdin_add_newline": true,
            "strip_empty_ends": true
        }
    },
    "msg": "",
    "rc": 0,
    "start": "2024-12-18 12:25:32.602981",
    "stderr": "",
    "stderr_lines": [],
    "stdout": "362e03085558   nginx:latest    \"/docker-entrypoint.…\"   35 minutes ago   Up 35 minutes                                                       nginx_container",
    "stdout_lines": [
        "362e03085558   nginx:latest    \"/docker-entrypoint.…\"   35 minutes ago   Up 35 minutes                                                       nginx_container"
    ]
}

TASK [Display the status of the Nginx container] *************************************************************************************************************************************
task path: /Users/simon/source/docker-net-test/playbook2.yml:14
ok: [localhost] => {
    "msg": [
        "362e03085558   nginx:latest    \"/docker-entrypoint.…\"   35 minutes ago   Up 35 minutes                                                       nginx_container"
    ]
}

TASK [Verify the network exists] *****************************************************************************************************************************************************
task path: /Users/simon/source/docker-net-test/playbook2.yml:18
<127.0.0.1> ESTABLISH LOCAL CONNECTION FOR USER: simon
<127.0.0.1> EXEC /bin/sh -c 'echo ~simon && sleep 0'
<127.0.0.1> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /Users/simon/.ansible/tmp `"&& mkdir "` echo /Users/simon/.ansible/tmp/ansible-tmp-1734524732.802664-80227-229173310682829 `" && echo ansible-tmp-1734524732.802664-80227-229173310682829="` echo /Users/simon/.ansible/tmp/ansible-tmp-1734524732.802664-80227-229173310682829 `" ) && sleep 0'
Using module file /opt/homebrew/Cellar/ansible/11.1.0/libexec/lib/python3.13/site-packages/ansible/modules/command.py
<127.0.0.1> PUT /Users/simon/.ansible/tmp/ansible-local-80114wwv6suld/tmpbuqg9v6l TO /Users/simon/.ansible/tmp/ansible-tmp-1734524732.802664-80227-229173310682829/AnsiballZ_command.py
<127.0.0.1> EXEC /bin/sh -c 'chmod u+x /Users/simon/.ansible/tmp/ansible-tmp-1734524732.802664-80227-229173310682829/ /Users/simon/.ansible/tmp/ansible-tmp-1734524732.802664-80227-229173310682829/AnsiballZ_command.py && sleep 0'
<127.0.0.1> EXEC /bin/sh -c 'sudo -H -S -p "[sudo via ansible, key=elfdwluorehhbqjdeeolyqgaymsbbrvg] password:" -u root /bin/sh -c '"'"'echo BECOME-SUCCESS-elfdwluorehhbqjdeeolyqgaymsbbrvg ; /opt/homebrew/Cellar/ansible/11.1.0/libexec/bin/python /Users/simon/.ansible/tmp/ansible-tmp-1734524732.802664-80227-229173310682829/AnsiballZ_command.py'"'"' && sleep 0'
<127.0.0.1> EXEC /bin/sh -c 'rm -f -r /Users/simon/.ansible/tmp/ansible-tmp-1734524732.802664-80227-229173310682829/ > /dev/null 2>&1 && sleep 0'
changed: [localhost] => {
    "changed": true,
    "cmd": "docker network list | grep custom_network",
    "delta": "0:00:00.065006",
    "end": "2024-12-18 12:25:33.207390",
    "failed_when_result": false,
    "invocation": {
        "module_args": {
            "_raw_params": "docker network list | grep custom_network",
            "_uses_shell": true,
            "argv": null,
            "chdir": null,
            "creates": null,
            "executable": null,
            "expand_argument_vars": true,
            "removes": null,
            "stdin": null,
            "stdin_add_newline": true,
            "strip_empty_ends": true
        }
    },
    "msg": "non-zero return code",
    "rc": 1,
    "start": "2024-12-18 12:25:33.142384",
    "stderr": "",
    "stderr_lines": [],
    "stdout": "",
    "stdout_lines": []
}

TASK [Display the network list] ******************************************************************************************************************************************************
task path: /Users/simon/source/docker-net-test/playbook2.yml:23
ok: [localhost] => {
    "msg": []
}

PLAY RECAP ***************************************************************************************************************************************************************************
localhost                  : ok=6    changed=3    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
@felixfontein felixfontein added documentation Improvements or additions to documentation docker-plain plain Docker (no swarm, no compose, no stack) labels Dec 18, 2024
@felixfontein
Copy link
Collaborator

Hmm, the code didn't change since the module was originally added (ansible/ansible@af3884f): absent() is always calling remove_network(), which calls disconnect_all_containers(). The comment "Use the force option to disconnect all containers and delete the network." was already contained in the first version of the module, and thus has been wrong since then.

For this reason this is a documentation bug that definitely needs fixing.

@felixfontein
Copy link
Collaborator

#1016 updates the docs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docker-plain plain Docker (no swarm, no compose, no stack) documentation Improvements or additions to documentation
Projects
None yet
2 participants