]>
Commit | Line | Data |
---|---|---|
9b12e4fe JC |
1 | package opts |
2 | ||
3 | import ( | |
4 | "fmt" | |
5 | "net" | |
6 | "os" | |
7 | "regexp" | |
8 | "strings" | |
9 | ) | |
10 | ||
11 | var ( | |
12 | alphaRegexp = regexp.MustCompile(`[a-zA-Z]`) | |
13 | 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*$`) | |
14 | ) | |
15 | ||
16 | // ListOpts holds a list of values and a validation function. | |
17 | type ListOpts struct { | |
18 | values *[]string | |
19 | validator ValidatorFctType | |
20 | } | |
21 | ||
22 | // NewListOpts creates a new ListOpts with the specified validator. | |
23 | func NewListOpts(validator ValidatorFctType) ListOpts { | |
24 | var values []string | |
25 | return *NewListOptsRef(&values, validator) | |
26 | } | |
27 | ||
28 | // NewListOptsRef creates a new ListOpts with the specified values and validator. | |
29 | func NewListOptsRef(values *[]string, validator ValidatorFctType) *ListOpts { | |
30 | return &ListOpts{ | |
31 | values: values, | |
32 | validator: validator, | |
33 | } | |
34 | } | |
35 | ||
36 | func (opts *ListOpts) String() string { | |
37 | return fmt.Sprintf("%v", []string((*opts.values))) | |
38 | } | |
39 | ||
40 | // Set validates if needed the input value and add it to the | |
41 | // internal slice. | |
42 | func (opts *ListOpts) Set(value string) error { | |
43 | if opts.validator != nil { | |
44 | v, err := opts.validator(value) | |
45 | if err != nil { | |
46 | return err | |
47 | } | |
48 | value = v | |
49 | } | |
50 | (*opts.values) = append((*opts.values), value) | |
51 | return nil | |
52 | } | |
53 | ||
54 | // Delete removes the specified element from the slice. | |
55 | func (opts *ListOpts) Delete(key string) { | |
56 | for i, k := range *opts.values { | |
57 | if k == key { | |
58 | (*opts.values) = append((*opts.values)[:i], (*opts.values)[i+1:]...) | |
59 | return | |
60 | } | |
61 | } | |
62 | } | |
63 | ||
64 | // GetMap returns the content of values in a map in order to avoid | |
65 | // duplicates. | |
66 | func (opts *ListOpts) GetMap() map[string]struct{} { | |
67 | ret := make(map[string]struct{}) | |
68 | for _, k := range *opts.values { | |
69 | ret[k] = struct{}{} | |
70 | } | |
71 | return ret | |
72 | } | |
73 | ||
74 | // GetAll returns the values of slice. | |
75 | func (opts *ListOpts) GetAll() []string { | |
76 | return (*opts.values) | |
77 | } | |
78 | ||
79 | // GetAllOrEmpty returns the values of the slice | |
80 | // or an empty slice when there are no values. | |
81 | func (opts *ListOpts) GetAllOrEmpty() []string { | |
82 | v := *opts.values | |
83 | if v == nil { | |
84 | return make([]string, 0) | |
85 | } | |
86 | return v | |
87 | } | |
88 | ||
89 | // Get checks the existence of the specified key. | |
90 | func (opts *ListOpts) Get(key string) bool { | |
91 | for _, k := range *opts.values { | |
92 | if k == key { | |
93 | return true | |
94 | } | |
95 | } | |
96 | return false | |
97 | } | |
98 | ||
99 | // Len returns the amount of element in the slice. | |
100 | func (opts *ListOpts) Len() int { | |
101 | return len((*opts.values)) | |
102 | } | |
103 | ||
104 | //MapOpts holds a map of values and a validation function. | |
105 | type MapOpts struct { | |
106 | values map[string]string | |
107 | validator ValidatorFctType | |
108 | } | |
109 | ||
110 | // Set validates if needed the input value and add it to the | |
111 | // internal map, by splitting on '='. | |
112 | func (opts *MapOpts) Set(value string) error { | |
113 | if opts.validator != nil { | |
114 | v, err := opts.validator(value) | |
115 | if err != nil { | |
116 | return err | |
117 | } | |
118 | value = v | |
119 | } | |
120 | vals := strings.SplitN(value, "=", 2) | |
121 | if len(vals) == 1 { | |
122 | (opts.values)[vals[0]] = "" | |
123 | } else { | |
124 | (opts.values)[vals[0]] = vals[1] | |
125 | } | |
126 | return nil | |
127 | } | |
128 | ||
129 | // GetAll returns the values of MapOpts as a map. | |
130 | func (opts *MapOpts) GetAll() map[string]string { | |
131 | return opts.values | |
132 | } | |
133 | ||
134 | func (opts *MapOpts) String() string { | |
135 | return fmt.Sprintf("%v", map[string]string((opts.values))) | |
136 | } | |
137 | ||
138 | // NewMapOpts creates a new MapOpts with the specified map of values and a validator. | |
139 | func NewMapOpts(values map[string]string, validator ValidatorFctType) *MapOpts { | |
140 | if values == nil { | |
141 | values = make(map[string]string) | |
142 | } | |
143 | return &MapOpts{ | |
144 | values: values, | |
145 | validator: validator, | |
146 | } | |
147 | } | |
148 | ||
149 | // ValidatorFctType defines a validator function that returns a validated string and/or an error. | |
150 | type ValidatorFctType func(val string) (string, error) | |
151 | ||
152 | // ValidatorFctListType defines a validator function that returns a validated list of string and/or an error | |
153 | type ValidatorFctListType func(val string) ([]string, error) | |
154 | ||
155 | // ValidateAttach validates that the specified string is a valid attach option. | |
156 | func ValidateAttach(val string) (string, error) { | |
157 | s := strings.ToLower(val) | |
158 | for _, str := range []string{"stdin", "stdout", "stderr"} { | |
159 | if s == str { | |
160 | return s, nil | |
161 | } | |
162 | } | |
163 | return val, fmt.Errorf("valid streams are STDIN, STDOUT and STDERR") | |
164 | } | |
165 | ||
166 | // ValidateEnv validates an environment variable and returns it. | |
167 | // If no value is specified, it returns the current value using os.Getenv. | |
168 | // | |
169 | // As on ParseEnvFile and related to #16585, environment variable names | |
170 | // are not validate what so ever, it's up to application inside docker | |
171 | // to validate them or not. | |
172 | func ValidateEnv(val string) (string, error) { | |
173 | arr := strings.Split(val, "=") | |
174 | if len(arr) > 1 { | |
175 | return val, nil | |
176 | } | |
177 | if !doesEnvExist(val) { | |
178 | return val, nil | |
179 | } | |
180 | return fmt.Sprintf("%s=%s", val, os.Getenv(val)), nil | |
181 | } | |
182 | ||
183 | // ValidateIPAddress validates an Ip address. | |
184 | func ValidateIPAddress(val string) (string, error) { | |
185 | var ip = net.ParseIP(strings.TrimSpace(val)) | |
186 | if ip != nil { | |
187 | return ip.String(), nil | |
188 | } | |
189 | return "", fmt.Errorf("%s is not an ip address", val) | |
190 | } | |
191 | ||
192 | // ValidateMACAddress validates a MAC address. | |
193 | func ValidateMACAddress(val string) (string, error) { | |
194 | _, err := net.ParseMAC(strings.TrimSpace(val)) | |
195 | if err != nil { | |
196 | return "", err | |
197 | } | |
198 | return val, nil | |
199 | } | |
200 | ||
201 | // ValidateDNSSearch validates domain for resolvconf search configuration. | |
202 | // A zero length domain is represented by a dot (.). | |
203 | func ValidateDNSSearch(val string) (string, error) { | |
204 | if val = strings.Trim(val, " "); val == "." { | |
205 | return val, nil | |
206 | } | |
207 | return validateDomain(val) | |
208 | } | |
209 | ||
210 | func validateDomain(val string) (string, error) { | |
211 | if alphaRegexp.FindString(val) == "" { | |
212 | return "", fmt.Errorf("%s is not a valid domain", val) | |
213 | } | |
214 | ns := domainRegexp.FindSubmatch([]byte(val)) | |
215 | if len(ns) > 0 && len(ns[1]) < 255 { | |
216 | return string(ns[1]), nil | |
217 | } | |
218 | return "", fmt.Errorf("%s is not a valid domain", val) | |
219 | } | |
220 | ||
221 | // ValidateExtraHost validates that the specified string is a valid extrahost and returns it. | |
222 | // ExtraHost are in the form of name:ip where the ip has to be a valid ip (ipv4 or ipv6). | |
223 | func ValidateExtraHost(val string) (string, error) { | |
224 | // allow for IPv6 addresses in extra hosts by only splitting on first ":" | |
225 | arr := strings.SplitN(val, ":", 2) | |
226 | if len(arr) != 2 || len(arr[0]) == 0 { | |
227 | return "", fmt.Errorf("bad format for add-host: %q", val) | |
228 | } | |
229 | if _, err := ValidateIPAddress(arr[1]); err != nil { | |
230 | return "", fmt.Errorf("invalid IP address in add-host: %q", arr[1]) | |
231 | } | |
232 | return val, nil | |
233 | } | |
234 | ||
235 | // ValidateLabel validates that the specified string is a valid label, and returns it. | |
236 | // Labels are in the form on key=value. | |
237 | func ValidateLabel(val string) (string, error) { | |
238 | if strings.Count(val, "=") < 1 { | |
239 | return "", fmt.Errorf("bad attribute format: %s", val) | |
240 | } | |
241 | return val, nil | |
242 | } | |
243 | ||
244 | func doesEnvExist(name string) bool { | |
245 | for _, entry := range os.Environ() { | |
246 | parts := strings.SplitN(entry, "=", 2) | |
247 | if parts[0] == name { | |
248 | return true | |
249 | } | |
250 | } | |
251 | return false | |
252 | } |