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

Passing stdin to request attach. #239

Closed
wants to merge 1 commit into from
Closed

Passing stdin to request attach. #239

wants to merge 1 commit into from

Conversation

Piwosz
Copy link

@Piwosz Piwosz commented Jun 10, 2014

Simple implementation of passing body content to post request.

Simple implementation of passing body content to post request.
@shin-
Copy link
Contributor

shin- commented Jun 21, 2014

Thanks! Can you make sure the unit tests pass?

@Piwosz
Copy link
Author

Piwosz commented Jun 21, 2014

I will take care this soon.

@mmerickel
Copy link
Contributor

So I really want this feature but I'm having trouble getting things to actually work out.

Based on snooping traffic from ID=$(echo foo | docker run -i -a stdin busybox cat); docker wait $ID; docker logs $ID I can tell you that the following test gives almost the exact same traffic. The only difference is that while the docker CLI does an attach prior to start, it does not send the stdin data until start is sent. There's no way to coordinate this that I can see and I'd expect it to work out anyway.

I'll continue to tinker with it but I'm kind of stumped based on the traffic I see. Both the docker CLI container and the one in the test are created with the same options and the attach is the same.

class TestAttachWithStdin(BaseTestCase):
    def runTest(self):
        container = self.client.create_container(
            'busybox', 'cat', stdin_open=True)
        container_id = container['Id']
        self.tmp_containers.append(container_id)
        self.client.attach(container_id, stdin='hello world')
        self.client.start(container_id)
        ret = self.client.wait(container_id)
        self.assertEqual(ret, 0)
        result = self.client.logs(container_id, stdout=True, stderr=False)
        self.assertEqual(result, b'hello world')

Side note, it's super easy to snoop the traffic from both the CLI and the tests by rebasing this against master and then using socat.

socat -x -v UNIX-LISTEN:/tmp/docker-proxy.sock,fork UNIX-CONNECT:/var/run/docker.sock &
export DOCKER_HOST=unix:///tmp/docker-proxy.sock
env/bin/python setup.py test
ID=$(echo foo | docker run -i -a stdin busybox cat); docker wait $ID; docker logs $ID

@nikicat
Copy link

nikicat commented Oct 6, 2014

👍 I'm waiting for this feature

@slix
Copy link
Contributor

slix commented May 28, 2015

👍 This is something I need.

Are the failing unit tests the only blocker for this being merged?

@slix
Copy link
Contributor

slix commented May 29, 2015

I tried out the pull request, but I couldn't get the changes to work. requests was passing the "stdin" parameter to the /attach endpoint as data, but no matter what I did, I could never get the stdin content to show up in the container. (Or whatever I did was clobbering stdout, which is how I was testing this out.)

I managed to get stdin to work via attach_socket though as a workaround! It doesn't require this pull request. I hope this helps anyone trying to use stdin:

client.create_container(
    image="ubuntu:14.04",
    command="whatever",
    stdin_open=True)
client.start(container)
s = client.attach_socket(container, params={'stdin': 1, 'stream': 1})
s.send("Hello, world! This is on stdin!")
s.close()

I don't know if that's the correct way to do this, so if anyone knows a better way, that'd be awesome. But this works for me!

Also, if you rebase this patch onto a recent commit, the unit tests no longer fail.

@rutsky
Copy link
Contributor

rutsky commented Oct 29, 2015

Any progress on this?

@slix's workaround doesn't work in Python 3 (s doesn't have send method) and I don't see any documentation for client.attach_socket.

@SakuraSound
Copy link
Contributor

@rutsky @slix's workaround does work in Python3. Make sure that when you create your container, you set the parameter stdin_open to True, since it defaults as False.

my example

stdin-test.py

import sys
import json
import logging

print("STARTED")
while True:
    line = sys.stdin.readline()
    print("GOT DATA")
    print(line)
    print("Above is data")
    data = json.loads(line)
    print(data)
    data['success'] = True
    logging.info(json.dumps(data))
    break
print("Finished")

Runner.py

import json
from docker.client import Client
from docker.utils import kwargs_from_env

data = {'msg': 'hello-world'}

cli = Client(**kwargs_from_env())
print(cli.version())

container = cli.create_container(image="example/stdin-test" ,stdin_open=True)
cli.start(container)
s = cli.attach_socket(container, params={'stdin': 1, 'stream': 1})
encoded = json.dumps(data).encode()
print(encoded)
sent = s.send(encoded)
print(sent)
s.close()
print(cli.logs(container))

Output

$ docker logs <WHATEVER THE NAME OF THE CONTAINER WAS THAT RAN>
STARTED
GOT DATA
{"msg": "hello-world"}
Above is data
{'msg': 'hello-world'}
Finished

@max-sixty
Copy link

@rutsky @slix's workaround does work in Python3. Make sure that when you create your container, you set the parameter stdin_open to True, since it defaults as False.

I get the same error:

{'KernelVersion': '4.4.15-moby', 'BuildTime': '2016-07-28T21:15:28.963402499+00:00', 'Version': '1.12.0', 'GitCommit': '8eab29e', 'Os': 'linux', 'GoVersion': 'go1.6.3', 'Arch': 'amd64', 'ApiVersion': '1.24'}
b'{"msg": "hello-world"}'
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-86-924b34147f26> in <module>()
     13 encoded = json.dumps(data).encode()
     14 print(encoded)
---> 15 sent = s.send(encoded)
     16 print(sent)
     17 s.close()

AttributeError: 'SocketIO' object has no attribute 'send'

@max-sixty
Copy link

However changing s.send to s._sock.send makes it work:

import json
from docker.client import Client
from docker.utils import kwargs_from_env

data = {'msg': 'hello-world'}

cli = Client(**kwargs_from_env())
print(cli.version())

container = cli.create_container(image="python:2" ,stdin_open=True)
cli.start(container)
s = cli.attach_socket(container, params={'stdin': 1, 'stream': 1})
encoded = json.dumps(data).encode()
print(encoded)
sent = s._sock.send(encoded) # <-- here
print(sent)
s.close()
print(cli.logs(container))

@bfirsh
Copy link
Contributor

bfirsh commented Nov 28, 2016

Closing in favour of #946 which seems to be more complete and less ancient. Feel free to reopen if you have an implementation, @Piwosz!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

9 participants