github.com/jwhonce/docker@v0.6.7-0.20190327063223-da823cf3a5a3/integration/secret/secret_test.go (about) 1 package secret // import "github.com/docker/docker/integration/secret" 2 3 import ( 4 "bytes" 5 "context" 6 "sort" 7 "testing" 8 "time" 9 10 "github.com/docker/docker/api/types" 11 "github.com/docker/docker/api/types/filters" 12 swarmtypes "github.com/docker/docker/api/types/swarm" 13 "github.com/docker/docker/client" 14 "github.com/docker/docker/integration/internal/swarm" 15 "github.com/docker/docker/pkg/stdcopy" 16 "gotest.tools/assert" 17 is "gotest.tools/assert/cmp" 18 "gotest.tools/skip" 19 ) 20 21 func TestSecretInspect(t *testing.T) { 22 skip.If(t, testEnv.DaemonInfo.OSType == "windows") 23 24 defer setupTest(t)() 25 d := swarm.NewSwarm(t, testEnv) 26 defer d.Stop(t) 27 client := d.NewClientT(t) 28 defer client.Close() 29 30 ctx := context.Background() 31 32 testName := "test_secret_" + t.Name() 33 secretID := createSecret(ctx, t, client, testName, []byte("TESTINGDATA"), nil) 34 35 secret, _, err := client.SecretInspectWithRaw(context.Background(), secretID) 36 assert.NilError(t, err) 37 assert.Check(t, is.Equal(secret.Spec.Name, testName)) 38 39 secret, _, err = client.SecretInspectWithRaw(context.Background(), testName) 40 assert.NilError(t, err) 41 assert.Check(t, is.Equal(secretID, secretID)) 42 } 43 44 func TestSecretList(t *testing.T) { 45 skip.If(t, testEnv.DaemonInfo.OSType == "windows") 46 47 defer setupTest(t)() 48 d := swarm.NewSwarm(t, testEnv) 49 defer d.Stop(t) 50 client := d.NewClientT(t) 51 defer client.Close() 52 ctx := context.Background() 53 54 testName0 := "test0_" + t.Name() 55 testName1 := "test1_" + t.Name() 56 testNames := []string{testName0, testName1} 57 sort.Strings(testNames) 58 59 // create secret test0 60 createSecret(ctx, t, client, testName0, []byte("TESTINGDATA0"), map[string]string{"type": "test"}) 61 62 // create secret test1 63 secret1ID := createSecret(ctx, t, client, testName1, []byte("TESTINGDATA1"), map[string]string{"type": "production"}) 64 65 // test by `secret ls` 66 entries, err := client.SecretList(ctx, types.SecretListOptions{}) 67 assert.NilError(t, err) 68 assert.Check(t, is.DeepEqual(secretNamesFromList(entries), testNames)) 69 70 testCases := []struct { 71 filters filters.Args 72 expected []string 73 }{ 74 // test filter by name `secret ls --filter name=xxx` 75 { 76 filters: filters.NewArgs(filters.Arg("name", testName0)), 77 expected: []string{testName0}, 78 }, 79 // test filter by id `secret ls --filter id=xxx` 80 { 81 filters: filters.NewArgs(filters.Arg("id", secret1ID)), 82 expected: []string{testName1}, 83 }, 84 // test filter by label `secret ls --filter label=xxx` 85 { 86 filters: filters.NewArgs(filters.Arg("label", "type")), 87 expected: testNames, 88 }, 89 { 90 filters: filters.NewArgs(filters.Arg("label", "type=test")), 91 expected: []string{testName0}, 92 }, 93 { 94 filters: filters.NewArgs(filters.Arg("label", "type=production")), 95 expected: []string{testName1}, 96 }, 97 } 98 for _, tc := range testCases { 99 entries, err = client.SecretList(ctx, types.SecretListOptions{ 100 Filters: tc.filters, 101 }) 102 assert.NilError(t, err) 103 assert.Check(t, is.DeepEqual(secretNamesFromList(entries), tc.expected)) 104 105 } 106 } 107 108 func createSecret(ctx context.Context, t *testing.T, client client.APIClient, name string, data []byte, labels map[string]string) string { 109 secret, err := client.SecretCreate(ctx, swarmtypes.SecretSpec{ 110 Annotations: swarmtypes.Annotations{ 111 Name: name, 112 Labels: labels, 113 }, 114 Data: data, 115 }) 116 assert.NilError(t, err) 117 assert.Check(t, secret.ID != "") 118 return secret.ID 119 } 120 121 func TestSecretsCreateAndDelete(t *testing.T) { 122 skip.If(t, testEnv.DaemonInfo.OSType == "windows") 123 124 defer setupTest(t)() 125 d := swarm.NewSwarm(t, testEnv) 126 defer d.Stop(t) 127 client := d.NewClientT(t) 128 defer client.Close() 129 ctx := context.Background() 130 131 testName := "test_secret_" + t.Name() 132 secretID := createSecret(ctx, t, client, testName, []byte("TESTINGDATA"), nil) 133 134 // create an already existin secret, daemon should return a status code of 409 135 _, err := client.SecretCreate(ctx, swarmtypes.SecretSpec{ 136 Annotations: swarmtypes.Annotations{ 137 Name: testName, 138 }, 139 Data: []byte("TESTINGDATA"), 140 }) 141 assert.Check(t, is.ErrorContains(err, "already exists")) 142 143 // Ported from original TestSecretsDelete 144 err = client.SecretRemove(ctx, secretID) 145 assert.NilError(t, err) 146 147 _, _, err = client.SecretInspectWithRaw(ctx, secretID) 148 assert.Check(t, is.ErrorContains(err, "No such secret")) 149 150 err = client.SecretRemove(ctx, "non-existin") 151 assert.Check(t, is.ErrorContains(err, "No such secret: non-existin")) 152 153 // Ported from original TestSecretsCreteaWithLabels 154 testName = "test_secret_with_labels_" + t.Name() 155 secretID = createSecret(ctx, t, client, testName, []byte("TESTINGDATA"), map[string]string{ 156 "key1": "value1", 157 "key2": "value2", 158 }) 159 160 insp, _, err := client.SecretInspectWithRaw(ctx, secretID) 161 assert.NilError(t, err) 162 assert.Check(t, is.Equal(insp.Spec.Name, testName)) 163 assert.Check(t, is.Equal(len(insp.Spec.Labels), 2)) 164 assert.Check(t, is.Equal(insp.Spec.Labels["key1"], "value1")) 165 assert.Check(t, is.Equal(insp.Spec.Labels["key2"], "value2")) 166 } 167 168 func TestSecretsUpdate(t *testing.T) { 169 skip.If(t, testEnv.DaemonInfo.OSType == "windows") 170 171 defer setupTest(t)() 172 d := swarm.NewSwarm(t, testEnv) 173 defer d.Stop(t) 174 client := d.NewClientT(t) 175 defer client.Close() 176 ctx := context.Background() 177 178 testName := "test_secret_" + t.Name() 179 secretID := createSecret(ctx, t, client, testName, []byte("TESTINGDATA"), nil) 180 181 insp, _, err := client.SecretInspectWithRaw(ctx, secretID) 182 assert.NilError(t, err) 183 assert.Check(t, is.Equal(insp.ID, secretID)) 184 185 // test UpdateSecret with full ID 186 insp.Spec.Labels = map[string]string{"test": "test1"} 187 err = client.SecretUpdate(ctx, secretID, insp.Version, insp.Spec) 188 assert.NilError(t, err) 189 190 insp, _, err = client.SecretInspectWithRaw(ctx, secretID) 191 assert.NilError(t, err) 192 assert.Check(t, is.Equal(insp.Spec.Labels["test"], "test1")) 193 194 // test UpdateSecret with full name 195 insp.Spec.Labels = map[string]string{"test": "test2"} 196 err = client.SecretUpdate(ctx, testName, insp.Version, insp.Spec) 197 assert.NilError(t, err) 198 199 insp, _, err = client.SecretInspectWithRaw(ctx, secretID) 200 assert.NilError(t, err) 201 assert.Check(t, is.Equal(insp.Spec.Labels["test"], "test2")) 202 203 // test UpdateSecret with prefix ID 204 insp.Spec.Labels = map[string]string{"test": "test3"} 205 err = client.SecretUpdate(ctx, secretID[:1], insp.Version, insp.Spec) 206 assert.NilError(t, err) 207 208 insp, _, err = client.SecretInspectWithRaw(ctx, secretID) 209 assert.NilError(t, err) 210 assert.Check(t, is.Equal(insp.Spec.Labels["test"], "test3")) 211 212 // test UpdateSecret in updating Data which is not supported in daemon 213 // this test will produce an error in func UpdateSecret 214 insp.Spec.Data = []byte("TESTINGDATA2") 215 err = client.SecretUpdate(ctx, secretID, insp.Version, insp.Spec) 216 assert.Check(t, is.ErrorContains(err, "only updates to Labels are allowed")) 217 } 218 219 func TestTemplatedSecret(t *testing.T) { 220 skip.If(t, testEnv.DaemonInfo.OSType == "windows") 221 d := swarm.NewSwarm(t, testEnv) 222 defer d.Stop(t) 223 client := d.NewClientT(t) 224 defer client.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 := client.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 := client.ConfigCreate(ctx, referencedConfigSpec) 245 assert.Check(t, err) 246 247 templatedSecretName := "templated_secret_" + t.Name() 248 secretSpec := swarmtypes.SecretSpec{ 249 Annotations: swarmtypes.Annotations{ 250 Name: templatedSecretName, 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 templatedSecret, err := client.SecretCreate(ctx, secretSpec) 261 assert.Check(t, err) 262 263 serviceName := "svc_" + t.Name() 264 serviceID := swarm.CreateService(t, d, 265 swarm.ServiceWithSecret( 266 &swarmtypes.SecretReference{ 267 File: &swarmtypes.SecretReferenceFileTarget{ 268 Name: "templated_secret", 269 UID: "0", 270 GID: "0", 271 Mode: 0600, 272 }, 273 SecretID: templatedSecret.ID, 274 SecretName: templatedSecretName, 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 var tasks []swarmtypes.Task 305 waitAndAssert(t, 60*time.Second, func(t *testing.T) bool { 306 tasks = swarm.GetRunningTasks(t, client, serviceID) 307 return len(tasks) > 0 308 }) 309 310 task := tasks[0] 311 waitAndAssert(t, 60*time.Second, func(t *testing.T) bool { 312 if task.NodeID == "" || (task.Status.ContainerStatus == nil || task.Status.ContainerStatus.ContainerID == "") { 313 task, _, _ = client.TaskInspectWithRaw(context.Background(), task.ID) 314 } 315 return task.NodeID != "" && task.Status.ContainerStatus != nil && task.Status.ContainerStatus.ContainerID != "" 316 }) 317 318 attach := swarm.ExecTask(t, d, task, types.ExecConfig{ 319 Cmd: []string{"/bin/cat", "/run/secrets/templated_secret"}, 320 AttachStdout: true, 321 AttachStderr: true, 322 }) 323 324 expect := "SERVICE_NAME=" + serviceName + "\n" + 325 "this is a secret\n" + 326 "this is a config\n" 327 assertAttachedStream(t, attach, expect) 328 329 attach = swarm.ExecTask(t, d, task, types.ExecConfig{ 330 Cmd: []string{"mount"}, 331 AttachStdout: true, 332 AttachStderr: true, 333 }) 334 assertAttachedStream(t, attach, "tmpfs on /run/secrets/templated_secret type tmpfs") 335 } 336 337 // Test case for 28884 338 func TestSecretCreateResolve(t *testing.T) { 339 skip.If(t, testEnv.DaemonInfo.OSType != "linux") 340 341 defer setupTest(t)() 342 d := swarm.NewSwarm(t, testEnv) 343 defer d.Stop(t) 344 client := d.NewClientT(t) 345 defer client.Close() 346 347 ctx := context.Background() 348 349 testName := "test_secret_" + t.Name() 350 secretID := createSecret(ctx, t, client, testName, []byte("foo"), nil) 351 352 fakeName := secretID 353 fakeID := createSecret(ctx, t, client, fakeName, []byte("fake foo"), nil) 354 355 entries, err := client.SecretList(ctx, types.SecretListOptions{}) 356 assert.NilError(t, err) 357 assert.Check(t, is.Contains(secretNamesFromList(entries), testName)) 358 assert.Check(t, is.Contains(secretNamesFromList(entries), fakeName)) 359 360 err = client.SecretRemove(ctx, secretID) 361 assert.NilError(t, err) 362 363 // Fake one will remain 364 entries, err = client.SecretList(ctx, types.SecretListOptions{}) 365 assert.NilError(t, err) 366 assert.Assert(t, is.DeepEqual(secretNamesFromList(entries), []string{fakeName})) 367 368 // Remove based on name prefix of the fake one should not work 369 // as search is only done based on: 370 // - Full ID 371 // - Full Name 372 // - Partial ID (prefix) 373 err = client.SecretRemove(ctx, fakeName[:5]) 374 assert.Assert(t, nil != err) 375 entries, err = client.SecretList(ctx, types.SecretListOptions{}) 376 assert.NilError(t, err) 377 assert.Assert(t, is.DeepEqual(secretNamesFromList(entries), []string{fakeName})) 378 379 // Remove based on ID prefix of the fake one should succeed 380 err = client.SecretRemove(ctx, fakeID[:5]) 381 assert.NilError(t, err) 382 entries, err = client.SecretList(ctx, types.SecretListOptions{}) 383 assert.NilError(t, err) 384 assert.Assert(t, is.Equal(0, len(entries))) 385 } 386 387 func assertAttachedStream(t *testing.T, attach types.HijackedResponse, expect string) { 388 buf := bytes.NewBuffer(nil) 389 _, err := stdcopy.StdCopy(buf, buf, attach.Reader) 390 assert.NilError(t, err) 391 assert.Check(t, is.Contains(buf.String(), expect)) 392 } 393 394 func waitAndAssert(t *testing.T, timeout time.Duration, f func(*testing.T) bool) { 395 t.Helper() 396 after := time.After(timeout) 397 for { 398 select { 399 case <-after: 400 t.Fatal("timed out waiting for condition") 401 default: 402 } 403 if f(t) { 404 return 405 } 406 time.Sleep(100 * time.Millisecond) 407 } 408 } 409 410 func secretNamesFromList(entries []swarmtypes.Secret) []string { 411 var values []string 412 for _, entry := range entries { 413 values = append(values, entry.Spec.Name) 414 } 415 sort.Strings(values) 416 return values 417 }