Add systemd support
This commit is contained in:
+94
-25
@@ -1,22 +1,34 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bitbucket.org/kardianos/osext"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"log/syslog"
|
"log/syslog"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
|
"bitbucket.org/kardianos/osext"
|
||||||
)
|
)
|
||||||
|
|
||||||
func newService(name, displayName, description string) (s *linuxUpstartService, err error) {
|
const (
|
||||||
s = &linuxUpstartService{
|
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,
|
name: name,
|
||||||
displayName: displayName,
|
displayName: displayName,
|
||||||
description: description,
|
description: description,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
s.logger, err = syslog.New(syslog.LOG_INFO, name)
|
s.logger, err = syslog.New(syslog.LOG_INFO, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -25,13 +37,49 @@ func newService(name, displayName, description string) (s *linuxUpstartService,
|
|||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type linuxUpstartService struct {
|
type linuxService struct {
|
||||||
|
flavor initFlavor
|
||||||
name, displayName, description string
|
name, displayName, description string
|
||||||
logger *syslog.Writer
|
logger *syslog.Writer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *linuxUpstartService) Install() error {
|
type initFlavor uint8
|
||||||
var confPath = "/etc/init/" + s.name + ".conf"
|
|
||||||
|
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)
|
_, err := os.Stat(confPath)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return fmt.Errorf("Init already exists: %s", confPath)
|
return fmt.Errorf("Init already exists: %s", confPath)
|
||||||
@@ -58,58 +106,66 @@ func (s *linuxUpstartService) Install() error {
|
|||||||
path,
|
path,
|
||||||
}
|
}
|
||||||
|
|
||||||
t := template.Must(template.New("upstartScript").Parse(upstartScript))
|
err = s.flavor.GetTemplate().Execute(f, to)
|
||||||
err = t.Execute(f, to)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if s.flavor == initSystemd {
|
||||||
|
return exec.Command("systemctl", "daemon-reload").Run()
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *linuxUpstartService) Remove() error {
|
func (s *linuxService) Remove() error {
|
||||||
return os.Remove("/etc/init/" + s.name + ".conf")
|
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 {
|
func (s *linuxService) Run(onStart, onStop func() error) (err error) {
|
||||||
var err error
|
|
||||||
|
|
||||||
err = onStart()
|
err = onStart()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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)
|
signal.Notify(sigChan, os.Interrupt, os.Kill)
|
||||||
|
|
||||||
<-sigChan
|
<-sigChan
|
||||||
|
|
||||||
return onStop()
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *linuxUpstartService) Start() error {
|
func (s *linuxService) Start() error {
|
||||||
cmd := exec.Command("start", s.name)
|
return exec.Command("service", s.name, "start").Run()
|
||||||
return cmd.Run()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *linuxUpstartService) Stop() error {
|
func (s *linuxService) Stop() error {
|
||||||
cmd := exec.Command("stop", s.name)
|
return exec.Command("service", s.name, "stop").Run()
|
||||||
return cmd.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...))
|
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...))
|
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...))
|
return s.logger.Info(fmt.Sprintf(format, a...))
|
||||||
}
|
}
|
||||||
|
|
||||||
var upstartScript = `# {{.Description}}
|
const upstartScript = `# {{.Description}}
|
||||||
|
|
||||||
description "{{.Display}}"
|
description "{{.Display}}"
|
||||||
|
|
||||||
@@ -133,3 +189,16 @@ end script
|
|||||||
# Start
|
# Start
|
||||||
exec {{.Path}}
|
exec {{.Path}}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
const systemdScript = `[Unit]
|
||||||
|
Description={{.Description}}
|
||||||
|
ConditionFileIsExecutable={{.Path}}
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
StartLimitInterval=5
|
||||||
|
StartLimitBurst=10
|
||||||
|
ExecStart={{.Path}}
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
`
|
||||||
|
|||||||
Reference in New Issue
Block a user