github.com/demonoid81/moby@v0.0.0-20200517203328-62dd8e17c460/integration/secret/secret_test.go (about) 1 package secret // import "github.com/demonoid81/moby/integration/secret" 2 3 import ( 4 "bytes" 5 "context" 6 "encoding/json" 7 "sort" 8 "testing" 9 "time" 10 11 "github.com/demonoid81/moby/api/types" 12 "github.com/demonoid81/moby/api/types/filters" 13 swarmtypes "github.com/demonoid81/moby/api/types/swarm" 14 "github.com/demonoid81/moby/client" 15 "github.com/demonoid81/moby/errdefs" 16 "github.com/demonoid81/moby/integration/internal/swarm" 17 "github.com/demonoid81/moby/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 116 func createSecret(ctx context.Context, t *testing.T, client client.APIClient, name string, data []byte, labels map[string]string) string { 117 secret, err := client.SecretCreate(ctx, swarmtypes.SecretSpec{ 118 Annotations: swarmtypes.Annotations{ 119 Name: name, 120 Labels: labels, 121 }, 122 Data: data, 123 }) 124 assert.NilError(t, err) 125 assert.Check(t, secret.ID != "") 126 return secret.ID 127 } 128 129 func TestSecretsCreateAndDelete(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_secret_" + t.Name() 140 secretID := createSecret(ctx, t, c, testName, []byte("TESTINGDATA"), nil) 141 142 // create an already existing secret, daemon should return a status code of 409 143 _, err := c.SecretCreate(ctx, swarmtypes.SecretSpec{ 144 Annotations: swarmtypes.Annotations{ 145 Name: testName, 146 }, 147 Data: []byte("TESTINGDATA"), 148 }) 149 assert.Check(t, errdefs.IsConflict(err)) 150 assert.Check(t, is.ErrorContains(err, testName)) 151 152 err = c.SecretRemove(ctx, secretID) 153 assert.NilError(t, err) 154 155 _, _, err = c.SecretInspectWithRaw(ctx, secretID) 156 assert.Check(t, errdefs.IsNotFound(err)) 157 assert.Check(t, is.ErrorContains(err, secretID)) 158 159 err = c.SecretRemove(ctx, "non-existing") 160 assert.Check(t, errdefs.IsNotFound(err)) 161 assert.Check(t, is.ErrorContains(err, "non-existing")) 162 163 testName = "test_secret_with_labels_" + t.Name() 164 secretID = createSecret(ctx, t, c, testName, []byte("TESTINGDATA"), map[string]string{ 165 "key1": "value1", 166 "key2": "value2", 167 }) 168 169 insp, _, err := c.SecretInspectWithRaw(ctx, secretID) 170 assert.NilError(t, err) 171 assert.Check(t, is.Equal(insp.Spec.Name, testName)) 172 assert.Check(t, is.Equal(len(insp.Spec.Labels), 2)) 173 assert.Check(t, is.Equal(insp.Spec.Labels["key1"], "value1")) 174 assert.Check(t, is.Equal(insp.Spec.Labels["key2"], "value2")) 175 } 176 177 func TestSecretsUpdate(t *testing.T) { 178 skip.If(t, testEnv.DaemonInfo.OSType == "windows") 179 180 defer setupTest(t)() 181 d := swarm.NewSwarm(t, testEnv) 182 defer d.Stop(t) 183 c := d.NewClientT(t) 184 defer c.Close() 185 ctx := context.Background() 186 187 testName := "test_secret_" + t.Name() 188 secretID := createSecret(ctx, t, c, testName, []byte("TESTINGDATA"), nil) 189 190 insp, _, err := c.SecretInspectWithRaw(ctx, secretID) 191 assert.NilError(t, err) 192 assert.Check(t, is.Equal(insp.ID, secretID)) 193 194 // test UpdateSecret with full ID 195 insp.Spec.Labels = map[string]string{"test": "test1"} 196 err = c.SecretUpdate(ctx, secretID, insp.Version, insp.Spec) 197 assert.NilError(t, err) 198 199 insp, _, err = c.SecretInspectWithRaw(ctx, secretID) 200 assert.NilError(t, err) 201 assert.Check(t, is.Equal(insp.Spec.Labels["test"], "test1")) 202 203 // test UpdateSecret with full name 204 insp.Spec.Labels = map[string]string{"test": "test2"} 205 err = c.SecretUpdate(ctx, testName, insp.Version, insp.Spec) 206 assert.NilError(t, err) 207 208 insp, _, err = c.SecretInspectWithRaw(ctx, secretID) 209 assert.NilError(t, err) 210 assert.Check(t, is.Equal(insp.Spec.Labels["test"], "test2")) 211 212 // test UpdateSecret with prefix ID 213 insp.Spec.Labels = map[string]string{"test": "test3"} 214 err = c.SecretUpdate(ctx, secretID[:1], insp.Version, insp.Spec) 215 assert.NilError(t, err) 216 217 insp, _, err = c.SecretInspectWithRaw(ctx, secretID) 218 assert.NilError(t, err) 219 assert.Check(t, is.Equal(insp.Spec.Labels["test"], "test3")) 220 221 // test UpdateSecret in updating Data which is not supported in daemon 222 // this test will produce an error in func UpdateSecret 223 insp.Spec.Data = []byte("TESTINGDATA2") 224 err = c.SecretUpdate(ctx, secretID, insp.Version, insp.Spec) 225 assert.Check(t, errdefs.IsInvalidParameter(err)) 226 assert.Check(t, is.ErrorContains(err, "only updates to Labels are allowed")) 227 } 228 229 func TestTemplatedSecret(t *testing.T) { 230 skip.If(t, testEnv.DaemonInfo.OSType == "windows") 231 d := swarm.NewSwarm(t, testEnv) 232 defer d.Stop(t) 233 c := d.NewClientT(t) 234 defer c.Close() 235 ctx := context.Background() 236 237 referencedSecretName := "referencedsecret_" + t.Name() 238 referencedSecretSpec := swarmtypes.SecretSpec{ 239 Annotations: swarmtypes.Annotations{ 240 Name: referencedSecretName, 241 }, 242 Data: []byte("this is a secret"), 243 } 244 referencedSecret, err := c.SecretCreate(ctx, referencedSecretSpec) 245 assert.Check(t, err) 246 247 referencedConfigName := "referencedconfig_" + t.Name() 248 referencedConfigSpec := swarmtypes.ConfigSpec{ 249 Annotations: swarmtypes.Annotations{ 250 Name: referencedConfigName, 251 }, 252 Data: []byte("this is a config"), 253 } 254 referencedConfig, err := c.ConfigCreate(ctx, referencedConfigSpec) 255 assert.Check(t, err) 256 257 templatedSecretName := "templated_secret_" + t.Name() 258 secretSpec := swarmtypes.SecretSpec{ 259 Annotations: swarmtypes.Annotations{ 260 Name: templatedSecretName, 261 }, 262 Templating: &swarmtypes.Driver{ 263 Name: "golang", 264 }, 265 Data: []byte("SERVICE_NAME={{.Service.Name}}\n" + 266 "{{secret \"referencedsecrettarget\"}}\n" + 267 "{{config \"referencedconfigtarget\"}}\n"), 268 } 269 270 templatedSecret, err := c.SecretCreate(ctx, secretSpec) 271 assert.Check(t, err) 272 273 serviceName := "svc_" + t.Name() 274 serviceID := swarm.CreateService(t, d, 275 swarm.ServiceWithSecret( 276 &swarmtypes.SecretReference{ 277 File: &swarmtypes.SecretReferenceFileTarget{ 278 Name: "templated_secret", 279 UID: "0", 280 GID: "0", 281 Mode: 0600, 282 }, 283 SecretID: templatedSecret.ID, 284 SecretName: templatedSecretName, 285 }, 286 ), 287 swarm.ServiceWithConfig( 288 &swarmtypes.ConfigReference{ 289 File: &swarmtypes.ConfigReferenceFileTarget{ 290 Name: "referencedconfigtarget", 291 UID: "0", 292 GID: "0", 293 Mode: 0600, 294 }, 295 ConfigID: referencedConfig.ID, 296 ConfigName: referencedConfigName, 297 }, 298 ), 299 swarm.ServiceWithSecret( 300 &swarmtypes.SecretReference{ 301 File: &swarmtypes.SecretReferenceFileTarget{ 302 Name: "referencedsecrettarget", 303 UID: "0", 304 GID: "0", 305 Mode: 0600, 306 }, 307 SecretID: referencedSecret.ID, 308 SecretName: referencedSecretName, 309 }, 310 ), 311 swarm.ServiceWithName(serviceName), 312 ) 313 314 poll.WaitOn(t, swarm.RunningTasksCount(c, serviceID, 1), swarm.ServicePoll, poll.WithTimeout(1*time.Minute)) 315 316 tasks := swarm.GetRunningTasks(t, c, serviceID) 317 assert.Assert(t, len(tasks) > 0, "no running tasks found for service %s", serviceID) 318 319 attach := swarm.ExecTask(t, d, tasks[0], types.ExecConfig{ 320 Cmd: []string{"/bin/cat", "/run/secrets/templated_secret"}, 321 AttachStdout: true, 322 AttachStderr: true, 323 }) 324 325 expect := "SERVICE_NAME=" + serviceName + "\n" + 326 "this is a secret\n" + 327 "this is a config\n" 328 assertAttachedStream(t, attach, expect) 329 330 attach = swarm.ExecTask(t, d, tasks[0], types.ExecConfig{ 331 Cmd: []string{"mount"}, 332 AttachStdout: true, 333 AttachStderr: true, 334 }) 335 assertAttachedStream(t, attach, "tmpfs on /run/secrets/templated_secret type tmpfs") 336 } 337 338 // Test case for 28884 339 func TestSecretCreateResolve(t *testing.T) { 340 skip.If(t, testEnv.DaemonInfo.OSType != "linux") 341 342 defer setupTest(t)() 343 d := swarm.NewSwarm(t, testEnv) 344 defer d.Stop(t) 345 c := d.NewClientT(t) 346 defer c.Close() 347 348 ctx := context.Background() 349 350 testName := "test_secret_" + t.Name() 351 secretID := createSecret(ctx, t, c, testName, []byte("foo"), nil) 352 353 fakeName := secretID 354 fakeID := createSecret(ctx, t, c, fakeName, []byte("fake foo"), nil) 355 356 entries, err := c.SecretList(ctx, types.SecretListOptions{}) 357 assert.NilError(t, err) 358 assert.Check(t, is.Contains(secretNamesFromList(entries), testName)) 359 assert.Check(t, is.Contains(secretNamesFromList(entries), fakeName)) 360 361 err = c.SecretRemove(ctx, secretID) 362 assert.NilError(t, err) 363 364 // Fake one will remain 365 entries, err = c.SecretList(ctx, types.SecretListOptions{}) 366 assert.NilError(t, err) 367 assert.Assert(t, is.DeepEqual(secretNamesFromList(entries), []string{fakeName})) 368 369 // Remove based on name prefix of the fake one should not work 370 // as search is only done based on: 371 // - Full ID 372 // - Full Name 373 // - Partial ID (prefix) 374 err = c.SecretRemove(ctx, fakeName[:5]) 375 assert.Assert(t, nil != err) 376 entries, err = c.SecretList(ctx, types.SecretListOptions{}) 377 assert.NilError(t, err) 378 assert.Assert(t, is.DeepEqual(secretNamesFromList(entries), []string{fakeName})) 379 380 // Remove based on ID prefix of the fake one should succeed 381 err = c.SecretRemove(ctx, fakeID[:5]) 382 assert.NilError(t, err) 383 entries, err = c.SecretList(ctx, types.SecretListOptions{}) 384 assert.NilError(t, err) 385 assert.Assert(t, is.Equal(0, len(entries))) 386 } 387 388 func assertAttachedStream(t *testing.T, attach types.HijackedResponse, expect string) { 389 buf := bytes.NewBuffer(nil) 390 _, err := stdcopy.StdCopy(buf, buf, attach.Reader) 391 assert.NilError(t, err) 392 assert.Check(t, is.Contains(buf.String(), expect)) 393 } 394 395 func secretNamesFromList(entries []swarmtypes.Secret) []string { 396 var values []string 397 for _, entry := range entries { 398 values = append(values, entry.Spec.Name) 399 } 400 sort.Strings(values) 401 return values 402 }