github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/service/systemd/cmdline.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package systemd 5 6 import ( 7 "fmt" 8 "os" 9 "strings" 10 11 "github.com/juju/errors" 12 "github.com/juju/utils/exec" 13 "github.com/juju/utils/shell" 14 ) 15 16 const executable = "/bin/systemctl" 17 18 type commands struct { 19 shell.BashRenderer 20 binary string 21 } 22 23 func (c commands) resolve(args string) string { 24 binary := c.binary 25 if binary == "" { 26 binary = executable 27 } 28 return binary + " " + args 29 } 30 31 func (c commands) unitFilename(name, dirname string) string { 32 return c.Join(dirname, name+".service") 33 } 34 35 func (c commands) listAll() string { 36 // We can't just use the same command as listRunning (with an extra 37 // "--all" because it misses some inactive units. 38 args := `list-unit-files --no-legend --no-page -t service` + 39 ` | grep -o -P '^\w[\S]*(?=\.service)'` 40 return c.resolve(args) 41 } 42 43 func (c commands) listRunning() string { 44 args := `--no-legend --no-page -t service` + 45 ` | grep -o -P '^\w[\S]*(?=\.service)'` 46 return c.resolve(args) 47 } 48 49 func (c commands) activeStatus(name string) string { 50 args := fmt.Sprintf("is-active %s.service || exit 0", name) 51 return c.resolve(args) 52 } 53 54 func (c commands) loadStatus(name string) string { 55 args := fmt.Sprintf("is-enabled %s.service || exit 0", name) 56 return c.resolve(args) 57 } 58 59 func (c commands) start(name string) string { 60 args := fmt.Sprintf("start %s.service", name) 61 return c.resolve(args) 62 } 63 64 func (c commands) stop(name string) string { 65 args := fmt.Sprintf("stop %s.service", name) 66 return c.resolve(args) 67 } 68 69 func (c commands) link(name, dirname string) string { 70 filename := c.unitFilename(name, dirname) 71 args := fmt.Sprintf("link %s", c.Quote(filename)) 72 return c.resolve(args) 73 } 74 75 func (c commands) enableLinked(name, dirname string) string { 76 filename := c.unitFilename(name, dirname) 77 args := fmt.Sprintf("enable %s", c.Quote(filename)) 78 return c.resolve(args) 79 } 80 81 func (c commands) enable(name string) string { 82 args := fmt.Sprintf("enable %s.service", name) 83 return c.resolve(args) 84 } 85 86 func (c commands) disable(name string) string { 87 args := fmt.Sprintf("disable %s.service", name) 88 return c.resolve(args) 89 } 90 91 func (c commands) reload() string { 92 args := "daemon-reload" 93 return c.resolve(args) 94 } 95 96 func (c commands) conf(name, dirname string) string { 97 serviceFile := c.unitFilename(name, dirname) 98 args := fmt.Sprintf("cat %s", serviceFile) 99 return args 100 } 101 102 func (c commands) mkdirs(dirname string) string { 103 cmds := c.MkdirAll(dirname) 104 return strings.Join(cmds, "\n") 105 } 106 107 func (c commands) writeConf(name, dirname string, data []byte) string { 108 filename := c.unitFilename(name, dirname) 109 cmds := c.WriteFile(filename, data) 110 return strings.Join(cmds, "\n") 111 } 112 113 func (c commands) writeFile(name, dirname string, data []byte) string { 114 filename := c.Join(dirname, name) 115 cmds := c.WriteFile(filename, data) 116 return strings.Join(cmds, "\n") 117 } 118 119 func (c commands) chmod(name, dirname string, perm os.FileMode) string { 120 filename := c.Join(dirname, name) 121 cmds := c.Chmod(filename, perm) 122 return strings.Join(cmds, "\n") 123 } 124 125 // Cmdline exposes the core operations of interacting with systemd units. 126 type Cmdline struct { 127 commands commands 128 } 129 130 // TODO(ericsnow) Support more commands (Status, Start, Install, Conf, etc.). 131 132 // ListAll returns the names of all enabled systemd units. 133 func (cl Cmdline) ListAll() ([]string, error) { 134 cmd := cl.commands.listAll() 135 136 out, err := cl.runCommand(cmd, "List") 137 if err != nil { 138 return nil, errors.Trace(err) 139 } 140 out = strings.TrimSpace(out) 141 142 if out == "" { 143 return nil, nil 144 } 145 return strings.Split(out, "\n"), nil 146 } 147 148 func (cl Cmdline) conf(name, dirname string) ([]byte, error) { 149 cmd := cl.commands.conf(name, dirname) 150 151 out, err := cl.runCommand(cmd, "get conf") 152 if err != nil { 153 return nil, errors.Trace(err) 154 } 155 out = strings.TrimSpace(out) 156 157 return []byte(out), nil 158 } 159 160 const runCommandMsg = "%s failed (%s)" 161 162 func (Cmdline) runCommand(cmd, label string) (string, error) { 163 resp, err := runCommands(exec.RunParams{ 164 Commands: cmd, 165 }) 166 if err != nil { 167 return "", errors.Annotatef(err, runCommandMsg, label, cmd) 168 } 169 out := string(resp.Stdout) 170 171 if resp.Code != 0 { 172 err := errors.Errorf( 173 "error executing %q: %s", 174 executable, 175 strings.Replace(string(resp.Stderr), "\n", "; ", -1), 176 ) 177 return out, errors.Annotatef(err, runCommandMsg, label, cmd) 178 } 179 return out, nil 180 } 181 182 var runCommands = func(args exec.RunParams) (*exec.ExecResponse, error) { 183 return exec.RunCommands(args) 184 }