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