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  }