diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3cabb688..9d66e018 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -108,28 +108,35 @@ jobs: fail-fast: false matrix: python_version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12"] - container_runtime: ["podman", "docker"] - update_runtime: [ true, false ] + container_runtime: ["podman"] + update_runtime: [true, false] + rootfull: [true, false] - exclude: + include: - container_runtime: "docker" python_version: "3.7" - update_runtime: true + update_runtime: false + rootfull: false - container_runtime: "docker" python_version: "3.8" - update_runtime: true + update_runtime: false + rootfull: false - container_runtime: "docker" python_version: "3.9" - update_runtime: true + update_runtime: false + rootfull: false - container_runtime: "docker" python_version: "3.10" - update_runtime: true + update_runtime: false + rootfull: false - container_runtime: "docker" python_version: "3.11" - update_runtime: true + update_runtime: false + rootfull: false - container_runtime: "docker" python_version: "3.12" - update_runtime: true + update_runtime: false + rootfull: false steps: - uses: actions/checkout@v4 @@ -143,6 +150,10 @@ jobs: key: nox-${{ matrix.python_version }}-${{ hashFiles('poetry.lock') }} - run: pip install --upgrade nox poetry nox-poetry + if: ${{ ! matrix.rootfull }} + + - run: sudo pip install --upgrade nox poetry nox-poetry + if: ${{ matrix.rootfull }} - name: update the container runtime if: ${{ matrix.update_runtime }} @@ -161,6 +172,7 @@ jobs: - run: | export CUR_USER="$(whoami)" sudo loginctl enable-linger ${CUR_USER} + if: ${{ ! matrix.rootfull }} - run: | mkdir ./tmp/ @@ -169,6 +181,16 @@ jobs: nox -s "test-${{ matrix.python_version }}(${{ matrix.container_runtime }})" -- -x -n auto --reruns 3 --pytest-container-log-level DEBUG nox -s "test-${{ matrix.python_version }}(${{ matrix.container_runtime }})" -- -x --reruns 3 --pytest-container-log-level DEBUG nox -s coverage + if: ${{ ! matrix.rootfull }} + + - run: | + mkdir ./tmp/ + chmod 1777 ./tmp + export TMPDIR="$(pwd)/tmp" + sudo --preserve-env nox -s "test-${{ matrix.python_version }}(${{ matrix.container_runtime }})" -- -x -n auto --reruns 3 --pytest-container-log-level DEBUG + sudo --preserve-env nox -s "test-${{ matrix.python_version }}(${{ matrix.container_runtime }})" -- -x --reruns 3 --pytest-container-log-level DEBUG + sudo --preserve-env nox -s coverage + if: ${{ matrix.rootfull }} - name: verify that no stray containers are left run: | diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 54da14b7..a6369b0a 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -14,6 +14,10 @@ Breaking changes: Improvements and new features: +- Add attributes :py:attr:`~pytest_container.inspect.ContainerInspect.name` and + :py:attr:`~pytest_container.inspect.ContainerNetworkSettings.ip_address` + exposing the container's name & IP + - Add property :py:attr:`~pytest_container.container.ContainerBase.extra_entrypoint_args` to support appending arguments to the container launch command diff --git a/pytest_container/inspect.py b/pytest_container/inspect.py index f1185537..b71fd687 100644 --- a/pytest_container/inspect.py +++ b/pytest_container/inspect.py @@ -242,6 +242,9 @@ class ContainerNetworkSettings: #: list of ports forwarded from the container to the host ports: List[PortForwarding] = field(default_factory=list) + #: IP Address of the container, if it has one + ip_address: Optional[str] = None + @dataclass(frozen=True) class Mount: @@ -280,9 +283,12 @@ class ContainerInspect: """ - #: The Container's ID + #: The container's ID id: str + #: the container's name + name: str + #: program that has been launched inside the container path: str diff --git a/pytest_container/runtime.py b/pytest_container/runtime.py index 3b7fb7f5..20aace03 100644 --- a/pytest_container/runtime.py +++ b/pytest_container/runtime.py @@ -386,7 +386,11 @@ def _network_settings_from_inspect( host_port=int(bindings[0]["HostPort"]), ) ) - return ContainerNetworkSettings(ports=ports) + + net_settings = container_inspect["NetworkSettings"] + ip = net_settings.get("IPAddress") or None + + return ContainerNetworkSettings(ports=ports, ip_address=ip) @staticmethod def _mounts_from_inspect( @@ -517,6 +521,7 @@ def inspect_container(self, container_id: str) -> ContainerInspect: return ContainerInspect( config=conf, state=state, + name=inspect["Name"], id=inspect["Id"], path=inspect["Path"], args=inspect["Args"], @@ -600,6 +605,8 @@ def inspect_container(self, container_id: str) -> ContainerInspect: return ContainerInspect( config=conf, state=state, + # docker prefixes the name with a / for reasons… + name=inspect["Name"].lstrip("/"), id=inspect["Id"], path=inspect["Path"], args=inspect["Args"], diff --git a/tests/test_inspect.py b/tests/test_inspect.py index 8d8c4eb6..cd5e5d02 100644 --- a/tests/test_inspect.py +++ b/tests/test_inspect.py @@ -7,14 +7,17 @@ from .test_container_build import LEAP +_CTR_NAME = "foobar-12345" IMAGE_WITH_EVERYTHING = DerivedContainer( + singleton=True, + extra_launch_args=["--name", _CTR_NAME], base=LEAP, containerfile="""VOLUME /src/ EXPOSE 8080 666 RUN useradd opensuse USER opensuse -ENTRYPOINT /bin/false +ENTRYPOINT /bin/bash ENV HOME=/src/ ENV MY_VAR= ENV SUFFIX_NAME=dc=example,dc=com @@ -23,13 +26,18 @@ ) -@pytest.mark.parametrize("container", [IMAGE_WITH_EVERYTHING], indirect=True) -def test_inspect(container: ContainerData, container_runtime: OciRuntimeBase): - inspect = container.inspect +@pytest.mark.parametrize( + "container_per_test", [IMAGE_WITH_EVERYTHING], indirect=True +) +def test_inspect( + container_per_test: ContainerData, container_runtime: OciRuntimeBase, host +) -> None: + inspect = container_per_test.inspect - assert inspect.id == container.container_id + assert inspect.id == container_per_test.container_id + assert inspect.name == _CTR_NAME assert inspect.config.user == "opensuse" - assert inspect.config.entrypoint == ["/bin/sh", "-c", "/bin/false"] + assert inspect.config.entrypoint == ["/bin/sh", "-c", "/bin/bash"] assert ( "HOME" in inspect.config.env and inspect.config.env["HOME"] == "/src/" @@ -39,9 +47,9 @@ def test_inspect(container: ContainerData, container_runtime: OciRuntimeBase): # prefixes it with `localhost` and the full build tag # (i.e. `pytest_container:$digest`), while docker just uses the digest expected_img = ( - str(container.container) + str(container_per_test.container) if container_runtime.runner_binary == "docker" - else f"localhost/pytest_container:{container.container}" + else f"localhost/pytest_container:{container_per_test.container}" ) assert inspect.config.image == expected_img @@ -59,3 +67,7 @@ def test_inspect(container: ContainerData, container_runtime: OciRuntimeBase): and isinstance(inspect.mounts[0], VolumeMount) and inspect.mounts[0].destination == "/src" ) + + assert inspect.network.ip_address or "" == host.check_output( + f'{container_runtime.runner_binary} inspect --format "{{{{ .NetworkSettings.IPAddress }}}}" {_CTR_NAME}' + )