From 5989370c39f76805e7a4f327f3594b489f37127f Mon Sep 17 00:00:00 2001 From: nbspsemicolon Date: Wed, 18 Jun 2025 12:42:13 -0400 Subject: [PATCH] pkg/systemd: expose [Pod] ExitPolicy key for pod create --exit-policy Add ExitPolicy key to pod quadlets with logic to default to stop. Docs updated with clarifcation on default value and usage example. Simple assert added to bats to verify default constraint exists. Changed argument order in ginkgo basic pod unit test Signed-off-by: Neil Bailey --- .../source/markdown/podman-pod-create.1.md.in | 2 +- docs/source/markdown/podman-systemd.unit.5.md | 40 +++++++++++++++++++ pkg/systemd/quadlet/quadlet.go | 16 +++++++- test/e2e/quadlet/basic.pod | 2 +- test/system/252-quadlet.bats | 5 +++ 5 files changed, 62 insertions(+), 3 deletions(-) diff --git a/docs/source/markdown/podman-pod-create.1.md.in b/docs/source/markdown/podman-pod-create.1.md.in index 6f696d8351..c377490ec6 100644 --- a/docs/source/markdown/podman-pod-create.1.md.in +++ b/docs/source/markdown/podman-pod-create.1.md.in @@ -76,7 +76,7 @@ Set the exit policy of the pod when the last container exits. Supported policie | Exit Policy | Description | | ------------------ | -------------------------------------------------------------------------------------------------------------------------- | | *continue* | The pod continues running, by keeping its infra container alive, when the last container exits. Used by default. | -| *stop* | The pod (including its infra container) is stopped when the last container exits. Used in `kube play`. | +| *stop* | The pod (including its infra container) is stopped when the last container exits. Used in `kube play` and quadlets. | @@option gidmap.pod diff --git a/docs/source/markdown/podman-systemd.unit.5.md b/docs/source/markdown/podman-systemd.unit.5.md index 3e802fd123..4b39835c0b 100644 --- a/docs/source/markdown/podman-systemd.unit.5.md +++ b/docs/source/markdown/podman-systemd.unit.5.md @@ -1006,6 +1006,7 @@ Valid options for `[Pod]` are listed below: | DNS=192.168.55.1 | --dns=192.168.55.1 | | DNSOption=ndots:1 | --dns-option=ndots:1 | | DNSSearch=example.com | --dns-search example.com | +| ExitPolicy=stop | --exit-policy stop | | GIDMap=0:10000:10 | --gidmap=0:10000:10 | | GlobalArgs=--log-level=debug | --log-level=debug | | HostName=name | --hostname=name | @@ -1059,6 +1060,12 @@ Set custom DNS search domains. Use **DNSSearch=.** to remove the search domain. This key can be listed multiple times. +### `ExitPolicy=` + +Set the exit policy of the pod when the last container exits. Default for quadlets is **stop**. + +To keep the pod active, set `ExitPolicy=continue`. + ### `GIDMap=` Create the pod in a new user namespace using the supplied GID mapping. @@ -2175,6 +2182,39 @@ Exec=sh -c "sleep inf" Pod=test.pod ``` +Example for a Pod with a oneshot Startup Task: + +`test.pod` +``` +[Pod] +PodName=test +ExitPolicy=continue +``` + +`startup-task.container` +``` +[Service] +Type=oneshot +RemainAfterExit=yes + +[Container] +Pod=test.pod +Image=quay.io/centos/centos:latest +Exec=sh -c "echo 'setup starting'; sleep 2; echo 'setup complete'" +``` + +`app.container` +``` +[Unit] +Requires=startup-task.container +After=startup-task.container + +[Container] +Pod=test.pod +Image=quay.io/centos/centos:latest +Exec=sh -c "echo 'app running.'; sleep 30" +``` + Example `s3fs.volume`: For further details, please see the [s3fs-fuse](https://github.com/s3fs-fuse/s3fs-fuse) project. diff --git a/pkg/systemd/quadlet/quadlet.go b/pkg/systemd/quadlet/quadlet.go index e11a7fde44..8a9b17ac58 100644 --- a/pkg/systemd/quadlet/quadlet.go +++ b/pkg/systemd/quadlet/quadlet.go @@ -86,6 +86,7 @@ const ( KeyEnvironmentHost = "EnvironmentHost" KeyExec = "Exec" KeyExitCodePropagation = "ExitCodePropagation" + KeyExitPolicy = "ExitPolicy" KeyExposeHostPort = "ExposeHostPort" KeyFile = "File" KeyForceRM = "ForceRM" @@ -472,6 +473,7 @@ var ( KeyDNS: true, KeyDNSOption: true, KeyDNSSearch: true, + KeyExitPolicy: true, KeyGIDMap: true, KeyGlobalArgs: true, KeyHostName: true, @@ -1538,10 +1540,11 @@ func ConvertPod(podUnit *parser.UnitFile, name string, unitsInfoMap map[string]* execStartPre.add("pod", "create") execStartPre.add( "--infra-conmon-pidfile=%t/%N.pid", - "--exit-policy=stop", "--replace", ) + handleExitPolicy(podUnit, PodGroup, execStartPre) + if err := handleUserMappings(podUnit, PodGroup, execStartPre, true); err != nil { return nil, warnings, err } @@ -1800,6 +1803,17 @@ func getAbsolutePath(quadletUnitFile *parser.UnitFile, filePath string) (string, return filePath, nil } +func handleExitPolicy(unitFile *parser.UnitFile, groupName string, podman *PodmanCmdline) { + exitPolicy, found := unitFile.Lookup(groupName, KeyExitPolicy) + + podman.add("--exit-policy") + if found { + podman.add(exitPolicy) + } else { + podman.add("stop") + } +} + func handlePublishPorts(unitFile *parser.UnitFile, groupName string, podman *PodmanCmdline) { publishPorts := unitFile.LookupAll(groupName, KeyPublishPort) for _, publishPort := range publishPorts { diff --git a/test/e2e/quadlet/basic.pod b/test/e2e/quadlet/basic.pod index 6e482e1940..08e10494d2 100644 --- a/test/e2e/quadlet/basic.pod +++ b/test/e2e/quadlet/basic.pod @@ -1,7 +1,7 @@ ## assert-key-is Unit RequiresMountsFor "%t/containers" ## assert-key-is Service Type forking ## assert-key-is Service SyslogIdentifier "%N" -## assert-key-is-regex Service ExecStartPre ".*/podman pod create --infra-conmon-pidfile=%t/%N.pid --exit-policy=stop --replace --infra-name systemd-basic-infra --name systemd-basic" +## assert-key-is-regex Service ExecStartPre ".*/podman pod create --infra-conmon-pidfile=%t/%N.pid --replace --exit-policy stop --infra-name systemd-basic-infra --name systemd-basic" ## assert-key-is-regex Service ExecStart ".*/podman pod start systemd-basic" ## assert-key-is-regex Service ExecStop ".*/podman pod stop --ignore --time=10 systemd-basic" ## assert-key-is-regex Service ExecStopPost ".*/podman pod rm --ignore --force systemd-basic" diff --git a/test/system/252-quadlet.bats b/test/system/252-quadlet.bats index 6a7cf884de..a3d95309dc 100644 --- a/test/system/252-quadlet.bats +++ b/test/system/252-quadlet.bats @@ -1693,6 +1693,11 @@ EOF # 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"