From a172bea54dbd95c86a6d991403b022e70a14b7f2 Mon Sep 17 00:00:00 2001 From: Daniel Theophanes Date: Fri, 11 May 2012 01:13:06 -0700 Subject: [PATCH] Add Linux Upstart support. --- service_linux.go | 123 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 service_linux.go diff --git a/service_linux.go b/service_linux.go new file mode 100644 index 0000000..9d3fca0 --- /dev/null +++ b/service_linux.go @@ -0,0 +1,123 @@ +package service + +import ( + "os" + "fmt" + "log/syslog" + "text/template" + "os/signal" +) + +func newService(name, displayName, description string) (s *linuxUpstartService, err error) { + s = &linuxUpstartService{ + name: name, + displayName: displayName, + description: description, + } + + s.logger, err = syslog.New(syslog.LOG_INFO, name) + if err != nil { + return nil, err + } + + return s, nil +} + +type linuxUpstartService struct { + name, displayName, description string + logger *syslog.Writer +} + +func (s *linuxUpstartService) Install() error { + var confPath = "/etc/init/" + s.name + ".conf" + _, 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 := getExePath() + if err != nil { + return err + } + + var to = &struct { + Display string + Description string + Path string + } { + s.displayName, + s.description, + path, + } + + t := template.Must(template.New("upstartScript").Parse(upstartScript)) + err = t.Execute(f,to) + + if err != nil { + return err + } + + return nil +} + +func (s *linuxUpstartService) Remove() error { + return os.Remove("/etc/init/" + s.name + ".conf") +} + +func (s *linuxUpstartService) Run(onStart, onStop func() error) error { + var err error + + err = onStart() + if err != nil { + return err + } + + var sigChan = make(chan os.Signal, 3) + + signal.Notify(sigChan, os.Kill) + + <- sigChan + + return onStop() +} + +func (s *linuxUpstartService) LogError(format string, a ...interface{}) error { + return s.logger.Err(fmt.Sprintf(format, a...)) +} +func (s *linuxUpstartService) LogWarning(format string, a ...interface{}) error { + return s.logger.Warning(fmt.Sprintf(format, a...)) +} +func (s *linuxUpstartService) LogInfo(format string, a ...interface{}) error { + return s.logger.Info(fmt.Sprintf(format, a...)) +} + +func getExePath() (exePath string, err error) { + return os.Readlink(`/proc/self/exe`) +} + +var upstartScript = `# {{.Description}} + +description "{{.Display}}" + +start on filesystem or runlevel [2345] +stop on runlevel [!2345] + +respawn +respawn limit 10 5 +umask 022 + +console none + +pre-start script + test -x {{.Path}} || { stop; exit 0; } +end script + +# Start +exec {{.Path}} +`