From 4889b5f340fd722036b124c022d11912b838ba5e Mon Sep 17 00:00:00 2001 From: Tam?s Gul?csi Date: Thu, 30 Jan 2014 18:57:00 +0100 Subject: [PATCH] Add systemd support --- service_linux.go | 119 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 94 insertions(+), 25 deletions(-) diff --git a/service_linux.go b/service_linux.go index 6d74e7a..ab98131 100644 --- a/service_linux.go +++ b/service_linux.go @@ -1,22 +1,34 @@ package service import ( - "bitbucket.org/kardianos/osext" "fmt" "log/syslog" "os" "os/exec" "os/signal" "text/template" + + "bitbucket.org/kardianos/osext" ) -func newService(name, displayName, description string) (s *linuxUpstartService, err error) { - s = &linuxUpstartService{ +const ( + initUpstart = initFlavor(iota) + initSystemd +) + +func newService(name, displayName, description string) (Service, error) { + flavor := initUpstart + if _, err := os.Stat("/run/systemd/system"); err == nil { + flavor = initSystemd + } + s := &linuxService{ + flavor: flavor, name: name, displayName: displayName, description: description, } + var err error s.logger, err = syslog.New(syslog.LOG_INFO, name) if err != nil { return nil, err @@ -25,13 +37,49 @@ func newService(name, displayName, description string) (s *linuxUpstartService, return s, nil } -type linuxUpstartService struct { +type linuxService struct { + flavor initFlavor name, displayName, description string logger *syslog.Writer } -func (s *linuxUpstartService) Install() error { - var confPath = "/etc/init/" + s.name + ".conf" +type initFlavor uint8 + +func (f initFlavor) String() string { + switch f { + case initUpstart: + return "Upstart" + case initSystemd: + return "systemd" + default: + return "unknown" + } +} + +func (f initFlavor) ConfigPath(name string) string { + switch f { + case initUpstart: + return "/etc/init/" + name + ".conf" + case initSystemd: + return "/etc/systemd/system/" + name + ".service" + default: + return "" + } +} + +func (f initFlavor) GetTemplate() *template.Template { + var templ string + switch f { + case initUpstart: + templ = upstartScript + case initSystemd: + templ = systemdScript + } + return template.Must(template.New(f.String() + "Script").Parse(templ)) +} + +func (s *linuxService) Install() error { + confPath := s.flavor.ConfigPath(s.name) _, err := os.Stat(confPath) if err == nil { return fmt.Errorf("Init already exists: %s", confPath) @@ -58,58 +106,66 @@ func (s *linuxUpstartService) Install() error { path, } - t := template.Must(template.New("upstartScript").Parse(upstartScript)) - err = t.Execute(f, to) + err = s.flavor.GetTemplate().Execute(f, to) if err != nil { return err } + if s.flavor == initSystemd { + return exec.Command("systemctl", "daemon-reload").Run() + } + return nil } -func (s *linuxUpstartService) Remove() error { - return os.Remove("/etc/init/" + s.name + ".conf") +func (s *linuxService) Remove() error { + if s.flavor == initSystemd { + exec.Command("systemctl", "disable", s.name+".service").Run() + } + if err := os.Remove(s.flavor.ConfigPath(s.name)); err != nil { + return err + } + return nil } -func (s *linuxUpstartService) Run(onStart, onStop func() error) error { - var err error - +func (s *linuxService) Run(onStart, onStop func() error) (err error) { err = onStart() if err != nil { return err } + defer func() { + err = onStop() + }() - var sigChan = make(chan os.Signal, 3) + sigChan := make(chan os.Signal, 3) signal.Notify(sigChan, os.Interrupt, os.Kill) <-sigChan - return onStop() + return nil } -func (s *linuxUpstartService) Start() error { - cmd := exec.Command("start", s.name) - return cmd.Run() +func (s *linuxService) Start() error { + return exec.Command("service", s.name, "start").Run() } -func (s *linuxUpstartService) Stop() error { - cmd := exec.Command("stop", s.name) - return cmd.Run() +func (s *linuxService) Stop() error { + return exec.Command("service", s.name, "stop").Run() } -func (s *linuxUpstartService) Error(format string, a ...interface{}) error { +func (s *linuxService) Error(format string, a ...interface{}) error { return s.logger.Err(fmt.Sprintf(format, a...)) } -func (s *linuxUpstartService) Warning(format string, a ...interface{}) error { +func (s *linuxService) Warning(format string, a ...interface{}) error { return s.logger.Warning(fmt.Sprintf(format, a...)) } -func (s *linuxUpstartService) Info(format string, a ...interface{}) error { +func (s *linuxService) Info(format string, a ...interface{}) error { return s.logger.Info(fmt.Sprintf(format, a...)) } -var upstartScript = `# {{.Description}} +const upstartScript = `# {{.Description}} description "{{.Display}}" @@ -133,3 +189,16 @@ end script # Start exec {{.Path}} ` + +const systemdScript = `[Unit] +Description={{.Description}} +ConditionFileIsExecutable={{.Path}} + +[Service] +StartLimitInterval=5 +StartLimitBurst=10 +ExecStart={{.Path}} + +[Install] +WantedBy=multi-user.target +`