diff --git a/libpod/container_internal.go b/libpod/container_internal.go index ca2eee1208..721d78d5ba 100644 --- a/libpod/container_internal.go +++ b/libpod/container_internal.go @@ -1546,6 +1546,14 @@ func (c *Container) pause() error { } } + if c.state.HCUnitName != "" { + if err := c.removeTransientFiles(context.Background(), + c.config.StartupHealthCheckConfig != nil && !c.state.StartupHCPassed, + c.state.HCUnitName); err != nil { + return fmt.Errorf("failed to remove HealthCheck timer: %v", err) + } + } + if err := c.ociRuntime.PauseContainer(c); err != nil { // TODO when using docker-py there is some sort of race/incompatibility here return err @@ -1554,6 +1562,7 @@ func (c *Container) pause() error { logrus.Debugf("Paused container %s", c.ID()) c.state.State = define.ContainerStatePaused + c.state.HCUnitName = "" return c.save() } @@ -1569,6 +1578,28 @@ func (c *Container) unpause() error { return err } + isStartupHealthCheck := c.config.StartupHealthCheckConfig != nil && !c.state.StartupHCPassed + isHealthCheckEnabled := c.config.HealthCheckConfig != nil && + !(len(c.config.HealthCheckConfig.Test) == 1 && c.config.HealthCheckConfig.Test[0] == "NONE") + if isHealthCheckEnabled || isStartupHealthCheck { + timer := c.config.HealthCheckConfig.Interval.String() + if isStartupHealthCheck { + timer = c.config.StartupHealthCheckConfig.Interval.String() + } + if err := c.createTimer(timer, isStartupHealthCheck); err != nil { + return err + } + } + + if isHealthCheckEnabled { + if err := c.updateHealthStatus(define.HealthCheckReset); err != nil { + return err + } + if err := c.startTimer(isStartupHealthCheck); err != nil { + return err + } + } + logrus.Debugf("Unpaused container %s", c.ID()) c.state.State = define.ContainerStateRunning diff --git a/test/system/080-pause.bats b/test/system/080-pause.bats index 8d9b760f74..c818d0849a 100644 --- a/test/system/080-pause.bats +++ b/test/system/080-pause.bats @@ -4,6 +4,7 @@ # load helpers +load helpers.systemd # bats test_tags=distro-integration, ci:parallel @test "podman pause/unpause" { @@ -86,4 +87,52 @@ load helpers run_podman rm -t 0 -f $cname $cname_notrunning } + +# bats test_tags=ci:parallel +@test "podman pause/unpause with HealthCheck interval" { + if is_rootless && ! is_cgroupsv2; then + skip "'podman pause' (rootless) only works with cgroups v2" + fi + + local ctrname="c-$(safename)" + local msg="healthmsg-$(random_string)" + + run_podman run -d --name $ctrname \ + --health-cmd "echo $msg" \ + --health-interval 1s \ + $IMAGE /home/podman/pause + cid="$output" + + run_podman healthcheck run $ctrname + is "$output" "" "output from 'podman healthcheck run'" + + run -0 systemctl status $cid-*.{service,timer} + assert "$output" =~ "active" "service should be running" + + run_podman --noout pause $ctrname + assert "$output" == "" "output should be empty" + + run -0 systemctl status $cid-*.{service,timer} + assert "$output" == "" "service should not be running" + + run_podman --noout unpause $ctrname + assert "$output" == "" "output should be empty" + + run_podman healthcheck run $ctrname + is "$output" "" "output from 'podman healthcheck run'" + + run -0 systemctl status $cid-*.{service,timer} + assert "$output" =~ "active" "service should be running" + + run_podman rm -t 0 -f $ctrname + + # Important check for https://github.com/containers/podman/issues/22884 + # We never should leak the unit files, healthcheck uses the cid in name so just grep that. + # (Ignore .scope units, those are conmon and can linger for 5 minutes) + # (Ignore .mount, too. They are created/removed by systemd based on the actual real mounts + # on the host and that is async and might be slow enough in CI to cause failures.) + run -0 systemctl list-units --quiet "*$cid*" + except_scope_mount=$(grep -vF ".scope " <<<"$output" | { grep -vF ".mount" || true; } ) + assert "$except_scope_mount" == "" "Healthcheck systemd unit cleanup: no units leaked" +} # vim: filetype=sh