mirror of
https://github.com/containers/podman.git
synced 2025-10-15 18:23:30 +08:00

The distro-integration tag was added for fedora openQA to only run a subset of tests. However since it was added only a few new tests have been labelled like that and in general a normal contributor or even maintianer has no idea when to add this tag. We also have been seeing several regressions getting into fedora that these tests would have caught. As such I worked with Adam to enable all tests for fedora openQA so we actually have proper coverage. This has been working for a few weeks so I think we can dop these tags so upstream does not need to bother with them at all. https://pagure.io/fedora-qa/os-autoinst-distri-fedora/issue/373 Signed-off-by: Paul Holzinger <pholzing@redhat.com>
1886 lines
60 KiB
Bash
1886 lines
60 KiB
Bash
#!/usr/bin/env bats -*- bats -*-
|
|
#
|
|
# Tests generated configurations for systemd.
|
|
#
|
|
|
|
# bats file_tags=ci:parallel
|
|
|
|
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
|
|
run systemctl reset-failed "$service"
|
|
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"
|
|
|
|
run cat $UNIT_DIR/$service
|
|
assert $status -eq 0 "Could not cat $UNIT_DIR/$service"
|
|
echo "$output"
|
|
local content="$output"
|
|
|
|
# Ensure this is teared down
|
|
UNIT_FILES+=("$UNIT_DIR/$service")
|
|
|
|
QUADLET_SERVICE_NAME="$service"
|
|
QUADLET_SERVICE_CONTENT="$content"
|
|
QUADLET_SYSLOG_ID="$(basename $service .service)"
|
|
QUADLET_CONTAINER_NAME="systemd-$QUADLET_SYSLOG_ID"
|
|
}
|
|
|
|
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
|
|
|
|
systemctl_start $startargs "$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
|
|
|
|
# reset-failed necessary to clean up stray systemd cruft
|
|
run systemctl reset-failed "$service"
|
|
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
|
|
}
|
|
|
|
function wait_for_journal() {
|
|
local step=1
|
|
local count=10
|
|
local expect_str=
|
|
|
|
while [ "$#" -gt 0 ]; do
|
|
case "$1" in
|
|
-s|--step)
|
|
step="$2"
|
|
shift 2
|
|
;;
|
|
-c|--count)
|
|
count="$2"
|
|
shift 2
|
|
;;
|
|
*)
|
|
expect_str="$1"
|
|
shift 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
while [ "$count" -gt 0 ]; do
|
|
run journalctl "--since=$STARTED_TIME" --unit="$QUADLET_SERVICE_NAME"
|
|
if [[ "$output" =~ "$expect_str" ]]; then
|
|
return
|
|
fi
|
|
sleep "$step"
|
|
count=$(( count - 1 ))
|
|
done
|
|
die "Timed out waiting for '$expect_str' in journalctl output"
|
|
}
|
|
|
|
@test "quadlet - basic" {
|
|
# Network=none is to work around a Pasta bug, can be removed once a patched Pasta is available.
|
|
# Ref https://github.com/containers/podman/pull/21563#issuecomment-1965145324
|
|
local quadlet_file=$PODMAN_TMPDIR/basic_$(safename).container
|
|
cat > $quadlet_file <<EOF
|
|
[Container]
|
|
Image=$IMAGE
|
|
# Note it is important that the trap is before the ready message,
|
|
# otherwise the signal handler may not registered in time before we do systemctl stop.
|
|
Exec=sh -c "echo STARTED CONTAINER; trap 'exit' SIGTERM; echo "READY=1" | socat -u STDIN unix-sendto:\$NOTIFY_SOCKET; while :; do sleep 0.1; done"
|
|
Notify=yes
|
|
LogDriver=passthrough
|
|
Network=none
|
|
EOF
|
|
|
|
run_quadlet "$quadlet_file"
|
|
service_setup $QUADLET_SERVICE_NAME
|
|
|
|
run -0 systemctl show --property=Wants --property=After "$QUADLET_SERVICE_NAME"
|
|
service="network-online.target"
|
|
if is_rootless; then
|
|
service="podman-user-wait-network-online.service"
|
|
fi
|
|
assert "${lines[0]}" == "Wants=$service" "quadlet unit Wants network dependency"
|
|
# Note systemd adds some other default services to After= so no exact match possible
|
|
assert "${lines[1]}" =~ "After=.*$service.*" "quadlet unit After network dependency"
|
|
|
|
# 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 inactive
|
|
}
|
|
|
|
@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_$(safename).container
|
|
mkdir -p $dir1 $dir2
|
|
|
|
cat > $dir1/$quadlet_file <<EOF
|
|
[Container]
|
|
Image=quay.io/libpod/this-is-the-one:wewant
|
|
Notify=yes
|
|
EOF
|
|
|
|
cat > $dir2/$quadlet_file <<EOF
|
|
[Container]
|
|
Image=quay.io/libpod/bad-bad-bad:nonono
|
|
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_$(safename).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 and journal output check" {
|
|
local quadlet_file=$PODMAN_TMPDIR/containername_$(safename).container
|
|
local token_out="STDOUT$(random_string 10)"
|
|
local token_err="STDERR$(random_string 10)"
|
|
cat > $quadlet_file <<EOF
|
|
[Container]
|
|
ContainerName=customcontainername
|
|
Image=$IMAGE
|
|
Exec=sh -c "echo $token_out; echo $token_err 1>&2; top -d 10"
|
|
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"
|
|
|
|
wait_for_journal "Started $QUADLET_SERVICE_NAME"
|
|
|
|
run journalctl "--since=$STARTED_TIME" --unit="$QUADLET_SERVICE_NAME"
|
|
assert "$output" =~ "$token_out" "Output can be found with journalctl"
|
|
assert "$output" =~ "$token_err" "Error can be found with journalctl"
|
|
assert "$output" =~ "Starting $QUADLET_SERVICE_NAME" "Status information can be found with journalctl"
|
|
|
|
# log priority 3 in journalctl is err. This is documented in syslog(3)
|
|
run journalctl "--since=$STARTED_TIME" --priority=3 --unit="$QUADLET_SERVICE_NAME"
|
|
assert "$output" =~ "$token_err" "Error can be found with journalctl --priority=3"
|
|
assert "$output" !~ "$token_out" "Output can not be found with journalctl --priority=3"
|
|
|
|
service_cleanup $QUADLET_SERVICE_NAME failed
|
|
}
|
|
|
|
@test "quadlet - labels" {
|
|
local quadlet_file=$PODMAN_TMPDIR/labels_$(safename).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_$(safename).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_$(safename).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
|
|
run_podman volume rm $volume_name
|
|
}
|
|
|
|
# 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_$(safename).volume
|
|
local quadlet_vol_file=$PODMAN_TMPDIR/${quadlet_vol_unit}
|
|
cat > $quadlet_vol_file <<EOF
|
|
[Volume]
|
|
EOF
|
|
|
|
local quadlet_tmpdir=$(mktemp -d --tmpdir=$PODMAN_TMPDIR quadlet.XXXXXX)
|
|
# Have quadlet create the systemd unit file for the volume unit
|
|
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=systemd-$(basename $quadlet_vol_file .volume)
|
|
|
|
local quadlet_file=$PODMAN_TMPDIR/user_$(safename).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
|
|
|
|
# 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" {
|
|
local volume_name="v-$(safename)"
|
|
|
|
# Save the unit name to use as the volume for the container
|
|
local quadlet_vol_unit=dep_$(safename).volume
|
|
local quadlet_vol_file=$PODMAN_TMPDIR/${quadlet_vol_unit}
|
|
cat > $quadlet_vol_file <<EOF
|
|
[Volume]
|
|
VolumeName=$volume_name
|
|
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 quadlet_file=$PODMAN_TMPDIR/user_$(safename).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_$(safename).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
|
|
run_podman network rm $network_name
|
|
}
|
|
|
|
@test "quadlet - network delete with dependencies" {
|
|
# Save the unit name to use as the network for the container
|
|
local network_name=$(safename)
|
|
local quadlet_network_unit=dep_$(safename).network
|
|
local quadlet_network_file=$PODMAN_TMPDIR/${quadlet_network_unit}
|
|
cat > $quadlet_network_file <<EOF
|
|
[Network]
|
|
NetworkName=${network_name}
|
|
NetworkDeleteOnStop=true
|
|
EOF
|
|
|
|
local quadlet_tmpdir=$(mktemp -d --tmpdir=$PODMAN_TMPDIR quadlet.XXXXXX)
|
|
# Have quadlet create the systemd unit file for the network unit
|
|
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 quadlet_container_file=$PODMAN_TMPDIR/user_$(safename).container
|
|
cat > $quadlet_container_file <<EOF
|
|
[Container]
|
|
Image=$IMAGE
|
|
Exec=top
|
|
Network=$quadlet_network_unit
|
|
EOF
|
|
|
|
run_quadlet "$quadlet_container_file" "$quadlet_tmpdir"
|
|
|
|
# Save the container service name for readability
|
|
local container_service=$QUADLET_SERVICE_NAME
|
|
|
|
# Network should not exist
|
|
run_podman 1 network exists $network_name
|
|
|
|
# Start the container service
|
|
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
|
|
|
|
# Stop the Network Service
|
|
service_cleanup $network_service inactive
|
|
|
|
# Container system unit should be active
|
|
run systemctl show --property=ActiveState "$container_service"
|
|
assert "$output" = "ActiveState=failed" \
|
|
"container service should be failed via dependency"
|
|
|
|
# Network should not exist
|
|
run_podman 1 network exists $network_name
|
|
}
|
|
|
|
# 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_$(safename).network
|
|
local quadlet_network_file=$PODMAN_TMPDIR/${quadlet_network_unit}
|
|
cat > $quadlet_network_file <<EOF
|
|
[Network]
|
|
EOF
|
|
|
|
local quadlet_tmpdir=$(mktemp -d --tmpdir=$PODMAN_TMPDIR quadlet.XXXXXX)
|
|
# Have quadlet create the systemd unit file for the network unit
|
|
run_quadlet "$quadlet_network_file" "$quadlet_tmpdir"
|
|
|
|
# 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_$(safename).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
|
|
|
|
# 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_$(safename).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_$(safename).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="p-$(safename)"
|
|
container_name="c-$(safename)"
|
|
yaml_source="$PODMAN_TMPDIR/basic_$(safename).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_$(safename).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}}" $pod_name-$container_name
|
|
is "$output" "running" "container should be started by systemd and hence be running"
|
|
|
|
service_cleanup $QUADLET_SERVICE_NAME inactive
|
|
}
|
|
|
|
@test "quadlet kube - named network dependency" {
|
|
# Save the unit name to use as the network for the container
|
|
local quadlet_network_unit=dep_$(safename).network
|
|
local quadlet_network_file=$PODMAN_TMPDIR/${quadlet_network_unit}
|
|
local network_name="n-$(safename)"
|
|
cat > $quadlet_network_file <<EOF
|
|
[Network]
|
|
NetworkName=${network_name}
|
|
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
|
|
|
|
# Create the YAMl file
|
|
pod_name="p-$(safename)"
|
|
container_name="c-$(safename)"
|
|
yaml_source="$PODMAN_TMPDIR/basic_$(safename).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_$(safename).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}}" $pod_name-$container_name
|
|
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\"}}" $pod_name-$container_name
|
|
assert "$output" != "<nil>" "container should be attached to network $network_name"
|
|
|
|
service_cleanup $QUADLET_SERVICE_NAME inactive
|
|
run_podman network rm $network_name
|
|
}
|
|
|
|
@test "quadlet - rootfs" {
|
|
skip_if_no_selinux
|
|
skip_if_rootless
|
|
|
|
# Mount a container image to use as rootfs. Because we (may) run in
|
|
# parallel, mount a working container, not $IMAGE
|
|
cname="c-$(safename)"
|
|
run_podman run -d --name $cname $IMAGE top
|
|
run_podman container mount $cname
|
|
mountpoint="$output"
|
|
|
|
local quadlet_file=$PODMAN_TMPDIR/basic_$(safename).container
|
|
cat > $quadlet_file <<EOF
|
|
[Container]
|
|
Rootfs=$mountpoint: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
|
|
|
|
# Done. Clean up.
|
|
service_cleanup $QUADLET_SERVICE_NAME failed
|
|
run_podman container unmount $cname
|
|
run_podman rm -f -t0 $cname
|
|
}
|
|
|
|
@test "quadlet - selinux disable" {
|
|
skip_if_no_selinux
|
|
local quadlet_file=$PODMAN_TMPDIR/basic_$(safename).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=name$(safename)
|
|
local quadlet_file=$PODMAN_TMPDIR/basic_$(safename).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_$(safename).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_$(safename).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.$(safename).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_start --wait $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_$(safename).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"
|
|
|
|
service_cleanup $QUADLET_SERVICE_NAME
|
|
|
|
rm -rf $tmp_path
|
|
}
|
|
|
|
@test "quadlet - tmpfs" {
|
|
local quadlet_file=$PODMAN_TMPDIR/basic_$(safename).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_$(safename).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="p-$(safename)"
|
|
container_name="c-$(safename)"
|
|
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}_$(safename)
|
|
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)
|
|
# When running under heavy load (e.g. parallel tests), it
|
|
# may take a little while for service to reach Started
|
|
for tries in $(seq 1 5); do
|
|
run journalctl "--since=$STARTED_TIME" --unit="$QUADLET_SERVICE_NAME"
|
|
if [[ "$output" =~ "Started.*\.service" ]]; then
|
|
break
|
|
fi
|
|
sleep 1
|
|
done
|
|
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 -a
|
|
assert "$output" !~ "$(safename)" \
|
|
"all containers are cleaned up even in case of errors"
|
|
done < <(parse_table "$exit_tests")
|
|
}
|
|
|
|
@test "quadlet kube - Working Directory" {
|
|
yaml_source="$PODMAN_TMPDIR/basic_$(safename).yaml"
|
|
local_path=local_path$(random_string)
|
|
pod_name="p-$(safename)"
|
|
container_name="c-$(safename)"
|
|
|
|
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_$(safename).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
|
|
}
|
|
|
|
# https://github.com/containers/podman/issues/20667
|
|
@test "quadlet kube - start error" {
|
|
local port=$(random_free_port)
|
|
# Create the YAMl file
|
|
pod_name="p-$(safename)"
|
|
container_name="c-$(safename)"
|
|
yaml_source="$PODMAN_TMPDIR/start_err$(safename).yaml"
|
|
cat >$yaml_source <<EOF
|
|
apiVersion: v1
|
|
kind: Pod
|
|
metadata:
|
|
name: $pod_name
|
|
spec:
|
|
containers:
|
|
- command:
|
|
- "top"
|
|
image: $IMAGE
|
|
name: $container_name
|
|
ports:
|
|
- containerPort: 80
|
|
hostPort: $port
|
|
EOF
|
|
|
|
# Bind the port to force a an error when starting the pod
|
|
timeout --foreground -v --kill=10 10 socat TCP-LISTEN:$port,bind=127.0.0.1,fork - &
|
|
socat_pid=$!
|
|
|
|
# Create the Quadlet file
|
|
local quadlet_file=$PODMAN_TMPDIR/start_err_$(safename).kube
|
|
cat > $quadlet_file <<EOF
|
|
[Kube]
|
|
Yaml=${yaml_source}
|
|
EOF
|
|
|
|
run_quadlet "$quadlet_file"
|
|
|
|
run -0 systemctl daemon-reload
|
|
|
|
echo "$_LOG_PROMPT systemctl start $QUADLET_SERVICE_NAME"
|
|
run systemctl start $QUADLET_SERVICE_NAME
|
|
echo $output
|
|
assert $status -eq 1 "systemctl start should report failure"
|
|
|
|
run -0 systemctl show --property=ActiveState $QUADLET_SERVICE_NAME
|
|
assert "$output" == "ActiveState=failed" "unit must be in failed state"
|
|
|
|
echo "$_LOG_PROMPT journalctl -u $QUADLET_SERVICE_NAME"
|
|
run -0 journalctl -eu $QUADLET_SERVICE_NAME
|
|
assert "$output" =~ "$port: bind: address already in use" "journal contains the real podman start error"
|
|
|
|
kill "$socat_pid"
|
|
}
|
|
|
|
# https://github.com/containers/podman/issues/25786
|
|
@test "quadlet kube - pod without containers" {
|
|
local port=$(random_free_port)
|
|
# Create the YAML file
|
|
pod_name="p-$(safename)"
|
|
yaml_source="$PODMAN_TMPDIR/no_cons_$(safename).yaml"
|
|
cat >$yaml_source <<EOF
|
|
apiVersion: v1
|
|
kind: Pod
|
|
metadata:
|
|
name: $pod_name
|
|
EOF
|
|
|
|
# Create the Quadlet file
|
|
local quadlet_file=$PODMAN_TMPDIR/no_cons_$(safename).kube
|
|
cat > $quadlet_file <<EOF
|
|
[Kube]
|
|
Yaml=${yaml_source}
|
|
EOF
|
|
|
|
run_quadlet "$quadlet_file"
|
|
service_setup $QUADLET_SERVICE_NAME
|
|
|
|
run_podman pod ps --format "{{.Name}}--{{.Status}}"
|
|
assert "$output" =~ "$pod_name--Running" "pod is running"
|
|
|
|
service_cleanup $QUADLET_SERVICE_NAME inactive
|
|
}
|
|
|
|
@test "quadlet - image files" {
|
|
local quadlet_tmpdir=$PODMAN_TMPDIR/quadlets
|
|
|
|
local registry=localhost:${PODMAN_LOGIN_REGISTRY_PORT}
|
|
local image_for_test=$registry/i-$(safename):$(random_string)
|
|
local authfile=$PODMAN_TMPDIR/authfile.json
|
|
|
|
local quadlet_image_unit=image_test_$(safename).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_$(safename).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_$(safename).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
|
|
|
|
# Generate a test image and push it to the registry.
|
|
# For safety in parallel runs, test image must be isolated
|
|
# from $IMAGE. A simple add-tag will not work. (#23756)
|
|
run_podman create -q $IMAGE true
|
|
local tmpcid=$output
|
|
run_podman commit -q $tmpcid $image_for_test
|
|
run_podman rm $tmpcid
|
|
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=r_$(safename)
|
|
|
|
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="p-$(safename)"
|
|
local container_name="c-$(safename)"
|
|
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
|
|
}
|
|
|
|
@test "quadlet - kube down force" {
|
|
local test_random_string=$(random_string)
|
|
|
|
local quadlet_kube_volume_name=test-volume_$test_random_string
|
|
local pod_name="p-$(safename)"
|
|
local container_name="c-$(safename)"
|
|
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}
|
|
}
|
|
|
|
@test "quadlet - image tag" {
|
|
local quadlet_tmpdir=$PODMAN_TMPDIR/quadlets
|
|
local archive_file=$PODMAN_TMPDIR/archive-file.tar
|
|
local image_for_test=localhost/i-$(safename):$(random_string)
|
|
|
|
local quadlet_image_unit=image_test_$(safename).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_$(safename).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_$(safename).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
|
|
|
|
# Generate a test image, save it into a file, and remove it.
|
|
# For safety in parallel runs, test image must be isolated
|
|
# from $IMAGE. A simple add-tag will not work. (#23756)
|
|
run_podman create -q $IMAGE true
|
|
local tmpcid=$output
|
|
run_podman commit -q $tmpcid $image_for_test
|
|
run_podman rm $tmpcid
|
|
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 volume rm $volume_name
|
|
run_podman image rm --ignore $image_for_test
|
|
}
|
|
|
|
@test "quadlet - pod simple" {
|
|
local quadlet_tmpdir=$PODMAN_TMPDIR/quadlets
|
|
|
|
local test_pod_name=pod_test_$(safename)
|
|
local quadlet_pod_unit=$test_pod_name.pod
|
|
local quadlet_pod_file=$PODMAN_TMPDIR/$quadlet_pod_unit
|
|
cat > $quadlet_pod_file <<EOF
|
|
[Pod]
|
|
PodName=$test_pod_name
|
|
EOF
|
|
|
|
local quadlet_container_unit=pod_test_$(safename).container
|
|
local quadlet_container_file=$PODMAN_TMPDIR/$quadlet_container_unit
|
|
cat > $quadlet_container_file <<EOF
|
|
[Container]
|
|
Image=$IMAGE
|
|
# Note it is important that the trap is before the ready message,
|
|
# otherwise the signal handler may not registered in time before we do systemctl stop.
|
|
Exec=sh -c "echo STARTED CONTAINER; trap 'exit' SIGTERM; echo "READY=1" | socat -u STDIN unix-sendto:\$NOTIFY_SOCKET; while :; do sleep 0.1; done"
|
|
Pod=$quadlet_pod_unit
|
|
Notify=yes
|
|
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 pod unit
|
|
run_quadlet "$quadlet_pod_file" "$quadlet_tmpdir"
|
|
# Save the pod service name since the variable will be overwritten
|
|
local pod_service=$QUADLET_SERVICE_NAME
|
|
|
|
# Have quadlet create the systemd unit file for the container unit
|
|
run_quadlet "$quadlet_container_file" "$quadlet_tmpdir"
|
|
local container_service=$QUADLET_SERVICE_NAME
|
|
local container_name=$QUADLET_CONTAINER_NAME
|
|
|
|
# Start the pod service
|
|
service_setup $pod_service
|
|
|
|
# Pod should exist
|
|
run_podman pod exists ${test_pod_name}
|
|
|
|
# Pod exit policy should be stop by default
|
|
run_podman pod inspect --format "{{.ExitPolicy}}" ${test_pod_name}
|
|
assert "$output" = "stop" \
|
|
"quadlet - pod: default ExitPolicy should be stop"
|
|
|
|
# Wait for systemd to activate the container service
|
|
wait_for_command_output "systemctl show --property=ActiveState $container_service" "ActiveState=active"
|
|
|
|
# Container should exist
|
|
run_podman container exists ${container_name}
|
|
|
|
# Shutdown the service
|
|
service_cleanup $pod_service inactive
|
|
|
|
# It might take a few seconds to go inactive, esp. under heavy load
|
|
for tries in $(seq 1 5); do
|
|
run systemctl show --property=ActiveState "$container_service"
|
|
if [[ "$output" = "ActiveState=inactive" ]]; then
|
|
break
|
|
fi
|
|
sleep 1
|
|
done
|
|
assert "ActiveState=inactive" \
|
|
"quadlet - pod base: container service ActiveState"
|
|
|
|
# Container should not exist
|
|
run_podman 1 container exists ${container_name}
|
|
}
|
|
|
|
# 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
|
|
|
|
# FIXME: how to make this parallel-safe? Can we?
|
|
local untagged_image=quay.io/libpod/busybox
|
|
local built_image="built-$(safename)"
|
|
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="p-$(safename)"
|
|
container_name="c-$(safename)"
|
|
yaml_source="$yaml_dir/build_$(safename).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_$(safename).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}}" $pod_name-$container_name
|
|
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
|
|
}
|
|
|
|
@test "quadlet - drop-in files" {
|
|
local quadlet_tmpdir="${PODMAN_TMPDIR}/dropins"
|
|
|
|
local quadlet_file="truncated-$(safename).container"
|
|
|
|
local -A dropin_dirs=(
|
|
[toplevel]=container.d
|
|
[truncated]=truncated-.container.d
|
|
[quadlet]="${quadlet_file}.d"
|
|
)
|
|
|
|
# Table of drop-in .conf files. Format is:
|
|
#
|
|
# apply | dir | parent dir (optional) | filename | [Section] | Content=...
|
|
#
|
|
# The parent dir used as regression test for https://github.com/containers/podman/issues/26555
|
|
local dropin_files="
|
|
y | toplevel | | 10 | [Unit] | Description=Test File for Dropin Configuration
|
|
n | toplevel | | 99 | [Install] | WantedBy=default.target
|
|
y | truncated | | 50 | [Container] | ContainerName=truncated-dropins
|
|
n | truncated | | 99 | [Service] | Restart=always
|
|
n | truncated | | 99 | [Install] | WantedBy=multiuser.target
|
|
y | quadlet | | 99 | [Service] | RestartSec=60s
|
|
n | toplevel | | 30 | [Service] | Environment=test=wrong
|
|
y | truncated | subdir | 30 | [Service] | Environment=test=right
|
|
"
|
|
|
|
# Pass 1: Create all drop-in directories and files
|
|
while read apply dir parent file section content; do
|
|
# By default parent will be '' when left empty in the table and not actually an empty string,
|
|
# make sure we set it to an empty string instead.
|
|
if [[ "$parent" == "''" ]]; then
|
|
parent=""
|
|
fi
|
|
# Parent can be empty which is fine, dir//file is the same as dir/file and what we want here.
|
|
local d="${quadlet_tmpdir}/$parent/${dropin_dirs[${dir}]}"
|
|
mkdir -p "${d}"
|
|
|
|
local f="${d}/${file}.conf"
|
|
echo "${section}" >>"${f}"
|
|
echo "${content}" >>"${f}"
|
|
done < <(parse_table "${dropin_files}")
|
|
|
|
# Create the base quadlet file
|
|
quadlet_base="${PODMAN_TMPDIR}/${quadlet_file}"
|
|
cat > "${quadlet_base}" <<EOF
|
|
[Container]
|
|
Image="${IMAGE}"
|
|
EOF
|
|
|
|
# Generate the quadlet file from the base file and any drop-in .conf files.
|
|
run_quadlet "${quadlet_base}" "${quadlet_tmpdir}"
|
|
|
|
# Pass 2: test whether the expected .conf files are applied
|
|
# and the overridden .conf files are not.
|
|
while read apply dir parent file section content; do
|
|
if [[ "$parent" == "''" ]]; then
|
|
parent=""
|
|
fi
|
|
if [[ "${apply}" = "y" ]]; then
|
|
assert "${QUADLET_SERVICE_CONTENT}" =~ "${content}" "Set in ${parent}/${dir}/${file}.conf"
|
|
else
|
|
assert "${QUADLET_SERVICE_CONTENT}" !~ "${content}" "Set in ${parent}/${dir}/${file}.conf but should have been overridden"
|
|
fi
|
|
done < <(parse_table "${dropin_files}")
|
|
}
|
|
|
|
# Following issue: https://github.com/containers/podman/issues/24599
|
|
# Make sure future changes do not break
|
|
@test "quadlet - build with pull" {
|
|
local quadlet_tmpdir=$PODMAN_TMPDIR/quadlets
|
|
|
|
mkdir $quadlet_tmpdir
|
|
|
|
local container_file_path=$quadlet_tmpdir/Containerfile
|
|
cat >$container_file_path << EOF
|
|
FROM $IMAGE
|
|
EOF
|
|
|
|
local image_tag=quay.io/i-$(safename):$(random_string)
|
|
local quadlet_file=$PODMAN_TMPDIR/pull_$(safename).build
|
|
cat >$quadlet_file << EOF
|
|
[Build]
|
|
ImageTag=$image_tag
|
|
File=$container_file_path
|
|
Pull=never
|
|
EOF
|
|
|
|
run_quadlet "$quadlet_file"
|
|
service_setup $QUADLET_SERVICE_NAME "wait"
|
|
|
|
run_podman rmi -i $image_tag
|
|
}
|
|
# vim: filetype=sh
|