github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/integration/secret/secret_test.go (about) 1 package secret // import "github.com/docker/docker/integration/secret" 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 TestSecretInspect(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 secretID := createSecret(ctx, t, c, testName, []byte("TESTINGDATA"), nil) 37 38 insp, body, err := c.SecretInspectWithRaw(ctx, secretID) 39 assert.NilError(t, err) 40 assert.Check(t, is.Equal(insp.Spec.Name, testName)) 41 42 var secret swarmtypes.Secret 43 err = json.Unmarshal(body, &secret) 44 assert.NilError(t, err) 45 assert.Check(t, is.DeepEqual(secret, insp)) 46 } 47 48 func TestSecretList(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 configs, err := c.SecretList(ctx, types.SecretListOptions{}) 59 assert.NilError(t, err) 60 assert.Check(t, is.Equal(len(configs), 0)) 61 62 testName0 := "test0_" + t.Name() 63 testName1 := "test1_" + t.Name() 64 testNames := []string{testName0, testName1} 65 sort.Strings(testNames) 66 67 // create secret test0 68 createSecret(ctx, t, c, testName0, []byte("TESTINGDATA0"), map[string]string{"type": "test"}) 69 70 // create secret test1 71 secret1ID := createSecret(ctx, t, c, testName1, []byte("TESTINGDATA1"), map[string]string{"type": "production"}) 72 73 // test by `secret ls` 74 entries, err := c.SecretList(ctx, types.SecretListOptions{}) 75 assert.NilError(t, err) 76 assert.Check(t, is.DeepEqual(secretNamesFromList(entries), testNames)) 77 78 testCases := []struct { 79 filters filters.Args 80 expected []string 81 }{ 82 // test filter by name `secret ls --filter name=xxx` 83 { 84 filters: filters.NewArgs(filters.Arg("name", testName0)), 85 expected: []string{testName0}, 86 }, 87 // test filter by id `secret ls --filter id=xxx` 88 { 89 filters: filters.NewArgs(filters.Arg("id", secret1ID)), 90 expected: []string{testName1}, 91 }, 92 // test filter by label `secret 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.SecretList(ctx, types.SecretListOptions{ 108 Filters: tc.filters, 109 }) 110 assert.NilError(t, err) 111 assert.Check(t, is.DeepEqual(secretNamesFromList(entries), tc.expected)) 112 } 113 } 114 115 func createSecret(ctx context.Context, t *testing.T, client client.APIClient, name string, data []byte, labels map[string]string) string { 116 secret, err := client.SecretCreate(ctx, swarmtypes.SecretSpec{ 117 Annotations: swarmtypes.Annotations{ 118 Name: name, 119 Labels: labels, 120 }, 121 Data: data, 122 }) 123 assert.NilError(t, err) 124 assert.Check(t, secret.ID != "") 125 return secret.ID 126 } 127 128 func TestSecretsCreateAndDelete(t *testing.T) { 129 skip.If(t, testEnv.DaemonInfo.OSType == "windows") 130 131 defer setupTest(t)() 132 d := swarm.NewSwarm(t, testEnv) 133 defer d.Stop(t) 134 c := d.NewClientT(t) 135 defer c.Close() 136 ctx := context.Background() 137 138 testName := "test_secret_" + t.Name() 139 secretID := createSecret(ctx, t, c, testName, []byte("TESTINGDATA"), nil) 140 141 // create an already existing secret, daemon should return a status code of 409 142 _, err := c.SecretCreate(ctx, swarmtypes.SecretSpec{ 143 Annotations: swarmtypes.Annotations{ 144 Name: testName, 145 }, 146 Data: []byte("TESTINGDATA"), 147 }) 148 assert.Check(t, errdefs.IsConflict(err)) 149 assert.Check(t, is.ErrorContains(err, testName)) 150 151 err = c.SecretRemove(ctx, secretID) 152 assert.NilError(t, err) 153 154 _, _, err = c.SecretInspectWithRaw(ctx, secretID) 155 assert.Check(t, errdefs.IsNotFound(err)) 156 assert.Check(t, is.ErrorContains(err, secretID)) 157 158 err = c.SecretRemove(ctx, "non-existing") 159 assert.Check(t, errdefs.IsNotFound(err)) 160 assert.Check(t, is.ErrorContains(err, "non-existing")) 161 162 testName = "test_secret_with_labels_" + t.Name() 163 secretID = createSecret(ctx, t, c, testName, []byte("TESTINGDATA"), map[string]string{ 164 "key1": "value1", 165 "key2": "value2", 166 }) 167 168 insp, _, err := c.SecretInspectWithRaw(ctx, secretID) 169 assert.NilError(t, err) 170 assert.Check(t, is.Equal(insp.Spec.Name, testName)) 171 assert.Check(t, is.Equal(len(insp.Spec.Labels), 2)) 172 assert.Check(t, is.Equal(insp.Spec.Labels["key1"], "value1")) 173 assert.Check(t, is.Equal(insp.Spec.Labels["key2"], "value2")) 174 } 175 176 func TestSecretsUpdate(t *testing.T) { 177 skip.If(t, testEnv.DaemonInfo.OSType == "windows") 178 179 defer setupTest(t)() 180 d := swarm.NewSwarm(t, testEnv) 181 defer d.Stop(t) 182 c := d.NewClientT(t) 183 defer c.Close() 184 ctx := context.Background() 185 186 testName := "test_secret_" + t.Name() 187 secretID := createSecret(ctx, t, c, testName, []byte("TESTINGDATA"), nil) 188 189 insp, _, err := c.SecretInspectWithRaw(ctx, secretID) 190 assert.NilError(t, err) 191 assert.Check(t, is.Equal(insp.ID, secretID)) 192 193 // test UpdateSecret with full ID 194 insp.Spec.Labels = map[string]string{"test": "test1"} 195 err = c.SecretUpdate(ctx, secretID, insp.Version, insp.Spec) 196 assert.NilError(t, err) 197 198 insp, _, err = c.SecretInspectWithRaw(ctx, secretID) 199 assert.NilError(t, err) 200 assert.Check(t, is.Equal(insp.Spec.Labels["test"], "test1")) 201 202 // test UpdateSecret with full name 203 insp.Spec.Labels = map[string]string{"test": "test2"} 204 err = c.SecretUpdate(ctx, testName, insp.Version, insp.Spec) 205 assert.NilError(t, err) 206 207 insp, _, err = c.SecretInspectWithRaw(ctx, secretID) 208 assert.NilError(t, err) 209 assert.Check(t, is.Equal(insp.Spec.Labels["test"], "test2")) 210 211 // test UpdateSecret with prefix ID 212 insp.Spec.Labels = map[string]string{"test": "test3"} 213 err = c.SecretUpdate(ctx, secretID[:1], insp.Version, insp.Spec) 214 assert.NilError(t, err) 215 216 insp, _, err = c.SecretInspectWithRaw(ctx, secretID) 217 assert.NilError(t, err) 218 assert.Check(t, is.Equal(insp.Spec.Labels["test"], "test3")) 219 220 // test UpdateSecret in updating Data which is not supported in daemon 221 // this test will produce an error in func UpdateSecret 222 insp.Spec.Data = []byte("TESTINGDATA2") 223 err = c.SecretUpdate(ctx, secretID, insp.Version, insp.Spec) 224 assert.Check(t, errdefs.IsInvalidParameter(err)) 225 assert.Check(t, is.ErrorContains(err, "only updates to Labels are allowed")) 226 } 227 228 func TestTemplatedSecret(t *testing.T) { 229 skip.If(t, testEnv.DaemonInfo.OSType == "windows") 230 d := swarm.NewSwarm(t, testEnv) 231 defer d.Stop(t) 232 c := d.NewClientT(t) 233 defer c.Close() 234 ctx := context.Background() 235 236 referencedSecretName := "referencedsecret_" + t.Name() 237 referencedSecretSpec := swarmtypes.SecretSpec{ 238 Annotations: swarmtypes.Annotations{ 239 Name: referencedSecretName, 240 }, 241 Data: []byte("this is a secret"), 242 } 243 referencedSecret, err := c.SecretCreate(ctx, referencedSecretSpec) 244 assert.Check(t, err) 245 246 referencedConfigName := "referencedconfig_" + t.Name() 247 referencedConfigSpec := swarmtypes.ConfigSpec{ 248 Annotations: swarmtypes.Annotations{ 249 Name: referencedConfigName, 250 }, 251 Data: []byte("this is a config"), 252 } 253 referencedConfig, err := c.ConfigCreate(ctx, referencedConfigSpec) 254 assert.Check(t, err) 255 256 templatedSecretName := "templated_secret_" + t.Name() 257 secretSpec := swarmtypes.SecretSpec{ 258 Annotations: swarmtypes.Annotations{ 259 Name: templatedSecretName, 260 }, 261 Templating: &swarmtypes.Driver{ 262 Name: "golang", 263 }, 264 Data: []byte("SERVICE_NAME={{.Service.Name}}\n" + 265 "{{secret \"referencedsecrettarget\"}}\n" + 266 "{{config \"referencedconfigtarget\"}}\n"), 267 } 268 269 templatedSecret, err := c.SecretCreate(ctx, secretSpec) 270 assert.Check(t, err) 271 272 serviceName := "svc_" + t.Name() 273 serviceID := swarm.CreateService(t, d, 274 swarm.ServiceWithSecret( 275 &swarmtypes.SecretReference{ 276 File: &swarmtypes.SecretReferenceFileTarget{ 277 Name: "templated_secret", 278 UID: "0", 279 GID: "0", 280 Mode: 0600, 281 }, 282 SecretID: templatedSecret.ID, 283 SecretName: templatedSecretName, 284 }, 285 ), 286 swarm.ServiceWithConfig( 287 &swarmtypes.ConfigReference{ 288 File: &swarmtypes.ConfigReferenceFileTarget{ 289 Name: "referencedconfigtarget", 290 UID: "0", 291 GID: "0", 292 Mode: 0600, 293 }, 294 ConfigID: referencedConfig.ID, 295 ConfigName: referencedConfigName, 296 }, 297 ), 298 swarm.ServiceWithSecret( 299 &swarmtypes.SecretReference{ 300 File: &swarmtypes.SecretReferenceFileTarget{ 301 Name: "referencedsecrettarget", 302 UID: "0", 303 GID: "0", 304 Mode: 0600, 305 }, 306 SecretID: referencedSecret.ID, 307 SecretName: referencedSecretName, 308 }, 309 ), 310 swarm.ServiceWithName(serviceName), 311 ) 312 313 poll.WaitOn(t, swarm.RunningTasksCount(c, serviceID, 1), swarm.ServicePoll, poll.WithTimeout(1*time.Minute)) 314 315 tasks := swarm.GetRunningTasks(t, c, serviceID) 316 assert.Assert(t, len(tasks) > 0, "no running tasks found for service %s", serviceID) 317 318 attach := swarm.ExecTask(t, d, tasks[0], 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, tasks[0], 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 c := d.NewClientT(t) 345 defer c.Close() 346 347 ctx := context.Background() 348 349 testName := "test_secret_" + t.Name() 350 secretID := createSecret(ctx, t, c, testName, []byte("foo"), nil) 351 352 fakeName := secretID 353 fakeID := createSecret(ctx, t, c, fakeName, []byte("fake foo"), nil) 354 355 entries, err := c.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 = c.SecretRemove(ctx, secretID) 361 assert.NilError(t, err) 362 363 // Fake one will remain 364 entries, err = c.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 = c.SecretRemove(ctx, fakeName[:5]) 374 assert.Assert(t, nil != err) 375 entries, err = c.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 = c.SecretRemove(ctx, fakeID[:5]) 381 assert.NilError(t, err) 382 entries, err = c.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 secretNamesFromList(entries []swarmtypes.Secret) []string { 395 var values []string 396 for _, entry := range entries { 397 values = append(values, entry.Spec.Name) 398 } 399 sort.Strings(values) 400 return values 401 }