github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/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  }