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

exec_run(cmd, socket=True) isn't implemented: blocks and only returns resulting stdout/stderr bytes #421

Open
djasa opened this issue Aug 15, 2024 · 4 comments

Comments

@djasa
Copy link

djasa commented Aug 15, 2024

As per docs and docker API examples, c.exec_run(cmd, socket=True) should return immediately with socket to be used for process' stdin/out/err as the second value of the returned tuple. However, podman-py waits for the process to finish and it only returns final stdout/err bytes as the output.

Fiddling with stream and tty parameters doesn't make any change in the behaviour.

Given that googling for "PodmanClient" "exec_run" "socket=True" or "PodmanClient" "exec_run" "stdin=True" yields zero results in both cases, maybe it's fine that socket=True isn't implemented, but then socket, stdin and stream parameters to exec_run() shouldn't be mentioned in the docs at all, or at the very least, throw the NotImplementedError exception when calling exec_run() with either of these set to True?

versions

  • Fedora 40: python3-podman-5.2.0-1.fc40.noarch
  • RHEL 9: python3-podman-5.2.0-1.el9.noarch

Reproducers:

just outputs

>>> pc = PodmanClient(base_url=podman_sock)
>>> c = pc.containers.get(cont_name)
>>> res = c.exec_run(["bash", "-c", "echo -n 'hello'; sleep 10; echo 'world!'"], socket=True); type(res[1])

Actual results:

  • type(res[1]) output only appears after 10 s
  • the type of res[1] is <class 'bytes'>

Expected result: res is returned right away and its output field is socket object for further I/O

with stdin

>>> res = c.exec_run("bash", socket=True, stdin=True); type(res[1])
exit<enter>

Expected results: bash receives the exit command and ends itself

Actual results:

  • bash never receives the exit command
  • API waits for data that can't come
  • no clean way to get out of the wait, keyboard interrupt in an interactive intepreter produces this traceback (on RHEL 9):
    >>> sock = c.exec_run("bash", stdin=True, socket=True, tty=False)
    exit
    
    ^CTraceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "/usr/lib/python3.9/site-packages/podman/domain/containers.py", line 198, in exec_run
        start_resp = self.client.post(
      File "/usr/lib/python3.9/site-packages/podman/api/client.py", line 327, in post
        return self._request(
      File "/usr/lib/python3.9/site-packages/podman/api/client.py", line 425, in _request
        self.request(
      File "/usr/lib/python3.9/site-packages/requests/sessions.py", line 544, in request
        resp = self.send(prep, **send_kwargs)
      File "/usr/lib/python3.9/site-packages/requests/sessions.py", line 699, in send
        r.content
      File "/usr/lib/python3.9/site-packages/requests/models.py", line 831, in content
        self._content = b''.join(self.iter_content(CONTENT_CHUNK_SIZE)) or b''
      File "/usr/lib/python3.9/site-packages/requests/models.py", line 753, in generate
        for chunk in self.raw.stream(chunk_size, decode_content=True):
      File "/usr/lib/python3.9/site-packages/urllib3/response.py", line 628, in stream
        data = self.read(amt=amt, decode_content=decode_content)
      File "/usr/lib/python3.9/site-packages/urllib3/response.py", line 567, in read
        data = self._fp_read(amt) if not fp_closed else b""
      File "/usr/lib/python3.9/site-packages/urllib3/response.py", line 533, in _fp_read
        return self._fp.read(amt) if amt is not None else self._fp.read()
      File "/usr/lib64/python3.9/http/client.py", line 463, in read
        n = self.readinto(b)
      File "/usr/lib64/python3.9/http/client.py", line 507, in readinto
        n = self.fp.readinto(b)
      File "/usr/lib64/python3.9/socket.py", line 704, in readinto
        return self._sock.recv_into(b)
    KeyboardInterrupt
@inknos
Copy link
Contributor

inknos commented Aug 15, 2024

hey @djasa , thanks for the detailed report. you are correct, exec_run differs in the implementation from docker python sdk. There are missing kwargs and some of the functionalities might not be there.

Furthermore, some commands might be in the docs as part of in progress work, then the work was dropped some time ago. We should definitely cleanup the docs a bit.

are you interested in taking care of the implementation of one or more arguments?

@djasa
Copy link
Author

djasa commented Aug 15, 2024

are you interested in taking care of the implementation of one or more arguments?

I'm sorry, it's out of my skills, I haven't yet even used socket-based APIs so far. 😅 It will be OK for me to use a call to podman exec as a work around, so even just docs fix or raising the NotImplementedError would be a good fix from my POV.

@inknos
Copy link
Contributor

inknos commented Aug 16, 2024

Got it, I will put it in the backlog. Thanks for the report, we got more interest around exec_run recently, so I hope to have it fixed soon

@milanbalazs
Copy link
Contributor

FYI: Based on the Podman API documentation the socket and stream parameters are not implemented, ref: ExecStart

The Docker Python SDK uses the exec_start method to start the exec which can handle the socket and stream parameters on API level.

So in my understanding, some changes are needed on Podman API side (or hacking in podman-py).

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

No branches or pull requests

3 participants