Skip to content

fix: Podman compatibility and testing #142

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

Open
wants to merge 19 commits into
base: main
Choose a base branch
from
Open

fix: Podman compatibility and testing #142

wants to merge 19 commits into from

Conversation

angela-ko
Copy link
Contributor

@angela-ko angela-ko commented Apr 29, 2025

Description of changes

Podman adds urls in front of all images

❯ podman image ls | grep docker_client
docker.io/local_host/foo/bar/docker_client_create_image_url_test  latest                        f499aed52e60  45 years ago   8.12 MB
docker.io/library/docker_client_create_image_test                 dummy                         f499aed52e60  45 years ago   8.12 MB

So we need to change the string matching to substring matching instead in tags.

Testing done

Tested locally with podman + Added ci testing with podman

License

  • [ x] By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
  • [ x] I sign the Developer Certificate of Origin below by adding my name and email address to the Signed-off-by line.
Developer Certificate of Origin
Developer Certificate of Origin
Version 1.1

Copyright (C) 2004, 2006 The Linux Foundation and its contributors.

Everyone is permitted to copy and distribute verbatim copies of this
license document, but changing it is not allowed.


Developer's Certificate of Origin 1.1

By making a contribution to this project, I certify that:

(a) The contribution was created in whole or in part by me and I
    have the right to submit it under the open source license
    indicated in the file; or

(b) The contribution is based upon previous work that, to the best
    of my knowledge, is covered under an appropriate open source
    license and I have the right under that license to submit that
    work with modifications, whether created in whole or in part
    by me, under the same open source license (unless I am
    permitted to submit under a different license), as indicated
    in the file; or

(c) The contribution was provided directly to me by some other
    person who certified (a), (b) or (c) and I have not modified
    it.

(d) I understand and agree that this project and the contribution
    are public and that a record of the contribution (including all
    personal information I submit with it, including my sign-off) is
    maintained indefinitely and may be redistributed consistent with
    this project or the open source license(s) involved.

Signed-off-by: Angela Ko angela.ko@simulation.science

Copy link

codecov bot commented Apr 29, 2025

Codecov Report

Attention: Patch coverage is 81.81818% with 2 lines in your changes missing coverage. Please review.

Project coverage is 75.69%. Comparing base (4e2aed2) to head (fc03af6).
Report is 5 commits behind head on main.

Files with missing lines Patch % Lines
tesseract_core/sdk/docker_client.py 81.81% 0 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #142      +/-   ##
==========================================
+ Coverage   75.63%   75.69%   +0.05%     
==========================================
  Files          27       27              
  Lines        2910     2921      +11     
  Branches      446      449       +3     
==========================================
+ Hits         2201     2211      +10     
  Misses        512      512              
- Partials      197      198       +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@heitorPB heitorPB changed the title Handle empty strings and repo urls in assertions fix: handle empty strings and repo urls in assertions Apr 30, 2025
@angela-ko angela-ko marked this pull request as ready for review April 30, 2025 17:55
@angela-ko
Copy link
Contributor Author

oh wait i just realized this might lead to over matching of images

@heitorPB like matching "repo" with "repo_1234_dsjklfj:latest" , so maybe we should go back to your tag split method instead....

@angela-ko
Copy link
Contributor Author

Also not sure why the images aren't being cleaned up in podman so need to fix that too in this pr

@dionhaefner
Copy link
Contributor

👌 Ping me when the outstanding issues are fixed and I'll have a closer look. Agree on not abusing substring matching here in favor of something more robust.

And some food for thought (not necessarily implemented here): Can we test w/ podman on CI?

@heitorPB
Copy link
Contributor

heitorPB commented Apr 30, 2025

And some food for thought (not necessarily implemented here): Can we test w/ podman on CI?

GitHub runners have Podman installed, so we can. But, one of the tests will fail with Podman. Podman doesn't support port-ranges in the docker-compose file (containers/podman#15111) and we have a test for that particular case. Can we skip that test when testing with Podman? How to do that?

@angela-ko angela-ko changed the title fix: handle empty strings and repo urls in assertions fix: Podman compatibility and testing Apr 30, 2025
@angela-ko
Copy link
Contributor Author

