github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/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 -l -t service` + 39 ` | grep -o -P '^\w[\S]*(?=\.service)'` 40 return c.resolve(args) 41 } 42 43 func (c commands) start(name string) string { 44 args := fmt.Sprintf("start %s.service", name) 45 return c.resolve(args) 46 } 47 48 func (c commands) link(name, dirname string) string { 49 filename := c.unitFilename(name, dirname) 50 args := fmt.Sprintf("link %s", c.Quote(filename)) 51 return c.resolve(args) 52 } 53 54 func (c commands) enableLinked(name, dirname string) string { 55 filename := c.unitFilename(name, dirname) 56 args := fmt.Sprintf("enable %s", c.Quote(filename)) 57 return c.resolve(args) 58 } 59 60 func (c commands) disable(name string) string { 61 args := fmt.Sprintf("disable %s.service", name) 62 return c.resolve(args) 63 } 64 65 func (c commands) reload() string { 66 args := "daemon-reload" 67 return c.resolve(args) 68 } 69 70 func (c commands) conf(name, dirname string) string { 71 serviceFile := c.unitFilename(name, dirname) 72 args := fmt.Sprintf("cat %s", serviceFile) 73 return args 74 } 75 76 func (c commands) mkdirs(dirname string) string { 77 cmds := c.MkdirAll(dirname) 78 return strings.Join(cmds, "\n") 79 } 80 81 func (c commands) writeConf(name, dirname string, data []byte) string { 82 filename := c.unitFilename(name, dirname) 83 cmds := c.WriteFile(filename, data) 84 return strings.Join(cmds, "\n") 85 } 86 87 func (c commands) writeFile(name, dirname string, data []byte) string { 88 filename := c.Join(dirname, name) 89 cmds := c.WriteFile(filename, data) 90 return strings.Join(cmds, "\n") 91 } 92 93 func (c commands) chmod(name, dirname string, perm os.FileMode) string { 94 filename := c.Join(dirname, name) 95 cmds := c.Chmod(filename, perm) 96 return strings.Join(cmds, "\n") 97 } 98 99 // Cmdline exposes the core operations of interacting with systemd units. 100 type Cmdline struct { 101 commands commands 102 } 103 104 // TODO(ericsnow) Support more commands (Status, Start, Install, Conf, etc.). 105 106 // ListAll returns the names of all enabled systemd units. 107 func (cl Cmdline) ListAll() ([]string, error) { 108 cmd := cl.commands.listAll() 109 110 out, err := cl.runCommand(cmd, "List") 111 if err != nil { 112 return nil, errors.Trace(err) 113 } 114 out = strings.TrimSpace(out) 115 116 if out == "" { 117 return nil, nil 118 } 119 return strings.Split(out, "\n"), nil 120 } 121 122 func (cl Cmdline) conf(name, dirname string) ([]byte, error) { 123 cmd := cl.commands.conf(name, dirname) 124 125 out, err := cl.runCommand(cmd, "get conf") 126 if err != nil { 127 return nil, errors.Trace(err) 128 } 129 out = strings.TrimSpace(out) 130 131 return []byte(out), nil 132 } 133 134 func (cl Cmdline) reload() error { 135 cmd := cl.commands.reload() 136 137 _, err := cl.runCommand(cmd, "") 138 if err != nil { 139 err = errors.Trace(err) 140 return err 141 } 142 143 return err 144 } 145 146 const runCommandMsg = "%s failed (%s)" 147 148 func (Cmdline) runCommand(cmd, label string) (string, error) { 149 resp, err := runCommands(exec.RunParams{ 150 Commands: cmd, 151 }) 152 if err != nil { 153 return "", errors.Annotatef(err, runCommandMsg, label, cmd) 154 } 155 out := string(resp.Stdout) 156 157 if resp.Code != 0 { 158 err := errors.Errorf( 159 "error executing %q: %s", 160 executable, 161 strings.Replace(string(resp.Stderr), "\n", "; ", -1), 162 ) 163 return out, errors.Annotatef(err, runCommandMsg, label, cmd) 164 } 165 return out, nil 166 } 167 168 var runCommands = func(args exec.RunParams) (*exec.ExecResponse, error) { 169 return exec.RunCommands(args) 170 }