github.com/OpenFlowLabs/storage@v1.12.13/opts/opts.go (about)

     1  package opts
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  	"regexp"
     7  	"strings"
     8  
     9  	"github.com/docker/docker/api/types/filters"
    10  )
    11  
    12  var (
    13  	alphaRegexp  = regexp.MustCompile(`[a-zA-Z]`)
    14  	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*$`)
    15  )
    16  
    17  // ListOpts holds a list of values and a validation function.
    18  type ListOpts struct {
    19  	values    *[]string
    20  	validator ValidatorFctType
    21  }
    22  
    23  // NewListOpts creates a new ListOpts with the specified validator.
    24  func NewListOpts(validator ValidatorFctType) ListOpts {
    25  	var values []string
    26  	return *NewListOptsRef(&values, validator)
    27  }
    28  
    29  // NewListOptsRef creates a new ListOpts with the specified values and validator.
    30  func NewListOptsRef(values *[]string, validator ValidatorFctType) *ListOpts {
    31  	return &ListOpts{
    32  		values:    values,
    33  		validator: validator,
    34  	}
    35  }
    36  
    37  func (opts *ListOpts) String() string {
    38  	return fmt.Sprintf("%v", []string((*opts.values)))
    39  }
    40  
    41  // Set validates if needed the input value and adds it to the
    42  // internal slice.
    43  func (opts *ListOpts) Set(value string) error {
    44  	if opts.validator != nil {
    45  		v, err := opts.validator(value)
    46  		if err != nil {
    47  			return err
    48  		}
    49  		value = v
    50  	}
    51  	(*opts.values) = append((*opts.values), value)
    52  	return nil
    53  }
    54  
    55  // Delete removes the specified element from the slice.
    56  func (opts *ListOpts) Delete(key string) {
    57  	for i, k := range *opts.values {
    58  		if k == key {
    59  			(*opts.values) = append((*opts.values)[:i], (*opts.values)[i+1:]...)
    60  			return
    61  		}
    62  	}
    63  }
    64  
    65  // GetMap returns the content of values in a map in order to avoid
    66  // duplicates.
    67  func (opts *ListOpts) GetMap() map[string]struct{} {
    68  	ret := make(map[string]struct{})
    69  	for _, k := range *opts.values {
    70  		ret[k] = struct{}{}
    71  	}
    72  	return ret
    73  }
    74  
    75  // GetAll returns the values of slice.
    76  func (opts *ListOpts) GetAll() []string {
    77  	return (*opts.values)
    78  }
    79  
    80  // GetAllOrEmpty returns the values of the slice
    81  // or an empty slice when there are no values.
    82  func (opts *ListOpts) GetAllOrEmpty() []string {
    83  	v := *opts.values
    84  	if v == nil {
    85  		return make([]string, 0)
    86  	}
    87  	return v
    88  }
    89  
    90  // Get checks the existence of the specified key.
    91  func (opts *ListOpts) Get(key string) bool {
    92  	for _, k := range *opts.values {
    93  		if k == key {
    94  			return true
    95  		}
    96  	}
    97  	return false
    98  }
    99  
   100  // Len returns the amount of element in the slice.
   101  func (opts *ListOpts) Len() int {
   102  	return len((*opts.values))
   103  }
   104  
   105  // Type returns a string name for this Option type
   106  func (opts *ListOpts) Type() string {
   107  	return "list"
   108  }
   109  
   110  // NamedOption is an interface that list and map options
   111  // with names implement.
   112  type NamedOption interface {
   113  	Name() string
   114  }
   115  
   116  // NamedListOpts is a ListOpts with a configuration name.
   117  // This struct is useful to keep reference to the assigned
   118  // field name in the internal configuration struct.
   119  type NamedListOpts struct {
   120  	name string
   121  	ListOpts
   122  }
   123  
   124  var _ NamedOption = &NamedListOpts{}
   125  
   126  // NewNamedListOptsRef creates a reference to a new NamedListOpts struct.
   127  func NewNamedListOptsRef(name string, values *[]string, validator ValidatorFctType) *NamedListOpts {
   128  	return &NamedListOpts{
   129  		name:     name,
   130  		ListOpts: *NewListOptsRef(values, validator),
   131  	}
   132  }
   133  
   134  // Name returns the name of the NamedListOpts in the configuration.
   135  func (o *NamedListOpts) Name() string {
   136  	return o.name
   137  }
   138  
   139  //MapOpts holds a map of values and a validation function.
   140  type MapOpts struct {
   141  	values    map[string]string
   142  	validator ValidatorFctType
   143  }
   144  
   145  // Set validates if needed the input value and add it to the
   146  // internal map, by splitting on '='.
   147  func (opts *MapOpts) Set(value string) error {
   148  	if opts.validator != nil {
   149  		v, err := opts.validator(value)
   150  		if err != nil {
   151  			return err
   152  		}
   153  		value = v
   154  	}
   155  	vals := strings.SplitN(value, "=", 2)
   156  	if len(vals) == 1 {
   157  		(opts.values)[vals[0]] = ""
   158  	} else {
   159  		(opts.values)[vals[0]] = vals[1]
   160  	}
   161  	return nil
   162  }
   163  
   164  // GetAll returns the values of MapOpts as a map.
   165  func (opts *MapOpts) GetAll() map[string]string {
   166  	return opts.values
   167  }
   168  
   169  func (opts *MapOpts) String() string {
   170  	return fmt.Sprintf("%v", map[string]string((opts.values)))
   171  }
   172  
   173  // Type returns a string name for this Option type
   174  func (opts *MapOpts) Type() string {
   175  	return "map"
   176  }
   177  
   178  // NewMapOpts creates a new MapOpts with the specified map of values and a validator.
   179  func NewMapOpts(values map[string]string, validator ValidatorFctType) *MapOpts {
   180  	if values == nil {
   181  		values = make(map[string]string)
   182  	}
   183  	return &MapOpts{
   184  		values:    values,
   185  		validator: validator,
   186  	}
   187  }
   188  
   189  // NamedMapOpts is a MapOpts struct with a configuration name.
   190  // This struct is useful to keep reference to the assigned
   191  // field name in the internal configuration struct.
   192  type NamedMapOpts struct {
   193  	name string
   194  	MapOpts
   195  }
   196  
   197  var _ NamedOption = &NamedMapOpts{}
   198  
   199  // NewNamedMapOpts creates a reference to a new NamedMapOpts struct.
   200  func NewNamedMapOpts(name string, values map[string]string, validator ValidatorFctType) *NamedMapOpts {
   201  	return &NamedMapOpts{
   202  		name:    name,
   203  		MapOpts: *NewMapOpts(values, validator),
   204  	}
   205  }
   206  
   207  // Name returns the name of the NamedMapOpts in the configuration.
   208  func (o *NamedMapOpts) Name() string {
   209  	return o.name
   210  }
   211  
   212  // ValidatorFctType defines a validator function that returns a validated string and/or an error.
   213  type ValidatorFctType func(val string) (string, error)
   214  
   215  // ValidatorFctListType defines a validator function that returns a validated list of string and/or an error
   216  type ValidatorFctListType func(val string) ([]string, error)
   217  
   218  // ValidateIPAddress validates an Ip address.
   219  func ValidateIPAddress(val string) (string, error) {
   220  	var ip = net.ParseIP(strings.TrimSpace(val))
   221  	if ip != nil {
   222  		return ip.String(), nil
   223  	}
   224  	return "", fmt.Errorf("%s is not an ip address", val)
   225  }
   226  
   227  // ValidateDNSSearch validates domain for resolvconf search configuration.
   228  // A zero length domain is represented by a dot (.).
   229  func ValidateDNSSearch(val string) (string, error) {
   230  	if val = strings.Trim(val, " "); val == "." {
   231  		return val, nil
   232  	}
   233  	return validateDomain(val)
   234  }
   235  
   236  func validateDomain(val string) (string, error) {
   237  	if alphaRegexp.FindString(val) == "" {
   238  		return "", fmt.Errorf("%s is not a valid domain", val)
   239  	}
   240  	ns := domainRegexp.FindSubmatch([]byte(val))
   241  	if len(ns) > 0 && len(ns[1]) < 255 {
   242  		return string(ns[1]), nil
   243  	}
   244  	return "", fmt.Errorf("%s is not a valid domain", val)
   245  }
   246  
   247  // ValidateLabel validates that the specified string is a valid label, and returns it.
   248  // Labels are in the form on key=value.
   249  func ValidateLabel(val string) (string, error) {
   250  	if strings.Count(val, "=") < 1 {
   251  		return "", fmt.Errorf("bad attribute format: %s", val)
   252  	}
   253  	return val, nil
   254  }
   255  
   256  // ValidateSysctl validates a sysctl and returns it.
   257  func ValidateSysctl(val string) (string, error) {
   258  	validSysctlMap := map[string]bool{
   259  		"kernel.msgmax":          true,
   260  		"kernel.msgmnb":          true,
   261  		"kernel.msgmni":          true,
   262  		"kernel.sem":             true,
   263  		"kernel.shmall":          true,
   264  		"kernel.shmmax":          true,
   265  		"kernel.shmmni":          true,
   266  		"kernel.shm_rmid_forced": true,
   267  	}
   268  	validSysctlPrefixes := []string{
   269  		"net.",
   270  		"fs.mqueue.",
   271  	}
   272  	arr := strings.Split(val, "=")
   273  	if len(arr) < 2 {
   274  		return "", fmt.Errorf("sysctl '%s' is not whitelisted", val)
   275  	}
   276  	if validSysctlMap[arr[0]] {
   277  		return val, nil
   278  	}
   279  
   280  	for _, vp := range validSysctlPrefixes {
   281  		if strings.HasPrefix(arr[0], vp) {
   282  			return val, nil
   283  		}
   284  	}
   285  	return "", fmt.Errorf("sysctl '%s' is not whitelisted", val)
   286  }
   287  
   288  // FilterOpt is a flag type for validating filters
   289  type FilterOpt struct {
   290  	filter filters.Args
   291  }
   292  
   293  // NewFilterOpt returns a new FilterOpt
   294  func NewFilterOpt() FilterOpt {
   295  	return FilterOpt{filter: filters.NewArgs()}
   296  }
   297  
   298  func (o *FilterOpt) String() string {
   299  	repr, err := filters.ToParam(o.filter)
   300  	if err != nil {
   301  		return "invalid filters"
   302  	}
   303  	return repr
   304  }
   305  
   306  // Set sets the value of the opt by parsing the command line value
   307  func (o *FilterOpt) Set(value string) error {
   308  	var err error
   309  	o.filter, err = filters.ParseFlag(value, o.filter)
   310  	return err
   311  }
   312  
   313  // Type returns the option type
   314  func (o *FilterOpt) Type() string {
   315  	return "filter"
   316  }
   317  
   318  // Value returns the value of this option
   319  func (o *FilterOpt) Value() filters.Args {
   320  	return o.filter
   321  }