@heitorPB I think the podman socket isn't correct:

DEBUG    tesseract:engine.py:94 #23 exporting config sha256:2db97d1217b95769fac0df0fcebf96a3f3b3961a1a9414db78161ff29a9045a3 done
DEBUG    tesseract:engine.py:94 #23 sending tarball
DEBUG    tesseract:engine.py:94 ERROR: failed to receive status: rpc error: code = Unavailable desc = error reading from server: read unix @->/run/user/1001/podman/podman.sock: read: connection reset by peer
WARNING  tesseract:engine.py:416 Build failed with logs:
WARNING  tesseract:engine.py:418 #0 building with "default" instance using docker-container driver

@heitorPB
Copy link
Contributor

heitorPB commented May 2, 2025

The podman socket (/run/user/1001/podman/podman.sock) is correct, I added a status command to the "set up podman" step and we can see the socket is active and the path is correct.

The error we get with a bad socket is different:
$  DOCKER_HOST=unix:///foo python -c 'import docker; print(docker.from_env().info())'
Traceback (most recent call last):
  File "/home/h/projects/pasteur/tesseract-core/.venv/lib/python3.13/site-packages/urllib3/connectionpool.py", line 787, in urlopen
    response = self._make_request(
        conn,
    ...<10 lines>...
        **response_kw,
    )
  File "/home/h/projects/pasteur/tesseract-core/.venv/lib/python3.13/site-packages/urllib3/connectionpool.py", line 493, in _make_request
    conn.request(
    ~~~~~~~~~~~~^
        method,
        ^^^^^^^
    ...<6 lines>...
        enforce_content_length=enforce_content_length,
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    )
    ^
  File "/home/h/projects/pasteur/tesseract-core/.venv/lib/python3.13/site-packages/urllib3/connection.py", line 445, in request
    self.endheaders()
    ~~~~~~~~~~~~~~~^^
  File "/home/h/.local/share/uv/python/cpython-3.13.3-linux-x86_64-gnu/lib/python3.13/http/client.py", line 1333, in endheaders
    self._send_output(message_body, encode_chunked=encode_chunked)
    ~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/h/.local/share/uv/python/cpython-3.13.3-linux-x86_64-gnu/lib/python3.13/http/client.py", line 1093, in _send_output
    self.send(msg)
    ~~~~~~~~~^^^^^
  File "/home/h/.local/share/uv/python/cpython-3.13.3-linux-x86_64-gnu/lib/python3.13/http/client.py", line 1037, in send
    self.connect()
    ~~~~~~~~~~~~^^
  File "/home/h/projects/pasteur/tesseract-core/.venv/lib/python3.13/site-packages/docker/transport/unixconn.py", line 26, in connect
    sock.connect(self.unix_socket)
    ~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^
