mirror of https://github.com/mindoc-org/mindoc.git
176 lines
3.5 KiB
Go
176 lines
3.5 KiB
Go
|
// Copyright 2015 Daniel Theophanes.
|
||
|
// Use of this source code is governed by a zlib-style
|
||
|
// license that can be found in the LICENSE file.
|
||
|
|
||
|
package service
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"os"
|
||
|
"os/signal"
|
||
|
"syscall"
|
||
|
"text/template"
|
||
|
)
|
||
|
|
||
|
func isSystemd() bool {
|
||
|
if _, err := os.Stat("/run/systemd/system"); err == nil {
|
||
|
return true
|
||
|
}
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
type systemd struct {
|
||
|
i Interface
|
||
|
*Config
|
||
|
}
|
||
|
|
||
|
func newSystemdService(i Interface, c *Config) (Service, error) {
|
||
|
s := &systemd{
|
||
|
i: i,
|
||
|
Config: c,
|
||
|
}
|
||
|
|
||
|
return s, nil
|
||
|
}
|
||
|
|
||
|
func (s *systemd) String() string {
|
||
|
if len(s.DisplayName) > 0 {
|
||
|
return s.DisplayName
|
||
|
}
|
||
|
return s.Name
|
||
|
}
|
||
|
|
||
|
// Systemd services should be supported, but are not currently.
|
||
|
var errNoUserServiceSystemd = errors.New("User services are not supported on systemd.")
|
||
|
|
||
|
func (s *systemd) configPath() (cp string, err error) {
|
||
|
if s.Option.bool(optionUserService, optionUserServiceDefault) {
|
||
|
err = errNoUserServiceSystemd
|
||
|
return
|
||
|
}
|
||
|
cp = "/etc/systemd/system/" + s.Config.Name + ".service"
|
||
|
return
|
||
|
}
|
||
|
func (s *systemd) template() *template.Template {
|
||
|
return template.Must(template.New("").Funcs(tf).Parse(systemdScript))
|
||
|
}
|
||
|
|
||
|
func (s *systemd) Install() error {
|
||
|
confPath, err := s.configPath()
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
_, err = os.Stat(confPath)
|
||
|
if err == nil {
|
||
|
return fmt.Errorf("Init already exists: %s", confPath)
|
||
|
}
|
||
|
|
||
|
f, err := os.Create(confPath)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
defer f.Close()
|
||
|
|
||
|
path, err := s.execPath()
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
var to = &struct {
|
||
|
*Config
|
||
|
Path string
|
||
|
ReloadSignal string
|
||
|
PIDFile string
|
||
|
}{
|
||
|
s.Config,
|
||
|
path,
|
||
|
s.Option.string(optionReloadSignal, ""),
|
||
|
s.Option.string(optionPIDFile, ""),
|
||
|
}
|
||
|
|
||
|
err = s.template().Execute(f, to)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
err = run("systemctl", "enable", s.Name+".service")
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
return run("systemctl", "daemon-reload")
|
||
|
}
|
||
|
|
||
|
func (s *systemd) Uninstall() error {
|
||
|
err := run("systemctl", "disable", s.Name+".service")
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
cp, err := s.configPath()
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
if err := os.Remove(cp); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (s *systemd) Logger(errs chan<- error) (Logger, error) {
|
||
|
if system.Interactive() {
|
||
|
return ConsoleLogger, nil
|
||
|
}
|
||
|
return s.SystemLogger(errs)
|
||
|
}
|
||
|
func (s *systemd) SystemLogger(errs chan<- error) (Logger, error) {
|
||
|
return newSysLogger(s.Name, errs)
|
||
|
}
|
||
|
|
||
|
func (s *systemd) Run() (err error) {
|
||
|
err = s.i.Start(s)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
s.Option.funcSingle(optionRunWait, func() {
|
||
|
var sigChan = make(chan os.Signal, 3)
|
||
|
signal.Notify(sigChan, syscall.SIGTERM, os.Interrupt)
|
||
|
<-sigChan
|
||
|
})()
|
||
|
|
||
|
return s.i.Stop(s)
|
||
|
}
|
||
|
|
||
|
func (s *systemd) Start() error {
|
||
|
return run("systemctl", "start", s.Name+".service")
|
||
|
}
|
||
|
|
||
|
func (s *systemd) Stop() error {
|
||
|
return run("systemctl", "stop", s.Name+".service")
|
||
|
}
|
||
|
|
||
|
func (s *systemd) Restart() error {
|
||
|
return run("systemctl", "restart", s.Name+".service")
|
||
|
}
|
||
|
|
||
|
const systemdScript = `[Unit]
|
||
|
Description={{.Description}}
|
||
|
ConditionFileIsExecutable={{.Path|cmdEscape}}
|
||
|
|
||
|
[Service]
|
||
|
StartLimitInterval=5
|
||
|
StartLimitBurst=10
|
||
|
ExecStart={{.Path|cmdEscape}}{{range .Arguments}} {{.|cmd}}{{end}}
|
||
|
{{if .ChRoot}}RootDirectory={{.ChRoot|cmd}}{{end}}
|
||
|
{{if .WorkingDirectory}}WorkingDirectory={{.WorkingDirectory|cmdEscape}}{{end}}
|
||
|
{{if .UserName}}User={{.UserName}}{{end}}
|
||
|
{{if .ReloadSignal}}ExecReload=/bin/kill -{{.ReloadSignal}} "$MAINPID"{{end}}
|
||
|
{{if .PIDFile}}PIDFile={{.PIDFile|cmd}}{{end}}
|
||
|
Restart=always
|
||
|
RestartSec=120
|
||
|
EnvironmentFile=-/etc/sysconfig/{{.Name}}
|
||
|
|
||
|
[Install]
|
||
|
WantedBy=multi-user.target
|
||
|
`
|