Skip to content

Commit

Permalink
add en/disable to snappy service command and status output
Browse files Browse the repository at this point in the history
  • Loading branch information
chipaca committed Aug 24, 2015
1 parent 7adbf7b commit f75e4d3
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 12 deletions.
24 changes: 24 additions & 0 deletions cmd/snappy/cmd_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ type cmdService struct {
Start svcStart `command:"start"`
Stop svcStop `command:"stop"`
Restart svcRestart `command:"restart"`
Enable svcEnable `command:"enable"`
Disable svcDisable `command:"disable"`
}
type svcBase struct {
Args struct {
Expand All @@ -47,6 +49,8 @@ type svcStatus struct{ svcBase }
type svcStart struct{ svcBase }
type svcStop struct{ svcBase }
type svcRestart struct{ svcBase }
type svcEnable struct{ svcBase }
type svcDisable struct{ svcBase }

func init() {
_, err := parser.AddCommand("service",
Expand All @@ -65,6 +69,8 @@ const (
doStart
doStop
doRestart
doEnable
doDisable
)

func (s *svcBase) doExecute(cmd int) ([]string, error) {
Expand All @@ -82,6 +88,10 @@ func (s *svcBase) doExecute(cmd int) ([]string, error) {
return nil, actor.Stop()
case doRestart:
return nil, actor.Restart()
case doEnable:
return nil, actor.Enable()
case doDisable:
return nil, actor.Disable()
default:
panic("can't happen")
}
Expand Down Expand Up @@ -137,3 +147,17 @@ func (s *svcRestart) Execute(args []string) error {
return err
})
}

func (s *svcEnable) Execute(args []string) error {
return withMutex(func() error {
_, err := s.doExecute(doEnable)
return err
})
}

func (s *svcDisable) Execute(args []string) error {
return withMutex(func() error {
_, err := s.doExecute(doDisable)
return err
})
}
12 changes: 11 additions & 1 deletion po/snappy.pot
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
msgid ""
msgstr "Project-Id-Version: snappy\n"
"Report-Msgid-Bugs-To: snappy-devel@lists.ubuntu.com\n"
"POT-Creation-Date: 2015-08-18 13:59+0100\n"
"POT-Creation-Date: 2015-08-24 11:49+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
Expand Down Expand Up @@ -336,6 +336,16 @@ msgstr ""
msgid "snappy autopilot triggered a reboot to boot into an up to date system -- temprorarily disable the reboot by running 'sudo shutdown -c'"
msgstr ""

#. TRANSLATORS: the first %s is the package name, the second is the service name; the %v is the error
#, c-format
msgid "unable to disable %s's service %s: %v"
msgstr ""

#. TRANSLATORS: the first %s is the package name, the second is the service name; the %v is the error
#, c-format
msgid "unable to enable %s's service %s: %v"
msgstr ""

#. TRANSLATORS: the first %s is the package name, the second is the service name; the %v is the error
#, c-format
msgid "unable to start %s's service %s: %v"
Expand Down
30 changes: 30 additions & 0 deletions snappy/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,3 +148,33 @@ func (actor *ServiceActor) Restart() error {

return actor.Start()
}

// Enable all the found services.
func (actor *ServiceActor) Enable() error {
for _, svc := range actor.svcs {
svcname := filepath.Base(generateServiceFileName(svc.m, *svc.svc))
if err := actor.sysd.Enable(svcname); err != nil {
// TRANSLATORS: the first %s is the package name, the second is the service name; the %v is the error
return fmt.Errorf(i18n.G("unable to enable %s's service %s: %v"), svc.m.Name, svc.svc.Name, err)
}
}

actor.sysd.DaemonReload()

return nil
}

// Disable all the found services.
func (actor *ServiceActor) Disable() error {
for _, svc := range actor.svcs {
svcname := filepath.Base(generateServiceFileName(svc.m, *svc.svc))
if err := actor.sysd.Disable(svcname); err != nil {
// TRANSLATORS: the first %s is the package name, the second is the service name; the %v is the error
return fmt.Errorf(i18n.G("unable to disable %s's service %s: %v"), svc.m.Name, svc.svc.Name, err)
}
}

actor.sysd.DaemonReload()

return nil
}
30 changes: 24 additions & 6 deletions snappy/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import (

"launchpad.net/snappy/progress"
"launchpad.net/snappy/systemd"
"os"
"path/filepath"
)

type ServiceActorSuite struct {
Expand Down Expand Up @@ -53,6 +55,8 @@ func (s *ServiceActorSuite) myRun(args ...string) (out []byte, err error) {

func (s *ServiceActorSuite) SetUpTest(c *C) {
SetRootDir(c.MkDir())
// TODO: this mkdir hack is so enable doesn't fail; remove when enable is the same as the rest
c.Assert(os.MkdirAll(filepath.Join(globalRootDir, "/etc/systemd/system/multi-user.target.wants"), 0755), IsNil)
systemd.SystemctlCmd = s.myRun
makeInstalledMockSnap(globalRootDir, "")
s.i = 0
Expand Down Expand Up @@ -89,28 +93,38 @@ func (s *ServiceActorSuite) TestFindServicesFindsServices(c *C) {

s.outs = [][]byte{
nil, // for the "stop"
[]byte("ActiveState=inactive\n"),
[]byte("ActiveState=inactive\n"), // for stop's check
nil, // for the "start"
nil, // for the "stop"
[]byte("ActiveState=inactive\n"),
nil, // for the "start"
[]byte("Id=x\nLoadState=loaded\nActiveState=active\nSubState=running\n"), // status
nil, // for restart's stop
[]byte("ActiveState=inactive\n"), // for restart's stop's check
nil, // for restart's start
// nil, // for the "enable" TODO: enable is different for now
nil, // for enable's reload
nil, // for the "disable"
nil, // for disable's reload
[]byte("Id=x\nLoadState=loaded\nActiveState=active\nSubState=running\nUnitFileState=enabled\n"), // status
}
s.errors = []error{
nil, nil, // stop & check
nil, // start
nil, nil, nil, // restart (== stop & start)
// nil, // enable TODO: enable is different for now
nil, // for enable's reload
nil, // disable
nil, // for disable's reload
nil, // status
&systemd.Timeout{}, // flag
}

c.Check(actor.Stop(), IsNil)
c.Check(actor.Start(), IsNil)
c.Check(actor.Restart(), IsNil)
c.Check(actor.Enable(), IsNil)
c.Check(actor.Disable(), IsNil)
status, err := actor.Status()
c.Check(err, IsNil)
c.Assert(status, HasLen, 1)
c.Check(status[0], Equals, "hello-app\tsvc1\tloaded; active (running)")
c.Check(status[0], Equals, "hello-app\tsvc1\tenabled; loaded; active (running)")
}

func (s *ServiceActorSuite) TestFindServicesReportsErrors(c *C) {
Expand All @@ -131,12 +145,16 @@ func (s *ServiceActorSuite) TestFindServicesReportsErrors(c *C) {
anError, // stop
anError, // start
anError, // restart
// anError, // enable TODO: enable is different for now
anError, // disable
anError, // status
}

c.Check(actor.Stop(), NotNil)
c.Check(actor.Start(), NotNil)
c.Check(actor.Restart(), NotNil)
// c.Check(actor.Enable(), NotNil) TODO: enable is different for now
c.Check(actor.Disable(), NotNil)
_, err = actor.Status()
c.Check(err, NotNil)
}
8 changes: 5 additions & 3 deletions systemd/systemd.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,12 +145,12 @@ func (*systemd) Start(serviceName string) error {
var statusregex = regexp.MustCompile(`(?m)^(?:(.*?)=(.*))?$`)

func (s *systemd) Status(serviceName string) (string, error) {
bs, err := SystemctlCmd("show", "--property=Id,LoadState,ActiveState,SubState", serviceName)
bs, err := SystemctlCmd("show", "--property=Id,LoadState,ActiveState,SubState,UnitFileState", serviceName)
if err != nil {
return "", err
}

load, active, sub := "", "", ""
load, active, sub, unit := "", "", "", ""

for _, bs := range statusregex.FindAllSubmatch(bs, -1) {
if len(bs[0]) > 0 {
Expand All @@ -163,11 +163,13 @@ func (s *systemd) Status(serviceName string) (string, error) {
active = v
case "SubState":
sub = v
case "UnitFileState":
unit = v
}
}
}

return fmt.Sprintf("%s; %s (%s)", load, active, sub), nil
return fmt.Sprintf("%s; %s; %s (%s)", unit, load, active, sub), nil
}

// Stop the given service, and wait until it has stopped.
Expand Down
4 changes: 2 additions & 2 deletions systemd/systemd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,12 +113,12 @@ func (s *SystemdTestSuite) TestStop(c *C) {

func (s *SystemdTestSuite) TestStatus(c *C) {
s.outs = [][]byte{
[]byte("Id=Thing\nLoadState=LoadState\nActiveState=ActiveState\nSubState=SubState\n"),
[]byte("Id=Thing\nLoadState=LoadState\nActiveState=ActiveState\nSubState=SubState\nUnitFileState=UnitFileState\n"),
}
s.errors = []error{nil}
out, err := New("", s.rep).Status("foo")
c.Assert(err, IsNil)
c.Check(out, Equals, "LoadState; ActiveState (SubState)")
c.Check(out, Equals, "UnitFileState; LoadState; ActiveState (SubState)")
}

func (s *SystemdTestSuite) TestStopTimeout(c *C) {
Expand Down

0 comments on commit f75e4d3

Please sign in to comment.