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