github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/service/common/conf.go (about) 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 }