~juju/pyjuju/go

« back to all changes in this revision

Viewing changes to upstart/service.go

  • Committer: William Reade
  • Date: 2012-05-04 13:43:57 UTC
  • mto: This revision was merged to the branch mainline in revision 193.
  • Revision ID: fwereade@gmail.com-20120504134357-trzcbnfhx2eh2c9r
first cut, untested

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
package upstart
 
2
 
 
3
import (
 
4
        "os"
 
5
        "os/exec"
 
6
        "path/filepath"
 
7
        "regexp"
 
8
        "strconv"
 
9
        "time"
 
10
)
 
11
 
 
12
var startedRE = regexp.MustCompile("^.* start/running, process (\\d+)\n$")
 
13
 
 
14
// Service provides visibility into and control over an upstart service.
 
15
type Service struct {
 
16
        Name    string
 
17
        InitDir string // defaults to "/etc/init"
 
18
}
 
19
 
 
20
func NewService(name string) *Service {
 
21
        return &Service{Name: name, InitDir: "/etc/init"}
 
22
}
 
23
 
 
24
// path returns the path to the service's configuration file.
 
25
func (s *Service) path() string {
 
26
        return filepath.Join(s.InitDir, s.Name+".conf")
 
27
}
 
28
 
 
29
// pid returns the Service's current pid, or -1 if it cannot be determined.
 
30
func (s *Service) pid() int {
 
31
        cmd := exec.Command("status", s.Name)
 
32
        out, err := cmd.CombinedOutput()
 
33
        if err != nil {
 
34
                return -1
 
35
        }
 
36
        match := startedRE.FindStringSubmatch(string(out))
 
37
        if match == nil {
 
38
                return -1
 
39
        }
 
40
        pid, err := strconv.Atoi(match[1])
 
41
        if err != nil {
 
42
                return -1
 
43
        }
 
44
        return pid
 
45
}
 
46
 
 
47
// Installed returns true if the Service appears to be installed.
 
48
func (s *Service) Installed() bool {
 
49
        _, err := os.Stat(s.path())
 
50
        return err == nil
 
51
}
 
52
 
 
53
// Running returns true if the Service appears to be running.
 
54
func (s *Service) Running() bool {
 
55
        return s.pid() != -1
 
56
}
 
57
 
 
58
// Stable returns true if the Service appears to be running stably, by
 
59
// checking that the reported pid does not change over the course of 5
 
60
// checks over 0.4 seconds.
 
61
func (s *Service) Stable() bool {
 
62
        pid := s.pid()
 
63
        if pid == -1 {
 
64
                return false
 
65
        }
 
66
        for i := 0; i < 4; i++ {
 
67
                <-time.After(100 * time.Millisecond)
 
68
                if s.pid() != pid {
 
69
                        return false
 
70
                }
 
71
        }
 
72
        return true
 
73
}
 
74
 
 
75
// Start starts the service.
 
76
func (s *Service) Start() error {
 
77
        if s.Running() {
 
78
                return nil
 
79
        }
 
80
        return exec.Command("start", s.Name).Run()
 
81
}
 
82
 
 
83
// Stop stops the service.
 
84
func (s *Service) Stop() error {
 
85
        if !s.Running() {
 
86
                return nil
 
87
        }
 
88
        return exec.Command("stop", s.Name).Run()
 
89
}
 
90
 
 
91
// Remove removes the service.
 
92
func (s *Service) Remove() error {
 
93
        if !s.Installed() {
 
94
                return nil
 
95
        }
 
96
        if err := s.Stop(); err != nil {
 
97
                return err
 
98
        }
 
99
        return os.Remove(s.path())
 
100
}