Signed-off-by: David Calavera <david.calavera@gmail.com>
David Calavera authored on 2016/02/03 04:33:41... | ... |
@@ -21,6 +21,15 @@ const ( |
21 | 21 |
disableNetworkBridge = "none" |
22 | 22 |
) |
23 | 23 |
|
24 |
+// flatOptions contains configuration keys |
|
25 |
+// that MUST NOT be parsed as deep structures. |
|
26 |
+// Use this to differentiate these options |
|
27 |
+// with others like the ones in CommonTLSOptions. |
|
28 |
+var flatOptions = map[string]bool{ |
|
29 |
+ "cluster-store-opts": true, |
|
30 |
+ "log-opts": true, |
|
31 |
+} |
|
32 |
+ |
|
24 | 33 |
// LogConfig represents the default log configuration. |
25 | 34 |
// It includes json tags to deserialize configuration from a file |
26 | 35 |
// using the same names that the flags in the command line uses. |
... | ... |
@@ -208,13 +217,14 @@ func getConflictFreeConfiguration(configFile string, flags *flag.FlagSet) (*Conf |
208 | 208 |
func configValuesSet(config map[string]interface{}) map[string]interface{} { |
209 | 209 |
flatten := make(map[string]interface{}) |
210 | 210 |
for k, v := range config { |
211 |
- if m, ok := v.(map[string]interface{}); ok { |
|
211 |
+ if m, isMap := v.(map[string]interface{}); isMap && !flatOptions[k] { |
|
212 | 212 |
for km, vm := range m { |
213 | 213 |
flatten[km] = vm |
214 | 214 |
} |
215 |
- } else { |
|
216 |
- flatten[k] = v |
|
215 |
+ continue |
|
217 | 216 |
} |
217 |
+ |
|
218 |
+ flatten[k] = v |
|
218 | 219 |
} |
219 | 220 |
return flatten |
220 | 221 |
} |
... | ... |
@@ -238,7 +238,7 @@ func TestLoadDaemonConfigWithEmbeddedOptions(t *testing.T) { |
238 | 238 |
t.Fatal(err) |
239 | 239 |
} |
240 | 240 |
if loadedConfig == nil { |
241 |
- t.Fatalf("expected configuration %v, got nil", c) |
|
241 |
+ t.Fatal("expected configuration, got nil") |
|
242 | 242 |
} |
243 | 243 |
if loadedConfig.CommonTLSOptions.CAFile != "/etc/certs/ca.pem" { |
244 | 244 |
t.Fatalf("expected CA file path /etc/certs/ca.pem, got %v", loadedConfig.CommonTLSOptions.CAFile) |
... | ... |
@@ -247,3 +247,47 @@ func TestLoadDaemonConfigWithEmbeddedOptions(t *testing.T) { |
247 | 247 |
t.Fatalf("expected LogConfig type syslog, got %v", loadedConfig.LogConfig.Type) |
248 | 248 |
} |
249 | 249 |
} |
250 |
+ |
|
251 |
+func TestLoadDaemonConfigWithMapOptions(t *testing.T) { |
|
252 |
+ c := &daemon.Config{} |
|
253 |
+ common := &cli.CommonFlags{} |
|
254 |
+ flags := mflag.NewFlagSet("test", mflag.ContinueOnError) |
|
255 |
+ |
|
256 |
+ flags.Var(opts.NewNamedMapOpts("cluster-store-opts", c.ClusterOpts, nil), []string{"-cluster-store-opt"}, "") |
|
257 |
+ flags.Var(opts.NewNamedMapOpts("log-opts", c.LogConfig.Config, nil), []string{"-log-opt"}, "") |
|
258 |
+ |
|
259 |
+ f, err := ioutil.TempFile("", "docker-config-") |
|
260 |
+ if err != nil { |
|
261 |
+ t.Fatal(err) |
|
262 |
+ } |
|
263 |
+ |
|
264 |
+ configFile := f.Name() |
|
265 |
+ f.Write([]byte(`{ |
|
266 |
+ "cluster-store-opts": {"kv.cacertfile": "/var/lib/docker/discovery_certs/ca.pem"}, |
|
267 |
+ "log-opts": {"tag": "test"} |
|
268 |
+}`)) |
|
269 |
+ f.Close() |
|
270 |
+ |
|
271 |
+ loadedConfig, err := loadDaemonCliConfig(c, flags, common, configFile) |
|
272 |
+ if err != nil { |
|
273 |
+ t.Fatal(err) |
|
274 |
+ } |
|
275 |
+ if loadedConfig == nil { |
|
276 |
+ t.Fatal("expected configuration, got nil") |
|
277 |
+ } |
|
278 |
+ if loadedConfig.ClusterOpts == nil { |
|
279 |
+ t.Fatal("expected cluster options, got nil") |
|
280 |
+ } |
|
281 |
+ |
|
282 |
+ expectedPath := "/var/lib/docker/discovery_certs/ca.pem" |
|
283 |
+ if caPath := loadedConfig.ClusterOpts["kv.cacertfile"]; caPath != expectedPath { |
|
284 |
+ t.Fatalf("expected %s, got %s", expectedPath, caPath) |
|
285 |
+ } |
|
286 |
+ |
|
287 |
+ if loadedConfig.LogConfig.Config == nil { |
|
288 |
+ t.Fatal("expected log config options, got nil") |
|
289 |
+ } |
|
290 |
+ if tag := loadedConfig.LogConfig.Config["tag"]; tag != "test" { |
|
291 |
+ t.Fatalf("expected log tag `test`, got %s", tag) |
|
292 |
+ } |
|
293 |
+} |