Skip to content

Commit

Permalink
Support container provisioner in toolbox
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
thrix committed Sep 19, 2024
1 parent 8245c47 commit ce8a3c6
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 2 deletions.
7 changes: 7 additions & 0 deletions tests/provision/container/toolbox/main.fmf
Original file line number Diff line number Diff line change
@@ -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
2 changes: 2 additions & 0 deletions tests/provision/container/toolbox/podman_wrapper
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/bash
flatpak-spawn --host podman "$@"
48 changes: 48 additions & 0 deletions tests/provision/container/toolbox/test.sh
Original file line number Diff line number Diff line change
@@ -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
41 changes: 39 additions & 2 deletions tmt/steps/provision/podman.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import dataclasses
import functools
import os
from shlex import quote
from typing import Any, Optional, Union, cast
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit ce8a3c6

Please sign in to comment.