generate systemd: custom stop signal

Commit 9ac5267598c3 changed the type of the generated systemd units from
forking to notify.  Parts of these changes was also removing the need to
pass any information via the file system (e.g., PIDFILE, container ID).
That in turn implies that systemd takes care of stopping the container.

By default, systemd first sends a SIGTERM and after a certain timeout,
it'll send a SIGKILL.  That's pretty much what Podman is doing, unless
the container was created with a custom stop signal which is the case
when the --stop-signal flag was used or systemd is mounted.

Account for that by using systemd's KillSignal option which allows for
changing SIGTERM to another signal.  Also make sure that we're using the
correct timeout for units generated with --new.

Fixes: #11304
Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
This commit is contained in:
Valentin Rothberg
2021-08-23 17:49:47 +02:00
parent eb9d731c68
commit 70801b3d71
6 changed files with 59 additions and 25 deletions

View File

@ -8,9 +8,9 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
) )
// minTimeoutStopSec is the minimal stop timeout for generated systemd units. // minTimeoutStopSec is the minimal stop timeout for generated systemd units
// Once exceeded, processes of the services are killed and the cgroup(s) are // without --new. Once exceeded, processes of the services are killed and the
// cleaned up. // cgroup(s) are cleaned up.
const minTimeoutStopSec = 60 const minTimeoutStopSec = 60
// validateRestartPolicy checks that the user-provided policy is valid. // validateRestartPolicy checks that the user-provided policy is valid.

View File