FileNotFoundError: [Errno 2] No such file or directory

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/h/projects/pasteur/tesseract-core/.venv/lib/python3.13/site-packages/requests/adapters.py", line 667, in send
    resp = conn.urlopen(
        method=request.method,
    ...<9 lines>...
        chunked=chunked,
    )
  File "/home/h/projects/pasteur/tesseract-core/.venv/lib/python3.13/site-packages/urllib3/connectionpool.py", line 841, in urlopen
    retries = retries.increment(
        method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]
    )
  File "/home/h/projects/pasteur/tesseract-core/.venv/lib/python3.13/site-packages/urllib3/util/retry.py", line 474, in increment
    raise reraise(type(error), error, _stacktrace)
          ~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/h/projects/pasteur/tesseract-core/.venv/lib/python3.13/site-packages/urllib3/util/util.py", line 38, in reraise
    raise value.with_traceback(tb)
  File "/home/h/projects/pasteur/tesseract-core/.venv/lib/python3.13/site-packages/urllib3/connectionpool.py", line 787, in urlopen
    response = self._make_request(
        conn,
    ...<10 lines>...
        **response_kw,
    )
  File "/home/h/projects/pasteur/tesseract-core/.venv/lib/python3.13/site-packages/urllib3/connectionpool.py", line 493, in _make_request
    conn.request(
    ~~~~~~~~~~~~^
        method,
        ^^^^^^^
    ...<6 lines>...
        enforce_content_length=enforce_content_length,
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    )
    ^
  File "/home/h/projects/pasteur/tesseract-core/.venv/lib/python3.13/site-packages/urllib3/connection.py", line 445, in request
    self.endheaders()
    ~~~~~~~~~~~~~~~^^
  File "/home/h/.local/share/uv/python/cpython-3.13.3-linux-x86_64-gnu/lib/python3.13/http/client.py", line 1333, in endheaders
    self._send_output(message_body, encode_chunked=encode_chunked)
    ~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/h/.local/share/uv/python/cpython-3.13.3-linux-x86_64-gnu/lib/python3.13/http/client.py", line 1093, in _send_output
    self.send(msg)
    ~~~~~~~~~^^^^^
  File "/home/h/.local/share/uv/python/cpython-3.13.3-linux-x86_64-gnu/lib/python3.13/http/client.py", line 1037, in send
    self.connect()
    ~~~~~~~~~~~~^^
  File "/home/h/projects/pasteur/tesseract-core/.venv/lib/python3.13/site-packages/docker/transport/unixconn.py", line 26, in connect
    sock.connect(self.unix_socket)
    ~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^
urllib3.exceptions.ProtocolError: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory'))

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/h/projects/pasteur/tesseract-core/.venv/lib/python3.13/site-packages/docker/api/client.py", line 223, in _retrieve_server_version
    return self.version(api_version=False)["ApiVersion"]
           ~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^
  File "/home/h/projects/pasteur/tesseract-core/.venv/lib/python3.13/site-packages/docker/api/daemon.py", line 181, in version
    return self._result(self._get(url), json=True)
                        ~~~~~~~~~^^^^^
  File "/home/h/projects/pasteur/tesseract-core/.venv/lib/python3.13/site-packages/docker/utils/decorators.py", line 44, in inner
    return f(self, *args, **kwargs)
  File "/home/h/projects/pasteur/tesseract-core/.venv/lib/python3.13/site-packages/docker/api/client.py", line 246, in _get
    return self.get(url, **self._set_request_timeout(kwargs))
           ~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/h/projects/pasteur/tesseract-core/.venv/lib/python3.13/site-packages/requests/sessions.py", line 602, in get
    return self.request("GET", url, **kwargs)
           ~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
  File "/home/h/projects/pasteur/tesseract-core/.venv/lib/python3.13/site-packages/requests/sessions.py", line 589, in request
    resp = self.send(prep, **send_kwargs)
  File "/home/h/projects/pasteur/tesseract-core/.venv/lib/python3.13/site-packages/requests/sessions.py", line 703, in send
    r = adapter.send(request, **kwargs)
  File "/home/h/projects/pasteur/tesseract-core/.venv/lib/python3.13/site-packages/requests/adapters.py", line 682, in send
    raise ConnectionError(err, request=request)
requests.exceptions.ConnectionError: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory'))

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
    import docker; print(docker.from_env().info())
                         ~~~~~~~~~~~~~~~^^
  File "/home/h/projects/pasteur/tesseract-core/.venv/lib/python3.13/site-packages/docker/client.py", line 94, in from_env
    return cls(
        timeout=timeout,
    ...<3 lines>...
        **kwargs_from_env(**kwargs)
    )
  File "/home/h/projects/pasteur/tesseract-core/.venv/lib/python3.13/site-packages/docker/client.py", line 45, in __init__
    self.api = APIClient(*args, **kwargs)
               ~~~~~~~~~^^^^^^^^^^^^^^^^^
  File "/home/h/projects/pasteur/tesseract-core/.venv/lib/python3.13/site-packages/docker/api/client.py", line 207, in __init__
    self._version = self._retrieve_server_version()
                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^
  File "/home/h/projects/pasteur/tesseract-core/.venv/lib/python3.13/site-packages/docker/api/client.py", line 230, in _retrieve_server_version
    raise DockerException(
        f'Error while fetching server API version: {e}'
    ) from e
