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