github.com/akashshinde/docker@v1.9.1/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 = "localhost"
    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  // GetAllOrEmpty returns the values of the slice
   105  // or an empty slice when there are no values.
   106  func (opts *ListOpts) GetAllOrEmpty() []string {
   107  	v := *opts.values
   108  	if v == nil {
   109  		return make([]string, 0)
   110  	}
   111  	return v
   112  }
   113  
   114  // Get checks the existence of the specified key.
   115  func (opts *ListOpts) Get(key string) bool {
   116  	for _, k := range *opts.values {
   117  		if k == key {
   118  			return true
   119  		}
   120  	}
   121  	return false
   122  }
   123  
   124  // Len returns the amount of element in the slice.
   125  func (opts *ListOpts) Len() int {
   126  	return len((*opts.values))
   127  }
   128  
   129  //MapOpts holds a map of values and a validation function.
   130  type MapOpts struct {
   131  	values    map[string]string
   132  	validator ValidatorFctType
   133  }
   134  
   135  // Set validates if needed the input value and add it to the
   136  // internal map, by splitting on '='.
   137  func (opts *MapOpts) Set(value string) error {
   138  	if opts.validator != nil {
   139  		v, err := opts.validator(value)
   140  		if err != nil {
   141  			return err
   142  		}
   143  		value = v
   144  	}
   145  	vals := strings.SplitN(value, "=", 2)
   146  	if len(vals) == 1 {
   147  		(opts.values)[vals[0]] = ""
   148  	} else {
   149  		(opts.values)[vals[0]] = vals[1]
   150  	}
   151  	return nil
   152  }
   153  
   154  // GetAll returns the values of MapOpts as a map.
   155  func (opts *MapOpts) GetAll() map[string]string {
   156  	return opts.values
   157  }
   158  
   159  func (opts *MapOpts) String() string {
   160  	return fmt.Sprintf("%v", map[string]string((opts.values)))
   161  }
   162  
   163  // NewMapOpts creates a new MapOpts with the specified map of values and a validator.
   164  func NewMapOpts(values map[string]string, validator ValidatorFctType) *MapOpts {
   165  	if values == nil {
   166  		values = make(map[string]string)
   167  	}
   168  	return &MapOpts{
   169  		values:    values,
   170  		validator: validator,
   171  	}
   172  }
   173  
   174  // ValidatorFctType defines a validator function that returns a validated string and/or an error.
   175  type ValidatorFctType func(val string) (string, error)
   176  
   177  // ValidatorFctListType defines a validator function that returns a validated list of string and/or an error
   178  type ValidatorFctListType func(val string) ([]string, error)
   179  
   180  // ValidateAttach validates that the specified string is a valid attach option.
   181  func ValidateAttach(val string) (string, error) {
   182  	s := strings.ToLower(val)
   183  	for _, str := range []string{"stdin", "stdout", "stderr"} {
   184  		if s == str {
   185  			return s, nil
   186  		}
   187  	}
   188  	return val, fmt.Errorf("valid streams are STDIN, STDOUT and STDERR")
   189  }
   190  
   191  // ValidateLink validates that the specified string has a valid link format (containerName:alias).
   192  func ValidateLink(val string) (string, error) {
   193  	if _, _, err := parsers.ParseLink(val); err != nil {
   194  		return val, err
   195  	}
   196  	return val, nil
   197  }
   198  
   199  // ValidDeviceMode checks if the mode for device is valid or not.
   200  // Valid mode is a composition of r (read), w (write), and m (mknod).
   201  func ValidDeviceMode(mode string) bool {
   202  	var legalDeviceMode = map[rune]bool{
   203  		'r': true,
   204  		'w': true,
   205  		'm': true,
   206  	}
   207  	if mode == "" {
   208  		return false
   209  	}
   210  	for _, c := range mode {
   211  		if !legalDeviceMode[c] {
   212  			return false
   213  		}
   214  		legalDeviceMode[c] = false
   215  	}
   216  	return true
   217  }
   218  
   219  // ValidateDevice validates a path for devices
   220  // It will make sure 'val' is in the form:
   221  //    [host-dir:]container-path[:mode]
   222  // It also validates the device mode.
   223  func ValidateDevice(val string) (string, error) {
   224  	return validatePath(val, ValidDeviceMode)
   225  }
   226  
   227  // ValidatePath validates a path for volumes
   228  // It will make sure 'val' is in the form:
   229  //    [host-dir:]container-path[:rw|ro]
   230  // It also validates the mount mode.
   231  func ValidatePath(val string) (string, error) {
   232  	return validatePath(val, volume.ValidMountMode)
   233  }
   234  
   235  func validatePath(val string, validator func(string) bool) (string, error) {
   236  	var containerPath string
   237  	var mode string
   238  
   239  	if strings.Count(val, ":") > 2 {
   240  		return val, fmt.Errorf("bad format for path: %s", val)
   241  	}
   242  
   243  	split := strings.SplitN(val, ":", 3)
   244  	if split[0] == "" {
   245  		return val, fmt.Errorf("bad format for path: %s", val)
   246  	}
   247  	switch len(split) {
   248  	case 1:
   249  		containerPath = split[0]
   250  		val = path.Clean(containerPath)
   251  	case 2:
   252  		if isValid := validator(split[1]); isValid {
   253  			containerPath = split[0]
   254  			mode = split[1]
   255  			val = fmt.Sprintf("%s:%s", path.Clean(containerPath), mode)
   256  		} else {
   257  			containerPath = split[1]
   258  			val = fmt.Sprintf("%s:%s", split[0], path.Clean(containerPath))
   259  		}
   260  	case 3:
   261  		containerPath = split[1]
   262  		mode = split[2]
   263  		if isValid := validator(split[2]); !isValid {
   264  			return val, fmt.Errorf("bad mode specified: %s", mode)
   265  		}
   266  		val = fmt.Sprintf("%s:%s:%s", split[0], containerPath, mode)
   267  	}
   268  
   269  	if !path.IsAbs(containerPath) {
   270  		return val, fmt.Errorf("%s is not an absolute path", containerPath)
   271  	}
   272  	return val, nil
   273  }
   274  
   275  // ValidateEnv validates an environment variable and returns it.
   276  // If no value is specified, it returns the current value using os.Getenv.
   277  //
   278  // As on ParseEnvFile and related to #16585, environment variable names
   279  // are not validate what so ever, it's up to application inside docker
   280  // to validate them or not.
   281  func ValidateEnv(val string) (string, error) {
   282  	arr := strings.Split(val, "=")
   283  	if len(arr) > 1 {
   284  		return val, nil
   285  	}
   286  	if !doesEnvExist(val) {
   287  		return val, nil
   288  	}
   289  	return fmt.Sprintf("%s=%s", val, os.Getenv(val)), nil
   290  }
   291  
   292  // ValidateIPAddress validates an Ip address.
   293  func ValidateIPAddress(val string) (string, error) {
   294  	var ip = net.ParseIP(strings.TrimSpace(val))
   295  	if ip != nil {
   296  		return ip.String(), nil
   297  	}
   298  	return "", fmt.Errorf("%s is not an ip address", val)
   299  }
   300  
   301  // ValidateMACAddress validates a MAC address.
   302  func ValidateMACAddress(val string) (string, error) {
   303  	_, err := net.ParseMAC(strings.TrimSpace(val))
   304  	if err != nil {
   305  		return "", err
   306  	}
   307  	return val, nil
   308  }
   309  
   310  // ValidateDNSSearch validates domain for resolvconf search configuration.
   311  // A zero length domain is represented by a dot (.).
   312  func ValidateDNSSearch(val string) (string, error) {
   313  	if val = strings.Trim(val, " "); val == "." {
   314  		return val, nil
   315  	}
   316  	return validateDomain(val)
   317  }
   318  
   319  func validateDomain(val string) (string, error) {
   320  	if alphaRegexp.FindString(val) == "" {
   321  		return "", fmt.Errorf("%s is not a valid domain", val)
   322  	}
   323  	ns := domainRegexp.FindSubmatch([]byte(val))
   324  	if len(ns) > 0 && len(ns[1]) < 255 {
   325  		return string(ns[1]), nil
   326  	}
   327  	return "", fmt.Errorf("%s is not a valid domain", val)
   328  }
   329  
   330  // ValidateExtraHost validates that the specified string is a valid extrahost and returns it.
   331  // ExtraHost are in the form of name:ip where the ip has to be a valid ip (ipv4 or ipv6).
   332  func ValidateExtraHost(val string) (string, error) {
   333  	// allow for IPv6 addresses in extra hosts by only splitting on first ":"
   334  	arr := strings.SplitN(val, ":", 2)
   335  	if len(arr) != 2 || len(arr[0]) == 0 {
   336  		return "", fmt.Errorf("bad format for add-host: %q", val)
   337  	}
   338  	if _, err := ValidateIPAddress(arr[1]); err != nil {
   339  		return "", fmt.Errorf("invalid IP address in add-host: %q", arr[1])
   340  	}
   341  	return val, nil
   342  }
   343  
   344  // ValidateLabel validates that the specified string is a valid label, and returns it.
   345  // Labels are in the form on key=value.
   346  func ValidateLabel(val string) (string, error) {
   347  	if strings.Count(val, "=") < 1 {
   348  		return "", fmt.Errorf("bad attribute format: %s", val)
   349  	}
   350  	return val, nil
   351  }
   352  
   353  // ValidateHost validates that the specified string is a valid host and returns it.
   354  func ValidateHost(val string) (string, error) {
   355  	_, err := parsers.ParseDockerDaemonHost(DefaultTCPHost, DefaultTLSHost, DefaultUnixSocket, "", val)
   356  	if err != nil {
   357  		return val, err
   358  	}
   359  	// Note: unlike most flag validators, we don't return the mutated value here
   360  	//       we need to know what the user entered later (using ParseHost) to adjust for tls
   361  	return val, nil
   362  }
   363  
   364  // ParseHost and set defaults for a Daemon host string
   365  func ParseHost(defaultHost, val string) (string, error) {
   366  	host, err := parsers.ParseDockerDaemonHost(DefaultTCPHost, DefaultTLSHost, DefaultUnixSocket, defaultHost, val)
   367  	if err != nil {
   368  		return val, err
   369  	}
   370  	return host, nil
   371  }
   372  
   373  func doesEnvExist(name string) bool {
   374  	for _, entry := range os.Environ() {
   375  		parts := strings.SplitN(entry, "=", 2)
   376  		if parts[0] == name {
   377  			return true
   378  		}
   379  	}
   380  	return false
   381  }