github.com/devdivbcp/moby@v17.12.0-ce-rc1.0.20200726071732-2d4bfdc789ad+incompatible/integration/config/config_test.go (about) 1 package config // import "github.com/docker/docker/integration/config" 2 3 import ( 4 "bytes" 5 "context" 6 "encoding/json" 7 "io/ioutil" 8 "path/filepath" 9 "sort" 10 "testing" 11 "time" 12 13 "github.com/docker/docker/api/types" 14 "github.com/docker/docker/api/types/filters" 15 swarmtypes "github.com/docker/docker/api/types/swarm" 16 "github.com/docker/docker/client" 17 "github.com/docker/docker/integration/internal/swarm" 18 "github.com/docker/docker/internal/test/daemon" 19 "github.com/docker/docker/pkg/stdcopy" 20 "gotest.tools/assert" 21 is "gotest.tools/assert/cmp" 22 "gotest.tools/poll" 23 "gotest.tools/skip" 24 ) 25 26 func TestConfigList(t *testing.T) { 27 skip.If(t, testEnv.DaemonInfo.OSType == "windows") 28 29 defer setupTest(t)() 30 d := swarm.NewSwarm(t, testEnv) 31 defer d.Stop(t) 32 client := d.NewClientT(t) 33 defer client.Close() 34 35 ctx := context.Background() 36 37 // This test case is ported from the original TestConfigsEmptyList 38 configs, err := client.ConfigList(ctx, types.ConfigListOptions{}) 39 assert.NilError(t, err) 40 assert.Check(t, is.Equal(len(configs), 0)) 41 42 testName0 := "test0-" + t.Name() 43 testName1 := "test1-" + t.Name() 44 testNames := []string{testName0, testName1} 45 sort.Strings(testNames) 46 47 // create config test0 48 createConfig(ctx, t, client, testName0, []byte("TESTINGDATA0"), map[string]string{"type": "test"}) 49 50 config1ID := createConfig(ctx, t, client, testName1, []byte("TESTINGDATA1"), map[string]string{"type": "production"}) 51 52 // test by `config ls` 53 entries, err := client.ConfigList(ctx, types.ConfigListOptions{}) 54 assert.NilError(t, err) 55 assert.Check(t, is.DeepEqual(configNamesFromList(entries), testNames)) 56 57 testCases := []struct { 58 filters filters.Args 59 expected []string 60 }{ 61 // test filter by name `config ls --filter name=xxx` 62 { 63 filters: filters.NewArgs(filters.Arg("name", testName0)), 64 expected: []string{testName0}, 65 }, 66 // test filter by id `config ls --filter id=xxx` 67 { 68 filters: filters.NewArgs(filters.Arg("id", config1ID)), 69 expected: []string{testName1}, 70 }, 71 // test filter by label `config ls --filter label=xxx` 72 { 73 filters: filters.NewArgs(filters.Arg("label", "type")), 74 expected: testNames, 75 }, 76 { 77 filters: filters.NewArgs(filters.Arg("label", "type=test")), 78 expected: []string{testName0}, 79 }, 80 { 81 filters: filters.NewArgs(filters.Arg("label", "type=production")), 82 expected: []string{testName1}, 83 }, 84 } 85 for _, tc := range testCases { 86 entries, err = client.ConfigList(ctx, types.ConfigListOptions{ 87 Filters: tc.filters, 88 }) 89 assert.NilError(t, err) 90 assert.Check(t, is.DeepEqual(configNamesFromList(entries), tc.expected)) 91 92 } 93 } 94 95 func createConfig(ctx context.Context, t *testing.T, client client.APIClient, name string, data []byte, labels map[string]string) string { 96 config, err := client.ConfigCreate(ctx, swarmtypes.ConfigSpec{ 97 Annotations: swarmtypes.Annotations{ 98 Name: name, 99 Labels: labels, 100 }, 101 Data: data, 102 }) 103 assert.NilError(t, err) 104 assert.Check(t, config.ID != "") 105 return config.ID 106 } 107 108 func TestConfigsCreateAndDelete(t *testing.T) { 109 skip.If(t, testEnv.DaemonInfo.OSType == "windows") 110 111 defer setupTest(t)() 112 d := swarm.NewSwarm(t, testEnv) 113 defer d.Stop(t) 114 client := d.NewClientT(t) 115 defer client.Close() 116 117 ctx := context.Background() 118 119 testName := "test_config-" + t.Name() 120 121 // This test case is ported from the original TestConfigsCreate 122 configID := createConfig(ctx, t, client, testName, []byte("TESTINGDATA"), nil) 123 124 insp, _, err := client.ConfigInspectWithRaw(ctx, configID) 125 assert.NilError(t, err) 126 assert.Check(t, is.Equal(insp.Spec.Name, testName)) 127 128 // This test case is ported from the original TestConfigsDelete 129 err = client.ConfigRemove(ctx, configID) 130 assert.NilError(t, err) 131 132 insp, _, err = client.ConfigInspectWithRaw(ctx, configID) 133 assert.Check(t, is.ErrorContains(err, "No such config")) 134 } 135 136 func TestConfigsUpdate(t *testing.T) { 137 skip.If(t, testEnv.DaemonInfo.OSType == "windows") 138 139 defer setupTest(t)() 140 d := swarm.NewSwarm(t, testEnv) 141 defer d.Stop(t) 142 client := d.NewClientT(t) 143 defer client.Close() 144 145 ctx := context.Background() 146 147 testName := "test_config-" + t.Name() 148 149 // This test case is ported from the original TestConfigsCreate 150 configID := createConfig(ctx, t, client, testName, []byte("TESTINGDATA"), nil) 151 152 insp, _, err := client.ConfigInspectWithRaw(ctx, configID) 153 assert.NilError(t, err) 154 assert.Check(t, is.Equal(insp.ID, configID)) 155 156 // test UpdateConfig with full ID 157 insp.Spec.Labels = map[string]string{"test": "test1"} 158 err = client.ConfigUpdate(ctx, configID, insp.Version, insp.Spec) 159 assert.NilError(t, err) 160 161 insp, _, err = client.ConfigInspectWithRaw(ctx, configID) 162 assert.NilError(t, err) 163 assert.Check(t, is.Equal(insp.Spec.Labels["test"], "test1")) 164 165 // test UpdateConfig with full name 166 insp.Spec.Labels = map[string]string{"test": "test2"} 167 err = client.ConfigUpdate(ctx, testName, insp.Version, insp.Spec) 168 assert.NilError(t, err) 169 170 insp, _, err = client.ConfigInspectWithRaw(ctx, configID) 171 assert.NilError(t, err) 172 assert.Check(t, is.Equal(insp.Spec.Labels["test"], "test2")) 173 174 // test UpdateConfig with prefix ID 175 insp.Spec.Labels = map[string]string{"test": "test3"} 176 err = client.ConfigUpdate(ctx, configID[:1], insp.Version, insp.Spec) 177 assert.NilError(t, err) 178 179 insp, _, err = client.ConfigInspectWithRaw(ctx, configID) 180 assert.NilError(t, err) 181 assert.Check(t, is.Equal(insp.Spec.Labels["test"], "test3")) 182 183 // test UpdateConfig in updating Data which is not supported in daemon 184 // this test will produce an error in func UpdateConfig 185 insp.Spec.Data = []byte("TESTINGDATA2") 186 err = client.ConfigUpdate(ctx, configID, insp.Version, insp.Spec) 187 assert.Check(t, is.ErrorContains(err, "only updates to Labels are allowed")) 188 } 189 190 func TestTemplatedConfig(t *testing.T) { 191 skip.If(t, testEnv.DaemonInfo.OSType == "windows") 192 d := swarm.NewSwarm(t, testEnv) 193 defer d.Stop(t) 194 client := d.NewClientT(t) 195 defer client.Close() 196 ctx := context.Background() 197 198 referencedSecretName := "referencedsecret-" + t.Name() 199 referencedSecretSpec := swarmtypes.SecretSpec{ 200 Annotations: swarmtypes.Annotations{ 201 Name: referencedSecretName, 202 }, 203 Data: []byte("this is a secret"), 204 } 205 referencedSecret, err := client.SecretCreate(ctx, referencedSecretSpec) 206 assert.Check(t, err) 207 208 referencedConfigName := "referencedconfig-" + t.Name() 209 referencedConfigSpec := swarmtypes.ConfigSpec{ 210 Annotations: swarmtypes.Annotations{ 211 Name: referencedConfigName, 212 }, 213 Data: []byte("this is a config"), 214 } 215 referencedConfig, err := client.ConfigCreate(ctx, referencedConfigSpec) 216 assert.Check(t, err) 217 218 templatedConfigName := "templated_config-" + t.Name() 219 configSpec := swarmtypes.ConfigSpec{ 220 Annotations: swarmtypes.Annotations{ 221 Name: templatedConfigName, 222 }, 223 Templating: &swarmtypes.Driver{ 224 Name: "golang", 225 }, 226 Data: []byte("SERVICE_NAME={{.Service.Name}}\n" + 227 "{{secret \"referencedsecrettarget\"}}\n" + 228 "{{config \"referencedconfigtarget\"}}\n"), 229 } 230 231 templatedConfig, err := client.ConfigCreate(ctx, configSpec) 232 assert.Check(t, err) 233 234 serviceID := swarm.CreateService(t, d, 235 swarm.ServiceWithConfig( 236 &swarmtypes.ConfigReference{ 237 File: &swarmtypes.ConfigReferenceFileTarget{ 238 Name: "/" + templatedConfigName, 239 UID: "0", 240 GID: "0", 241 Mode: 0600, 242 }, 243 ConfigID: templatedConfig.ID, 244 ConfigName: templatedConfigName, 245 }, 246 ), 247 swarm.ServiceWithConfig( 248 &swarmtypes.ConfigReference{ 249 File: &swarmtypes.ConfigReferenceFileTarget{ 250 Name: "referencedconfigtarget", 251 UID: "0", 252 GID: "0", 253 Mode: 0600, 254 }, 255 ConfigID: referencedConfig.ID, 256 ConfigName: referencedConfigName, 257 }, 258 ), 259 swarm.ServiceWithSecret( 260 &swarmtypes.SecretReference{ 261 File: &swarmtypes.SecretReferenceFileTarget{ 262 Name: "referencedsecrettarget", 263 UID: "0", 264 GID: "0", 265 Mode: 0600, 266 }, 267 SecretID: referencedSecret.ID, 268 SecretName: referencedSecretName, 269 }, 270 ), 271 swarm.ServiceWithName("svc"), 272 ) 273 274 var tasks []swarmtypes.Task 275 getRunningTasks := func(log poll.LogT) poll.Result { 276 tasks = swarm.GetRunningTasks(t, client, serviceID) 277 if len(tasks) > 0 { 278 return poll.Success() 279 } 280 return poll.Continue("task still waiting") 281 } 282 poll.WaitOn(t, getRunningTasks, swarm.ServicePoll, poll.WithTimeout(1*time.Minute)) 283 284 task := tasks[0] 285 getTask := func(log poll.LogT) poll.Result { 286 if task.NodeID == "" || (task.Status.ContainerStatus == nil || task.Status.ContainerStatus.ContainerID == "") { 287 task, _, _ = client.TaskInspectWithRaw(context.Background(), task.ID) 288 } 289 if task.NodeID != "" && task.Status.ContainerStatus != nil && task.Status.ContainerStatus.ContainerID != "" { 290 return poll.Success() 291 } 292 return poll.Continue("task still waiting") 293 } 294 poll.WaitOn(t, getTask, swarm.ServicePoll, poll.WithTimeout(1*time.Minute)) 295 296 attach := swarm.ExecTask(t, d, task, types.ExecConfig{ 297 Cmd: []string{"/bin/cat", "/" + templatedConfigName}, 298 AttachStdout: true, 299 AttachStderr: true, 300 }) 301 302 expect := "SERVICE_NAME=svc\n" + 303 "this is a secret\n" + 304 "this is a config\n" 305 assertAttachedStream(t, attach, expect) 306 307 attach = swarm.ExecTask(t, d, task, types.ExecConfig{ 308 Cmd: []string{"mount"}, 309 AttachStdout: true, 310 AttachStderr: true, 311 }) 312 assertAttachedStream(t, attach, "tmpfs on /"+templatedConfigName+" type tmpfs") 313 } 314 315 func assertAttachedStream(t *testing.T, attach types.HijackedResponse, expect string) { 316 buf := bytes.NewBuffer(nil) 317 _, err := stdcopy.StdCopy(buf, buf, attach.Reader) 318 assert.NilError(t, err) 319 assert.Check(t, is.Contains(buf.String(), expect)) 320 } 321 322 func TestConfigInspect(t *testing.T) { 323 skip.If(t, testEnv.DaemonInfo.OSType == "windows") 324 325 defer setupTest(t)() 326 d := swarm.NewSwarm(t, testEnv) 327 defer d.Stop(t) 328 client := d.NewClientT(t) 329 defer client.Close() 330 331 ctx := context.Background() 332 333 testName := t.Name() 334 configID := createConfig(ctx, t, client, testName, []byte("TESTINGDATA"), nil) 335 336 insp, body, err := client.ConfigInspectWithRaw(ctx, configID) 337 assert.NilError(t, err) 338 assert.Check(t, is.Equal(insp.Spec.Name, testName)) 339 340 var config swarmtypes.Config 341 err = json.Unmarshal(body, &config) 342 assert.NilError(t, err) 343 assert.Check(t, is.DeepEqual(config, insp)) 344 } 345 346 func TestConfigCreateWithLabels(t *testing.T) { 347 skip.If(t, testEnv.DaemonInfo.OSType != "linux") 348 349 defer setupTest(t)() 350 d := swarm.NewSwarm(t, testEnv) 351 defer d.Stop(t) 352 client := d.NewClientT(t) 353 defer client.Close() 354 355 ctx := context.Background() 356 357 labels := map[string]string{ 358 "key1": "value1", 359 "key2": "value2", 360 } 361 testName := t.Name() 362 configID := createConfig(ctx, t, client, testName, []byte("TESTINGDATA"), labels) 363 364 insp, _, err := client.ConfigInspectWithRaw(ctx, configID) 365 assert.NilError(t, err) 366 assert.Check(t, is.Equal(insp.Spec.Name, testName)) 367 assert.Check(t, is.Equal(2, len(insp.Spec.Labels))) 368 assert.Check(t, is.Equal("value1", insp.Spec.Labels["key1"])) 369 assert.Check(t, is.Equal("value2", insp.Spec.Labels["key2"])) 370 } 371 372 // Test case for 28884 373 func TestConfigCreateResolve(t *testing.T) { 374 skip.If(t, testEnv.DaemonInfo.OSType != "linux") 375 376 defer setupTest(t)() 377 d := swarm.NewSwarm(t, testEnv) 378 defer d.Stop(t) 379 client := d.NewClientT(t) 380 defer client.Close() 381 382 ctx := context.Background() 383 384 configName := "test_config_" + t.Name() 385 386 configID := createConfig(ctx, t, client, configName, []byte("foo"), nil) 387 fakeName := configID 388 fakeID := createConfig(ctx, t, client, fakeName, []byte("fake foo"), nil) 389 390 entries, err := client.ConfigList(ctx, types.ConfigListOptions{}) 391 assert.NilError(t, err) 392 assert.Assert(t, is.Contains(configNamesFromList(entries), configName)) 393 assert.Assert(t, is.Contains(configNamesFromList(entries), fakeName)) 394 395 err = client.ConfigRemove(ctx, configID) 396 assert.NilError(t, err) 397 398 // Fake one will remain 399 entries, err = client.ConfigList(ctx, types.ConfigListOptions{}) 400 assert.NilError(t, err) 401 assert.Assert(t, is.DeepEqual(configNamesFromList(entries), []string{fakeName})) 402 403 // Remove based on name prefix of the fake one 404 // (which is the same as the ID of foo one) should not work 405 // as search is only done based on: 406 // - Full ID 407 // - Full Name 408 // - Partial ID (prefix) 409 err = client.ConfigRemove(ctx, configID[:5]) 410 assert.Assert(t, nil != err) 411 entries, err = client.ConfigList(ctx, types.ConfigListOptions{}) 412 assert.NilError(t, err) 413 assert.Assert(t, is.DeepEqual(configNamesFromList(entries), []string{fakeName})) 414 415 // Remove based on ID prefix of the fake one should succeed 416 err = client.ConfigRemove(ctx, fakeID[:5]) 417 assert.NilError(t, err) 418 entries, err = client.ConfigList(ctx, types.ConfigListOptions{}) 419 assert.NilError(t, err) 420 assert.Assert(t, is.Equal(0, len(entries))) 421 } 422 423 func TestConfigDaemonLibtrustID(t *testing.T) { 424 skip.If(t, testEnv.DaemonInfo.OSType != "linux") 425 defer setupTest(t)() 426 427 d := daemon.New(t) 428 defer d.Stop(t) 429 430 trustKey := filepath.Join(d.RootDir(), "key.json") 431 err := ioutil.WriteFile(trustKey, []byte(`{"crv":"P-256","d":"dm28PH4Z4EbyUN8L0bPonAciAQa1QJmmyYd876mnypY","kid":"WTJ3:YSIP:CE2E:G6KJ:PSBD:YX2Y:WEYD:M64G:NU2V:XPZV:H2CR:VLUB","kty":"EC","x":"Mh5-JINSjaa_EZdXDttri255Z5fbCEOTQIZjAcScFTk","y":"eUyuAjfxevb07hCCpvi4Zi334Dy4GDWQvEToGEX4exQ"}`), 0644) 432 assert.NilError(t, err) 433 434 config := filepath.Join(d.RootDir(), "daemon.json") 435 err = ioutil.WriteFile(config, []byte(`{"deprecated-key-path": "`+trustKey+`"}`), 0644) 436 assert.NilError(t, err) 437 438 d.Start(t, "--config-file", config) 439 info := d.Info(t) 440 assert.Equal(t, info.ID, "WTJ3:YSIP:CE2E:G6KJ:PSBD:YX2Y:WEYD:M64G:NU2V:XPZV:H2CR:VLUB") 441 } 442 443 func configNamesFromList(entries []swarmtypes.Config) []string { 444 var values []string 445 for _, entry := range entries { 446 values = append(values, entry.Spec.Name) 447 } 448 sort.Strings(values) 449 return values 450 }