github.com/zhouyu0/docker-note@v0.0.0-20190722021225-b8d3825084db/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 names := func(entries []swarmtypes.Secret) []string { 66 var values []string 67 for _, entry := range entries { 68 values = append(values, entry.Spec.Name) 69 } 70 sort.Strings(values) 71 return values 72 } 73 74 // test by `secret ls` 75 entries, err := client.SecretList(ctx, types.SecretListOptions{}) 76 assert.NilError(t, err) 77 assert.Check(t, is.DeepEqual(names(entries), testNames)) 78 79 testCases := []struct { 80 filters filters.Args 81 expected []string 82 }{ 83 // test filter by name `secret ls --filter name=xxx` 84 { 85 filters: filters.NewArgs(filters.Arg("name", testName0)), 86 expected: []string{testName0}, 87 }, 88 // test filter by id `secret ls --filter id=xxx` 89 { 90 filters: filters.NewArgs(filters.Arg("id", secret1ID)), 91 expected: []string{testName1}, 92 }, 93 // test filter by label `secret ls --filter label=xxx` 94 { 95 filters: filters.NewArgs(filters.Arg("label", "type")), 96 expected: testNames, 97 }, 98 { 99 filters: filters.NewArgs(filters.Arg("label", "type=test")), 100 expected: []string{testName0}, 101 }, 102 { 103 filters: filters.NewArgs(filters.Arg("label", "type=production")), 104 expected: []string{testName1}, 105 }, 106 } 107 for _, tc := range testCases { 108 entries, err = client.SecretList(ctx, types.SecretListOptions{ 109 Filters: tc.filters, 110 }) 111 assert.NilError(t, err) 112 assert.Check(t, is.DeepEqual(names(entries), tc.expected)) 113 114 } 115 } 116 117 func createSecret(ctx context.Context, t *testing.T, client client.APIClient, name string, data []byte, labels map[string]string) string { 118 secret, err := client.SecretCreate(ctx, swarmtypes.SecretSpec{ 119 Annotations: swarmtypes.Annotations{ 120 Name: name, 121 Labels: labels, 122 }, 123 Data: data, 124 }) 125 assert.NilError(t, err) 126 assert.Check(t, secret.ID != "") 127 return secret.ID 128 } 129 130 func TestSecretsCreateAndDelete(t *testing.T) { 131 skip.If(t, testEnv.DaemonInfo.OSType == "windows") 132 133 defer setupTest(t)() 134 d := swarm.NewSwarm(t, testEnv) 135 defer d.Stop(t) 136 client := d.NewClientT(t) 137 defer client.Close() 138 ctx := context.Background() 139 140 testName := "test_secret_" + t.Name() 141 secretID := createSecret(ctx, t, client, testName, []byte("TESTINGDATA"), nil) 142 143 // create an already existin secret, daemon should return a status code of 409 144 _, err := client.SecretCreate(ctx, swarmtypes.SecretSpec{ 145 Annotations: swarmtypes.Annotations{ 146 Name: testName, 147 }, 148 Data: []byte("TESTINGDATA"), 149 }) 150 assert.Check(t, is.ErrorContains(err, "already exists")) 151 152 // Ported from original TestSecretsDelete 153 err = client.SecretRemove(ctx, secretID) 154 assert.NilError(t, err) 155 156 _, _, err = client.SecretInspectWithRaw(ctx, secretID) 157 assert.Check(t, is.ErrorContains(err, "No such secret")) 158 159 err = client.SecretRemove(ctx, "non-existin") 160 assert.Check(t, is.ErrorContains(err, "No such secret: non-existin")) 161 162 // Ported from original TestSecretsCreteaWithLabels 163 testName = "test_secret_with_labels_" + t.Name() 164 secretID = createSecret(ctx, t, client, testName, []byte("TESTINGDATA"), map[string]string{ 165 "key1": "value1", 166 "key2": "value2", 167 }) 168 169 insp, _, err := client.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 client := d.NewClientT(t) 184 defer client.Close() 185 ctx := context.Background() 186 187 testName := "test_secret_" + t.Name() 188 secretID := createSecret(ctx, t, client, testName, []byte("TESTINGDATA"), nil) 189 190 insp, _, err := client.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 = client.SecretUpdate(ctx, secretID, 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"], "test1")) 202 203 // test UpdateSecret with full name 204 insp.Spec.Labels = map[string]string{"test": "test2"} 205 err = client.SecretUpdate(ctx, testName, 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"], "test2")) 211 212 // test UpdateSecret with prefix ID 213 insp.Spec.Labels = map[string]string{"test": "test3"} 214 err = client.SecretUpdate(ctx, secretID[:1], insp.Version, insp.Spec) 215 assert.NilError(t, err) 216 217 insp, _, err = client.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 = client.SecretUpdate(ctx, secretID, insp.Version, insp.Spec) 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 client := d.NewClientT(t) 233 defer client.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 := client.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 := client.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 := client.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 var tasks []swarmtypes.Task 314 waitAndAssert(t, 60*time.Second, func(t *testing.T) bool { 315 tasks = swarm.GetRunningTasks(t, d, serviceID) 316 return len(tasks) > 0 317 }) 318 319 task := tasks[0] 320 waitAndAssert(t, 60*time.Second, func(t *testing.T) bool { 321 if task.NodeID == "" || (task.Status.ContainerStatus == nil || task.Status.ContainerStatus.ContainerID == "") { 322 task, _, _ = client.TaskInspectWithRaw(context.Background(), task.ID) 323 } 324 return task.NodeID != "" && task.Status.ContainerStatus != nil && task.Status.ContainerStatus.ContainerID != "" 325 }) 326 327 attach := swarm.ExecTask(t, d, task, types.ExecConfig{ 328 Cmd: []string{"/bin/cat", "/run/secrets/templated_secret"}, 329 AttachStdout: true, 330 AttachStderr: true, 331 }) 332 333 expect := "SERVICE_NAME=" + serviceName + "\n" + 334 "this is a secret\n" + 335 "this is a config\n" 336 assertAttachedStream(t, attach, expect) 337 338 attach = swarm.ExecTask(t, d, task, types.ExecConfig{ 339 Cmd: []string{"mount"}, 340 AttachStdout: true, 341 AttachStderr: true, 342 }) 343 assertAttachedStream(t, attach, "tmpfs on /run/secrets/templated_secret type tmpfs") 344 } 345 346 func assertAttachedStream(t *testing.T, attach types.HijackedResponse, expect string) { 347 buf := bytes.NewBuffer(nil) 348 _, err := stdcopy.StdCopy(buf, buf, attach.Reader) 349 assert.NilError(t, err) 350 assert.Check(t, is.Contains(buf.String(), expect)) 351 } 352 353 func waitAndAssert(t *testing.T, timeout time.Duration, f func(*testing.T) bool) { 354 t.Helper() 355 after := time.After(timeout) 356 for { 357 select { 358 case <-after: 359 t.Fatalf("timed out waiting for condition") 360 default: 361 } 362 if f(t) { 363 return 364 } 365 time.Sleep(100 * time.Millisecond) 366 } 367 }