Skip to content

Commit

Permalink
many: support refresh-mode: sig{term,hup,usr1}{,-all}
Browse files Browse the repository at this point in the history
  • Loading branch information
mvo5 committed Feb 8, 2018
1 parent dbc944a commit 0d9da90
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 13 deletions.
2 changes: 1 addition & 1 deletion snap/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,7 @@ func ValidateApp(app *AppInfo) error {

// validate refresh-mode
switch app.RefreshMode {
case "", "keep", "restart":
case "", "keep", "restart", "sigterm", "sigterm-all", "sighup", "sighup-all", "sigusr1", "sigusr1-all":
// valid
default:
return fmt.Errorf(`"refresh-mode" field contains invalid value %q`, app.RefreshMode)
Expand Down
6 changes: 6 additions & 0 deletions snap/validate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,12 @@ func (s *ValidateSuite) TestAppRefreshMode(c *C) {
{"", true},
{"keep", true},
{"restart", true},
{"sigterm", true},
{"sigterm-all", true},
{"sighup", true},
{"sighup-all", true},
{"sigusr1", true},
{"sigusr1-all", true},
// bad
{"invalid-thing", false},
} {
Expand Down
9 changes: 6 additions & 3 deletions systemd/systemd.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ type Systemd interface {
Disable(service string) error
Start(service ...string) error
Stop(service string, timeout time.Duration) error
Kill(service, signal string) error
Kill(service, signal, who string) error
Restart(service string, timeout time.Duration) error
Status(services ...string) ([]*ServiceStatus, error)
LogReader(services []string, n string, follow bool) (io.ReadCloser, error)
Expand Down Expand Up @@ -311,8 +311,11 @@ loop:
}

// Kill all processes of the unit with the given signal
func (s *systemd) Kill(serviceName, signal string) error {
_, err := systemctlCmd("kill", serviceName, "-s", signal)
func (s *systemd) Kill(serviceName, signal, who string) error {
if who == "" {
who = "all"
}
_, err := systemctlCmd("kill", serviceName, "-s", signal, "--kill-who="+who)
return err
}

Expand Down
4 changes: 2 additions & 2 deletions systemd/systemd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -387,8 +387,8 @@ func (s *SystemdTestSuite) TestRestart(c *C) {
}

func (s *SystemdTestSuite) TestKill(c *C) {
c.Assert(New("", s.rep).Kill("foo", "HUP"), IsNil)
c.Check(s.argses, DeepEquals, [][]string{{"kill", "foo", "-s", "HUP"}})
c.Assert(New("", s.rep).Kill("foo", "HUP", ""), IsNil)
c.Check(s.argses, DeepEquals, [][]string{{"kill", "foo", "-s", "HUP", "--kill-who=all"}})
}

func (s *SystemdTestSuite) TestIsTimeout(c *C) {
Expand Down
32 changes: 28 additions & 4 deletions wrappers/services.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,9 @@ func stopService(sysd systemd.Systemd, app *snap.AppInfo, inter interacter) erro
}
inter.Notify(fmt.Sprintf("%s refused to stop, killing.", serviceName))
// ignore errors for kill; nothing we'd do differently at this point
sysd.Kill(serviceName, "TERM")
sysd.Kill(serviceName, "TERM", "")
time.Sleep(killWait)
sysd.Kill(serviceName, "KILL")
sysd.Kill(serviceName, "KILL", "")

}

Expand Down Expand Up @@ -225,8 +225,32 @@ func StopServices(apps []*snap.AppInfo, reason snap.ServiceStopReason, inter int
continue
}
// Skip stop on refresh when refresh mode is "keep"
if app.RefreshMode == "keep" && reason == snap.StopReasonRefresh {
continue
if reason == snap.StopReasonRefresh {
switch app.RefreshMode {
case "keep":
// 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 "", "restart":
// do nothing here, the default below to stop
}
}
if err := stopService(sysd, app, inter); err != nil {
return err
Expand Down
63 changes: 60 additions & 3 deletions wrappers/services_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,8 @@ apps:
c.Check(sysdLog, DeepEquals, [][]string{
{"stop", svcFName},
// check kill invocations
{"kill", svcFName, "-s", "TERM"},
{"kill", svcFName, "-s", "KILL"},
{"kill", svcFName, "-s", "TERM", "--kill-who=all"},
{"kill", svcFName, "-s", "KILL", "--kill-who=all"},
})
}

Expand Down Expand Up @@ -609,7 +609,7 @@ func (s *servicesTestSuite) TestServiceAfterBefore(c *C) {

}

func (s *servicesTestSuite) TestStopServiceSurvive(c *C) {
func (s *servicesTestSuite) TestStopServiceKeep(c *C) {
var sysdLog [][]string
r := systemd.MockSystemctl(func(cmd ...string) ([]byte, error) {
sysdLog = append(sysdLog, cmd)
Expand Down Expand Up @@ -649,3 +649,60 @@ apps:
})

}

func (s *servicesTestSuite) TestStopServiceSigs(c *C) {
var sysdLog [][]string
r := systemd.MockSystemctl(func(cmd ...string) ([]byte, error) {
sysdLog = append(sysdLog, cmd)
return []byte("ActiveState=inactive\n"), nil
})
defer r()

survivorFile := filepath.Join(s.tempdir, "/etc/systemd/system/snap.survive-snap.srv.service")
for _, t := range []struct {
mode string
expectedSig string
expectedWho string
}{
{mode: "sigterm", expectedSig: "TERM", expectedWho: "main"},
{mode: "sigterm-all", expectedSig: "TERM", expectedWho: "all"},
{mode: "sighup", expectedSig: "HUP", expectedWho: "main"},
{mode: "sighup-all", expectedSig: "HUP", expectedWho: "all"},
{mode: "sigusr1", expectedSig: "USR1", expectedWho: "main"},
{mode: "sigusr1-all", expectedSig: "USR1", expectedWho: "all"},
} {
surviveYaml := fmt.Sprintf(`name: survive-snap
version: 1.0
apps:
srv:
command: bin/survivor
refresh-mode: %s
daemon: simple
`, t.mode)
info := snaptest.MockSnap(c, surviveYaml, &snap.SideInfo{Revision: snap.R(1)})

sysdLog = nil
err := wrappers.AddSnapServices(info, nil)
c.Assert(err, IsNil)
c.Check(sysdLog, DeepEquals, [][]string{
{"--root", dirs.GlobalRootDir, "enable", filepath.Base(survivorFile)},
{"daemon-reload"},
})

sysdLog = nil
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},
}, 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"},
})
}

}

0 comments on commit 0d9da90

Please sign in to comment.