diff --git a/docs/source/markdown/podman-systemd.unit.5.md b/docs/source/markdown/podman-systemd.unit.5.md index bbd556bd87..86e07d4352 100644 --- a/docs/source/markdown/podman-systemd.unit.5.md +++ b/docs/source/markdown/podman-systemd.unit.5.md @@ -86,6 +86,17 @@ Valid options for `[Container]` are listed below: | Exec=/usr/bin/command | Command after image specification - /usr/bin/command | | ExposeHostPort=50-59 | --expose 50-59 | | Group=1234 | --user UID:1234 | +| HealthCmd="/usr/bin/command" | --health-cmd="/usr/bin/command" | +| HealthInterval=2m | --health-interval=2m | +| HealthOnFailure=kill | --health-on-failure=kill | +| HealthRetries=5 | --health-retries=5 | +| HealthStartPeriod=1m | --health-start-period=period=1m | +| HealthStartupCmd="/usr/bin/command" | --health-startup-cmd="/usr/bin/command" | +| HealthStartupInterval=1m | --health-startup-interval=2m | +| HealthStartupRetries=8 | --health-startup-retries=8 | +| HealthStartupSuccess=2 | --health-startup-success=2 | +| HealthStartupTimeout=1m33s | --health-startup-timeout=1m33s | +| HealthTimeout=20s | --health-timeout=20s | | Image=ubi8 | Image specification - ubi8 | | IP=192.5.0.1 | --ip 192.5.0.0 | | IP6=fd46:db93:aa76:ac37::10 | --ip6 2001:db8::1 | @@ -196,6 +207,65 @@ This key can be listed multiple times. The (numeric) gid to run as inside the container. This does not need to match the gid on the host, which can be modified with `RemapUsers`, but if that is not specified, this gid is also used on the host. + +### `HealthCmd=` + +Set or alter a healthcheck command for a container. A value of none disables existing healthchecks. +Equivalent to the Podman `--health-cmd` option. + +### `HealthInterval=` + +Set an interval for the healthchecks. An interval of disable results in no automatic timer setup. +Equivalent to the Podman `--health-interval` option. + +### `HealthOnFailure=` + +Action to take once the container transitions to an unhealthy state. +The "kill" action in combination integrates best with systemd. Once +the container turns unhealthy, it gets killed and systemd will restart +service. +Equivalent to the Podman `--health-on-failure` option. + +### `HealthRetries=` + +The number of retries allowed before a healthcheck is considered to be unhealthy. +Equivalent to the Podman `--health-retries` option. + +### `HealthStartPeriod=` + +The initialization time needed for a container to bootstrap. +Equivalent to the Podman `--health-start-period` option. + +### `HealthStartupCmd=` + +Set a startup healthcheck command for a container. +Equivalent to the Podman `--health-startup-cmd` option. + +### `HealthStartupInterval=` + +Set an interval for the startup healthcheck. An interval of disable results in no automatic timer setup. +Equivalent to the Podman `--health-startup-interval` option. + +### `HealthStartupRetries=` + +The number of attempts allowed before the startup healthcheck restarts the container. +Equivalent to the Podman `--health-startup-retries` option. + +### `HealthStartupSuccess=` + +The number of successful runs required before the startup healthcheck will succeed and the regular healthcheck will begin. +Equivalent to the Podman `--health-startup-success` option. + +### `HealthStartupTimeout=` + +The maximum time a startup healthcheck command has to complete before it is marked as failed. +Equivalent to the Podman `--health-startup-timeout` option. + +### `HealthTimeout=` + +The maximum time allowed to complete the healthcheck before an interval is considered failed. +Equivalent to the Podman `--health-timeout` option. + ### `Image=` The image to run in the container. This image must be locally installed for the service to work diff --git a/pkg/systemd/quadlet/quadlet.go b/pkg/systemd/quadlet/quadlet.go index cfdac299ab..ecee2225e1 100644 --- a/pkg/systemd/quadlet/quadlet.go +++ b/pkg/systemd/quadlet/quadlet.go @@ -48,6 +48,17 @@ const ( KeyExec = "Exec" KeyExposeHostPort = "ExposeHostPort" KeyGroup = "Group" + KeyHealthCmd = "HealthCmd" + KeyHealthInterval = "HealthInterval" + KeyHealthOnFailure = "HealthOnFailure" + KeyHealthRetries = "HealthRetries" + KeyHealthStartPeriod = "HealthStartPeriod" + KeyHealthStartupCmd = "HealthStartupCmd" + KeyHealthStartupInterval = "HealthStartupInterval" + KeyHealthStartupRetries = "HealthStartupRetries" + KeyHealthStartupSuccess = "HealthStartupSuccess" + KeyHealthStartupTimeout = "HealthStartupTimeout" + KeyHealthTimeout = "HealthTimeout" KeyImage = "Image" KeyIP = "IP" KeyIP6 = "IP6" @@ -106,6 +117,17 @@ var ( KeyExec: true, KeyExposeHostPort: true, KeyGroup: true, + KeyHealthCmd: true, + KeyHealthInterval: true, + KeyHealthOnFailure: true, + KeyHealthRetries: true, + KeyHealthStartPeriod: true, + KeyHealthStartupCmd: true, + KeyHealthStartupInterval: true, + KeyHealthStartupRetries: true, + KeyHealthStartupSuccess: true, + KeyHealthStartupTimeout: true, + KeyHealthTimeout: true, KeyImage: true, KeyIP: true, KeyIP6: true, @@ -560,6 +582,8 @@ func ConvertContainer(container *parser.UnitFile, isUser bool) (*parser.UnitFile podman.add("--mount", mountStr) } + handleHealth(container, ContainerGroup, podman) + podmanArgs := container.LookupAllArgs(ContainerGroup, KeyPodmanArgs) podman.add(podmanArgs...) @@ -1042,3 +1066,27 @@ func handleStorageSource(unitFile *parser.UnitFile, source string) string { return source } + +func handleHealth(unitFile *parser.UnitFile, groupName string, podman *PodmanCmdline) { + keyArgMap := [][2]string{ + {KeyHealthCmd, "cmd"}, + {KeyHealthInterval, "interval"}, + {KeyHealthOnFailure, "on-failure"}, + {KeyHealthRetries, "retries"}, + {KeyHealthStartPeriod, "start-period"}, + {KeyHealthTimeout, "timeout"}, + {KeyHealthStartupCmd, "startup-cmd"}, + {KeyHealthStartupInterval, "startup-interval"}, + {KeyHealthStartupRetries, "startup-retries"}, + {KeyHealthStartupSuccess, "startup-success"}, + {KeyHealthStartupTimeout, "startup-timeout"}, + } + + for _, keyArg := range keyArgMap { + val, found := unitFile.Lookup(groupName, keyArg[0]) + if found && len(val) > 0 { + podman.addf("--health-%s", keyArg[1]) + podman.addf("%s", val) + } + } +} diff --git a/test/e2e/quadlet/health.container b/test/e2e/quadlet/health.container new file mode 100644 index 0000000000..a80b67fbc9 --- /dev/null +++ b/test/e2e/quadlet/health.container @@ -0,0 +1,24 @@ +[Container] +Image=localhost/imagename +## assert-podman-args "--health-cmd" "\"hello world\"" +HealthCmd="hello world" +## assert-podman-args "--health-interval" "1m" +HealthInterval=1m +## assert-podman-args "--health-on-failure" "stop" +HealthOnFailure=stop +## assert-podman-args "--health-retries" "9" +HealthRetries=9 +## assert-podman-args "--health-start-period" "2m3s" +HealthStartPeriod=2m3s +## assert-podman-args "--health-timeout" "20s" +HealthTimeout=20s +## assert-podman-args "--health-startup-cmd" "'[\"hello\", world]'" +HealthStartupCmd='["hello", world]' +## assert-podman-args "--health-startup-interval" "5m" +HealthStartupInterval=5m +## assert-podman-args "--health-startup-retries" "10" +HealthStartupRetries=10 +## assert-podman-args "--health-startup-success" "2" +HealthStartupSuccess=2 +## assert-podman-args "--health-startup-timeout" "2h" +HealthStartupTimeout=2h diff --git a/test/e2e/quadlet_test.go b/test/e2e/quadlet_test.go index 466310cb04..ddccbcfce4 100644 --- a/test/e2e/quadlet_test.go +++ b/test/e2e/quadlet_test.go @@ -531,6 +531,7 @@ var _ = Describe("quadlet system generator", func() { Entry("secrets.container", "secrets.container"), Entry("logdriver.container", "logdriver.container"), Entry("mount.container", "mount.container"), + Entry("health.container", "health.container"), Entry("basic.volume", "basic.volume"), Entry("label.volume", "label.volume"),