Files
podman/test/system/252-quadlet.bats
rcmadhankumar f6b4d72a88 [v4.9-rhel] Fix: Remove appending rw as the default mount option
The backstory for this is that runc 1.2 (opencontainers/runc#3967)
fixed a long-standing bug in our mount flag handling (a bug that crun
still has). Before runc 1.2, when dealing with locked mount flags that
user namespaced containers cannot clear, trying to explicitly clearing
locked flags (like rw clearing MS_RDONLY) would silently ignore the rw
flag in most cases and would result in a read-only mount. This is
obviously not what the user expects.

What runc 1.2 did is that it made it so that passing clearing flags
like rw would always result in an attempt to clear the flag (which was
not the case before), and would (in all cases) explicitly return an
error if we try to clear locking flags. (This also let us finally fix a
bunch of other long-standing issues with locked mount flags causing
seemingly spurious errors).

The problem is that podman sets rw on all mounts by default (even if
the user doesn't specify anything). This is actually a no-op in
runc 1.1 and crun because of a bug in how clearing flags were handled
(rw is the absence of MS_RDONLY but until runc 1.2 we didn't correctly
track clearing flags like that, meaning that rw would literally be
handled as if it were not set at all by users) but in runc 1.2 leads to
unfortunate breakages and a subtle change in behaviour (before, a ro
mount being bind-mounted into a container would also be ro -- though
due to the above bug even setting rw explicitly would result in ro in
most cases -- but with runc 1.2 the mount will always be rw even if
the user didn't explicitly request it which most users would find
surprising). By the way, this "always set rw" behaviour is a departure
from Docker and it is not necesssary.

Fixes: https://issues.redhat.com/browse/RHEL-152630,
https://issues.redhat.com/browse/RHEL-153022

Signed-off-by: rcmadhankumar <madhankumar.chellamuthu@suse.com>
(cherry picked from commit bf7dcd5619)
Signed-off-by: Tom Sweeney <tsweeney@redhat.com>
2026-03-05 16:38:06 -05:00

1482 lines
46 KiB
Bash

#!/usr/bin/env bats -*- bats -*-
#
# Tests generated configurations for systemd.
#
load helpers
load helpers.network
load helpers.registry
load helpers.systemd
UNIT_FILES=()
function start_time() {
sleep_to_next_second # Ensure we're on a new second with no previous logging
STARTED_TIME=$(date "+%F %R:%S") # Start time for new log time
}
function setup() {
skip_if_remote "quadlet tests are meaningless over remote"
skip_if_rootless_cgroupsv1 "Can't use --cgroups=split w/ CGv1 (issue 17456, wontfix)"
skip_if_journald_unavailable "Needed for RHEL. FIXME: we might be able to re-enable a subset of tests."
test -x "$QUADLET" || die "Cannot run quadlet tests without executable \$QUADLET ($QUADLET)"
start_time
basic_setup
}
function teardown() {
for UNIT_FILE in ${UNIT_FILES[@]}; do
if [[ -e "$UNIT_FILE" ]]; then
local service=$(basename "$UNIT_FILE")
run systemctl stop "$service"
if [ $status -ne 0 ]; then
echo "# WARNING: systemctl stop failed in teardown: $output" >&3
fi
rm -f "$UNIT_FILE"
fi
done
systemctl daemon-reload
basic_teardown
}
# Converts the quadlet file and installs the result it in $UNIT_DIR
function run_quadlet() {
local sourcefile="$1"
local service=$(quadlet_to_service_name "$sourcefile")
# quadlet always works on an entire directory, so copy the file
# to transform to the given or newly created tmpdir
local quadlet_tmpdir="$2"
if [ -z "$quadlet_tmpdir" ]; then
quadlet_tmpdir=$(mktemp -d --tmpdir=$PODMAN_TMPDIR quadlet.XXXXXX)
fi
cp $sourcefile $quadlet_tmpdir/
echo "$_LOG_PROMPT $QUADLET $_DASHUSER $UNIT_DIR"
QUADLET_UNIT_DIRS="$quadlet_tmpdir" run \
timeout --foreground -v --kill=10 $PODMAN_TIMEOUT \
$QUADLET $_DASHUSER $UNIT_DIR
echo "$output"
assert $status -eq 0 "Failed to convert quadlet file: $sourcefile"
is "$output" "" "quadlet should report no errors"
# Ensure this is teared down
UNIT_FILES+=("$UNIT_DIR/$service")
QUADLET_SERVICE_NAME="$service"
QUADLET_SYSLOG_ID="$(basename $service .service)"
QUADLET_CONTAINER_NAME="systemd-$QUADLET_SYSLOG_ID"
cat $UNIT_DIR/$QUADLET_SERVICE_NAME
}
function service_setup() {
local service="$1"
local option="$2"
systemctl daemon-reload
local startargs=""
local statusexit=0
local activestate="active"
# If option wait, start and wait for service to exist
if [ "$option" == "wait" ]; then
startargs="--wait"
statusexit=3
local activestate="inactive"
fi
echo "$_LOG_PROMPT systemctl $startargs start $service"
run systemctl $startargs start "$service"
echo "$output"
assert $status -eq 0 "Error starting systemd unit $service"
# FIXME FIXME FIXME: this is racy with short-lived containers!
echo "$_LOG_PROMPT systemctl status $service"
run systemctl status "$service"
echo "$output"
assert $status -eq $statusexit "systemctl status $service"
echo "$_LOG_PROMPT systemctl show --value --property=ActiveState $service"
run systemctl show --value --property=ActiveState "$service"
echo "$output"
assert $status -eq 0 "systemctl show $service"
is "$output" $activestate
}
# Helper to stop a systemd service running a container
function service_cleanup() {
local service="$1"
local expected_state="$2"
run systemctl stop "$service"
assert $status -eq 0 "Error stopping systemd unit $service: $output"
# Regression test for #11304: confirm that unit stops into correct state
if [[ -n "$expected_state" ]]; then
run systemctl show --property=ActiveState "$service"
assert "$output" = "ActiveState=$expected_state" \
"state of service $service after systemctl stop"
fi
rm -f "$UNIT_DIR/$service"
systemctl daemon-reload
}
function create_secret() {
local secret_name=$(random_string)
local secret_file=$PODMAN_TMPDIR/secret_$(random_string)
local secret=$(random_string)
echo $secret > $secret_file
run_podman secret create $secret_name $secret_file
SECRET_NAME=$secret_name
SECRET=$secret
}
function remove_secret() {
local secret_name="$1"
run_podman secret rm $secret_name
}
@test "quadlet - basic" {
local quadlet_file=$PODMAN_TMPDIR/basic_$(random_string).container
cat > $quadlet_file <<EOF
[Container]
Image=$IMAGE
Exec=sh -c "echo STARTED CONTAINER; echo "READY=1" | socat -u STDIN unix-sendto:\$NOTIFY_SOCKET; sleep inf"
Notify=yes
LogDriver=passthrough
EOF
run_quadlet "$quadlet_file"
service_setup $QUADLET_SERVICE_NAME
# Check that we can read the logs from the container with podman logs even
# with the `passthrough` driver. The log may need a short period of time
# to bubble up into the journal logs, so wait for it.
wait_for_output "STARTED CONTAINER" $QUADLET_CONTAINER_NAME
# Make sure it's an *exact* match, not just a substring (i.e. no spurious
# warnings or other cruft).
run_podman logs $QUADLET_CONTAINER_NAME
assert "$output" == "STARTED CONTAINER" "exact/full match when using the 'passthrough' driver"
# Also look for the logs via `journalctl`.
run journalctl "--since=$STARTED_TIME" --unit="$QUADLET_SERVICE_NAME"
is "$output" '.*STARTED CONTAINER.*'
run_podman container inspect --format "{{.State.Status}}" $QUADLET_CONTAINER_NAME
is "$output" "running" "container should be started by systemd and hence be running"
service_cleanup $QUADLET_SERVICE_NAME failed
}
@test "quadlet conflict names" {
# If two directories in the search have files with the same name, quadlet should
# only process the first name
dir1=$PODMAN_TMPDIR/$(random_string)
dir2=$PODMAN_TMPDIR/$(random_string)
local quadlet_file=basic_$(random_string).container
mkdir -p $dir1 $dir2
cat > $dir1/$quadlet_file <<EOF
[Container]
Image=$IMAGE
Notify=yes
EOF
cat > $dir2/$quadlet_file <<EOF
[Container]
Image=$IMAGE
Notify=no
EOF
QUADLET_UNIT_DIRS="$dir1:$dir2" run \
timeout --foreground -v --kill=10 $PODMAN_TIMEOUT \
$QUADLET --dryrun
assert "$output" =~ "Notify=yes" "quadlet should show Notify=yes"
assert "$output" !~ "Notify=no" "quadlet should not show Notify=no"
}
@test "quadlet - envvar" {
local quadlet_file=$PODMAN_TMPDIR/envvar_$(random_string).container
cat > $quadlet_file <<EOF
[Container]
Image=$IMAGE
Exec=sh -c "echo OUTPUT: \"\$FOOBAR\" \"\$BAR\""
Environment="FOOBAR=Foo Bar" BAR=bar
LogDriver=passthrough
EOF
run_quadlet "$quadlet_file"
service_setup $QUADLET_SERVICE_NAME wait
# Ensure we have the right output, sync is done via waiting for service to exit (service_setup wait)
# Note: Here we have to filter by syslog id instead of unit, because there is a (known) race
# condition where if the cgroup is cleaned up before journald sees the message, then the journal
# doesn't know the cgroup and thus not the unit. (See https://github.com/systemd/systemd/issues/2913)
run journalctl "--since=$STARTED_TIME" SYSLOG_IDENTIFIER="$QUADLET_SYSLOG_ID"
is "$output" '.*OUTPUT: Foo Bar bar.*'
service_cleanup $QUADLET_SERVICE_NAME inactive
}
@test "quadlet - ContainerName" {
local quadlet_file=$PODMAN_TMPDIR/containername_$(random_string).container
cat > $quadlet_file <<EOF
[Container]
ContainerName=customcontainername
Image=$IMAGE
Exec=top"
EOF
run_quadlet "$quadlet_file"
service_setup $QUADLET_SERVICE_NAME
# Ensure we can access with the custom container name
run_podman container inspect --format "{{.State.Status}}" customcontainername
is "$output" "running" "container should be started by systemd and hence be running"
service_cleanup $QUADLET_SERVICE_NAME failed
}
@test "quadlet - labels" {
local quadlet_file=$PODMAN_TMPDIR/labels_$(random_string).container
cat > $quadlet_file <<EOF
[Container]
Image=$IMAGE
Exec=top
Label="foo=foo bar" "key=val"
Annotation="afoo=afoo bar"
Annotation="akey=aval"
EOF
run_quadlet "$quadlet_file"
service_setup $QUADLET_SERVICE_NAME
run_podman container inspect --format "{{.Config.Labels.foo}}" $QUADLET_CONTAINER_NAME
is "$output" "foo bar"
run_podman container inspect --format "{{.Config.Labels.key}}" $QUADLET_CONTAINER_NAME
is "$output" "val"
run_podman container inspect --format "{{.Config.Annotations.afoo}}" $QUADLET_CONTAINER_NAME
is "$output" "afoo bar"
run_podman container inspect --format "{{.Config.Annotations.akey}}" $QUADLET_CONTAINER_NAME
is "$output" "aval"
service_cleanup $QUADLET_SERVICE_NAME failed
}
@test "quadlet - oneshot" {
local quadlet_file=$PODMAN_TMPDIR/oneshot_$(random_string).container
cat > $quadlet_file <<EOF
[Container]
Image=$IMAGE
Exec=echo INITIALIZED
[Service]
Type=oneshot
RemainAfterExit=yes
EOF
run_quadlet "$quadlet_file"
service_setup $QUADLET_SERVICE_NAME
# Ensure we have output. Output is synced by oneshot command exit
run journalctl "--since=$STARTED_TIME" SYSLOG_IDENTIFIER="$QUADLET_SYSLOG_ID"
is "$output" '.*INITIALIZED.*'
service_cleanup $QUADLET_SERVICE_NAME inactive
}
@test "quadlet - volume" {
local quadlet_file=$PODMAN_TMPDIR/basic_$(random_string).volume
cat > $quadlet_file <<EOF
[Volume]
Label=foo=bar other="with space"
EOF
run_quadlet "$quadlet_file"
service_setup $QUADLET_SERVICE_NAME
local volume_name=systemd-$(basename $quadlet_file .volume)
run_podman volume ls
is "$output" ".*local.*${volume_name}.*"
run_podman volume inspect --format "{{.Labels.foo}}" $volume_name
is "$output" "bar"
run_podman volume inspect --format "{{.Labels.other}}" $volume_name
is "$output" "with space"
service_cleanup $QUADLET_SERVICE_NAME inactive
}
# A quadlet container depends on a quadlet volume
@test "quadlet - volume dependency" {
# Save the unit name to use as the volume for the container
local quadlet_vol_unit=dep_$(random_string).volume
local quadlet_vol_file=$PODMAN_TMPDIR/${quadlet_vol_unit}
cat > $quadlet_vol_file <<EOF
[Volume]
EOF
# Have quadlet create the systemd unit file for the volume unit
run_quadlet "$quadlet_vol_file"
# Save the volume service name since the variable will be overwritten
local vol_service=$QUADLET_SERVICE_NAME
local volume_name=systemd-$(basename $quadlet_vol_file .volume)
local quadlet_file=$PODMAN_TMPDIR/user_$(random_string).container
cat > $quadlet_file <<EOF
[Container]
Image=$IMAGE
Exec=top
Volume=$quadlet_vol_unit:/tmp
EOF
# Have quadlet create the systemd unit file for the container unit
run_quadlet "$quadlet_file"
# Save the container service name for readability
local container_service=$QUADLET_SERVICE_NAME
# Volume should not exist
run_podman 1 volume exists ${volume_name}
# Start the container service which should also trigger the start of the volume service
service_setup $container_service
# Volume system unit should be active
run systemctl show --property=ActiveState "$vol_service"
assert "$output" = "ActiveState=active" \
"volume should be active via dependency"
# Volume should exist
run_podman volume exists ${volume_name}
# Shutdown the service and remove the volume
service_cleanup $container_service failed
run_podman volume rm $volume_name
}
# A quadlet container depends on a named quadlet volume
@test "quadlet - named volume dependency" {
# Save the unit name to use as the volume for the container
local quadlet_vol_unit=dep_$(random_string).volume
local quadlet_vol_file=$PODMAN_TMPDIR/${quadlet_vol_unit}
cat > $quadlet_vol_file <<EOF
[Volume]
VolumeName=foo
EOF
# Have quadlet create the systemd unit file for the volume unit
local quadlet_tmpdir=$(mktemp -d --tmpdir=$PODMAN_TMPDIR quadlet.XXXXXX)
run_quadlet "$quadlet_vol_file" "$quadlet_tmpdir"
# Save the volume service name since the variable will be overwritten
local vol_service=$QUADLET_SERVICE_NAME
local volume_name="foo"
local quadlet_file=$PODMAN_TMPDIR/user_$(random_string).container
cat > $quadlet_file <<EOF
[Container]
Image=$IMAGE
Exec=top
Volume=$quadlet_vol_unit:/tmp
EOF
# Have quadlet create the systemd unit file for the container unit
run_quadlet "$quadlet_file" "$quadlet_tmpdir"
# Save the container service name for readability
local container_service=$QUADLET_SERVICE_NAME
local container_name=systemd-$(basename $quadlet_file .container)
# Volume should not exist
run_podman 1 volume exists ${volume_name}
# Start the container service which should also trigger the start of the volume service
service_setup $container_service
# Volume system unit should be active
run systemctl show --property=ActiveState "$vol_service"
assert "$output" = "ActiveState=active" "volume should be active via dependency"
# Volume should exist
run_podman volume exists ${volume_name}
# Container should be attached to defined volume
run_podman container inspect --format "{{(index .Mounts 0).Name}}" $container_name
assert "$output" = "$volume_name" "container should be attached to network $volume_name"
# Shutdown the service and remove the volume
service_cleanup $container_service failed
run_podman volume rm $volume_name
}
@test "quadlet - network" {
local quadlet_file=$PODMAN_TMPDIR/basic_$(random_string).network
cat > $quadlet_file <<EOF
[Network]
Label=foo=bar other="with space"
EOF
run_quadlet "$quadlet_file"
service_setup $QUADLET_SERVICE_NAME
local network_name=systemd-$(basename $quadlet_file .network)
run_podman network exists $network_name
run_podman network inspect --format "{{.Labels.foo}}" $network_name
is "$output" "bar"
run_podman network inspect --format "{{.Labels.other}}" $network_name
is "$output" "with space"
service_cleanup $QUADLET_SERVICE_NAME inactive
}
# A quadlet container depends on a quadlet network
@test "quadlet - network dependency" {
# Save the unit name to use as the network for the container
local quadlet_network_unit=dep_$(random_string).network
local quadlet_network_file=$PODMAN_TMPDIR/${quadlet_network_unit}
cat > $quadlet_network_file <<EOF
[Network]
EOF
# Have quadlet create the systemd unit file for the network unit
run_quadlet "$quadlet_network_file"
# Save the volume service name since the variable will be overwritten
local network_service=$QUADLET_SERVICE_NAME
local network_name=systemd-$(basename $quadlet_network_file .network)
local quadlet_file=$PODMAN_TMPDIR/user_$(random_string).container
cat > $quadlet_file <<EOF
[Container]
Image=$IMAGE
Exec=top
Network=$quadlet_network_unit
EOF
run_quadlet "$quadlet_file"
# Save the container service name for readability
local container_service=$QUADLET_SERVICE_NAME
# Network should not exist
run_podman 1 network exists $network_name
service_setup $container_service
# Network system unit should be active
run systemctl show --property=ActiveState "$network_service"
assert "$output" = "ActiveState=active" \
"network should be active via dependency"
# Network should exist
run_podman network exists $network_name
service_cleanup $QUADLET_SERVICE_NAME failed
run_podman network rm $network_name
}
# A quadlet container depends on a named quadlet network
@test "quadlet - named network dependency" {
# Save the unit name to use as the network for the container
local quadlet_network_unit=dep_$(random_string).network
local quadlet_network_file=$PODMAN_TMPDIR/${quadlet_network_unit}
cat > $quadlet_network_file <<EOF
[Network]
NetworkName=foo
EOF
# Have quadlet create the systemd unit file for the network unit
local quadlet_tmpdir=$(mktemp -d --tmpdir=$PODMAN_TMPDIR quadlet.XXXXXX)
run_quadlet "$quadlet_network_file" "$quadlet_tmpdir"
# Save the network service name since the variable will be overwritten
local network_service=$QUADLET_SERVICE_NAME
local network_name="foo"
local quadlet_file=$PODMAN_TMPDIR/user_$(random_string).container
cat > $quadlet_file <<EOF
[Container]
Image=$IMAGE
Exec=top
Network=$quadlet_network_unit
EOF
run_quadlet "$quadlet_file" "$quadlet_tmpdir"
# Save the container service name for readability
local container_service=$QUADLET_SERVICE_NAME
local container_name=systemd-$(basename $quadlet_file .container)
# Network should not exist
run_podman 1 network exists $network_name
service_setup $container_service
# Network system unit should be active
run systemctl show --property=ActiveState "$network_service"
assert "$output" = "ActiveState=active" "network should be active via dependency"
# Network should exist
run_podman network exists $network_name
# Container should be attached to defined network
run_podman container inspect --format "{{index .NetworkSettings.Networks \"$network_name\"}}" $container_name
assert "$output" != "<nil>" "container should be attached to network $network_name"
service_cleanup $QUADLET_SERVICE_NAME failed
run_podman network rm $network_name
}
@test "quadlet kube - basic" {
# Create the YAMl file
pod_name="test_pod"
container_name="test"
yaml_source="$PODMAN_TMPDIR/basic_$(random_string).yaml"
cat >$yaml_source <<EOF
apiVersion: v1
kind: Pod
metadata:
labels:
app: test
name: $pod_name
spec:
containers:
- command:
- "sh"
args:
- "-c"
- "echo STARTED CONTAINER; top -b"
image: $IMAGE
name: $container_name
EOF
# Create the Quadlet file
local quadlet_file=$PODMAN_TMPDIR/basic_$(random_string).kube
cat > $quadlet_file <<EOF
[Kube]
Yaml=${yaml_source}
EOF
run_quadlet "$quadlet_file"
service_setup $QUADLET_SERVICE_NAME
# Ensure we have output.
wait_for_output "STARTED CONTAINER" $pod_name-$container_name
run_podman container inspect --format "{{.State.Status}}" test_pod-test
is "$output" "running" "container should be started by systemd and hence be running"
service_cleanup $QUADLET_SERVICE_NAME inactive
run_podman rmi $(pause_image)
}
@test "quadlet kube - named network dependency" {
# Save the unit name to use as the network for the container
local quadlet_network_unit=dep_$(random_string).network
local quadlet_network_file=$PODMAN_TMPDIR/${quadlet_network_unit}
cat > $quadlet_network_file <<EOF
[Network]
NetworkName=foo
EOF
# Have quadlet create the systemd unit file for the network unit
local quadlet_tmpdir=$(mktemp -d --tmpdir=$PODMAN_TMPDIR quadlet.XXXXXX)
run_quadlet "$quadlet_network_file" "$quadlet_tmpdir"
# Save the network service name since the variable will be overwritten
local network_service=$QUADLET_SERVICE_NAME
local network_name="foo"
# Create the YAMl file
pod_name="test_pod"
container_name="test"
yaml_source="$PODMAN_TMPDIR/basic_$(random_string).yaml"
cat >$yaml_source <<EOF
apiVersion: v1
kind: Pod
metadata:
labels:
app: test
name: $pod_name
spec:
containers:
- command:
- "sh"
args:
- "-c"
- "echo STARTED CONTAINER; top -b"
image: $IMAGE
name: $container_name
EOF
# Create the Quadlet file
local quadlet_file=$PODMAN_TMPDIR/basic_$(random_string).kube
cat > $quadlet_file <<EOF
[Kube]
Yaml=${yaml_source}
Network=$quadlet_network_unit
EOF
# Network should not exist
run_podman 1 network exists $network_name
run_quadlet "$quadlet_file" "$quadlet_tmpdir"
service_setup $QUADLET_SERVICE_NAME
# Network system unit should be active
run systemctl show --property=ActiveState "$network_service"
assert "$output" = "ActiveState=active" "network should be active via dependency"
# Network should exist
run_podman network exists $network_name
# Ensure we have output.
wait_for_output "STARTED CONTAINER" $pod_name-$container_name
run_podman container inspect --format "{{.State.Status}}" test_pod-test
assert "$output" =~ "running" "container should be started by systemd and hence be running"
# Container should be attached to defined network
run_podman container inspect --format "{{index .NetworkSettings.Networks \"$network_name\"}}" test_pod-test
assert "$output" != "<nil>" "container should be attached to network $network_name"
service_cleanup $QUADLET_SERVICE_NAME inactive
run_podman network rm $network_name
run_podman rmi $(pause_image)
}
@test "quadlet - rootfs" {
skip_if_no_selinux
skip_if_rootless
local quadlet_file=$PODMAN_TMPDIR/basic_$(random_string).container
cat > $quadlet_file <<EOF
[Container]
Rootfs=/:O
Exec=sh -c "echo STARTED CONTAINER; echo "READY=1" | socat -u STDIN unix-sendto:\$NOTIFY_SOCKET; top -b"
Notify=yes
EOF
run_quadlet "$quadlet_file"
service_setup $QUADLET_SERVICE_NAME
wait_for_output "STARTED CONTAINER" $QUADLET_CONTAINER_NAME
}
@test "quadlet - selinux disable" {
skip_if_no_selinux
local quadlet_file=$PODMAN_TMPDIR/basic_$(random_string).container
cat > $quadlet_file <<EOF
[Container]
Image=$IMAGE
SecurityLabelDisable=true
Exec=sh -c "echo STARTED CONTAINER; top -b"
EOF
run_quadlet "$quadlet_file"
service_setup $QUADLET_SERVICE_NAME
# Ensure we have output. Output is synced via sd-notify (socat in Exec)
wait_for_output "STARTED CONTAINER" $QUADLET_CONTAINER_NAME
run_podman container inspect --format "{{.ProcessLabel}}" $QUADLET_CONTAINER_NAME
is "$output" "" "container should be started without specifying a Process Label"
service_cleanup $QUADLET_SERVICE_NAME failed
}
@test "quadlet - selinux labels" {
skip_if_no_selinux
NAME=$(random_string)
local quadlet_file=$PODMAN_TMPDIR/basic_$(random_string).container
cat > $quadlet_file <<EOF
[Container]
ContainerName=$NAME
Image=$IMAGE
SecurityLabelType=spc_t
SecurityLabelLevel=s0:c100,c200
SecurityLabelFileType=container_ro_file_t
Exec=sh -c "echo STARTED CONTAINER; top -b"
EOF
run_quadlet "$quadlet_file"
service_setup $QUADLET_SERVICE_NAME
# Ensure we have output. Output is synced via sd-notify (socat in Exec)
wait_for_output "STARTED CONTAINER" $NAME
run_podman container ps
run_podman container inspect --format "{{.ProcessLabel}}" $NAME
is "$output" "system_u:system_r:spc_t:s0:c100,c200" "container should be started with correct Process Label"
run_podman container inspect --format "{{.MountLabel}}" $NAME
is "$output" "system_u:object_r:container_ro_file_t:s0:c100,c200" "container should be started with correct Mount Label"
service_cleanup $QUADLET_SERVICE_NAME failed
}
@test "quadlet - secret as environment variable" {
create_secret
local quadlet_file=$PODMAN_TMPDIR/basic_$(random_string).container
cat > $quadlet_file <<EOF
[Container]
ContainerName=$NAME
Image=$IMAGE
Secret=$SECRET_NAME,type=env,target=MYSECRET
Exec=sh -c "echo STARTED CONTAINER; echo "READY=1" | socat -u STDIN unix-sendto:\$NOTIFY_SOCKET; top -b"
Notify=yes
EOF
run_quadlet "$quadlet_file"
service_setup $QUADLET_SERVICE_NAME
# Ensure we have output. Output is synced via sd-notify (socat in Exec)
wait_for_output "STARTED CONTAINER" $QUADLET_CONTAINER_NAME
run_podman exec $QUADLET_CONTAINER_NAME /bin/sh -c "printenv MYSECRET"
is "$output" $SECRET
service_cleanup $QUADLET_SERVICE_NAME failed
remove_secret $SECRET_NAME
}
@test "quadlet - secret as a file" {
create_secret
local quadlet_file=$PODMAN_TMPDIR/basic_$(random_string).container
cat > $quadlet_file <<EOF
[Container]
ContainerName=$NAME
Image=$IMAGE
Secret=$SECRET_NAME,type=mount,target=/root/secret
Exec=sh -c "echo STARTED CONTAINER; echo "READY=1" | socat -u STDIN unix-sendto:\$NOTIFY_SOCKET; top -b"
Notify=yes
EOF
run_quadlet "$quadlet_file"
service_setup $QUADLET_SERVICE_NAME
# Ensure we have output. Output is synced via sd-notify (socat in Exec)
wait_for_output "STARTED CONTAINER" $QUADLET_CONTAINER_NAME
run_podman exec $QUADLET_CONTAINER_NAME /bin/sh -c "cat /root/secret"
is "$output" $SECRET
service_cleanup $QUADLET_SERVICE_NAME failed
remove_secret $SECRET_NAME
}
@test "quadlet - volume path using systemd %T specifier" {
# "specifier" is systemd-speak for "replaceable fields"; see systemd.unit(5)
#
# Step 1: determine what systemd is using for %T. There does not
# seem to be any systemctly way to find this.
percent_t_file="${PODMAN_TMPDIR}/foo"
local service=get-percent-t.$(random_string 10).service
local unitfile=${UNIT_DIR}/$service
cat >$unitfile <<EOF
[Unit]
Description=Get the value of percent T
[Service]
ExecStart=/bin/bash -c "echo %T >$percent_t_file"
Type=oneshot
EOF
systemctl daemon-reload
systemctl --wait start $service
percent_t=$(< $percent_t_file)
# Clean up. Don't bother to systemctl-reload, service_setup does that below.
rm -f $unitfile
# Sanity check: just make sure it's not "/"
assert "${#percent_t}" -ge 4 "sanity check: length of %T ($percent_t)"
# Step 2: Make a subdirectory in %T, and in there, a scratch file
local tmp_path=$(mktemp -d --tmpdir=${percent_t} quadlet.volume.XXXXXX)
local tmp_subdir=$(basename $tmp_path)
local file_name="f$(random_string 10).txt"
local file_content="data_$(random_string 15)"
echo $file_content > $tmp_path/$file_name
local quadlet_file=$PODMAN_TMPDIR/basic_$(random_string).container
cat > $quadlet_file <<EOF
[Container]
Image=$IMAGE
Volume=%T/$tmp_subdir:/test_content:Z
Exec=sh -c "echo STARTED CONTAINER; echo "READY=1" | socat -u STDIN unix-sendto:\$NOTIFY_SOCKET; top"
Notify=yes
EOF
run_quadlet "$quadlet_file"
service_setup $QUADLET_SERVICE_NAME
run_podman exec $QUADLET_CONTAINER_NAME cat /test_content/$file_name
is "$output" "$file_content" "contents of testfile in container volume"
rm -rf $tmp_path
}
@test "quadlet - tmpfs" {
local quadlet_file=$PODMAN_TMPDIR/basic_$(random_string).container
cat > $quadlet_file <<EOF
[Container]
Image=$IMAGE
Exec=top
Tmpfs=/tmpfs1
Tmpfs=/tmpfs2:ro
EOF
run_quadlet "$quadlet_file"
service_setup $QUADLET_SERVICE_NAME
run_podman container inspect --format '{{index .HostConfig.Tmpfs "/tmpfs1"}}' $QUADLET_CONTAINER_NAME
is "$output" "rprivate,nosuid,nodev,tmpcopyup" "regular tmpfs mount"
run_podman container inspect --format '{{index .HostConfig.Tmpfs "/tmpfs2"}}' $QUADLET_CONTAINER_NAME
is "$output" "ro,rprivate,nosuid,nodev,tmpcopyup" "read-only tmpfs mount"
run_podman container inspect --format '{{index .HostConfig.Tmpfs "/tmpfs3"}}' $QUADLET_CONTAINER_NAME
is "$output" "" "nonexistent tmpfs mount"
service_cleanup $QUADLET_SERVICE_NAME failed
}
@test "quadlet - userns" {
local quadlet_file=$PODMAN_TMPDIR/basic_$(random_string).container
cat > $quadlet_file <<EOF
[Container]
Image=$IMAGE
Exec=top
UserNS=keep-id:uid=200,gid=210
EOF
run_quadlet "$quadlet_file"
service_setup $QUADLET_SERVICE_NAME
run_podman container inspect --format '{{.Config.CreateCommand}}' $QUADLET_CONTAINER_NAME
is "${output/* --userns keep-id:uid=200,gid=210 */found}" "found"
service_cleanup $QUADLET_SERVICE_NAME failed
}
@test "quadlet - exit-code propagation" {
pod_name="test_pod"
container_name="ctr"
exit_tests="
all | true | 0 | inactive
all | false | 137 | failed
none | false | 0 | inactive
"
while read exit_code_prop cmd exit_code service_state; do
local basename=propagate-${exit_code_prop}-${cmd}-$(random_string)
local quadlet_file=$PODMAN_TMPDIR/$basename.kube
local yaml_file=$PODMAN_TMPDIR/$basename.yaml
cat > $yaml_file <<EOF
apiVersion: v1
kind: Pod
metadata:
labels:
app: test
name: $pod_name
spec:
restartPolicy: Never
containers:
- name: $container_name
image: $IMAGE
command:
- $cmd
EOF
cat > $quadlet_file <<EOF
[Kube]
Yaml=$yaml_file
ExitCodePropagation=$exit_code_prop
LogDriver=journald
EOF
run_quadlet "$quadlet_file"
run systemctl status $QUADLET_SERVICE_NAME
yaml_sha=$(sha256sum $yaml_file)
service_container="${yaml_sha:0:12}-service"
service_setup $QUADLET_SERVICE_NAME
# Ensure we have output. Output is synced via sd-notify (socat in Exec)
run journalctl "--since=$STARTED_TIME" --unit="$QUADLET_SERVICE_NAME"
is "$output" '.*Started.*\.service.*'
# Opportunistic test: confirm that the Propagation field got set.
# This is racy, because the container is short-lived and quadlet
# cleans up on exit (via kube-down in ExecStopPost). So we use '?'
# and only check output if the inspect succeeds.
run_podman '?' container inspect --format '{{.KubeExitCodePropagation}}' $service_container
if [[ $status -eq 0 ]]; then
is "$output" "$exit_code_prop" \
"$basename: service container has the expected policy set in its annotations"
else
assert "$output" =~ "no such container $service_container" \
"$basename: unexpected error from podman container inspect"
fi
# Container must stop of its own accord before we call service_cleanup(),
# otherwise the 'systemctl stop' there may affect the unit's status.
# Again, use '?' to handle the abovementioned race condition.
run_podman '?' wait $service_container
if [[ $status -eq 0 ]]; then
assert "$output" = "$exit_code" \
"$basename: service container reflects expected exit code"
else
assert "$output" =~ "no container with name or ID" \
"$basename: unexpected error from podman wait"
fi
# This is the actual propagation check
service_cleanup $QUADLET_SERVICE_NAME $service_state
run_podman ps -aq
is "$output" "" "all containers are cleaned up even in case of errors"
done < <(parse_table "$exit_tests")
run_podman rmi $(pause_image)
}
@test "quadlet kube - Working Directory" {
yaml_source="$PODMAN_TMPDIR/basic_$(random_string).yaml"
local_path=local_path$(random_string)
pod_name=test_pod
container_name=test
cat >$yaml_source <<EOF
apiVersion: v1
kind: Pod
metadata:
labels:
app: test
name: $pod_name
spec:
containers:
- command:
- "sh"
args:
- "-c"
- "echo STARTED CONTAINER; top -b"
image: $IMAGE
name: $container_name
volumeMounts:
- mountPath: /test
name: test-volume
volumes:
- name: test-volume
hostPath:
# directory location on host
path: ./$local_path
# this field is optional
type: DirectoryOrCreate
EOF
# Create the Quadlet file
local quadlet_file=$PODMAN_TMPDIR/basic_$(random_string).kube
cat > $quadlet_file <<EOF
[Kube]
Yaml=${yaml_source}
SetWorkingDirectory=yaml
EOF
run_quadlet "$quadlet_file"
service_setup $QUADLET_SERVICE_NAME
# Ensure we have output.
wait_for_output "STARTED CONTAINER" $pod_name-$container_name
run_podman container inspect --format "{{.State.Status}}" $pod_name-$container_name
is "$output" "running" "container should be started by systemd and hence be running"
run_podman ps
run_podman exec $pod_name-$container_name /bin/sh -c "echo hello > /test/test.txt"
is $(cat $PODMAN_TMPDIR/$local_path/test.txt) "hello"
service_cleanup $QUADLET_SERVICE_NAME inactive
run_podman rmi $(pause_image)
}
@test "quadlet - image files" {
local quadlet_tmpdir=$PODMAN_TMPDIR/quadlets
local registry=localhost:${PODMAN_LOGIN_REGISTRY_PORT}
local image_for_test=$registry/quadlet_image_test:$(random_string)
local authfile=$PODMAN_TMPDIR/authfile.json
local quadlet_image_unit=image_test_$(random_string).image
local quadlet_image_file=$PODMAN_TMPDIR/$quadlet_image_unit
cat > $quadlet_image_file <<EOF
[Image]
Image=$image_for_test
AuthFile=$authfile
TLSVerify=false
EOF
local quadlet_volume_unit=image_test_$(random_string).volume
local quadlet_volume_file=$PODMAN_TMPDIR/$quadlet_volume_unit
local volume_name=systemd-$(basename $quadlet_volume_file .volume)
cat > $quadlet_volume_file <<EOF
[Volume]
Driver=image
Image=$quadlet_image_unit
EOF
local quadlet_container_unit=image_test_$(random_string).container
local quadlet_container_file=$PODMAN_TMPDIR/$quadlet_container_unit
cat > $quadlet_container_file <<EOF
[Container]
Image=$quadlet_image_unit
Volume=$quadlet_volume_unit:/vol
Exec=sh -c "echo STARTED CONTAINER; echo "READY=1" | socat -u STDIN unix-sendto:\$NOTIFY_SOCKET; sleep inf"
EOF
# In order to test image pull but without possible Network issues,
# this test uses an additional registry.
# Start the registry and populate the authfile that we can use for the test.
start_registry
run_podman login --authfile=$authfile \
--tls-verify=false \
--username ${PODMAN_LOGIN_USER} \
--password ${PODMAN_LOGIN_PASS} \
$registry
# Push the test image to the registry
run_podman image tag $IMAGE $image_for_test
run_podman image push --tls-verify=false --authfile=$authfile $image_for_test
# Remove the local image to make sure it will be pulled again
run_podman image rm --ignore $image_for_test
# Use the same directory for all quadlet files to make sure later steps access previous ones
mkdir $quadlet_tmpdir
# Have quadlet create the systemd unit file for the image unit
run_quadlet "$quadlet_image_file" "$quadlet_tmpdir"
# Save the image service name since the variable will be overwritten
local image_service=$QUADLET_SERVICE_NAME
# Have quadlet create the systemd unit file for the volume unit
run_quadlet "$quadlet_volume_file" "$quadlet_tmpdir"
# Save the image service name since the variable will be overwritten
local volume_service=$QUADLET_SERVICE_NAME
# Image should not exist
run_podman 1 image exists ${image_for_test}
# Volume should not exist
run_podman 1 volume exists ${volume_name}
# Have quadlet create the systemd unit file for the image unit
run_quadlet "$quadlet_container_file" "$quadlet_tmpdir"
local container_service=$QUADLET_SERVICE_NAME
local container_name=$QUADLET_CONTAINER_NAME
service_setup $container_service
# Image system unit should be active
run systemctl show --property=ActiveState "$image_service"
assert "$output" = "ActiveState=active" \
"quadlet - image files: image should be active via dependency but is not"
# Volume system unit should be active
run systemctl show --property=ActiveState "$volume_service"
assert "$output" = "ActiveState=active" \
"quadlet - image files: volume should be active via dependency but is not"
# Image should exist
run_podman image exists ${image_for_test}
# Volume should exist
run_podman volume exists ${volume_name}
# Verify that the volume was created correctly
run_podman volume inspect --format "{{ .Driver }}" $volume_name
assert "$output" = "image" \
"quadlet - image files: volume driver should be image"
run_podman volume inspect --format "{{ .Options.image }}" $volume_name
assert "$output" = "$image_for_test" \
"quadlet - image files: the image for the volume should be $image_for_test"
# Verify that the container mounts the volume
run_podman container inspect --format "{{(index .Mounts 0).Type}}" $container_name
assert "$output" = "volume" \
"quadlet - image files: container should be attached to a volume of type volume"
run_podman container inspect --format "{{(index .Mounts 0).Name}}" $container_name
assert "$output" = "$volume_name" \
"quadlet - image files: container should be attached to the volume named $volume_name"
run_podman exec $QUADLET_CONTAINER_NAME cat /home/podman/testimage-id
assert "$output" = $PODMAN_TEST_IMAGE_TAG \
"quadlet - image files: incorrect testimage-id in root"
run_podman exec $QUADLET_CONTAINER_NAME cat /vol/home/podman/testimage-id
assert "$output" = $PODMAN_TEST_IMAGE_TAG \
"quadlet - image files: incorrect testimage-id in bound volume"
# Shutdown the service and remove the volume
service_cleanup $container_service failed
run_podman volume rm $volume_name
run_podman image rm --ignore $image_for_test
}
@test "quadlet - kube oneshot" {
local quadlet_tmpdir=$PODMAN_TMPDIR/quadlets
local test_random_string=$(random_string)
local quadlet_kube_volume_name=test-volume_$test_random_string
local quadlet_kube_volume_yaml_file=$PODMAN_TMPDIR/volume_$test_random_string.yaml
cat > $quadlet_kube_volume_yaml_file <<EOF
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: $quadlet_kube_volume_name
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
EOF
local quadlet_kube_volume_unit_file=$PODMAN_TMPDIR/volume_$test_random_string.kube
cat > $quadlet_kube_volume_unit_file <<EOF
[Kube]
Yaml=$quadlet_kube_volume_yaml_file
[Service]
Type=oneshot
RemainAfterExit=yes
EOF
local pod_name="test_pod_$test_random_string"
local container_name="test"
local quadlet_kube_pod_yaml_file=$PODMAN_TMPDIR/pod_$test_random_string.yaml
cat > $quadlet_kube_pod_yaml_file <<EOF
apiVersion: v1
kind: Pod
metadata:
labels:
app: test
name: $pod_name
spec:
containers:
- command:
- "sh"
args:
- "-c"
- "echo STARTED CONTAINER; top -b"
image: $IMAGE
name: $container_name
volumeMounts:
- name: storage
mountPath: /mnt/storage
volumes:
- name: storage
persistentVolumeClaim:
claimName: $quadlet_kube_volume_name
EOF
# Use the same directory for all quadlet files to make sure later steps access previous ones
mkdir $quadlet_tmpdir
# Have quadlet create the systemd unit file for the kube based volume unit
run_quadlet "$quadlet_kube_volume_unit_file" "$quadlet_tmpdir"
# Save the volume service name since the variable will be overwritten
local volume_service=$QUADLET_SERVICE_NAME
# Volume should not exist
run_podman 1 volume exists ${quadlet_kube_volume_name}
local quadlet_kube_pod_unit_file=$PODMAN_TMPDIR/pod_$test_random_string.kube
cat > $quadlet_kube_pod_unit_file <<EOF
[Kube]
Yaml=$quadlet_kube_pod_yaml_file
[Unit]
Requires=$volume_service
After=$volume_service
EOF
# Have quadlet create the systemd unit file for the pod unit
run_quadlet "$quadlet_kube_pod_unit_file" "$quadlet_tmpdir"
local pod_service=$QUADLET_SERVICE_NAME
service_setup $pod_service
# Volume system unit should be active
run systemctl show --property=ActiveState "$volume_service"
assert "$output" = "ActiveState=active" \
"quadlet - kube oneshot: volume should be active via dependency but is not"
# Volume should exist
run_podman volume exists ${quadlet_kube_volume_name}
run_podman container inspect --format "{{(index .Mounts 0).Type}}" $pod_name-$container_name
assert "$output" = "volume" \
"quadlet - kube oneshot: volume .Type"
run_podman container inspect --format "{{(index .Mounts 0).Name}}" $pod_name-$container_name
assert "$output" = "$quadlet_kube_volume_name" \
"quadlet - kube oneshot: volume .Name"
# Shutdown the service and remove the volume
service_cleanup $pod_service inactive
run_podman volume rm $quadlet_kube_volume_name
run_podman rmi --ignore $(pause_image)
}
@test "quadlet - kube down force" {
local test_random_string=$(random_string)
local quadlet_kube_volume_name=test-volume_$test_random_string
local pod_name="test_pod_$test_random_string"
local container_name="test"
local quadlet_kube_pod_yaml_file=$PODMAN_TMPDIR/pod_$test_random_string.yaml
cat > $quadlet_kube_pod_yaml_file <<EOF
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: $quadlet_kube_volume_name
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
---
apiVersion: v1
kind: Pod
metadata:
labels:
app: test
name: $pod_name
spec:
containers:
- command:
- "sh"
args:
- "-c"
- "echo STARTED CONTAINER; top -b"
image: $IMAGE
name: $container_name
volumeMounts:
- name: storage
mountPath: /mnt/storage
volumes:
- name: storage
persistentVolumeClaim:
claimName: $quadlet_kube_volume_name
EOF
local quadlet_kube_pod_unit_file=$PODMAN_TMPDIR/pod_$test_random_string.kube
cat > $quadlet_kube_pod_unit_file <<EOF
[Kube]
Yaml=$quadlet_kube_pod_yaml_file
KubeDownForce=true
EOF
# Have quadlet create the systemd unit file for the pod unit
run_quadlet "$quadlet_kube_pod_unit_file" "$quadlet_tmpdir"
local pod_service=$QUADLET_SERVICE_NAME
# Volume should not exist
run_podman 1 volume exists ${quadlet_kube_volume_name}
service_setup $pod_service
# Volume should exist
run_podman volume exists ${quadlet_kube_volume_name}
run_podman container inspect --format "{{(index .Mounts 0).Type}}" $pod_name-$container_name
assert "$output" = "volume" \
"quadlet - kube oneshot: volume .Type"
run_podman container inspect --format "{{(index .Mounts 0).Name}}" $pod_name-$container_name
assert "$output" = "$quadlet_kube_volume_name" \
"quadlet - kube oneshot: volume .Name"
# Shutdown the service
service_cleanup $pod_service failed
# Volume should not exist
run_podman 1 volume exists ${quadlet_kube_volume_name}
run_podman rmi --ignore $(pause_image)
}
@test "quadlet - image tag" {
local quadlet_tmpdir=$PODMAN_TMPDIR/quadlets
local archive_file=$PODMAN_TMPDIR/archive-file.tar
local image_for_test=localhost/quadlet_image_test:$(random_string)
local quadlet_image_unit=image_test_$(random_string).image
local quadlet_image_file=$PODMAN_TMPDIR/$quadlet_image_unit
cat > $quadlet_image_file <<EOF
[Image]
Image=docker-archive:$archive_file
ImageTag=$image_for_test
EOF
local quadlet_volume_unit=image_test_$(random_string).volume
local quadlet_volume_file=$PODMAN_TMPDIR/$quadlet_volume_unit
local volume_name=systemd-$(basename $quadlet_volume_file .volume)
cat > $quadlet_volume_file <<EOF
[Volume]
Driver=image
Image=$quadlet_image_unit
EOF
local quadlet_container_unit=image_test_$(random_string).container
local quadlet_container_file=$PODMAN_TMPDIR/$quadlet_container_unit
cat > $quadlet_container_file <<EOF
[Container]
Image=$IMAGE
Exec=sh -c "echo STARTED CONTAINER; echo "READY=1" | socat -u STDIN unix-sendto:\$NOTIFY_SOCKET; sleep inf"
Volume=$quadlet_volume_unit:/vol
EOF
# Tag the image, save it into a file and remove it
run_podman image tag $IMAGE $image_for_test
run_podman image save --format docker-archive --output $archive_file $image_for_test
run_podman image rm $image_for_test
# Use the same directory for all quadlet files to make sure later steps access previous ones
mkdir $quadlet_tmpdir
# Have quadlet create the systemd unit file for the image unit
run_quadlet "$quadlet_image_file" "$quadlet_tmpdir"
# Save the image service name since the variable will be overwritten
local image_service=$QUADLET_SERVICE_NAME
# Have quadlet create the systemd unit file for the volume unit
run_quadlet "$quadlet_volume_file" "$quadlet_tmpdir"
# Save the image service name since the variable will be overwritten
local volume_service=$QUADLET_SERVICE_NAME
# Image should not exist
run_podman 1 image exists ${image_for_test}
# Volume should not exist
run_podman 1 volume exists ${volume_name}
# Have quadlet create the systemd unit file for the image unit
run_quadlet "$quadlet_container_file" "$quadlet_tmpdir"
local container_service=$QUADLET_SERVICE_NAME
local container_name=$QUADLET_CONTAINER_NAME
service_setup $container_service
# Image system unit should be active
run systemctl show --property=ActiveState "$image_service"
assert "$output" = "ActiveState=active" \
"quadlet - image tag: image service ActiveState"
# Volume system unit should be active
run systemctl show --property=ActiveState "$volume_service"
assert "$output" = "ActiveState=active" \
"quadlet - image tag: volume service ActiveState"
# Image should exist
run_podman image exists ${image_for_test}
# Volume should exist
run_podman volume exists ${volume_name}
run_podman exec $QUADLET_CONTAINER_NAME cat /vol/home/podman/testimage-id
assert "$output" = $PODMAN_TEST_IMAGE_TAG \
"quadlet - image files: incorrect testimage-id in bound volume"
# Shutdown the service and remove the image
service_cleanup $container_service failed
run_podman image rm --ignore $image_for_test
run_podman rmi --ignore $(pause_image)
}
# This test reproduces https://github.com/containers/podman/issues/20432
# In order to reproduce the issue, the image in the FROM must no be available locally
# and must not have a tag. The first forces Pull and the second the resolution where the crash occurs
# Using a local registry does not work since kube play does not pass the autofile and tls-verify flags to the build
@test "quadlet - kube build from unavailable image with no tag" {
local quadlet_tmpdir=$PODMAN_TMPDIR/quadlets
local untagged_image=quay.io/libpod/busybox
local built_image=test_image
local yaml_dir=$quadlet_tmpdir/$built_image
local build_dir=$yaml_dir/$built_image
# Use the same directory for all quadlet files to make sure later steps access previous ones
mkdir -p $build_dir
container_file_path=$build_dir/Containerfile
cat >$container_file_path << EOF
FROM $untagged_image
EOF
# Create the YAMl file
pod_name="test_pod"
container_name="test"
yaml_source="$yaml_dir/build_$(random_string).yaml"
cat >$yaml_source <<EOF
apiVersion: v1
kind: Pod
metadata:
labels:
app: test
name: $pod_name
spec:
containers:
- command:
- "sh"
args:
- "-c"
- "echo STARTED CONTAINER; sleep inf"
image: $built_image
name: $container_name
EOF
# Create the Quadlet file
local quadlet_file=$quadlet_tmpdir/build_$(random_string).kube
cat > $quadlet_file <<EOF
[Kube]
Yaml=${yaml_source}
PodmanArgs=--build
SetWorkingDirectory=yaml
EOF
# Make sure the tagged image is not locally available
run_podman rmi -i $untagged_image:latest
run_quadlet "$quadlet_file"
service_setup $QUADLET_SERVICE_NAME
# Ensure we have output.
wait_for_output "STARTED CONTAINER" $pod_name-$container_name
run_podman container inspect --format "{{.State.Status}}" test_pod-test
is "$output" "running" "container should be started by systemd and hence be running"
service_cleanup $QUADLET_SERVICE_NAME inactive
run_podman rmi $untagged_image:latest $built_image $(pause_image)
}
# vim: filetype=sh