github.com/rawahars/moby@v24.0.4+incompatible/opts/opts.go (about) 1 package opts // import "github.com/docker/docker/opts" 2 3 import ( 4 "fmt" 5 "net" 6 "path" 7 "regexp" 8 "strings" 9 10 units "github.com/docker/go-units" 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 if len(*opts.values) == 0 { 40 return "" 41 } 42 return fmt.Sprintf("%v", *opts.values) 43 } 44 45 // Set validates if needed the input value and adds it to the 46 // internal slice. 47 func (opts *ListOpts) Set(value string) error { 48 if opts.validator != nil { 49 v, err := opts.validator(value) 50 if err != nil { 51 return err 52 } 53 value = v 54 } 55 *opts.values = append(*opts.values, value) 56 return nil 57 } 58 59 // Delete removes the specified element from the slice. 60 func (opts *ListOpts) Delete(key string) { 61 for i, k := range *opts.values { 62 if k == key { 63 *opts.values = append((*opts.values)[:i], (*opts.values)[i+1:]...) 64 return 65 } 66 } 67 } 68 69 // GetMap returns the content of values in a map in order to avoid 70 // duplicates. 71 func (opts *ListOpts) GetMap() map[string]struct{} { 72 ret := make(map[string]struct{}) 73 for _, k := range *opts.values { 74 ret[k] = struct{}{} 75 } 76 return ret 77 } 78 79 // GetAll returns the values of slice. 80 func (opts *ListOpts) GetAll() []string { 81 return *opts.values 82 } 83 84 // GetAllOrEmpty returns the values of the slice 85 // or an empty slice when there are no values. 86 func (opts *ListOpts) GetAllOrEmpty() []string { 87 v := *opts.values 88 if v == nil { 89 return make([]string, 0) 90 } 91 return v 92 } 93 94 // Get checks the existence of the specified key. 95 func (opts *ListOpts) Get(key string) bool { 96 for _, k := range *opts.values { 97 if k == key { 98 return true 99 } 100 } 101 return false 102 } 103 104 // Len returns the amount of element in the slice. 105 func (opts *ListOpts) Len() int { 106 return len(*opts.values) 107 } 108 109 // Type returns a string name for this Option type 110 func (opts *ListOpts) Type() string { 111 return "list" 112 } 113 114 // WithValidator returns the ListOpts with validator set. 115 func (opts *ListOpts) WithValidator(validator ValidatorFctType) *ListOpts { 116 opts.validator = validator 117 return opts 118 } 119 120 // NamedOption is an interface that list and map options 121 // with names implement. 122 type NamedOption interface { 123 Name() string 124 } 125 126 // NamedListOpts is a ListOpts with a configuration name. 127 // This struct is useful to keep reference to the assigned 128 // field name in the internal configuration struct. 129 type NamedListOpts struct { 130 name string 131 ListOpts 132 } 133 134 var _ NamedOption = &NamedListOpts{} 135 136 // NewNamedListOptsRef creates a reference to a new NamedListOpts struct. 137 func NewNamedListOptsRef(name string, values *[]string, validator ValidatorFctType) *NamedListOpts { 138 return &NamedListOpts{ 139 name: name, 140 ListOpts: *NewListOptsRef(values, validator), 141 } 142 } 143 144 // Name returns the name of the NamedListOpts in the configuration. 145 func (o *NamedListOpts) Name() string { 146 return o.name 147 } 148 149 // NamedMapMapOpts is a MapMapOpts with a configuration name. 150 // This struct is useful to keep reference to the assigned 151 // field name in the internal configuration struct. 152 type NamedMapMapOpts struct { 153 name string 154 MapMapOpts 155 } 156 157 // NewNamedMapMapOpts creates a reference to a new NamedMapOpts struct. 158 func NewNamedMapMapOpts(name string, values map[string]map[string]string, validator ValidatorFctType) *NamedMapMapOpts { 159 return &NamedMapMapOpts{ 160 name: name, 161 MapMapOpts: *NewMapMapOpts(values, validator), 162 } 163 } 164 165 // Name returns the name of the NamedListOpts in the configuration. 166 func (o *NamedMapMapOpts) Name() string { 167 return o.name 168 } 169 170 // MapMapOpts holds a map of maps of values and a validation function. 171 type MapMapOpts struct { 172 values map[string]map[string]string 173 validator ValidatorFctType 174 } 175 176 // Set validates if needed the input value and add it to the 177 // internal map, by splitting on '='. 178 func (opts *MapMapOpts) Set(value string) error { 179 if opts.validator != nil { 180 v, err := opts.validator(value) 181 if err != nil { 182 return err 183 } 184 value = v 185 } 186 rk, rv, found := strings.Cut(value, "=") 187 if !found { 188 return fmt.Errorf("invalid value %q for map option, should be root-key=key=value", value) 189 } 190 k, v, found := strings.Cut(rv, "=") 191 if !found { 192 return fmt.Errorf("invalid value %q for map option, should be root-key=key=value", value) 193 } 194 if _, ok := opts.values[rk]; !ok { 195 opts.values[rk] = make(map[string]string) 196 } 197 opts.values[rk][k] = v 198 return nil 199 } 200 201 // GetAll returns the values of MapOpts as a map. 202 func (opts *MapMapOpts) GetAll() map[string]map[string]string { 203 return opts.values 204 } 205 206 func (opts *MapMapOpts) String() string { 207 return fmt.Sprintf("%v", opts.values) 208 } 209 210 // Type returns a string name for this Option type 211 func (opts *MapMapOpts) Type() string { 212 return "mapmap" 213 } 214 215 // NewMapMapOpts creates a new MapMapOpts with the specified map of values and a validator. 216 func NewMapMapOpts(values map[string]map[string]string, validator ValidatorFctType) *MapMapOpts { 217 if values == nil { 218 values = make(map[string]map[string]string) 219 } 220 return &MapMapOpts{ 221 values: values, 222 validator: validator, 223 } 224 } 225 226 // MapOpts holds a map of values and a validation function. 227 type MapOpts struct { 228 values map[string]string 229 validator ValidatorFctType 230 } 231 232 // Set validates if needed the input value and add it to the 233 // internal map, by splitting on '='. 234 func (opts *MapOpts) Set(value string) error { 235 if opts.validator != nil { 236 v, err := opts.validator(value) 237 if err != nil { 238 return err 239 } 240 value = v 241 } 242 k, v, _ := strings.Cut(value, "=") 243 (opts.values)[k] = v 244 return nil 245 } 246 247 // GetAll returns the values of MapOpts as a map. 248 func (opts *MapOpts) GetAll() map[string]string { 249 return opts.values 250 } 251 252 func (opts *MapOpts) String() string { 253 return fmt.Sprintf("%v", opts.values) 254 } 255 256 // Type returns a string name for this Option type 257 func (opts *MapOpts) Type() string { 258 return "map" 259 } 260 261 // NewMapOpts creates a new MapOpts with the specified map of values and a validator. 262 func NewMapOpts(values map[string]string, validator ValidatorFctType) *MapOpts { 263 if values == nil { 264 values = make(map[string]string) 265 } 266 return &MapOpts{ 267 values: values, 268 validator: validator, 269 } 270 } 271 272 // NamedMapOpts is a MapOpts struct with a configuration name. 273 // This struct is useful to keep reference to the assigned 274 // field name in the internal configuration struct. 275 type NamedMapOpts struct { 276 name string 277 MapOpts 278 } 279 280 var _ NamedOption = &NamedMapOpts{} 281 282 // NewNamedMapOpts creates a reference to a new NamedMapOpts struct. 283 func NewNamedMapOpts(name string, values map[string]string, validator ValidatorFctType) *NamedMapOpts { 284 return &NamedMapOpts{ 285 name: name, 286 MapOpts: *NewMapOpts(values, validator), 287 } 288 } 289 290 // Name returns the name of the NamedMapOpts in the configuration. 291 func (o *NamedMapOpts) Name() string { 292 return o.name 293 } 294 295 // ValidatorFctType defines a validator function that returns a validated string and/or an error. 296 type ValidatorFctType func(val string) (string, error) 297 298 // ValidatorFctListType defines a validator function that returns a validated list of string and/or an error 299 type ValidatorFctListType func(val string) ([]string, error) 300 301 // ValidateIPAddress validates an Ip address. 302 func ValidateIPAddress(val string) (string, error) { 303 var ip = net.ParseIP(strings.TrimSpace(val)) 304 if ip != nil { 305 return ip.String(), nil 306 } 307 return "", fmt.Errorf("%s is not an ip address", val) 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 // ValidateLabel validates that the specified string is a valid label, 331 // it does not use the reserved namespaces com.docker.*, io.docker.*, org.dockerproject.* 332 // and returns it. 333 // Labels are in the form on key=value. 334 func ValidateLabel(val string) (string, error) { 335 if strings.Count(val, "=") < 1 { 336 return "", fmt.Errorf("bad attribute format: %s", val) 337 } 338 339 lowered := strings.ToLower(val) 340 if strings.HasPrefix(lowered, "com.docker.") || strings.HasPrefix(lowered, "io.docker.") || 341 strings.HasPrefix(lowered, "org.dockerproject.") { 342 return "", fmt.Errorf( 343 "label %s is not allowed: the namespaces com.docker.*, io.docker.*, and org.dockerproject.* are reserved for internal use", 344 val) 345 } 346 347 return val, nil 348 } 349 350 // ValidateSingleGenericResource validates that a single entry in the 351 // generic resource list is valid. 352 // i.e 'GPU=UID1' is valid however 'GPU:UID1' or 'UID1' isn't 353 func ValidateSingleGenericResource(val string) (string, error) { 354 if strings.Count(val, "=") < 1 { 355 return "", fmt.Errorf("invalid node-generic-resource format `%s` expected `name=value`", val) 356 } 357 return val, nil 358 } 359 360 // ParseLink parses and validates the specified string as a link format (name:alias) 361 func ParseLink(val string) (string, string, error) { 362 if val == "" { 363 return "", "", fmt.Errorf("empty string specified for links") 364 } 365 arr := strings.Split(val, ":") 366 if len(arr) > 2 { 367 return "", "", fmt.Errorf("bad format for links: %s", val) 368 } 369 if len(arr) == 1 { 370 return val, val, nil 371 } 372 // This is kept because we can actually get a HostConfig with links 373 // from an already created container and the format is not `foo:bar` 374 // but `/foo:/c1/bar` 375 if strings.HasPrefix(arr[0], "/") { 376 _, alias := path.Split(arr[1]) 377 return arr[0][1:], alias, nil 378 } 379 return arr[0], arr[1], nil 380 } 381 382 // MemBytes is a type for human readable memory bytes (like 128M, 2g, etc) 383 type MemBytes int64 384 385 // String returns the string format of the human readable memory bytes 386 func (m *MemBytes) String() string { 387 // NOTE: In spf13/pflag/flag.go, "0" is considered as "zero value" while "0 B" is not. 388 // We return "0" in case value is 0 here so that the default value is hidden. 389 // (Sometimes "default 0 B" is actually misleading) 390 if m.Value() != 0 { 391 return units.BytesSize(float64(m.Value())) 392 } 393 return "0" 394 } 395 396 // Set sets the value of the MemBytes by passing a string 397 func (m *MemBytes) Set(value string) error { 398 val, err := units.RAMInBytes(value) 399 *m = MemBytes(val) 400 return err 401 } 402 403 // Type returns the type 404 func (m *MemBytes) Type() string { 405 return "bytes" 406 } 407 408 // Value returns the value in int64 409 func (m *MemBytes) Value() int64 { 410 return int64(*m) 411 } 412 413 // UnmarshalJSON is the customized unmarshaler for MemBytes 414 func (m *MemBytes) UnmarshalJSON(s []byte) error { 415 if len(s) <= 2 || s[0] != '"' || s[len(s)-1] != '"' { 416 return fmt.Errorf("invalid size: %q", s) 417 } 418 val, err := units.RAMInBytes(string(s[1 : len(s)-1])) 419 *m = MemBytes(val) 420 return err 421 }