diff options
| author | Michael Vogt <michael.vogt@gmail.com> | 2018-04-16 11:41:09 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-04-16 11:41:09 +0200 |
| commit | 75dfe705e2b1eed9c608dcca39d71773946b954e (patch) | |
| tree | 4b4dcfb6e24f628fd1deb1d5a46483c380d3660d | |
| parent | f3d16a317616b1aa37a95c229159cc58f2b09a1f (diff) | |
| parent | 1ca0f37350dc77665d8de502ea778ac059589656 (diff) | |
Merge pull request #5050 from mvo5/snap-refresh-mode-fixes-2.32
many: add "stop-mode: sig{term,hup,usr[12]}{,-all}" instead of conflating that with refresh-mode #5043
| -rw-r--r-- | snap/info.go | 28 | ||||
| -rw-r--r-- | snap/info_snap_yaml.go | 2 | ||||
| -rw-r--r-- | snap/info_test.go | 38 | ||||
| -rw-r--r-- | snap/validate.go | 11 | ||||
| -rw-r--r-- | snap/validate_test.go | 37 | ||||
| -rwxr-xr-x | tests/lib/snaps/test-snapd-service/bin/reload | 2 | ||||
| -rwxr-xr-x | tests/lib/snaps/test-snapd-service/bin/start-refresh-mode | 11 | ||||
| -rwxr-xr-x | tests/lib/snaps/test-snapd-service/bin/start-stop-mode | 11 | ||||
| -rwxr-xr-x | tests/lib/snaps/test-snapd-service/bin/start-stop-mode-sigterm | 8 | ||||
| -rwxr-xr-x | tests/lib/snaps/test-snapd-service/bin/stop-stop-mode (renamed from tests/lib/snaps/test-snapd-service/bin/stop-refresh-mode) | 0 | ||||
| -rw-r--r-- | tests/lib/snaps/test-snapd-service/meta/snap.yaml | 64 | ||||
| -rw-r--r-- | tests/main/snap-service-refresh-mode/task.yaml | 37 | ||||
| -rw-r--r-- | tests/main/snap-service-stop-mode-sigkill/task.yaml | 37 | ||||
| -rw-r--r-- | tests/main/snap-service-stop-mode/task.yaml | 54 | ||||
| -rw-r--r-- | wrappers/services.go | 60 | ||||
| -rw-r--r-- | wrappers/services_gen_test.go | 21 | ||||
| -rw-r--r-- | wrappers/services_test.go | 28 |
17 files changed, 333 insertions, 116 deletions
diff --git a/snap/info.go b/snap/info.go index 63ba061506..c179347fc1 100644 --- a/snap/info.go +++ b/snap/info.go @@ -537,6 +537,33 @@ type TimerInfo struct { Timer string } +// StopModeType is the type for the "stop-mode:" of a snap app +type StopModeType string + +// KillAll returns if the stop-mode means all processes should be killed +// when the service is stopped or just the main process. +func (st StopModeType) KillAll() bool { + return string(st) == "" || strings.HasSuffix(string(st), "-all") +} + +// KillSignal returns the signal that should be used to kill the process +// (or an empty string if no signal is needed) +func (st StopModeType) KillSignal() string { + if st == "" { + return "" + } + return strings.ToUpper(strings.TrimSuffix(string(st), "-all")) +} + +func (st StopModeType) Valid() error { + switch st { + case "", "sigterm", "sigterm-all", "sighup", "sighup-all", "sigusr1", "sigusr1-all", "sigusr2", "sigusr2-all": + // valid + return nil + } + return fmt.Errorf(`"stop-mode" field contains invalid value %q`, st) +} + // AppInfo provides information about a app. type AppInfo struct { Snap *Info @@ -553,6 +580,7 @@ type AppInfo struct { RestartCond RestartCondition Completer string RefreshMode string + StopMode StopModeType // TODO: this should go away once we have more plumbing and can change // things vs refactor diff --git a/snap/info_snap_yaml.go b/snap/info_snap_yaml.go index 3f074a7d65..112f9af079 100644 --- a/snap/info_snap_yaml.go +++ b/snap/info_snap_yaml.go @@ -68,6 +68,7 @@ type appYaml struct { StopTimeout timeout.Timeout `yaml:"stop-timeout,omitempty"` Completer string `yaml:"completer,omitempty"` RefreshMode string `yaml:"refresh-mode,omitempty"` + StopMode StopModeType `yaml:"stop-mode,omitempty"` RestartCond RestartCondition `yaml:"restart-condition,omitempty"` SlotNames []string `yaml:"slots,omitempty"` @@ -300,6 +301,7 @@ func setAppsFromSnapYaml(y snapYaml, snap *Info) error { Environment: yApp.Environment, Completer: yApp.Completer, RefreshMode: yApp.RefreshMode, + StopMode: yApp.StopMode, Before: yApp.Before, After: yApp.After, Autostart: yApp.Autostart, diff --git a/snap/info_test.go b/snap/info_test.go index 51849c4c40..52e4e0c531 100644 --- a/snap/info_test.go +++ b/snap/info_test.go @@ -927,3 +927,41 @@ func (s *infoSuite) TestExpandSnapVariables(c *C) { c.Assert(info.ExpandSnapVariables("$SNAP_COMMON/stuff"), Equals, "/var/snap/foo/common/stuff") c.Assert(info.ExpandSnapVariables("$GARBAGE/rocks"), Equals, "/rocks") } + +func (s *infoSuite) TestStopModeTypeKillMode(c *C) { + for _, t := range []struct { + stopMode string + killall bool + }{ + {"", true}, + {"sigterm", false}, + {"sigterm-all", true}, + {"sighup", false}, + {"sighup-all", true}, + {"sigusr1", false}, + {"sigusr1-all", true}, + {"sigusr2", false}, + {"sigusr2-all", true}, + } { + c.Check(snap.StopModeType(t.stopMode).KillAll(), Equals, t.killall, Commentf("wrong KillAll for %v", t.stopMode)) + } +} + +func (s *infoSuite) TestStopModeTypeKillSignal(c *C) { + for _, t := range []struct { + stopMode string + killSig string + }{ + {"", ""}, + {"sigterm", "SIGTERM"}, + {"sigterm-all", "SIGTERM"}, + {"sighup", "SIGHUP"}, + {"sighup-all", "SIGHUP"}, + {"sigusr1", "SIGUSR1"}, + {"sigusr1-all", "SIGUSR1"}, + {"sigusr2", "SIGUSR2"}, + {"sigusr2-all", "SIGUSR2"}, + } { + c.Check(snap.StopModeType(t.stopMode).KillSignal(), Equals, t.killSig) + } +} diff --git a/snap/validate.go b/snap/validate.go index bff6ee205a..2909432288 100644 --- a/snap/validate.go +++ b/snap/validate.go @@ -534,13 +534,20 @@ func ValidateApp(app *AppInfo) error { return err } - // validate refresh-mode + // validate stop-mode + if err := app.StopMode.Valid(); err != nil { + return err + } + // validate stop-mode switch app.RefreshMode { - case "", "endure", "restart", "sigterm", "sigterm-all", "sighup", "sighup-all", "sigusr1", "sigusr1-all", "sigusr2", "sigusr2-all": + case "", "endure", "restart": // valid default: return fmt.Errorf(`"refresh-mode" field contains invalid value %q`, app.RefreshMode) } + if app.StopMode != "" && app.Daemon == "" { + return fmt.Errorf(`"stop-mode" cannot be used for %q, only for services`, app.Name) + } if app.RefreshMode != "" && app.Daemon == "" { return fmt.Errorf(`"refresh-mode" cannot be used for %q, only for services`, app.Name) } diff --git a/snap/validate_test.go b/snap/validate_test.go index 36e975c8d3..384ed2fe5c 100644 --- a/snap/validate_test.go +++ b/snap/validate_test.go @@ -415,16 +415,14 @@ func (s *ValidateSuite) TestAppDaemonValue(c *C) { } } -func (s *ValidateSuite) TestAppRefreshMode(c *C) { +func (s *ValidateSuite) TestAppStopMode(c *C) { // check services for _, t := range []struct { - refresh string - ok bool + stopMode string + ok bool }{ // good {"", true}, - {"endure", true}, - {"restart", true}, {"sigterm", true}, {"sigterm-all", true}, {"sighup", true}, @@ -437,9 +435,34 @@ func (s *ValidateSuite) TestAppRefreshMode(c *C) { {"invalid-thing", false}, } { if t.ok { - c.Check(ValidateApp(&AppInfo{Name: "foo", Daemon: "simple", RefreshMode: t.refresh}), IsNil) + c.Check(ValidateApp(&AppInfo{Name: "foo", Daemon: "simple", StopMode: StopModeType(t.stopMode)}), IsNil) + } else { + c.Check(ValidateApp(&AppInfo{Name: "foo", Daemon: "simple", StopMode: StopModeType(t.stopMode)}), ErrorMatches, fmt.Sprintf(`"stop-mode" field contains invalid value %q`, t.stopMode)) + } + } + + // non-services cannot have a stop-mode + err := ValidateApp(&AppInfo{Name: "foo", Daemon: "", StopMode: "sigterm"}) + c.Check(err, ErrorMatches, `"stop-mode" cannot be used for "foo", only for services`) +} + +func (s *ValidateSuite) TestAppRefreshMode(c *C) { + // check services + for _, t := range []struct { + refreshMode string + ok bool + }{ + // good + {"", true}, + {"endure", true}, + {"restart", true}, + // bad + {"invalid-thing", false}, + } { + if t.ok { + c.Check(ValidateApp(&AppInfo{Name: "foo", Daemon: "simple", RefreshMode: t.refreshMode}), IsNil) } else { - c.Check(ValidateApp(&AppInfo{Name: "foo", Daemon: "simple", RefreshMode: t.refresh}), ErrorMatches, fmt.Sprintf(`"refresh-mode" field contains invalid value %q`, t.refresh)) + c.Check(ValidateApp(&AppInfo{Name: "foo", Daemon: "simple", RefreshMode: t.refreshMode}), ErrorMatches, fmt.Sprintf(`"refresh-mode" field contains invalid value %q`, t.refreshMode)) } } diff --git a/tests/lib/snaps/test-snapd-service/bin/reload b/tests/lib/snaps/test-snapd-service/bin/reload index e04f606e14..4e14f5aa90 100755 --- a/tests/lib/snaps/test-snapd-service/bin/reload +++ b/tests/lib/snaps/test-snapd-service/bin/reload @@ -5,4 +5,4 @@ if [ -z "$MAINPID" ]; then exit 1 fi echo "reloading main PID: $MAINPID" -kill -HUP $MAINPID +kill -HUP "$MAINPID" diff --git a/tests/lib/snaps/test-snapd-service/bin/start-refresh-mode b/tests/lib/snaps/test-snapd-service/bin/start-refresh-mode deleted file mode 100755 index dd14f4bd97..0000000000 --- a/tests/lib/snaps/test-snapd-service/bin/start-refresh-mode +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -trap "echo got sigusr1" USR1 -trap "echo got sigusr2" USR2 -trap "echo got sighup" HUP - -while true; do - echo "running $1 process" - sleep 1 -done - diff --git a/tests/lib/snaps/test-snapd-service/bin/start-stop-mode b/tests/lib/snaps/test-snapd-service/bin/start-stop-mode new file mode 100755 index 0000000000..57c2c67504 --- /dev/null +++ b/tests/lib/snaps/test-snapd-service/bin/start-stop-mode @@ -0,0 +1,11 @@ +#!/bin/bash + +SIG=0 +trap "echo got sigusr1; SIG=1" USR1 +trap "echo got sigusr2; SIG=1" USR2 +trap "echo got sighup; SIG=1" HUP + +while [ "$SIG" = "0" ]; do + echo "running $1 process" + sleep 1 +done diff --git a/tests/lib/snaps/test-snapd-service/bin/start-stop-mode-sigterm b/tests/lib/snaps/test-snapd-service/bin/start-stop-mode-sigterm new file mode 100755 index 0000000000..e1465aa7ac --- /dev/null +++ b/tests/lib/snaps/test-snapd-service/bin/start-stop-mode-sigterm @@ -0,0 +1,8 @@ +#!/bin/sh + +set -e + +echo "start-refresh-mode-sigkill" + +echo "running a process" +sleep 3133731337 diff --git a/tests/lib/snaps/test-snapd-service/bin/stop-refresh-mode b/tests/lib/snaps/test-snapd-service/bin/stop-stop-mode index 16f1c0ccf0..16f1c0ccf0 100755 --- a/tests/lib/snaps/test-snapd-service/bin/stop-refresh-mode +++ b/tests/lib/snaps/test-snapd-service/bin/stop-stop-mode diff --git a/tests/lib/snaps/test-snapd-service/meta/snap.yaml b/tests/lib/snaps/test-snapd-service/meta/snap.yaml index 77501a5d4d..f457127fbe 100644 --- a/tests/lib/snaps/test-snapd-service/meta/snap.yaml +++ b/tests/lib/snaps/test-snapd-service/meta/snap.yaml @@ -9,48 +9,46 @@ apps: test-snapd-other-service: command: bin/start-other daemon: simple - test-snapd-endure-service: - command: bin/start-refresh-mode endure - stop-command: bin/stop-refresh-mode endure - daemon: simple - refresh-mode: endure - test-snapd-sigterm-service: - command: bin/start-refresh-mode sigterm - stop-command: bin/stop-refresh-mode sigterm - daemon: simple - refresh-mode: sigterm - test-snapd-sigterm-all-service: - command: bin/start-refresh-mode sigterm-all - stop-command: bin/stop-refresh-mode sigterm-all - daemon: simple - refresh-mode: sigterm test-snapd-sighup-service: - command: bin/start-refresh-mode sighup - stop-command: bin/stop-refresh-mode sighup + command: bin/start-stop-mode sighup + stop-command: bin/stop-stop-mode sighup daemon: simple - refresh-mode: sighup + stop-mode: sighup test-snapd-sighup-all-service: - command: bin/start-refresh-mode sighup-all - stop-command: bin/stop-refresh-mode sighup-all + command: bin/start-stop-mode sighup-all + stop-command: bin/stop-stop-mode sighup-all daemon: simple - refresh-mode: sighup-all + stop-mode: sighup-all test-snapd-sigusr1-service: - command: bin/start-refresh-mode sigusr1 - stop-command: bin/stop-refresh-mode sigusr1 + command: bin/start-stop-mode sigusr1 + stop-command: bin/stop-stop-mode sigusr1 daemon: simple - refresh-mode: sigusr1 + stop-mode: sigusr1 test-snapd-sigusr1-all-service: - command: bin/start-refresh-mode sigusr1-all - stop-command: bin/stop-refresh-mode sigusr1-all + command: bin/start-stop-mode sigusr1-all + stop-command: bin/stop-stop-mode sigusr1-all daemon: simple - refresh-mode: sigusr1-all + stop-mode: sigusr1-all test-snapd-sigusr2-service: - command: bin/start-refresh-mode sigusr2 - stop-command: bin/stop-refresh-mode sigusr2 + command: bin/start-stop-mode sigusr2 + stop-command: bin/stop-stop-mode sigusr2 daemon: simple - refresh-mode: sigusr2 + stop-mode: sigusr2 test-snapd-sigusr2-all-service: - command: bin/start-refresh-mode sigusr2-all - stop-command: bin/stop-refresh-mode sigusr2-all + command: bin/start-stop-mode sigusr2-all + stop-command: bin/stop-stop-mode sigusr2-all daemon: simple - refresh-mode: sigusr2-all + stop-mode: sigusr2-all + test-snapd-sigterm-service: + command: bin/start-stop-mode-sigterm + daemon: simple + stop-mode: sigterm + test-snapd-sigterm-all-service: + command: bin/start-stop-mode-sigterm + daemon: simple + stop-mode: sigterm-all + test-snapd-endure-service: + command: bin/start-stop-mode endure + stop-command: bin/stop-stop-mode endure + daemon: simple + refresh-mode: endure diff --git a/tests/main/snap-service-refresh-mode/task.yaml b/tests/main/snap-service-refresh-mode/task.yaml index b6dfa43afc..f71d1e6543 100644 --- a/tests/main/snap-service-refresh-mode/task.yaml +++ b/tests/main/snap-service-refresh-mode/task.yaml @@ -3,7 +3,8 @@ summary: "Check that refresh-modes works" kill-timeout: 3m debug: | - journalctl -u snap.test-snapd-service.test-snapd-endure-service + grep -n '' *.pid || true + systemctl status snap.test-snapd-service.test-snapd-endure-service || true execute: | echo "When the service snap is installed" @@ -12,35 +13,19 @@ execute: | echo "We can see it running" systemctl status snap.test-snapd-service.test-snapd-endure-service|MATCH "running" + systemctl show -p MainPID snap.test-snapd-service.test-snapd-endure-service > old-main.pid echo "When it is re-installed" install_local test-snapd-service - # note that we do not spread test sigterm{,-all} because catching this - # signal in the service means the stop will timeout with a 90s delay - refresh_modes="endure sighup sighup-all sigusr1 sigusr1-all sigusr2 sigusr2-all" - for s in $refresh_modes; do - echo "We can still see it running" - systemctl status snap.test-snapd-service.test-snapd-${s}-service|MATCH "running" - - echo "And it is not re-started" - if journalctl -u snap.test-snapd-service.test-snapd-${s}-service | grep "stop ${s}"; then - echo "reinstall did stop a service that shouldn't" - exit 1 - fi - - if [[ "$s" == sig* ]]; then - echo "checking that the right signal was sent" - sleep 1 - journalctl -u snap.test-snapd-service.test-snapd-${s}-service | MATCH "got ${s%%-all}" - fi - done - - echo "But regular services are restarted" - journalctl -u snap.test-snapd-service.test-snapd-service | MATCH "stop service" + echo "We can still see it running with the same PID" + systemctl show -p MainPID snap.test-snapd-service.test-snapd-endure-service > new-main.pid + + test "$(cat new-endure.pid)" = "$(cat old-endure.pid)" echo "Once the snap is removed, the service is stopped" snap remove test-snapd-service - for s in $refresh_modes; do - journalctl | MATCH "stop ${s}" - done + journalctl | MATCH "stop endure" + +restore: + rm -f *.pid || true diff --git a/tests/main/snap-service-stop-mode-sigkill/task.yaml b/tests/main/snap-service-stop-mode-sigkill/task.yaml new file mode 100644 index 0000000000..0d0bd4619c --- /dev/null +++ b/tests/main/snap-service-stop-mode-sigkill/task.yaml @@ -0,0 +1,37 @@ +summary: "Check that refresh-modes sigkill works" + +kill-timeout: 3m + +restore: | + # remove to ensure all services are stopped + snap remove test-snapd-service || true + killall sleep || true + +debug: | + ps afx + +execute: | + echo "Ensure no stray sleep processes are around" + killall sleep || true + + echo "When the service snap is installed" + . $TESTSLIB/snaps.sh + install_local test-snapd-service + + refresh_modes="sigterm sigterm-all" + for s in $refresh_modes; do + systemctl show -p ActiveState snap.test-snapd-service.test-snapd-${s}-service | MATCH "ActiveState=active" + done + + echo "we expect two sleep processes (children) from the two sigterm services" + n=$(ps afx | grep [3]133731337 | grep -v grep | wc -l) + [ "$n" = "2" ] + + echo "When it is re-installed one process uses sigterm, the other sigterm-all" + install_local test-snapd-service + + echo "After reinstall the sigterm-all service and all children got killed" + echo "but the sigterm service only got a kill for the main process " + echo "and one sleep is still alive" + n=$(ps afx | grep [3]133731337 | wc -l) + [ "$n" = "3" ] diff --git a/tests/main/snap-service-stop-mode/task.yaml b/tests/main/snap-service-stop-mode/task.yaml new file mode 100644 index 0000000000..2a8f3ccdd5 --- /dev/null +++ b/tests/main/snap-service-stop-mode/task.yaml @@ -0,0 +1,54 @@ +summary: "Check that stop-modes works" + +kill-timeout: 3m + +# journald in ubuntu-14.04 not reliable +systems: [-ubuntu-14.04-*] + +debug: | + stop_modes="sighup sighup-all sigusr1 sigusr1-all sigusr2 sigusr2-all" + for s in $stop_modes; do + systemctl status snap.test-snapd-service.test-snapd-${s}-service || true + done + +execute: | + echo "When the service snap is installed" + . $TESTSLIB/snaps.sh + install_local test-snapd-service + + echo "We can see it running" + systemctl status snap.test-snapd-service.test-snapd-service|MATCH "running" + + stop_modes="sighup sighup-all sigusr1 sigusr1-all sigusr2 sigusr2-all" + for s in $stop_modes; do + systemctl show -p ActiveState snap.test-snapd-service.test-snapd-${s}-service | MATCH "ActiveState=active" + done + + echo "When it is re-installed" + install_local test-snapd-service + + # note that sigterm{,-all} is tested separately + for s in $stop_modes; do + echo "We can see it is running" + systemctl show -p ActiveState snap.test-snapd-service.test-snapd-${s}-service | MATCH "ActiveState=active" + + echo "and it got the right signal" + echo "checking that the right signal was sent" + sleep 1 + journalctl -u snap.test-snapd-service.test-snapd-${s}-service | MATCH "got ${s%%-all}" + done + + echo "Regular services are restarted normally" + journalctl -u snap.test-snapd-service.test-snapd-service | MATCH "stop service" + + echo "Once the snap is removed, all services are stopped" + snap remove test-snapd-service + for s in $stop_modes; do + journalctl | MATCH "stop ${s}" + done + +restore: | + rm -f *.pid || true + # remove to ensure all services are stopped + snap remove test-snapd-service || true + killall sleep || true diff --git a/wrappers/services.go b/wrappers/services.go index 90aa09f32b..bdcbb679fe 100644 --- a/wrappers/services.go +++ b/wrappers/services.go @@ -230,45 +230,30 @@ func StopServices(apps []*snap.AppInfo, reason snap.ServiceStopReason, inter int if !app.IsService() || !osutil.FileExists(app.ServiceFile()) { continue } - // Skip stop on refresh when refresh mode is set to something + // Skip stop on refresh when stop mode is set to something // other than "restart" (or "" which is the same) if reason == snap.StopReasonRefresh { - logger.Debugf(" %s refresh-mode: %v", app.Name, app.RefreshMode) + logger.Debugf(" %s stop-mode: %v", app.Name, app.StopMode) switch app.RefreshMode { case "endure": // skip this service continue - case "sigterm": - sysd.Kill(app.ServiceName(), "TERM", "main") - continue - case "sigterm-all": - sysd.Kill(app.ServiceName(), "TERM", "all") - continue - case "sighup": - sysd.Kill(app.ServiceName(), "HUP", "main") - continue - case "sighup-all": - sysd.Kill(app.ServiceName(), "HUP", "all") - continue - case "sigusr1": - sysd.Kill(app.ServiceName(), "USR1", "main") - continue - case "sigusr1-all": - sysd.Kill(app.ServiceName(), "USR1", "all") - continue - case "sigusr2": - sysd.Kill(app.ServiceName(), "USR2", "main") - continue - case "sigusr2-all": - sysd.Kill(app.ServiceName(), "USR2", "all") - continue - case "", "restart": - // do nothing here, the default below to stop } } if err := stopService(sysd, app, inter); err != nil { return err } + + // ensure the service is really stopped on remove regardless + // of stop-mode + if reason == snap.StopReasonRemove && !app.StopMode.KillAll() { + // FIXME: make this smarter and avoid the killWait + // delay if not needed (i.e. if all processes + // have died) + sysd.Kill(app.ServiceName(), "TERM", "all") + time.Sleep(killWait) + sysd.Kill(app.ServiceName(), "KILL", "") + } } return nil @@ -367,6 +352,12 @@ RemainAfterExit={{.Remain}} {{- if .App.BusName}} BusName={{.App.BusName}} {{- end}} +{{- if .KillMode}} +KillMode={{.KillMode}} +{{- end}} +{{- if .KillSignal}} +KillSignal={{.KillSignal}} +{{- end}} {{- if not .App.Sockets}} [Install] @@ -391,6 +382,10 @@ WantedBy={{.ServicesTarget}} remain = "yes" } } + var killMode string + if !appInfo.StopMode.KillAll() { + killMode = "process" + } wrapperData := struct { App *snap.AppInfo @@ -401,6 +396,8 @@ WantedBy={{.ServicesTarget}} PrerequisiteTarget string MountUnit string Remain string + KillMode string + KillSignal string Before []string After []string @@ -415,8 +412,11 @@ WantedBy={{.ServicesTarget}} PrerequisiteTarget: systemd.PrerequisiteTarget, MountUnit: filepath.Base(systemd.MountUnitPath(appInfo.Snap.MountDir())), Remain: remain, - Before: genServiceNames(appInfo.Snap, appInfo.Before), - After: genServiceNames(appInfo.Snap, appInfo.After), + KillMode: killMode, + KillSignal: appInfo.StopMode.KillSignal(), + + Before: genServiceNames(appInfo.Snap, appInfo.Before), + After: genServiceNames(appInfo.Snap, appInfo.After), // systemd runs as PID 1 so %h will not work. Home: "/root", diff --git a/wrappers/services_gen_test.go b/wrappers/services_gen_test.go index 9d24e9e8e2..21edd7a089 100644 --- a/wrappers/services_gen_test.go +++ b/wrappers/services_gen_test.go @@ -333,3 +333,24 @@ WantedBy=multi-user.target c.Logf("service: \n%v\n", string(generatedWrapper)) c.Assert(string(generatedWrapper), Equals, expectedService) } + +func (s *servicesWrapperGenSuite) TestKillModeSig(c *C) { + for _, rm := range []string{"sigterm", "sighup", "sigusr1", "sigusr2"} { + service := &snap.AppInfo{ + Snap: &snap.Info{ + SuggestedName: "snap", + Version: "0.3.4", + SideInfo: snap.SideInfo{Revision: snap.R(44)}, + }, + Name: "app", + Command: "bin/foo start", + Daemon: "simple", + StopMode: snap.StopModeType(rm), + } + + generatedWrapper, err := wrappers.GenerateSnapServiceFile(service) + c.Assert(err, IsNil) + + c.Assert(string(generatedWrapper), testutil.Contains, "\nKillMode=process\n") + } +} diff --git a/wrappers/services_test.go b/wrappers/services_test.go index b33216fa40..1c010925fa 100644 --- a/wrappers/services_test.go +++ b/wrappers/services_test.go @@ -652,6 +652,9 @@ func (s *servicesTestSuite) TestStopServiceSigs(c *C) { }) defer r() + r = wrappers.MockKillWait(1 * time.Millisecond) + defer r() + survivorFile := filepath.Join(s.tempdir, "/etc/systemd/system/snap.survive-snap.srv.service") for _, t := range []struct { mode string @@ -672,7 +675,7 @@ version: 1.0 apps: srv: command: bin/survivor - refresh-mode: %s + stop-mode: %s daemon: simple `, t.mode) info := snaptest.MockSnap(c, surviveYaml, &snap.SideInfo{Revision: snap.R(1)}) @@ -689,16 +692,29 @@ apps: err = wrappers.StopServices(info.Services(), snap.StopReasonRefresh, progress.Null) c.Assert(err, IsNil) c.Check(sysdLog, DeepEquals, [][]string{ - {"kill", filepath.Base(survivorFile), "-s", t.expectedSig, "--kill-who=" + t.expectedWho}, + {"stop", filepath.Base(survivorFile)}, + {"show", "--property=ActiveState", "snap.survive-snap.srv.service"}, }, Commentf("failure in %s", t.mode)) sysdLog = nil err = wrappers.StopServices(info.Services(), snap.StopReasonRemove, progress.Null) c.Assert(err, IsNil) - c.Check(sysdLog, DeepEquals, [][]string{ - {"stop", filepath.Base(survivorFile)}, - {"show", "--property=ActiveState", "snap.survive-snap.srv.service"}, - }) + switch t.expectedWho { + case "all": + c.Check(sysdLog, DeepEquals, [][]string{ + {"stop", filepath.Base(survivorFile)}, + {"show", "--property=ActiveState", "snap.survive-snap.srv.service"}, + }) + case "main": + c.Check(sysdLog, DeepEquals, [][]string{ + {"stop", filepath.Base(survivorFile)}, + {"show", "--property=ActiveState", "snap.survive-snap.srv.service"}, + {"kill", filepath.Base(survivorFile), "-s", "TERM", "--kill-who=all"}, + {"kill", filepath.Base(survivorFile), "-s", "KILL", "--kill-who=all"}, + }) + default: + panic("not reached") + } } } |
