1// Package upstart implements the Upstart init system.
2
3package upstart
4
5import (
6	"fmt"
7	"os"
8	"os/exec"
9	"strings"
10
11	"github.com/nextdns/nextdns/host/service"
12	"github.com/nextdns/nextdns/host/service/internal"
13)
14
15type Service struct {
16	service.Config
17	service.ConfigFileStorer
18	Path string
19}
20
21func New(c service.Config) (Service, error) {
22	if _, err := exec.LookPath("initctl"); err != nil {
23		return Service{}, service.ErrNotSuported
24	}
25	out, err := internal.RunOutput("initctl", "version")
26	if err != nil || !strings.Contains(out, "upstart") {
27		return Service{}, service.ErrNotSuported
28	}
29	return Service{
30		Config:           c,
31		ConfigFileStorer: service.ConfigFileStorer{File: "/etc/" + c.Name + ".conf"},
32		Path:             "/etc/init/" + c.Name + ".conf",
33	}, nil
34}
35
36func (s Service) Install() error {
37	return internal.CreateWithTemplate(s.Path, tmpl, 0644, s.Config)
38}
39
40func (s Service) Uninstall() error {
41	if err := os.Remove(s.Path); err != nil {
42		return err
43	}
44	return nil
45}
46
47func (s Service) Status() (service.Status, error) {
48	out, err := internal.RunOutput("initctl", "status", s.Name)
49	if internal.ExitCode(err) == 0 && err != nil {
50		return service.StatusUnknown, err
51	}
52
53	switch {
54	case strings.HasPrefix(out, fmt.Sprintf("%s start/running", s.Name)):
55		return service.StatusRunning, nil
56	case strings.HasPrefix(out, fmt.Sprintf("%s stop/waiting", s.Name)):
57		return service.StatusStopped, nil
58	default:
59		return service.StatusNotInstalled, nil
60	}
61}
62
63func (s Service) Start() error {
64	return internal.Run("initctl", "start", s.Name)
65}
66
67func (s Service) Stop() error {
68	return internal.Run("initctl", "stop", s.Name)
69}
70
71func (s Service) Restart() error {
72	return internal.Run("initctl", "restart", s.Name)
73}
74
75var tmpl = `# {{.Description}}
76
77{{if .DisplayName}}description "{{.DisplayName}}"{{end}}
78start on filesystem or runlevel [2345]
79stop on runlevel [!2345]
80
81respawn
82respawn limit 10 5
83umask 022
84
85console none
86
87env {{.RunModeEnv}}=1
88
89script
90	exec {{.Executable}}{{range .Arguments}} {{.}}{{end}}
91end script
92`
93