-
Notifications
You must be signed in to change notification settings - Fork 122
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
shutdown(SHUT_WR) does not work for SSLSocket, causing docker_api connection and docker_container_exec module to have problems with TCP TLS sockets #605
Comments
Sorry this took so long (too busy with other things). I've been able to reproduce this and will try to debug it over the next days. In my case already interpreter discovery has some problems (and I found and fixed one bug in case Docker SDK for Python isn't installed)... |
The problem is So |
Hmm, the longer I look at this, the more I get the feeling that this is simply not possible at all with Python's |
I created #621 to warn about this in the docs and changelog. I'm currently thinking that it might be possible to work around this by using PyOpenSSL's |
References: |
Some test code that can be useful for reproducing this without the whole baggage of Ansible modules/plugins: import os
import selectors
import socket
import sys
import time
from ansible_collections.community.docker.plugins.module_utils._api.api.client import APIClient
from ansible_collections.community.docker.plugins.module_utils._api.tls import TLSConfig
from ansible_collections.community.docker.plugins.plugin_utils.socket_handler import (
DockerSocketHandler,
)
# from docker import APIClient
# from docker.tls import TLSConfig
client = APIClient(base_url='tcp://127.0.0.1:2376', tls=TLSConfig(client_cert=(os.path.expanduser('~/.docker/cert.pem'), os.path.expanduser('~/.docker/key.pem')), ca_cert=os.path.expanduser('~/.docker/ca.pem'), verify=True))
url = client._url('/containers/{0}/exec', 'test')
res = client._post_json(url, data={
'Container': 'test',
'User': '',
'Privileged': False,
'Tty': False,
'AttachStdin': True,
'AttachStdout': True,
'AttachStderr': True,
'Cmd': ['python'],
'Env': None,
})
cmd = client._result(res, True)
res = client._post_json(
client._url('/exec/{0}/start', cmd['Id']),
headers={
'Connection': 'Upgrade',
'Upgrade': 'tcp'
},
data={
'Tty': False,
'Detach': False
},
stream=True
)
exec_socket = client._get_raw_response_socket(res)
if True:
from ansible_collections.community.docker.plugins.module_utils.socket_helper import (
make_unblocking,
shutdown_writing,
)
make_unblocking(exec_socket)
exec_socket.send(b'print(1)\n\n\n')
selector = selectors.DefaultSelector()
selector.register(exec_socket, selectors.EVENT_READ)
# exec_socket.shutdown(socket.SHUT_WR)
eof = False
while not eof:
print('select...')
events = selector.select(1)
print(f'got {len(events)} events')
for key, event in events:
if key.fileobj == exec_socket:
buf = exec_socket.recv(262144)
print(buf)
if not buf:
eof = True
sys.exit()
else:
class Display:
def vvvv(self, output, host=None):
print(host, output)
display = Display()
try:
with DockerSocketHandler(display, exec_socket, container='test') as exec_socket_handler:
exec_socket_handler.write(b'print(1)')
stdout, stderr = exec_socket_handler.consume()
print(stdout, stderr)
finally:
exec_socket.close() This needs a container called |
SUMMARY
Hosts targeted via the
docker_containers
inventory module fail facts gathering if TCP TLS socket is in use.ISSUE TYPE
COMPONENT NAME
community.docker.docker_containers.docker_api
connectionANSIBLE VERSION
COLLECTION VERSION
CONFIGURATION
OS / ENVIRONMENT
Docker host:
Docker version:
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
:inventory/remote-docker.yml
:Container deployment and bootstrap:
bootstrap-install-python/tasks/main.yml
: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
This is not present when executing on a Docker TCP socket without TLS or with the local Unix socket.
The text was updated successfully, but these errors were encountered: