diff --git a/README.md b/README.md index d2fe1ed..f18fd48 100644 --- a/README.md +++ b/README.md @@ -173,7 +173,7 @@ func main() { } ``` -## Contributors +## Contributors (unsorted) - [Igor Dolzhikov](https://github.com/takama) - [Sheile](https://github.com/Sheile) @@ -183,6 +183,7 @@ func main() { - [Fatih Kaya](https://github.com/fatihky) - [Jannick Fahlbusch](https://github.com/jannickfahlbusch) - [TobyZXJ](https://github.com/tobyzxj) +- [Pichu Chen](https://github.com/PichuChen) All the contributors are welcome. If you would like to be the contributor please accept some rules. - The pull requests will be accepted only in "develop" branch diff --git a/daemon.go b/daemon.go index 7a7a229..f49e139 100644 --- a/daemon.go +++ b/daemon.go @@ -3,7 +3,7 @@ // license that can be found in the LICENSE file. /* -Package daemon 0.5.2 for use with Go (golang) services. +Package daemon 0.6.0 for use with Go (golang) services. Package daemon provides primitives for daemonization of golang services. This package is not provide implementation of user daemon, diff --git a/daemon_linux.go b/daemon_linux.go index dda3b25..03a1e5c 100644 --- a/daemon_linux.go +++ b/daemon_linux.go @@ -11,6 +11,9 @@ import ( // Get the daemon properly func newDaemon(name, description string, dependencies []string) (Daemon, error) { + if _, err := os.Stat("/sbin/initctl"); err == nil { + return &upstartRecord{name, description, dependencies}, nil + } if _, err := os.Stat("/run/systemd/system"); err == nil { return &systemDRecord{name, description, dependencies}, nil } diff --git a/daemon_linux_upstart.go b/daemon_linux_upstart.go new file mode 100644 index 0000000..5b1d359 --- /dev/null +++ b/daemon_linux_upstart.go @@ -0,0 +1,192 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by +// license that can be found in the LICENSE file. + +package daemon + +import ( + "os" + "os/exec" + "regexp" + "strings" + "text/template" +) + +// upstartRecord - standard record (struct) for linux upstart version of daemon package +type upstartRecord struct { + name string + description string + dependencies []string +} + +// Standard service path for systemV daemons +func (linux *upstartRecord) servicePath() string { + return "/etc/init/" + linux.name + ".conf" +} + +// Is a service installed +func (linux *upstartRecord) isInstalled() bool { + + if _, err := os.Stat(linux.servicePath()); err == nil { + return true + } + + return false +} + +// Check service is running +func (linux *upstartRecord) checkRunning() (string, bool) { + output, err := exec.Command("status", linux.name).Output() + if err == nil { + if matched, err := regexp.MatchString(linux.name+" start/running", string(output)); err == nil && matched { + reg := regexp.MustCompile("process ([0-9]+)") + data := reg.FindStringSubmatch(string(output)) + if len(data) > 1 { + return "Service (pid " + data[1] + ") is running...", true + } + return "Service is running...", true + } + } + + return "Service is stopped", false +} + +// Install the service +func (linux *upstartRecord) Install(args ...string) (string, error) { + installAction := "Install " + linux.description + ":" + + if ok, err := checkPrivileges(); !ok { + return installAction + failed, err + } + + srvPath := linux.servicePath() + + if linux.isInstalled() { + return installAction + failed, ErrAlreadyInstalled + } + + file, err := os.Create(srvPath) + if err != nil { + return installAction + failed, err + } + defer file.Close() + + execPatch, err := executablePath(linux.name) + if err != nil { + return installAction + failed, err + } + + templ, err := template.New("upstatConfig").Parse(upstatConfig) + if err != nil { + return installAction + failed, err + } + + if err := templ.Execute( + file, + &struct { + Name, Description, Path, Args string + }{linux.name, linux.description, execPatch, strings.Join(args, " ")}, + ); err != nil { + return installAction + failed, err + } + + if err := os.Chmod(srvPath, 0755); err != nil { + return installAction + failed, err + } + + return installAction + success, nil +} + +// Remove the service +func (linux *upstartRecord) Remove() (string, error) { + removeAction := "Removing " + linux.description + ":" + + if ok, err := checkPrivileges(); !ok { + return removeAction + failed, err + } + + if !linux.isInstalled() { + return removeAction + failed, ErrNotInstalled + } + + if err := os.Remove(linux.servicePath()); err != nil { + return removeAction + failed, err + } + + return removeAction + success, nil +} + +// Start the service +func (linux *upstartRecord) Start() (string, error) { + startAction := "Starting " + linux.description + ":" + + if ok, err := checkPrivileges(); !ok { + return startAction + failed, err + } + + if !linux.isInstalled() { + return startAction + failed, ErrNotInstalled + } + + if _, ok := linux.checkRunning(); ok { + return startAction + failed, ErrAlreadyRunning + } + + if err := exec.Command("start", linux.name).Run(); err != nil { + return startAction + failed, err + } + + return startAction + success, nil +} + +// Stop the service +func (linux *upstartRecord) Stop() (string, error) { + stopAction := "Stopping " + linux.description + ":" + + if ok, err := checkPrivileges(); !ok { + return stopAction + failed, err + } + + if !linux.isInstalled() { + return stopAction + failed, ErrNotInstalled + } + + if _, ok := linux.checkRunning(); !ok { + return stopAction + failed, ErrAlreadyStopped + } + + if err := exec.Command("stop", linux.name).Run(); err != nil { + return stopAction + failed, err + } + + return stopAction + success, nil +} + +// Status - Get service status +func (linux *upstartRecord) Status() (string, error) { + + if ok, err := checkPrivileges(); !ok { + return "", err + } + + if !linux.isInstalled() { + return "Status could not defined", ErrNotInstalled + } + + statusAction, _ := linux.checkRunning() + + return statusAction, nil +} + +var upstatConfig = `# {{.Name}} {{.Description}} + +description "{{.Description}}" +author "Pichu Chen " + +start on runlevel [2345] +stop on runlevel [016] + +#kill timeout 5 + +exec {{.Path}} >> /var/log/{{.Name}}.log 2>> /var/log/{{.Name}}.err +`