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  }