github.com/jogo/docker@v1.7.0-rc1/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 ) 15 16 var ( 17 alphaRegexp = regexp.MustCompile(`[a-zA-Z]`) 18 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*$`) 19 DefaultHTTPHost = "127.0.0.1" // Default HTTP Host used if only port is provided to -H flag e.g. docker -d -H tcp://:8080 20 // TODO Windows. DefaultHTTPPort is only used on Windows if a -H parameter 21 // is not supplied. A better longer term solution would be to use a named 22 // pipe as the default on the Windows daemon. 23 DefaultHTTPPort = 2375 // Default HTTP Port 24 DefaultUnixSocket = "/var/run/docker.sock" // Docker daemon by default always listens on the default unix socket 25 ) 26 27 func ListVar(values *[]string, names []string, usage string) { 28 flag.Var(newListOptsRef(values, nil), names, usage) 29 } 30 31 func MapVar(values map[string]string, names []string, usage string) { 32 flag.Var(newMapOpt(values, nil), names, usage) 33 } 34 35 func LogOptsVar(values map[string]string, names []string, usage string) { 36 flag.Var(newMapOpt(values, ValidateLogOpts), names, usage) 37 } 38 39 func HostListVar(values *[]string, names []string, usage string) { 40 flag.Var(newListOptsRef(values, ValidateHost), names, usage) 41 } 42 43 func IPListVar(values *[]string, names []string, usage string) { 44 flag.Var(newListOptsRef(values, ValidateIPAddress), names, usage) 45 } 46 47 func DnsSearchListVar(values *[]string, names []string, usage string) { 48 flag.Var(newListOptsRef(values, ValidateDnsSearch), names, usage) 49 } 50 51 func IPVar(value *net.IP, names []string, defaultValue, usage string) { 52 flag.Var(NewIpOpt(value, defaultValue), names, usage) 53 } 54 55 func LabelListVar(values *[]string, names []string, usage string) { 56 flag.Var(newListOptsRef(values, ValidateLabel), names, usage) 57 } 58 59 func UlimitMapVar(values map[string]*ulimit.Ulimit, names []string, usage string) { 60 flag.Var(NewUlimitOpt(values), names, usage) 61 } 62 63 // ListOpts type 64 type ListOpts struct { 65 values *[]string 66 validator ValidatorFctType 67 } 68 69 func NewListOpts(validator ValidatorFctType) ListOpts { 70 var values []string 71 return *newListOptsRef(&values, validator) 72 } 73 74 func newListOptsRef(values *[]string, validator ValidatorFctType) *ListOpts { 75 return &ListOpts{ 76 values: values, 77 validator: validator, 78 } 79 } 80 81 func (opts *ListOpts) String() string { 82 return fmt.Sprintf("%v", []string((*opts.values))) 83 } 84 85 // Set validates if needed the input value and add it to the 86 // internal slice. 87 func (opts *ListOpts) Set(value string) error { 88 if opts.validator != nil { 89 v, err := opts.validator(value) 90 if err != nil { 91 return err 92 } 93 value = v 94 } 95 (*opts.values) = append((*opts.values), value) 96 return nil 97 } 98 99 // Delete remove the given element from the slice. 100 func (opts *ListOpts) Delete(key string) { 101 for i, k := range *opts.values { 102 if k == key { 103 (*opts.values) = append((*opts.values)[:i], (*opts.values)[i+1:]...) 104 return 105 } 106 } 107 } 108 109 // GetMap returns the content of values in a map in order to avoid 110 // duplicates. 111 // FIXME: can we remove this? 112 func (opts *ListOpts) GetMap() map[string]struct{} { 113 ret := make(map[string]struct{}) 114 for _, k := range *opts.values { 115 ret[k] = struct{}{} 116 } 117 return ret 118 } 119 120 // GetAll returns the values' slice. 121 // FIXME: Can we remove this? 122 func (opts *ListOpts) GetAll() []string { 123 return (*opts.values) 124 } 125 126 // Get checks the existence of the given key. 127 func (opts *ListOpts) Get(key string) bool { 128 for _, k := range *opts.values { 129 if k == key { 130 return true 131 } 132 } 133 return false 134 } 135 136 // Len returns the amount of element in the slice. 137 func (opts *ListOpts) Len() int { 138 return len((*opts.values)) 139 } 140 141 //MapOpts type 142 type MapOpts struct { 143 values map[string]string 144 validator ValidatorFctType 145 } 146 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 func (opts *MapOpts) String() string { 165 return fmt.Sprintf("%v", map[string]string((opts.values))) 166 } 167 168 func newMapOpt(values map[string]string, validator ValidatorFctType) *MapOpts { 169 return &MapOpts{ 170 values: values, 171 validator: validator, 172 } 173 } 174 175 // Validators 176 type ValidatorFctType func(val string) (string, error) 177 type ValidatorFctListType func(val string) ([]string, error) 178 179 func ValidateLogOpts(val string) (string, error) { 180 allowedKeys := map[string]string{} 181 vals := strings.Split(val, "=") 182 if allowedKeys[vals[0]] != "" { 183 return val, nil 184 } 185 return "", fmt.Errorf("%s is not a valid log opt", vals[0]) 186 } 187 188 func ValidateAttach(val string) (string, error) { 189 s := strings.ToLower(val) 190 for _, str := range []string{"stdin", "stdout", "stderr"} { 191 if s == str { 192 return s, nil 193 } 194 } 195 return val, fmt.Errorf("valid streams are STDIN, STDOUT and STDERR.") 196 } 197 198 func ValidateLink(val string) (string, error) { 199 if _, _, err := parsers.ParseLink(val); err != nil { 200 return val, err 201 } 202 return val, nil 203 } 204 205 func ValidatePath(val string) (string, error) { 206 var containerPath string 207 208 if strings.Count(val, ":") > 2 { 209 return val, fmt.Errorf("bad format for volumes: %s", val) 210 } 211 212 splited := strings.SplitN(val, ":", 2) 213 if len(splited) == 1 { 214 containerPath = splited[0] 215 val = path.Clean(splited[0]) 216 } else { 217 containerPath = splited[1] 218 val = fmt.Sprintf("%s:%s", splited[0], path.Clean(splited[1])) 219 } 220 221 if !path.IsAbs(containerPath) { 222 return val, fmt.Errorf("%s is not an absolute path", containerPath) 223 } 224 return val, nil 225 } 226 227 func ValidateEnv(val string) (string, error) { 228 arr := strings.Split(val, "=") 229 if len(arr) > 1 { 230 return val, nil 231 } 232 if !doesEnvExist(val) { 233 return val, nil 234 } 235 return fmt.Sprintf("%s=%s", val, os.Getenv(val)), nil 236 } 237 238 func ValidateIPAddress(val string) (string, error) { 239 var ip = net.ParseIP(strings.TrimSpace(val)) 240 if ip != nil { 241 return ip.String(), nil 242 } 243 return "", fmt.Errorf("%s is not an ip address", val) 244 } 245 246 func ValidateMACAddress(val string) (string, error) { 247 _, err := net.ParseMAC(strings.TrimSpace(val)) 248 if err != nil { 249 return "", err 250 } 251 return val, nil 252 } 253 254 // Validates domain for resolvconf search configuration. 255 // A zero length domain is represented by . 256 func ValidateDnsSearch(val string) (string, error) { 257 if val = strings.Trim(val, " "); val == "." { 258 return val, nil 259 } 260 return validateDomain(val) 261 } 262 263 func validateDomain(val string) (string, error) { 264 if alphaRegexp.FindString(val) == "" { 265 return "", fmt.Errorf("%s is not a valid domain", val) 266 } 267 ns := domainRegexp.FindSubmatch([]byte(val)) 268 if len(ns) > 0 && len(ns[1]) < 255 { 269 return string(ns[1]), nil 270 } 271 return "", fmt.Errorf("%s is not a valid domain", val) 272 } 273 274 func ValidateExtraHost(val string) (string, error) { 275 // allow for IPv6 addresses in extra hosts by only splitting on first ":" 276 arr := strings.SplitN(val, ":", 2) 277 if len(arr) != 2 || len(arr[0]) == 0 { 278 return "", fmt.Errorf("bad format for add-host: %q", val) 279 } 280 if _, err := ValidateIPAddress(arr[1]); err != nil { 281 return "", fmt.Errorf("invalid IP address in add-host: %q", arr[1]) 282 } 283 return val, nil 284 } 285 286 func ValidateLabel(val string) (string, error) { 287 if strings.Count(val, "=") != 1 { 288 return "", fmt.Errorf("bad attribute format: %s", val) 289 } 290 return val, nil 291 } 292 293 func ValidateHost(val string) (string, error) { 294 host, err := parsers.ParseHost(DefaultHTTPHost, DefaultUnixSocket, val) 295 if err != nil { 296 return val, err 297 } 298 return host, nil 299 } 300 301 func doesEnvExist(name string) bool { 302 for _, entry := range os.Environ() { 303 parts := strings.SplitN(entry, "=", 2) 304 if parts[0] == name { 305 return true 306 } 307 } 308 return false 309 }