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