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