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