docker.errors.DockerException: Error while fetching server API version: ('Connection aborted.', FileNotFoundError(2, 'No such file or directory'))

The errors we are seeing here for podman are a bit weird. It appears that it built the images, but failed to load them?

@jpbrodrick89
Copy link
Contributor

Seems similar to what we observed with docker py and podman. The images were all fine and runnable from command line in our case. Would you like me to see if I can replicate your issue when back in office on Tues? (If you've not fixed it by then!)

@heitorPB
Copy link
Contributor

heitorPB commented May 2, 2025

The funny thing is: all tests pass on my Linux machine, the errors only appear in the CI. I can't replicate the failures locally. It would be great if you could run the tests and report whether it passes or not.

@dionhaefner
Copy link
Contributor

dionhaefner commented May 5, 2025

Judging from this run it looks like every single image build fails. So this is unlikely to be an issue with resources running low.

I suggest to reproduce this on CI via a simple docker buildx build that does not use Tesseract code (potentially via tesseract build --generate-only, or even a dead simple dummy Dockerfile). If the problem reproduces, we know something's off with the setup. If it doesn't we'll keep digging to isolate the feature we use that podman chokes on.

As soon as this is isolated we'll have a much easier time to either experiment with the setup (e.g. upgrade podman) or create an upstream issue asking for help.

@angela-ko
Copy link
Contributor Author

Heitor mentioned that it might be a podman versioning issue -- we reran the ubuntu 24 podman test (previous one got cancelled for some reason) and it seems to be passing.

@dionhaefner
Copy link
Contributor

That was my suspicion too :) Can we nail down then which version we require? Just so we can add a blurb to the docs a la "make sure you grab at least Podman vfoo.bar".

(No need for this to be a tight bound, but even knowing "version X works while version Y doesn't" is useful.)

@heitorPB
Copy link
Contributor

heitorPB commented May 5, 2025

Podman 4.9 works on the CI, but version 3.x doesn't. I'm running with podman 5.4.1 and it also works :)

Comment on lines 290 to 296
- name: Set up Podman
run: |
systemctl start --user podman.socket
systemctl status --user podman.socket
podman -v
cat /etc/os-release
Copy link
Contributor

@dionhaefner dionhaefner May 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seeing this is the only difference from the Docker tests, could we please add this as an additional dimension of the test matrix above? That is, we use something like this:

    strategy:
      matrix:
        os: [ubuntu-24.04]
        python-version: ["3.12"]

        arch: ["x64"]
        docker-engine: ["docker"]

        unit-tesseract: ${{ fromJson(needs.get-e2e-matrix.outputs.matrix) }}

        include:
          # Test on arm to ensure compatibility with Apple M1 chips
          # (OSX runners don't have access to Docker so we use Linux ARM runners instead)
          - os: "ubuntu-22.04"
            python-version: "3.12"
            arch: "arm"
            docker-engine: "docker"
            unit-tesseract: "base"
         # Test with podman as Docker engine
         - os: "ubuntu-22.04"
            python-version: "3.12"
            arch: "x64"
            docker-engine: "podman"
            unit-tesseract: "base"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Podman test differs in two things:

  1. starting the podman.socket
  2. using the socket in the uv run ... command:
    DOCKER_HOST=unix:///run/user/1001/podman/podman.sock \
    uv run --no-sync pytest \
      --always-run-endtoend \
      --cov-report=term-missing:skip-covered \
      --cov-report=xml:coverage.xml \
      --cov=tesseract_core \
      tests/endtoend_tests \
      -k "not test_examples"
    ...
    

How to do both of that as a new matrix dimension?

Copy link
Contributor

@dionhaefner dionhaefner May 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can do this: (untested)

      - name: Set up Podman
        if: matrix.docker-engine == "podman"
        run: |
          systemctl start --user podman.socket
          systemctl status --user podman.socket
          podman -v
          cat /etc/os-release
          echo "DOCKER_HOST=unix:///run/user/1001/podman/podman.sock" >> $GITHUB_ENV

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.

4 participants