community.docker icon indicating copy to clipboard operation
community.docker copied to clipboard

shutdown(SHUT_WR) does not work for SSLSocket, causing docker_api connection and docker_container_exec module to have problems with TCP TLS sockets

Open christophert opened this issue 1 year ago • 6 comments

SUMMARY

Hosts targeted via the docker_containers inventory module fail facts gathering if TCP TLS socket is in use.

ISSUE TYPE
  • Bug Report
COMPONENT NAME

community.docker.docker_containers.docker_api connection

ANSIBLE VERSION
ansible [core 2.14.4]
  config file = /home/user/Documents/Projects/ansible/ansible.cfg
  configured module search path = ['/home/user/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /home/user/Documents/Projects/ansible/.venv/lib64/python3.11/site-packages/ansible
  ansible collection location = /home/user/.ansible/collections:/usr/share/ansible/collections
  executable location = /home/user/Documents/Projects/ansible/.venv/bin/ansible
  python version = 3.11.2 (main, Feb  8 2023, 00:00:00) [GCC 12.2.1 20221121 (Red Hat 12.2.1-4)] (/home/user/Documents/Projects/ansible/.venv/bin/python)
  jinja version = 3.1.2
  libyaml = True
COLLECTION VERSION
# /home/user/.ansible/collections/ansible_collections
Collection       Version
---------------- -------
community.docker 3.4.3  

# /home/user/Documents/Projects/ansible/.venv/lib64/python3.11/site-packages/ansible_collections
Collection       Version
---------------- -------
community.docker 3.4.3  

# /home/user/Documents/Projects/ansible/.venv/lib/python3.11/site-packages/ansible_collections
Collection       Version
---------------- -------
community.docker 3.4.3  
CONFIGURATION
CONFIG_FILE() = /home/user/Documents/Projects/ansible/ansible.cfg
DEFAULT_ROLES_PATH(/home/user/Documents/Projects/ansible/ansible.cfg) = ['/home/user/Documents/Projects/ansible/roles']
OS / ENVIRONMENT
Linux vm-dev 6.2.9-200.fc37.aarch64 #1 SMP PREEMPT_DYNAMIC Thu Mar 30 22:54:14 UTC 2023 aarch64 aarch64 aarch64 GNU/Linux

Docker host:

Linux kali 6.1.0-kali7-arm64 #1 SMP Debian 6.1.20-1kali1 (2023-03-22) aarch64 GNU/Linux

Docker version:

Client: Docker Engine - Community
 Version:           23.0.3
 API version:       1.42
 Go version:        go1.19.7
 Git commit:        3e7cbfd
 Built:             Tue Apr  4 22:02:03 2023
 OS/Arch:           linux/arm64
 Context:           default

Server: Docker Engine - Community
 Engine:
  Version:          23.0.3
  API version:      1.42 (minimum version 1.12)
  Go version:       go1.19.7
  Git commit:       59118bf
  Built:            Tue Apr  4 22:02:03 2023
  OS/Arch:          linux/arm64
  Experimental:     false
 containerd:
  Version:          1.6.20
  GitCommit:        2806fc1057397dbaeefbea0e4e17bddfbd388f38
 runc:
  Version:          1.1.5
  GitCommit:        v1.1.5-0-gf19387a
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0
STEPS TO REPRODUCE

Setup a Docker host that exposes a TLS-protected TCP socket for control, deploy a container, and attempt to gather facts from the container/use async against the container.

Inventory files: inventory/kali.yml:

---

docker_hosts:
  hosts:
    kali:
      ansible_host: 192.168.200.133
      ansible_connection: ssh
      ansible_user: mgmt
      ansible_password: password
      ansible_ssh_common_args: '-o StrictHostKeyChecking=no'

inventory/remote-docker.yml:

plugin: community.docker.docker_containers
docker_host: tcp://192.168.200.133:2376
tls: true
tls_hostname: server
validate_certs: true
ca_cert: credentials/ca.pem
client_cert: credentials/client.pem
client_key: credentials/client.key
groups:
  docker_containers: true

Container deployment and bootstrap:

---

- hosts: docker_hosts
  tasks:
    - name: deploy container
      community.docker.docker_container:
        name: test
        image: ubuntu:22.04
        command: sleep infinity
        detach: true
        auto_remove: true

    - meta: refresh_inventory

- hosts: docker_containers
  gather_facts: false
  roles:
    - bootstrap-install-python
  tasks:
    - name: gather facts
      gather_facts:

bootstrap-install-python/tasks/main.yml:

---

- name: Install Python
  ansible.builtin.raw: |
    if [ -x "$(command -v apt-get)" ]; then apt-get update && apt-get install -y python3.11-full python-is-python3
    elif [ -x "$(command -v dnf)" ]; then dnf install -y python3
    else echo "Failed to install package."; fi
EXPECTED RESULTS

Gathering facts should complete with any unhandled errors being thrown by Ansible.

ACTUAL RESULTS

The actual result is that ansible will hang for about 30-45 seconds when gathering facts, then return

[WARNING]: Unhandled error in Python interpreter discovery for host test:
Expecting value: line 1 column 1 (char 0)

This is not present when executing on a Docker TCP socket without TLS or with the local Unix socket.

ansible-playbook [core 2.14.4]
  config file = /home/user/Documents/Projects/ansible/ansible.cfg
  configured module search path = ['/home/user/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /home/user/Documents/Projects/ansible/.venv/lib64/python3.11/site-packages/ansible
  ansible collection location = /home/user/.ansible/collections:/usr/share/ansible/collections
  executable location = /home/user/Documents/Projects/ansible/.venv/bin/ansible-playbook
  python version = 3.11.2 (main, Feb  8 2023, 00:00:00) [GCC 12.2.1 20221121 (Red Hat 12.2.1-4)] (/home/user/Documents/Projects/ansible/.venv/bin/python)
  jinja version = 3.1.2
  libyaml = True
Using /home/user/Documents/Projects/ansible/ansible.cfg as config file
setting up inventory plugins
host_list declined parsing /home/user/Documents/Projects/ansible/inventory/kali.yml as it did not pass its verify_file() method
script declined parsing /home/user/Documents/Projects/ansible/inventory/kali.yml as it did not pass its verify_file() method
Parsed /home/user/Documents/Projects/ansible/inventory/kali.yml inventory source with yaml plugin
setting up inventory plugins
host_list declined parsing /home/user/Documents/Projects/ansible/inventory/remote-docker.yml as it did not pass its verify_file() method
script declined parsing /home/user/Documents/Projects/ansible/inventory/remote-docker.yml as it did not pass its verify_file() method
Loading collection community.docker from /home/user/.ansible/collections/ansible_collections/community/docker
Using inventory plugin 'ansible_collections.community.docker.plugins.inventory.docker_containers' to process inventory source '/home/user/Documents/Projects/ansible/inventory/remote-docker.yml'
Parsed /home/user/Documents/Projects/ansible/inventory/remote-docker.yml inventory source with auto plugin
Loading callback plugin default of type stdout, v2.0 from /home/user/Documents/Projects/ansible/.venv/lib64/python3.11/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: test.yml *************************************************************
Positional arguments: playbooks/test.yml
verbosity: 4
connection: smart
timeout: 10
become_method: sudo
tags: ('all',)
inventory: ('/home/user/Documents/Projects/ansible/inventory/kali.yml', '/home/user/Documents/Projects/ansible/inventory/remote-docker.yml')
forks: 5
1 plays in playbooks/test.yml

PLAY [docker_containers] *******************************************************

TASK [Gathering Facts] *********************************************************
task path: /home/user/Documents/Projects/ansible/playbooks/test.yml:3
[WARNING]: Unhandled error in Python interpreter discovery for host test:
Expecting value: line 1 column 1 (char 0)
[WARNING]: Platform linux on host test is using the discovered Python
interpreter at /usr/bin/python3.11, but future installation of another Python
interpreter could change the meaning of that path. See
https://docs.ansible.com/ansible-
core/2.14/reference_appendices/interpreter_discovery.html for more information.
<test> ESTABLISH DOCKER CONNECTION FOR USER: ?
Trying to determine actual user
Actual user is ''
<test> EXEC ['/bin/sh', '-c', "/bin/sh -c 'echo ~ && sleep 0'"]
<test> EXEC ['/bin/sh', '-c', '/bin/sh -c \'( umask 77 && mkdir -p "` echo /root/.ansible/tmp `"&& mkdir "` echo /root/.ansible/tmp/ansible-tmp-1681167100.4895165-43204-22990817581602 `" && echo ansible-tmp-1681167100.4895165-43204-22990817581602="` echo /root/.ansible/tmp/ansible-tmp-1681167100.4895165-43204-22990817581602 `" ) && sleep 0\'']
<test> Attempting python interpreter discovery
<test> EXEC ['/bin/sh', '-c', '/bin/sh -c \'echo PLATFORM; uname; echo FOUND; command -v \'"\'"\'python3.11\'"\'"\'; command -v \'"\'"\'python3.10\'"\'"\'; command -v \'"\'"\'python3.9\'"\'"\'; command -v \'"\'"\'python3.8\'"\'"\'; command -v \'"\'"\'python3.7\'"\'"\'; command -v \'"\'"\'python3.6\'"\'"\'; command -v \'"\'"\'python3.5\'"\'"\'; command -v \'"\'"\'/usr/bin/python3\'"\'"\'; command -v \'"\'"\'/usr/libexec/platform-python\'"\'"\'; command -v \'"\'"\'python2.7\'"\'"\'; command -v \'"\'"\'/usr/bin/python\'"\'"\'; command -v \'"\'"\'python\'"\'"\'; echo ENDFOUND && sleep 0\'']
<test> EXEC ['/bin/sh', '-c', "/bin/sh -c '/usr/bin/python3.11 && sleep 0'"], with stdin (1234 bytes)
<test> wrote 1234 bytes, 0 are left
<test> Shutting socket down for writing
<test> select... (None)
<test> select event read:True write:False
<test> read 498 bytes
<test> select... (None)
<test> select event read:True write:False
<test> read 24 bytes
<test> select... (None)
<test> select event read:True write:False
<test> read 0 bytes
Using module file /home/user/Documents/Projects/ansible/.venv/lib64/python3.11/site-packages/ansible/modules/setup.py
<test> PUT /home/user/.ansible/tmp/ansible-local-431996hdrm4ms/tmpkj4e_tms TO /root/.ansible/tmp/ansible-tmp-1681167100.4895165-43204-22990817581602/AnsiballZ_setup.py
<test> EXEC ['/bin/sh', '-c', 'id -u && id -g']
<test> PUT: Determined uid=b'0' and gid=b'0' for user ""
<test> EXEC ['/bin/sh', '-c', "/bin/sh -c 'chmod u+x /root/.ansible/tmp/ansible-tmp-1681167100.4895165-43204-22990817581602/ /root/.ansible/tmp/ansible-tmp-1681167100.4895165-43204-22990817581602/AnsiballZ_setup.py && sleep 0'"]
<test> EXEC ['/bin/sh', '-c', "/bin/sh -c '/usr/bin/python3.11 /root/.ansible/tmp/ansible-tmp-1681167100.4895165-43204-22990817581602/AnsiballZ_setup.py && sleep 0'"]
<test> EXEC ['/bin/sh', '-c', "/bin/sh -c 'rm -f -r /root/.ansible/tmp/ansible-tmp-1681167100.4895165-43204-22990817581602/ > /dev/null 2>&1 && sleep 0'"]
ok: [test]

TASK [test] ********************************************************************
task path: /home/user/Documents/Projects/ansible/playbooks/test.yml:6
<test> ESTABLISH DOCKER CONNECTION FOR USER: ?
Trying to determine actual user
Actual user is ''
<test> EXEC ['/bin/sh', '-c', "/bin/sh -c 'echo ~ && sleep 0'"]
<test> EXEC ['/bin/sh', '-c', '/bin/sh -c \'( umask 77 && mkdir -p "` echo /root/.ansible/tmp `"&& mkdir "` echo /root/.ansible/tmp/ansible-tmp-1681167188.2423344-43258-266621346864131 `" && echo ansible-tmp-1681167188.2423344-43258-266621346864131="` echo /root/.ansible/tmp/ansible-tmp-1681167188.2423344-43258-266621346864131 `" ) && sleep 0\'']
Using module file /home/user/Documents/Projects/ansible/.venv/lib64/python3.11/site-packages/ansible/modules/command.py
<test> PUT /home/user/.ansible/tmp/ansible-local-431996hdrm4ms/tmpw9yzpqfk TO /root/.ansible/tmp/ansible-tmp-1681167188.2423344-43258-266621346864131/AnsiballZ_command.py
<test> EXEC ['/bin/sh', '-c', 'id -u && id -g']
<test> PUT: Determined uid=b'0' and gid=b'0' for user ""
<test> PUT /home/user/.ansible/tmp/ansible-local-431996hdrm4ms/tmpa5b3u4zx TO /root/.ansible/tmp/ansible-tmp-1681167188.2423344-43258-266621346864131/async_wrapper.py
<test> EXEC ['/bin/sh', '-c', "/bin/sh -c 'chmod u+x /root/.ansible/tmp/ansible-tmp-1681167188.2423344-43258-266621346864131/ /root/.ansible/tmp/ansible-tmp-1681167188.2423344-43258-266621346864131/AnsiballZ_command.py /root/.ansible/tmp/ansible-tmp-1681167188.2423344-43258-266621346864131/async_wrapper.py && sleep 0'"]
<test> EXEC ['/bin/sh', '-c', '/bin/sh -c \'ANSIBLE_ASYNC_DIR=\'"\'"\'~/.ansible_async\'"\'"\' /usr/bin/python3.11 /root/.ansible/tmp/ansible-tmp-1681167188.2423344-43258-266621346864131/async_wrapper.py 170992352143 15 /root/.ansible/tmp/ansible-tmp-1681167188.2423344-43258-266621346864131/AnsiballZ_command.py _ && sleep 0\'']
<test> EXEC ['/bin/sh', '-c', "/bin/sh -c 'echo ~ && sleep 0'"]
<test> EXEC ['/bin/sh', '-c', "/bin/sh -c 'echo ~ && sleep 0'"]
<test> EXEC ['/bin/sh', '-c', '/bin/sh -c \'( umask 77 && mkdir -p "` echo /root/.ansible/tmp `"&& mkdir "` echo /root/.ansible/tmp/ansible-tmp-1681167189.9324355-43258-17675217124816 `" && echo ansible-tmp-1681167189.9324355-43258-17675217124816="` echo /root/.ansible/tmp/ansible-tmp-1681167189.9324355-43258-17675217124816 `" ) && sleep 0\'']
Using module file /home/user/Documents/Projects/ansible/.venv/lib64/python3.11/site-packages/ansible/modules/async_status.py
<test> PUT /home/user/.ansible/tmp/ansible-local-431996hdrm4ms/tmptolr2c4t TO /root/.ansible/tmp/ansible-tmp-1681167189.9324355-43258-17675217124816/AnsiballZ_async_status.py
<test> EXEC ['/bin/sh', '-c', "/bin/sh -c 'chmod u+x /root/.ansible/tmp/ansible-tmp-1681167189.9324355-43258-17675217124816/ /root/.ansible/tmp/ansible-tmp-1681167189.9324355-43258-17675217124816/AnsiballZ_async_status.py && sleep 0'"]
<test> EXEC ['/bin/sh', '-c', "/bin/sh -c '/usr/bin/python3.11 /root/.ansible/tmp/ansible-tmp-1681167189.9324355-43258-17675217124816/AnsiballZ_async_status.py && sleep 0'"]
<test> EXEC ['/bin/sh', '-c', "/bin/sh -c 'echo ~ && sleep 0'"]
Using module file /home/user/Documents/Projects/ansible/.venv/lib64/python3.11/site-packages/ansible/modules/async_status.py
<test> PUT /home/user/.ansible/tmp/ansible-local-431996hdrm4ms/tmpgz9bh8lh TO /root/.ansible/tmp/ansible-tmp-1681167189.9324355-43258-17675217124816/AnsiballZ_async_status.py
<test> EXEC ['/bin/sh', '-c', "/bin/sh -c 'chmod u+x /root/.ansible/tmp/ansible-tmp-1681167189.9324355-43258-17675217124816/ /root/.ansible/tmp/ansible-tmp-1681167189.9324355-43258-17675217124816/AnsiballZ_async_status.py && sleep 0'"]
<test> EXEC ['/bin/sh', '-c', "/bin/sh -c '/usr/bin/python3.11 /root/.ansible/tmp/ansible-tmp-1681167189.9324355-43258-17675217124816/AnsiballZ_async_status.py && sleep 0'"]
<test> EXEC ['/bin/sh', '-c', "/bin/sh -c 'rm -f -r /root/.ansible/tmp/ansible-tmp-1681167189.9324355-43258-17675217124816/ > /dev/null 2>&1 && sleep 0'"]
ASYNC OK on test: jid=170992352143.4734
changed: [test] => {
    "ansible_job_id": "170992352143.4734",
    "changed": true,
    "cmd": [
        "whoami"
    ],
    "delta": "0:00:00.002106",
    "end": "2023-04-10 22:53:08.805420",
    "finished": 1,
    "invocation": {
        "module_args": {
            "_raw_params": "whoami",
            "_uses_shell": false,
            "argv": null,
            "chdir": null,
            "creates": null,
            "executable": null,
            "removes": null,
            "stdin": null,
            "stdin_add_newline": true,
            "strip_empty_ends": true
        }
    },
    "msg": "",
    "rc": 0,
    "results_file": "/root/.ansible_async/170992352143.4734",
    "start": "2023-04-10 22:53:08.803314",
    "started": 1,
    "stderr": "",
    "stderr_lines": [],
    "stdout": "root",
    "stdout_lines": [
        "root"
    ]
}

TASK [debug] *******************************************************************
task path: /home/user/Documents/Projects/ansible/playbooks/test.yml:11
ok: [test] => {
    "command": {
        "ansible_job_id": "170992352143.4734",
        "changed": true,
        "cmd": [
            "whoami"
        ],
        "delta": "0:00:00.002106",
        "end": "2023-04-10 22:53:08.805420",
        "failed": false,
        "finished": 1,
        "msg": "",
        "rc": 0,
        "results_file": "/root/.ansible_async/170992352143.4734",
        "start": "2023-04-10 22:53:08.803314",
        "started": 1,
        "stderr": "",
        "stderr_lines": [],
        "stdout": "root",
        "stdout_lines": [
            "root"
        ]
    }
}

PLAY RECAP *********************************************************************
test                       : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

christophert avatar Apr 10 '23 22:04 christophert