github.com/goern/docker@v1.9.0-rc1/opts/opts.go (about)

     1  package opts
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  	"os"
     7  	"path"
     8  	"regexp"
     9  	"strings"
    10  
    11  	"github.com/docker/docker/pkg/parsers"
    12  	"github.com/docker/docker/volume"
    13  )
    14  
    15  var (
    16  	alphaRegexp  = regexp.MustCompile(`[a-zA-Z]`)
    17  	domainRegexp = regexp.MustCompile(`^(:?(:?[a-zA-Z0-9]|(:?[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9]))(:?\.(:?[a-zA-Z0-9]|(:?[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])))*)\.?\s*$`)
    18  	// DefaultHTTPHost Default HTTP Host used if only port is provided to -H flag e.g. docker daemon -H tcp://:8080
    19  	DefaultHTTPHost = "127.0.0.1"
    20  
    21  	// DefaultHTTPPort Default HTTP Port used if only the protocol is provided to -H flag e.g. docker daemon -H tcp://
    22  	// TODO Windows. DefaultHTTPPort is only used on Windows if a -H parameter
    23  	// is not supplied. A better longer term solution would be to use a named
    24  	// pipe as the default on the Windows daemon.
    25  	// These are the IANA registered port numbers for use with Docker
    26  	// see http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml?search=docker
    27  	DefaultHTTPPort = 2375 // Default HTTP Port
    28  	// DefaultTLSHTTPPort Default HTTP Port used when TLS enabled
    29  	DefaultTLSHTTPPort = 2376 // Default TLS encrypted HTTP Port
    30  	// DefaultUnixSocket Path for the unix socket.
    31  	// Docker daemon by default always listens on the default unix socket
    32  	DefaultUnixSocket = "/var/run/docker.sock"
    33  	// DefaultTCPHost constant defines the default host string used by docker on Windows
    34  	DefaultTCPHost = fmt.Sprintf("tcp://%s:%d", DefaultHTTPHost, DefaultHTTPPort)
    35  	// DefaultTLSHost constant defines the default host string used by docker for TLS sockets
    36  	DefaultTLSHost = fmt.Sprintf("tcp://%s:%d", DefaultHTTPHost, DefaultTLSHTTPPort)
    37  )
    38  
    39  // ListOpts holds a list of values and a validation function.
    40  type ListOpts struct {
    41  	values    *[]string
    42  	validator ValidatorFctType
    43  }
    44  
    45  // NewListOpts creates a new ListOpts with the specified validator.
    46  func NewListOpts(validator ValidatorFctType) ListOpts {
    47  	var values []string
    48  	return *NewListOptsRef(&values, validator)
    49  }
    50  
    51  // NewListOptsRef creates a new ListOpts with the specified values and validator.
    52  func NewListOptsRef(values *[]string, validator ValidatorFctType) *ListOpts {
    53  	return &ListOpts{
    54  		values:    values,
    55  		validator: validator,
    56  	}
    57  }
    58  
    59  func (opts *ListOpts) String() string {
    60  	return fmt.Sprintf("%v", []string((*opts.values)))
    61  }
    62  
    63  // Set validates if needed the input value and add it to the
    64  // internal slice.
    65  func (opts *ListOpts) Set(value string) error {
    66  	if opts.validator != nil {
    67  		v, err := opts.validator(value)
    68  		if err != nil {
    69  			return err
    70  		}
    71  		value = v
    72  	}
    73  	(*opts.values) = append((*opts.values), value)
    74  	return nil
    75  }
    76  
    77  // Delete removes the specified element from the slice.
    78  func (opts *ListOpts) Delete(key string) {
    79  	for i, k := range *opts.values {
    80  		if k == key {
    81  			(*opts.values) = append((*opts.values)[:i], (*opts.values)[i+1:]...)
    82  			return
    83  		}
    84  	}
    85  }
    86  
    87  // GetMap returns the content of values in a map in order to avoid
    88  // duplicates.
    89  // FIXME: can we remove this?
    90  func (opts *ListOpts) GetMap() map[string]struct{} {
    91  	ret := make(map[string]struct{})
    92  	for _, k := range *opts.values {
    93  		ret[k] = struct{}{}
    94  	}
    95  	return ret
    96  }
    97  
    98  // GetAll returns the values of slice.
    99  // FIXME: Can we remove this?
   100  func (opts *ListOpts) GetAll() []string {
   101  	return (*opts.values)
   102  }
   103  
   104  // Get checks the existence of the specified key.
   105  func (opts *ListOpts) Get(key string) bool {
   106  	for _, k := range *opts.values {
   107  		if k == key {
   108  			return true
   109  		}
   110  	}
   111  	return false
   112  }
   113  
   114  // Len returns the amount of element in the slice.
   115  func (opts *ListOpts) Len() int {
   116  	return len((*opts.values))
   117  }
   118  
   119  //MapOpts holds a map of values and a validation function.
   120  type MapOpts struct {
   121  	values    map[string]string
   122  	validator ValidatorFctType
   123  }
   124  
   125  // Set validates if needed the input value and add it to the
   126  // internal map, by splitting on '='.
   127  func (opts *MapOpts) Set(value string) error {
   128  	if opts.validator != nil {
   129  		v, err := opts.validator(value)
   130  		if err != nil {
   131  			return err
   132  		}
   133  		value = v
   134  	}
   135  	vals := strings.SplitN(value, "=", 2)
   136  	if len(vals) == 1 {
   137  		(opts.values)[vals[0]] = ""
   138  	} else {
   139  		(opts.values)[vals[0]] = vals[1]
   140  	}
   141  	return nil
   142  }
   143  
   144  // GetAll returns the values of MapOpts as a map.
   145  func (opts *MapOpts) GetAll() map[string]string {
   146  	return opts.values
   147  }
   148  
   149  func (opts *MapOpts) String() string {
   150  	return fmt.Sprintf("%v", map[string]string((opts.values)))
   151  }
   152  
   153  // NewMapOpts creates a new MapOpts with the specified map of values and a validator.
   154  func NewMapOpts(values map[string]string, validator ValidatorFctType) *MapOpts {
   155  	if values == nil {
   156  		values = make(map[string]string)
   157  	}
   158  	return &MapOpts{
   159  		values:    values,
   160  		validator: validator,
   161  	}
   162  }
   163  
   164  // ValidatorFctType defines a validator function that returns a validated string and/or an error.
   165  type ValidatorFctType func(val string) (string, error)
   166  
   167  // ValidatorFctListType defines a validator function that returns a validated list of string and/or an error
   168  type ValidatorFctListType func(val string) ([]string, error)
   169  
   170  // ValidateAttach validates that the specified string is a valid attach option.
   171  func ValidateAttach(val string) (string, error) {
   172  	s := strings.ToLower(val)
   173  	for _, str := range []string{"stdin", "stdout", "stderr"} {
   174  		if s == str {
   175  			return s, nil
   176  		}
   177  	}
   178  	return val, fmt.Errorf("valid streams are STDIN, STDOUT and STDERR")
   179  }
   180  
   181  // ValidateLink validates that the specified string has a valid link format (containerName:alias).
   182  func ValidateLink(val string) (string, error) {
   183  	if _, _, err := parsers.ParseLink(val); err != nil {
   184  		return val, err
   185  	}
   186  	return val, nil
   187  }
   188  
   189  // ValidDeviceMode checks if the mode for device is valid or not.
   190  // Valid mode is a composition of r (read), w (write), and m (mknod).
   191  func ValidDeviceMode(mode string) bool {
   192  	var legalDeviceMode = map[rune]bool{
   193  		'r': true,
   194  		'w': true,
   195  		'm': true,
   196  	}
   197  	if mode == "" {
   198  		return false
   199  	}
   200  	for _, c := range mode {
   201  		if !legalDeviceMode[c] {
   202  			return false
   203  		}
   204  		legalDeviceMode[c] = false
   205  	}
   206  	return true
   207  }
   208  
   209  // ValidateDevice validates a path for devices
   210  // It will make sure 'val' is in the form:
   211  //    [host-dir:]container-path[:mode]
   212  // It also validates the device mode.
   213  func ValidateDevice(val string) (string, error) {
   214  	return validatePath(val, ValidDeviceMode)
   215  }
   216  
   217  // ValidatePath validates a path for volumes
   218  // It will make sure 'val' is in the form:
   219  //    [host-dir:]container-path[:rw|ro]
   220  // It also validates the mount mode.
   221  func ValidatePath(val string) (string, error) {
   222  	return validatePath(val, volume.ValidMountMode)
   223  }
   224  
   225  func validatePath(val string, validator func(string) bool) (string, error) {
   226  	var containerPath string
   227  	var mode string
   228  
   229  	if strings.Count(val, ":") > 2 {
   230  		return val, fmt.Errorf("bad format for path: %s", val)
   231  	}
   232  
   233  	split := strings.SplitN(val, ":", 3)
   234  	if split[0] == "" {
   235  		return val, fmt.Errorf("bad format for path: %s", val)
   236  	}
   237  	switch len(split) {
   238  	case 1:
   239  		containerPath = split[0]
   240  		val = path.Clean(containerPath)
   241  	case 2:
   242  		if isValid := validator(split[1]); isValid {
   243  			containerPath = split[0]
   244  			mode = split[1]
   245  			val = fmt.Sprintf("%s:%s", path.Clean(containerPath), mode)
   246  		} else {
   247  			containerPath = split[1]
   248  			val = fmt.Sprintf("%s:%s", split[0], path.Clean(containerPath))
   249  		}
   250  	case 3:
   251  		containerPath = split[1]
   252  		mode = split[2]
   253  		if isValid := validator(split[2]); !isValid {
   254  			return val, fmt.Errorf("bad mode specified: %s", mode)
   255  		}
   256  		val = fmt.Sprintf("%s:%s:%s", split[0], containerPath, mode)
   257  	}
   258  
   259  	if !path.IsAbs(containerPath) {
   260  		return val, fmt.Errorf("%s is not an absolute path", containerPath)
   261  	}
   262  	return val, nil
   263  }
   264  
   265  // ValidateEnv validates an environment variable and returns it.
   266  // If no value is specified, it returns the current value using os.Getenv.
   267  //
   268  // As on ParseEnvFile and related to #16585, environment variable names
   269  // are not validate what so ever, it's up to application inside docker
   270  // to validate them or not.
   271  func ValidateEnv(val string) (string, error) {
   272  	arr := strings.Split(val, "=")
   273  	if len(arr) > 1 {
   274  		return val, nil
   275  	}
   276  	if !doesEnvExist(val) {
   277  		return val, nil
   278  	}
   279  	return fmt.Sprintf("%s=%s", val, os.Getenv(val)), nil
   280  }
   281  
   282  // ValidateIPAddress validates an Ip address.
   283  func ValidateIPAddress(val string) (string, error) {
   284  	var ip = net.ParseIP(strings.TrimSpace(val))
   285  	if ip != nil {
   286  		return ip.String(), nil
   287  	}
   288  	return "", fmt.Errorf("%s is not an ip address", val)
   289  }
   290  
   291  // ValidateMACAddress validates a MAC address.
   292  func ValidateMACAddress(val string) (string, error) {
   293  	_, err := net.ParseMAC(strings.TrimSpace(val))
   294  	if err != nil {
   295  		return "", err
   296  	}
   297  	return val, nil
   298  }
   299  
   300  // ValidateDNSSearch validates domain for resolvconf search configuration.
   301  // A zero length domain is represented by a dot (.).
   302  func ValidateDNSSearch(val string) (string, error) {
   303  	if val = strings.Trim(val, " "); val == "." {
   304  		return val, nil
   305  	}
   306  	return validateDomain(val)
   307  }
   308  
   309  func validateDomain(val string) (string, error) {
   310  	if alphaRegexp.FindString(val) == "" {
   311  		return "", fmt.Errorf("%s is not a valid domain", val)
   312  	}
   313  	ns := domainRegexp.FindSubmatch([]byte(val))
   314  	if len(ns) > 0 && len(ns[1]) < 255 {
   315  		return string(ns[1]), nil
   316  	}
   317  	return "", fmt.Errorf("%s is not a valid domain", val)
   318  }
   319  
   320  // ValidateExtraHost validates that the specified string is a valid extrahost and returns it.
   321  // ExtraHost are in the form of name:ip where the ip has to be a valid ip (ipv4 or ipv6).
   322  func ValidateExtraHost(val string) (string, error) {
   323  	// allow for IPv6 addresses in extra hosts by only splitting on first ":"
   324  	arr := strings.SplitN(val, ":", 2)
   325  	if len(arr) != 2 || len(arr[0]) == 0 {
   326  		return "", fmt.Errorf("bad format for add-host: %q", val)
   327  	}
   328  	if _, err := ValidateIPAddress(arr[1]); err != nil {
   329  		return "", fmt.Errorf("invalid IP address in add-host: %q", arr[1])
   330  	}
   331  	return val, nil
   332  }
   333  
   334  // ValidateLabel validates that the specified string is a valid label, and returns it.
   335  // Labels are in the form on key=value.
   336  func ValidateLabel(val string) (string, error) {
   337  	if strings.Count(val, "=") < 1 {
   338  		return "", fmt.Errorf("bad attribute format: %s", val)
   339  	}
   340  	return val, nil
   341  }
   342  
   343  // ValidateHost validates that the specified string is a valid host and returns it.
   344  func ValidateHost(val string) (string, error) {
   345  	_, err := parsers.ParseDockerDaemonHost(DefaultTCPHost, DefaultUnixSocket, val)
   346  	if err != nil {
   347  		return val, err
   348  	}
   349  	// Note: unlike most flag validators, we don't return the mutated value here
   350  	//       we need to know what the user entered later (using ParseHost) to adjust for tls
   351  	return val, nil
   352  }
   353  
   354  // ParseHost and set defaults for a Daemon host string
   355  func ParseHost(val string) (string, error) {
   356  	host, err := parsers.ParseDockerDaemonHost(DefaultTCPHost, DefaultUnixSocket, val)
   357  	if err != nil {
   358  		return val, err
   359  	}
   360  	return host, nil
   361  }
   362  
   363  func doesEnvExist(name string) bool {
   364  	for _, entry := range os.Environ() {
   365  		parts := strings.SplitN(entry, "=", 2)
   366  		if parts[0] == name {
   367  			return true
   368  		}
   369  	}
   370  	return false
   371  }