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  }