@ -16,6 +16,7 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/spf13/pflag" "github.com/spf13/pflag"
"golang.org/x/sys/unix"
) )
// containerInfo contains data required for generating a container's systemd // containerInfo contains data required for generating a container's systemd
@ -32,6 +33,8 @@ type containerInfo struct {
// StopTimeout sets the timeout Podman waits before killing the container // StopTimeout sets the timeout Podman waits before killing the container
// during service stop. // during service stop.
StopTimeout uint StopTimeout uint
// KillSignal of the container.
KillSignal string
// RestartPolicy of the systemd unit (e.g., no, on-failure, always). // RestartPolicy of the systemd unit (e.g., no, on-failure, always).
RestartPolicy string RestartPolicy string
// PIDFile of the service. Required for forking services. Must point to the // PIDFile of the service. Required for forking services. Must point to the
@ -102,6 +105,9 @@ Environment={{{{- range $index, $value := .ExtraEnvs -}}}}{{{{if $index}}}} {{{{
{{{{- end}}}} {{{{- end}}}}
Restart={{{{.RestartPolicy}}}} Restart={{{{.RestartPolicy}}}}
TimeoutStopSec={{{{.TimeoutStopSec}}}} TimeoutStopSec={{{{.TimeoutStopSec}}}}
{{{{- if .KillSignal}}}}
KillSignal={{{{.KillSignal}}}}
{{{{- end}}}}
{{{{- if .ExecStartPre}}}} {{{{- if .ExecStartPre}}}}
ExecStartPre={{{{.ExecStartPre}}}} ExecStartPre={{{{.ExecStartPre}}}}
{{{{- end}}}} {{{{- end}}}}
@ -184,6 +190,13 @@ func generateContainerInfo(ctr *libpod.Container, options entities.GenerateSyste
containerEnv: envs, containerEnv: envs,
} }
// Set a custom kill signal for non SIGTERM (already default in
// systemd) signals.
stopSignal := ctr.StopSignal()
if stopSignal != uint(unix.SIGTERM) {
info.KillSignal = fmt.Sprintf("%d", stopSignal)
}
return &info, nil return &info, nil
} }
@ -359,7 +372,15 @@ func executeContainerTemplate(info *containerInfo, options entities.GenerateSyst
info.ExecStart = strings.Join(startCommand, " ") info.ExecStart = strings.Join(startCommand, " ")
} }
info.TimeoutStopSec = minTimeoutStopSec + info.StopTimeout info.TimeoutStopSec = info.StopTimeout
// For units without --new add an additional 60 seconds to the stop
// timeout to make sure that Podman stop has enough time to properly
// shutdown and cleanup the container before systemd starts to nuke
// everything in the cgroup.
if !options.New {
info.TimeoutStopSec += minTimeoutStopSec
}
if info.PodmanVersion == "" { if info.PodmanVersion == "" {
info.PodmanVersion = version.Version.String() info.PodmanVersion = version.Version.String()

View File

@ -129,7 +129,7 @@ RequiresMountsFor=/var/run/containers/storage
[Service] [Service]
Environment=PODMAN_SYSTEMD_UNIT=%n Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always Restart=always
TimeoutStopSec=70 TimeoutStopSec=10
ExecStart=/usr/bin/podman container run --cgroups=no-conmon --rm --sdnotify=conmon -d --replace --name jadda-jadda --hostname hello-world awesome-image:latest command arg1 ... argN "foo=arg \"with \" space" ExecStart=/usr/bin/podman container run --cgroups=no-conmon --rm --sdnotify=conmon -d --replace --name jadda-jadda --hostname hello-world awesome-image:latest command arg1 ... argN "foo=arg \"with \" space"
Type=notify Type=notify
NotifyAccess=all NotifyAccess=all
@ -151,7 +151,7 @@ RequiresMountsFor=/var/run/containers/storage
[Service] [Service]
Environment=PODMAN_SYSTEMD_UNIT=%n Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always Restart=always
TimeoutStopSec=70 TimeoutStopSec=10
ExecStart=/usr/bin/podman container run --cgroups=no-conmon --rm -d --replace --sdnotify=container --name jadda-jadda --hostname hello-world awesome-image:latest command arg1 ... argN "foo=arg \"with \" space" ExecStart=/usr/bin/podman container run --cgroups=no-conmon --rm -d --replace --sdnotify=container --name jadda-jadda --hostname hello-world awesome-image:latest command arg1 ... argN "foo=arg \"with \" space"
Type=notify Type=notify
NotifyAccess=all NotifyAccess=all
@ -173,7 +173,7 @@ RequiresMountsFor=/var/run/containers/storage
[Service] [Service]
Environment=PODMAN_SYSTEMD_UNIT=%n Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always Restart=always
TimeoutStopSec=70 TimeoutStopSec=10
ExecStart=/usr/bin/podman run --cgroups=no-conmon --rm --sdnotify=conmon --replace -d --name jadda-jadda --hostname hello-world awesome-image:latest command arg1 ... argN ExecStart=/usr/bin/podman run --cgroups=no-conmon --rm --sdnotify=conmon --replace -d --name jadda-jadda --hostname hello-world awesome-image:latest command arg1 ... argN
Type=notify Type=notify
NotifyAccess=all NotifyAccess=all
@ -195,7 +195,7 @@ RequiresMountsFor=/var/run/containers/storage
[Service] [Service]
Environment=PODMAN_SYSTEMD_UNIT=%n Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always Restart=always
TimeoutStopSec=70 TimeoutStopSec=10
ExecStart=/usr/bin/podman run --cgroups=no-conmon --rm --pod-id-file %t/pod-foobar.pod-id-file --sdnotify=conmon --replace -d --name jadda-jadda --hostname hello-world awesome-image:latest command arg1 ... argN ExecStart=/usr/bin/podman run --cgroups=no-conmon --rm --pod-id-file %t/pod-foobar.pod-id-file --sdnotify=conmon --replace -d --name jadda-jadda --hostname hello-world awesome-image:latest command arg1 ... argN
Type=notify Type=notify
NotifyAccess=all NotifyAccess=all
@ -217,7 +217,7 @@ RequiresMountsFor=/var/run/containers/storage
[Service] [Service]
Environment=PODMAN_SYSTEMD_UNIT=%n Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always Restart=always
TimeoutStopSec=70 TimeoutStopSec=10
ExecStart=/usr/bin/podman run --cgroups=no-conmon --rm --sdnotify=conmon --replace --detach --name jadda-jadda --hostname hello-world awesome-image:latest command arg1 ... argN ExecStart=/usr/bin/podman run --cgroups=no-conmon --rm --sdnotify=conmon --replace --detach --name jadda-jadda --hostname hello-world awesome-image:latest command arg1 ... argN
Type=notify Type=notify
NotifyAccess=all NotifyAccess=all
@ -239,7 +239,7 @@ RequiresMountsFor=/var/run/containers/storage
[Service] [Service]
Environment=PODMAN_SYSTEMD_UNIT=%n Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always Restart=always
TimeoutStopSec=70 TimeoutStopSec=10
ExecStart=/usr/bin/podman run --cgroups=no-conmon --rm --sdnotify=conmon -d awesome-image:latest ExecStart=/usr/bin/podman run --cgroups=no-conmon --rm --sdnotify=conmon -d awesome-image:latest
Type=notify Type=notify
NotifyAccess=all NotifyAccess=all
@ -262,7 +262,7 @@ RequiresMountsFor=/var/run/containers/storage
[Service] [Service]
Environment=PODMAN_SYSTEMD_UNIT=%n Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always Restart=always
TimeoutStopSec=102 TimeoutStopSec=42
ExecStart=/usr/bin/podman run --cgroups=no-conmon --rm --sdnotify=conmon ` + ExecStart=/usr/bin/podman run --cgroups=no-conmon --rm --sdnotify=conmon ` +
detachparam + detachparam +
` awesome-image:latest ` awesome-image:latest
@ -288,7 +288,7 @@ RequiresMountsFor=/var/run/containers/storage
[Service] [Service]
Environment=PODMAN_SYSTEMD_UNIT=%n Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always Restart=always
TimeoutStopSec=102 TimeoutStopSec=42
ExecStart=/usr/bin/podman run --cgroups=no-conmon --rm --sdnotify=conmon -d --replace --name test -p 80:80 awesome-image:latest somecmd --detach=false ExecStart=/usr/bin/podman run --cgroups=no-conmon --rm --sdnotify=conmon -d --replace --name test -p 80:80 awesome-image:latest somecmd --detach=false
Type=notify Type=notify
NotifyAccess=all NotifyAccess=all
@ -310,7 +310,7 @@ RequiresMountsFor=/var/run/containers/storage
[Service] [Service]
Environment=PODMAN_SYSTEMD_UNIT=%n Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always Restart=always
TimeoutStopSec=102 TimeoutStopSec=42
ExecStart=/usr/bin/podman --events-backend none --runroot /root run --cgroups=no-conmon --rm --sdnotify=conmon -d awesome-image:latest ExecStart=/usr/bin/podman --events-backend none --runroot /root run --cgroups=no-conmon --rm --sdnotify=conmon -d awesome-image:latest
Type=notify Type=notify
NotifyAccess=all NotifyAccess=all
@ -332,7 +332,7 @@ RequiresMountsFor=/var/run/containers/storage
[Service] [Service]
Environment=PODMAN_SYSTEMD_UNIT=%n Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always Restart=always
TimeoutStopSec=70 TimeoutStopSec=10
ExecStart=/usr/bin/podman container run --cgroups=no-conmon --rm --sdnotify=conmon -d awesome-image:latest ExecStart=/usr/bin/podman container run --cgroups=no-conmon --rm --sdnotify=conmon -d awesome-image:latest
Type=notify Type=notify
NotifyAccess=all NotifyAccess=all
@ -354,7 +354,7 @@ RequiresMountsFor=/var/run/containers/storage
[Service] [Service]
Environment=PODMAN_SYSTEMD_UNIT=%n Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always Restart=always
TimeoutStopSec=70 TimeoutStopSec=10
ExecStart=/usr/bin/podman run --cgroups=no-conmon --rm --sdnotify=conmon -d --replace --name test --log-driver=journald --log-opt=tag={{.Name}} awesome-image:latest ExecStart=/usr/bin/podman run --cgroups=no-conmon --rm --sdnotify=conmon -d --replace --name test --log-driver=journald --log-opt=tag={{.Name}} awesome-image:latest
Type=notify Type=notify
NotifyAccess=all NotifyAccess=all
@ -376,7 +376,7 @@ RequiresMountsFor=/var/run/containers/storage
[Service] [Service]
Environment=PODMAN_SYSTEMD_UNIT=%n Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always Restart=always
TimeoutStopSec=70 TimeoutStopSec=10
ExecStart=/usr/bin/podman run --cgroups=no-conmon --rm --sdnotify=conmon -d --replace --name test awesome-image:latest sh -c "kill $$$$ && echo %%\\" ExecStart=/usr/bin/podman run --cgroups=no-conmon --rm --sdnotify=conmon -d --replace --name test awesome-image:latest sh -c "kill $$$$ && echo %%\\"
Type=notify Type=notify
NotifyAccess=all NotifyAccess=all
@ -398,7 +398,7 @@ RequiresMountsFor=/var/run/containers/storage
[Service] [Service]
Environment=PODMAN_SYSTEMD_UNIT=%n Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always Restart=always
TimeoutStopSec=70 TimeoutStopSec=10
ExecStart=/usr/bin/podman run --cgroups=no-conmon --rm --sdnotify=conmon -d --conmon-pidfile=foo --cidfile=foo awesome-image:latest podman run --cgroups=foo --conmon-pidfile=foo --cidfile=foo alpine ExecStart=/usr/bin/podman run --cgroups=no-conmon --rm --sdnotify=conmon -d --conmon-pidfile=foo --cidfile=foo awesome-image:latest podman run --cgroups=foo --conmon-pidfile=foo --cidfile=foo alpine
Type=notify Type=notify
NotifyAccess=all NotifyAccess=all
@ -420,7 +420,7 @@ RequiresMountsFor=/var/run/containers/storage
[Service] [Service]
Environment=PODMAN_SYSTEMD_UNIT=%n Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always Restart=always
TimeoutStopSec=70 TimeoutStopSec=10
ExecStart=/usr/bin/podman run --cgroups=no-conmon --rm --pod-id-file %t/pod-foobar.pod-id-file --sdnotify=conmon -d --conmon-pidfile=foo --cidfile=foo awesome-image:latest podman run --cgroups=foo --conmon-pidfile=foo --cidfile=foo --pod-id-file /tmp/pod-foobar.pod-id-file alpine ExecStart=/usr/bin/podman run --cgroups=no-conmon --rm --pod-id-file %t/pod-foobar.pod-id-file --sdnotify=conmon -d --conmon-pidfile=foo --cidfile=foo awesome-image:latest podman run --cgroups=foo --conmon-pidfile=foo --cidfile=foo --pod-id-file /tmp/pod-foobar.pod-id-file alpine
Type=notify Type=notify
NotifyAccess=all NotifyAccess=all
@ -443,7 +443,7 @@ RequiresMountsFor=/var/run/containers/storage
Environment=PODMAN_SYSTEMD_UNIT=%n Environment=PODMAN_SYSTEMD_UNIT=%n
Environment=FOO=abc "BAR=my test" USER=%%a Environment=FOO=abc "BAR=my test" USER=%%a
Restart=always Restart=always
TimeoutStopSec=70 TimeoutStopSec=10
ExecStart=/usr/bin/podman run --cgroups=no-conmon --rm --sdnotify=conmon -d --env FOO --env=BAR --env=MYENV=2 -e USER awesome-image:latest ExecStart=/usr/bin/podman run --cgroups=no-conmon --rm --sdnotify=conmon -d --env FOO --env=BAR --env=MYENV=2 -e USER awesome-image:latest
Type=notify Type=notify
NotifyAccess=all NotifyAccess=all

View File

@ -323,7 +323,7 @@ func executePodTemplate(info *podInfo, options entities.GenerateSystemdOptions)
info.ExecStop = "{{{{.Executable}}}} {{{{if .RootFlags}}}}{{{{ .RootFlags}}}} {{{{end}}}}pod stop --ignore --pod-id-file {{{{.PodIDFile}}}} {{{{if (ge .StopTimeout 0)}}}}-t {{{{.StopTimeout}}}}{{{{end}}}}" info.ExecStop = "{{{{.Executable}}}} {{{{if .RootFlags}}}}{{{{ .RootFlags}}}} {{{{end}}}}pod stop --ignore --pod-id-file {{{{.PodIDFile}}}} {{{{if (ge .StopTimeout 0)}}}}-t {{{{.StopTimeout}}}}{{{{end}}}}"
info.ExecStopPost = "{{{{.Executable}}}} {{{{if .RootFlags}}}}{{{{ .RootFlags}}}} {{{{end}}}}pod rm --ignore -f --pod-id-file {{{{.PodIDFile}}}}" info.ExecStopPost = "{{{{.Executable}}}} {{{{if .RootFlags}}}}{{{{ .RootFlags}}}} {{{{end}}}}pod rm --ignore -f --pod-id-file {{{{.PodIDFile}}}}"
} }
info.TimeoutStopSec = minTimeoutStopSec + info.StopTimeout info.TimeoutStopSec = info.StopTimeout
if info.PodmanVersion == "" { if info.PodmanVersion == "" {
info.PodmanVersion = version.Version.String() info.PodmanVersion = version.Version.String()

View File

@ -54,7 +54,7 @@ Before=container-1.service container-2.service
[Service] [Service]
Environment=PODMAN_SYSTEMD_UNIT=%n Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=always Restart=always
TimeoutStopSec=102 TimeoutStopSec=42
ExecStart=/usr/bin/podman start jadda-jadda-infra ExecStart=/usr/bin/podman start jadda-jadda-infra
ExecStop=/usr/bin/podman stop -t 42 jadda-jadda-infra ExecStop=/usr/bin/podman stop -t 42 jadda-jadda-infra
ExecStopPost=/usr/bin/podman stop -t 42 jadda-jadda-infra ExecStopPost=/usr/bin/podman stop -t 42 jadda-jadda-infra
@ -82,7 +82,7 @@ Before=container-1.service container-2.service
[Service] [Service]
Environment=PODMAN_SYSTEMD_UNIT=%n Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=on-failure Restart=on-failure
TimeoutStopSec=70 TimeoutStopSec=10
ExecStartPre=/bin/rm -f %t/pod-123abc.pid %t/pod-123abc.pod-id ExecStartPre=/bin/rm -f %t/pod-123abc.pid %t/pod-123abc.pod-id
ExecStartPre=/usr/bin/podman pod create --infra-conmon-pidfile %t/pod-123abc.pid --pod-id-file %t/pod-123abc.pod-id --name foo "bar=arg with space" --replace ExecStartPre=/usr/bin/podman pod create --infra-conmon-pidfile %t/pod-123abc.pid --pod-id-file %t/pod-123abc.pod-id --name foo "bar=arg with space" --replace
ExecStart=/usr/bin/podman pod start --pod-id-file %t/pod-123abc.pod-id ExecStart=/usr/bin/podman pod start --pod-id-file %t/pod-123abc.pod-id
@ -110,7 +110,7 @@ Before=container-1.service container-2.service
[Service] [Service]
Environment=PODMAN_SYSTEMD_UNIT=%n Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=on-failure Restart=on-failure
TimeoutStopSec=70 TimeoutStopSec=10
ExecStartPre=/bin/rm -f %t/pod-123abc.pid %t/pod-123abc.pod-id ExecStartPre=/bin/rm -f %t/pod-123abc.pid %t/pod-123abc.pod-id
ExecStartPre=/usr/bin/podman --events-backend none --runroot /root pod create --infra-conmon-pidfile %t/pod-123abc.pid --pod-id-file %t/pod-123abc.pod-id --name foo "bar=arg with space" --replace ExecStartPre=/usr/bin/podman --events-backend none --runroot /root pod create --infra-conmon-pidfile %t/pod-123abc.pid --pod-id-file %t/pod-123abc.pod-id --name foo "bar=arg with space" --replace
ExecStart=/usr/bin/podman --events-backend none --runroot /root pod start --pod-id-file %t/pod-123abc.pod-id ExecStart=/usr/bin/podman --events-backend none --runroot /root pod start --pod-id-file %t/pod-123abc.pod-id
@ -138,7 +138,7 @@ Before=container-1.service container-2.service
[Service] [Service]
Environment=PODMAN_SYSTEMD_UNIT=%n Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=on-failure Restart=on-failure
TimeoutStopSec=70 TimeoutStopSec=10
ExecStartPre=/bin/rm -f %t/pod-123abc.pid %t/pod-123abc.pod-id ExecStartPre=/bin/rm -f %t/pod-123abc.pid %t/pod-123abc.pod-id
ExecStartPre=/usr/bin/podman pod create --infra-conmon-pidfile %t/pod-123abc.pid --pod-id-file %t/pod-123abc.pod-id --name foo --replace ExecStartPre=/usr/bin/podman pod create --infra-conmon-pidfile %t/pod-123abc.pid --pod-id-file %t/pod-123abc.pod-id --name foo --replace
ExecStart=/usr/bin/podman pod start --pod-id-file %t/pod-123abc.pod-id ExecStart=/usr/bin/podman pod start --pod-id-file %t/pod-123abc.pod-id
@ -166,7 +166,7 @@ Before=container-1.service container-2.service
[Service] [Service]
Environment=PODMAN_SYSTEMD_UNIT=%n Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=on-failure Restart=on-failure
TimeoutStopSec=70 TimeoutStopSec=10
ExecStartPre=/bin/rm -f %t/pod-123abc.pid %t/pod-123abc.pod-id ExecStartPre=/bin/rm -f %t/pod-123abc.pid %t/pod-123abc.pod-id
ExecStartPre=/usr/bin/podman pod create --infra-conmon-pidfile %t/pod-123abc.pid --pod-id-file %t/pod-123abc.pod-id --name foo --label key={{someval}} --replace ExecStartPre=/usr/bin/podman pod create --infra-conmon-pidfile %t/pod-123abc.pid --pod-id-file %t/pod-123abc.pod-id --name foo --label key={{someval}} --replace
ExecStart=/usr/bin/podman pod start --pod-id-file %t/pod-123abc.pod-id ExecStart=/usr/bin/podman pod start --pod-id-file %t/pod-123abc.pod-id

View File

@ -125,4 +125,17 @@ function service_cleanup() {
service_cleanup service_cleanup
} }
@test "podman generate systemd - stop-signal" {
cname=$(random_string)
run_podman create --name $cname --stop-signal=42 $IMAGE
run_podman generate systemd --new $cname
is "$output" ".*KillSignal=42.*" "KillSignal is set"
# Regression test for #11304: systemd wants a custom stop-signal.
run_podman rm -f $cname
run_podman create --name $cname --systemd=true $IMAGE systemd
run_podman generate systemd --new $cname
is "$output" ".*KillSignal=37.*" "KillSignal is set"
}
# vim: filetype=sh # vim: filetype=sh