1
// Copyright 2015 Canonical Ltd.
2
// Licensed under the AGPLv3, see LICENCE file for details.
10
"github.com/juju/errors"
11
"github.com/juju/utils/shell"
14
// Conf is responsible for defining services. Its fields
15
// represent elements of a service configuration.
17
// Desc is the init service's description.
20
// Transient indicates whether or not the service is a one-off.
23
// AfterStopped is the name, if any, of another service. This
24
// service will not start until after the other stops.
27
// Env holds the environment variables that will be set when the
29
// Currently not used on Windows.
32
// TODO(ericsnow) Add a Limit type, since the possible keys are known.
34
// Limit holds the ulimit values that will be set when the command
35
// runs. Each value will be used as both the soft and hard limit.
36
// Currently not used on Windows.
39
// Timeout is how many seconds may pass before an exec call (e.g.
40
// ExecStart) times out. Values less than or equal to 0 (the
41
// default) are treated as though there is no timeout.
44
// ExecStart is the command (with arguments) that will be run. The
45
// path to the executable must be absolute.
46
// The command will be restarted if it exits with a non-zero exit code.
49
// ExecStopPost is the command that will be run after the service stops.
50
// The path to the executable must be absolute.
53
// Logfile, if set, indicates where the service's output should be
57
// TODO(ericsnow) Turn ExtraScript into ExecStartPre.
59
// ExtraScript allows to insert script before command execution.
62
// ServiceBinary is the actual binary without any arguments.
65
// ServiceArgs is a string array of unquoted arguments
69
// IsZero determines whether or not the conf is a zero value.
70
func (c Conf) IsZero() bool {
71
return reflect.DeepEqual(c, Conf{})
74
// Validate checks the conf's values for correctness.
75
func (c Conf) Validate(renderer shell.Renderer) error {
77
return errors.New("missing Desc")
80
// Check the Exec* fields.
81
if c.ExecStart == "" {
82
return errors.New("missing ExecStart")
84
for field, cmd := range map[string]string{
85
"ExecStart": c.ExecStart,
86
"ExecStopPost": c.ExecStopPost,
91
if err := c.checkExec(field, cmd, renderer); err != nil {
92
return errors.Trace(err)
99
func (c Conf) checkExec(name, cmd string, renderer shell.Renderer) error {
100
path := executable(cmd)
101
if !renderer.IsAbs(path) {
102
return errors.NotValidf("relative path in %s (%s)", name, path)
107
func executable(cmd string) string {
108
path := strings.Fields(cmd)[0]
112
// Unquote returns the string embedded between matching quotation marks.
113
// If there aren't any matching quotation marks then the string is
115
func Unquote(str string) string {
120
first, last := string(str[0]), string(str[len(str)-1])
122
if first == `"` && last == `"` {
123
return str[1 : len(str)-1]
126
if first == "'" && last == "'" {
127
return str[1 : len(str)-1]