podman-py icon indicating copy to clipboard operation
podman-py copied to clipboard

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

Open djasa opened this issue 1 year ago • 4 comments

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
    

djasa avatar Aug 15 '24 15:08 djasa

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?

inknos avatar Aug 15 '24 15:08 inknos

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.

djasa avatar Aug 15 '24 16:08 djasa

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

inknos avatar Aug 16 '24 11:08 inknos

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).

milanbalazs avatar Sep 12 '24 22:09 milanbalazs