From ce8a3c6e64e0491e681bb85f5557d014d67e67a4 Mon Sep 17 00:00:00 2001 From: Miroslav Vadkerti Date: Fri, 20 Sep 2024 00:36:01 +0200 Subject: [PATCH] Support container provisioner in toolbox For Fedora Silverblue users it is common to run podman via `flatpak-spawn --host` which runs podman on the host system itself. This requires to pass the toolbox container name when running `podman cp` to correctly copy stuff from the toolbox container, where `tmt` is installed to the provisioned container. Fixes #1020 Signed-off-by: Miroslav Vadkerti --- tests/provision/container/toolbox/main.fmf | 7 +++ .../container/toolbox/podman_wrapper | 2 + tests/provision/container/toolbox/test.sh | 48 +++++++++++++++++++ tmt/steps/provision/podman.py | 41 +++++++++++++++- 4 files changed, 96 insertions(+), 2 deletions(-) create mode 100644 tests/provision/container/toolbox/main.fmf create mode 100755 tests/provision/container/toolbox/podman_wrapper create mode 100755 tests/provision/container/toolbox/test.sh diff --git a/tests/provision/container/toolbox/main.fmf b/tests/provision/container/toolbox/main.fmf new file mode 100644 index 0000000000..ced5aad6eb --- /dev/null +++ b/tests/provision/container/toolbox/main.fmf @@ -0,0 +1,7 @@ +summary: Test container provisioner in toolbox +description: + Make sure that container provisioner works well + in a toolbox container. +tag+: + - provision-only + - provision-container diff --git a/tests/provision/container/toolbox/podman_wrapper b/tests/provision/container/toolbox/podman_wrapper new file mode 100755 index 0000000000..a1792117bf --- /dev/null +++ b/tests/provision/container/toolbox/podman_wrapper @@ -0,0 +1,2 @@ +#!/bin/bash +flatpak-spawn --host podman "$@" diff --git a/tests/provision/container/toolbox/test.sh b/tests/provision/container/toolbox/test.sh new file mode 100755 index 0000000000..af19992689 --- /dev/null +++ b/tests/provision/container/toolbox/test.sh @@ -0,0 +1,48 @@ +#!/bin/bash +. /usr/share/beakerlib/beakerlib.sh || exit 1 + +rlJournalStart + rlPhaseStartSetup + rlRun "toolbox_container_name=\$(uuidgen)" 0 "Generate toolbox container name" + rlPhaseEnd + + rlPhaseStartTest "Create toolbox container" + rlRun "toolbox create -y $toolbox_container_name" + rlPhaseEnd + + toolbox_run() { + toolbox run --container "$toolbox_container_name" "$@" + } + + if env | grep -q PACKIT_COPR_PROJECT; then + rlPhaseStartTest "Install tmt in from copr repository" + TMT_COMMAND="tmt" + rlRun "toolbox_run dnf -y install dnf-plugins-core" + rlRun "toolbox_run dnf -y copr enable $PACKIT_COPR_PROJECT" + rlRun "toolbox_run dnf -y install tmt-provision-container" + rlPhaseEnd + else + rlPhaseStartTest "Install hatch, expecting local execution" + TMT_COMMAND="hatch run dev:tmt" + rlRun "toolbox_run dnf -y install hatch" + rlPhaseEnd + fi + + rlPhaseStartTest "Print tmt version installed in toolbox" + rlRun "toolbox_run $TMT_COMMAND --version" + rlPhaseEnd + + rlPhaseStartTest "Add podman wrapper" + rlRun "podman cp podman_wrapper $toolbox_container_name:/usr/bin/podman" + rlRun "toolbox_run podman --version" + rlPhaseEnd + + rlPhaseStartTest "Verify container provisioner works from toolbox" + rlRun -s "toolbox_run tmt run -a -vvv provision -h container execute -h tmt -s 'echo hello from container'" + rlAssertGrep "content: hello from container" $rlRun_LOG + rlPhaseEnd + + rlPhaseStartCleanup + rlRun "toolbox rm -f $toolbox_container_name" 0 "Remove toolbox container" + rlPhaseEnd +rlJournalEnd diff --git a/tmt/steps/provision/podman.py b/tmt/steps/provision/podman.py index 36f6533be2..1dccbf6d6d 100644 --- a/tmt/steps/provision/podman.py +++ b/tmt/steps/provision/podman.py @@ -1,4 +1,5 @@ import dataclasses +import functools import os from shlex import quote from typing import Any, Optional, Union, cast @@ -283,6 +284,33 @@ def _run_ansible( log=log, silent=silent) + @functools.cached_property + def _is_toolbox(self) -> bool: + """ Return ``True`` if running in toolbox, ``False`` otherwise. """ + if os.path.exists('/run/.toolboxenv'): + return True + + return False + + @functools.cached_property + def _toolbox_container_name(self) -> Optional[str]: + """ Returns toolbox container name if running in toolbox, ``None`` otherwise. """ + if not self._is_toolbox: + return None + + if not os.path.exists('/run/.containerenv'): + self.logger.warning( + "Unable to detect toolbox container name, '/run/.containerenv' not found." + ) + return None + + with open('/run/.containerenv') as envfile: + for line in envfile.readline(): + if line.startswith('name="'): + return line[6:-1] + + return None + def podman( self, command: Command, @@ -376,10 +404,19 @@ def push( self._run_guest_command(Command( "chcon", "--recursive", "--type=container_file_t", self.parent.plan.workdir ), shell=False, silent=True) + # In case explicit destination is given, use `podman cp` to copy data - # to the container + # to the container. If running in toolbox, make sure to copy from the toolbox + # container instead of localhost. if source and destination: - self.podman(Command("cp", source, f"{self.container}:{destination}")) + self.podman( + Command( + "cp", + f"{self._toolbox_container_name}:{source}" + if self._toolbox_container_name else source, + f"{self.container}:{destination}" + ) + ) def pull( self,