~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/github.com/juju/juju/service/common/conf.go

  • Committer: Nicholas Skaggs
  • Date: 2016-10-24 20:56:05 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161024205605-z8lta0uvuhtxwzwl
Initi with beta15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2015 Canonical Ltd.
 
2
// Licensed under the AGPLv3, see LICENCE file for details.
 
3
 
 
4
package common
 
5
 
 
6
import (
 
7
        "reflect"
 
8
        "strings"
 
9
 
 
10
        "github.com/juju/errors"
 
11
        "github.com/juju/utils/shell"
 
12
)
 
13
 
 
14
// Conf is responsible for defining services. Its fields
 
15
// represent elements of a service configuration.
 
16
type Conf struct {
 
17
        // Desc is the init service's description.
 
18
        Desc string
 
19
 
 
20
        // Transient indicates whether or not the service is a one-off.
 
21
        Transient bool
 
22
 
 
23
        // AfterStopped is the name, if any, of another service. This
 
24
        // service will not start until after the other stops.
 
25
        AfterStopped string
 
26
 
 
27
        // Env holds the environment variables that will be set when the
 
28
        // command runs.
 
29
        // Currently not used on Windows.
 
30
        Env map[string]string
 
31
 
 
32
        // TODO(ericsnow) Add a Limit type, since the possible keys are known.
 
33
 
 
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.
 
37
        Limit map[string]int
 
38
 
 
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.
 
42
        Timeout int
 
43
 
 
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.
 
47
        ExecStart string
 
48
 
 
49
        // ExecStopPost is the command that will be run after the service stops.
 
50
        // The path to the executable must be absolute.
 
51
        ExecStopPost string
 
52
 
 
53
        // Logfile, if set, indicates where the service's output should be
 
54
        // written.
 
55
        Logfile string
 
56
 
 
57
        // TODO(ericsnow) Turn ExtraScript into ExecStartPre.
 
58
 
 
59
        // ExtraScript allows to insert script before command execution.
 
60
        ExtraScript string
 
61
 
 
62
        // ServiceBinary is the actual binary without any arguments.
 
63
        ServiceBinary string
 
64
 
 
65
        // ServiceArgs is a string array of unquoted arguments
 
66
        ServiceArgs []string
 
67
}
 
68
 
 
69
// IsZero determines whether or not the conf is a zero value.
 
70
func (c Conf) IsZero() bool {
 
71
        return reflect.DeepEqual(c, Conf{})
 
72
}
 
73
 
 
74
// Validate checks the conf's values for correctness.
 
75
func (c Conf) Validate(renderer shell.Renderer) error {
 
76
        if c.Desc == "" {
 
77
                return errors.New("missing Desc")
 
78
        }
 
79
 
 
80
        // Check the Exec* fields.
 
81
        if c.ExecStart == "" {
 
82
                return errors.New("missing ExecStart")
 
83
        }
 
84
        for field, cmd := range map[string]string{
 
85
                "ExecStart":    c.ExecStart,
 
86
                "ExecStopPost": c.ExecStopPost,
 
87
        } {
 
88
                if cmd == "" {
 
89
                        continue
 
90
                }
 
91
                if err := c.checkExec(field, cmd, renderer); err != nil {
 
92
                        return errors.Trace(err)
 
93
                }
 
94
        }
 
95
 
 
96
        return nil
 
97
}
 
98
 
 
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)
 
103
        }
 
104
        return nil
 
105
}
 
106
 
 
107
func executable(cmd string) string {
 
108
        path := strings.Fields(cmd)[0]
 
109
        return Unquote(path)
 
110
}
 
111
 
 
112
// Unquote returns the string embedded between matching quotation marks.
 
113
// If there aren't any matching quotation marks then the string is
 
114
// returned as-is.
 
115
func Unquote(str string) string {
 
116
        if len(str) < 2 {
 
117
                return str
 
118
        }
 
119
 
 
120
        first, last := string(str[0]), string(str[len(str)-1])
 
121
 
 
122
        if first == `"` && last == `"` {
 
123
                return str[1 : len(str)-1]
 
124
        }
 
125
 
 
126
        if first == "'" && last == "'" {
 
127
                return str[1 : len(str)-1]
 
128
        }
 
129
 
 
130
        return str
 
131
}