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