github.com/zhouyu0/docker-note@v0.0.0-20190722021225-b8d3825084db/integration/config/config_test.go (about)

     1  package config // import "github.com/docker/docker/integration/config"
     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/integration/internal/swarm"
    16  	"github.com/docker/docker/pkg/stdcopy"
    17  	"gotest.tools/assert"
    18  	is "gotest.tools/assert/cmp"
    19  	"gotest.tools/skip"
    20  )
    21  
    22  func TestConfigList(t *testing.T) {
    23  	skip.If(t, testEnv.DaemonInfo.OSType == "windows")
    24  
    25  	defer setupTest(t)()
    26  	d := swarm.NewSwarm(t, testEnv)
    27  	defer d.Stop(t)
    28  	client := d.NewClientT(t)
    29  	defer client.Close()
    30  
    31  	ctx := context.Background()
    32  
    33  	// This test case is ported from the original TestConfigsEmptyList
    34  	configs, err := client.ConfigList(ctx, types.ConfigListOptions{})
    35  	assert.NilError(t, err)
    36  	assert.Check(t, is.Equal(len(configs), 0))
    37  
    38  	testName0 := "test0-" + t.Name()
    39  	testName1 := "test1-" + t.Name()
    40  	testNames := []string{testName0, testName1}
    41  	sort.Strings(testNames)
    42  
    43  	// create config test0
    44  	createConfig(ctx, t, client, testName0, []byte("TESTINGDATA0"), map[string]string{"type": "test"})
    45  
    46  	config1ID := createConfig(ctx, t, client, testName1, []byte("TESTINGDATA1"), map[string]string{"type": "production"})
    47  
    48  	// test by `config ls`
    49  	entries, err := client.ConfigList(ctx, types.ConfigListOptions{})
    50  	assert.NilError(t, err)
    51  	assert.Check(t, is.DeepEqual(configNamesFromList(entries), testNames))
    52  
    53  	testCases := []struct {
    54  		filters  filters.Args
    55  		expected []string
    56  	}{
    57  		// test filter by name `config ls --filter name=xxx`
    58  		{
    59  			filters:  filters.NewArgs(filters.Arg("name", testName0)),
    60  			expected: []string{testName0},
    61  		},
    62  		// test filter by id `config ls --filter id=xxx`
    63  		{
    64  			filters:  filters.NewArgs(filters.Arg("id", config1ID)),
    65  			expected: []string{testName1},
    66  		},
    67  		// test filter by label `config ls --filter label=xxx`
    68  		{
    69  			filters:  filters.NewArgs(filters.Arg("label", "type")),
    70  			expected: testNames,
    71  		},
    72  		{
    73  			filters:  filters.NewArgs(filters.Arg("label", "type=test")),
    74  			expected: []string{testName0},
    75  		},
    76  		{
    77  			filters:  filters.NewArgs(filters.Arg("label", "type=production")),
    78  			expected: []string{testName1},
    79  		},
    80  	}
    81  	for _, tc := range testCases {
    82  		entries, err = client.ConfigList(ctx, types.ConfigListOptions{
    83  			Filters: tc.filters,
    84  		})
    85  		assert.NilError(t, err)
    86  		assert.Check(t, is.DeepEqual(configNamesFromList(entries), tc.expected))
    87  
    88  	}
    89  }
    90  
    91  func createConfig(ctx context.Context, t *testing.T, client client.APIClient, name string, data []byte, labels map[string]string) string {
    92  	config, err := client.ConfigCreate(ctx, swarmtypes.ConfigSpec{
    93  		Annotations: swarmtypes.Annotations{
    94  			Name:   name,
    95  			Labels: labels,
    96  		},
    97  		Data: data,
    98  	})
    99  	assert.NilError(t, err)
   100  	assert.Check(t, config.ID != "")
   101  	return config.ID
   102  }
   103  
   104  func TestConfigsCreateAndDelete(t *testing.T) {
   105  	skip.If(t, testEnv.DaemonInfo.OSType == "windows")
   106  
   107  	defer setupTest(t)()
   108  	d := swarm.NewSwarm(t, testEnv)
   109  	defer d.Stop(t)
   110  	client := d.NewClientT(t)
   111  	defer client.Close()
   112  
   113  	ctx := context.Background()
   114  
   115  	testName := "test_config-" + t.Name()
   116  
   117  	// This test case is ported from the original TestConfigsCreate
   118  	configID := createConfig(ctx, t, client, testName, []byte("TESTINGDATA"), nil)
   119  
   120  	insp, _, err := client.ConfigInspectWithRaw(ctx, configID)
   121  	assert.NilError(t, err)
   122  	assert.Check(t, is.Equal(insp.Spec.Name, testName))
   123  
   124  	// This test case is ported from the original TestConfigsDelete
   125  	err = client.ConfigRemove(ctx, configID)
   126  	assert.NilError(t, err)
   127  
   128  	insp, _, err = client.ConfigInspectWithRaw(ctx, configID)
   129  	assert.Check(t, is.ErrorContains(err, "No such config"))
   130  }
   131  
   132  func TestConfigsUpdate(t *testing.T) {
   133  	skip.If(t, testEnv.DaemonInfo.OSType == "windows")
   134  
   135  	defer setupTest(t)()
   136  	d := swarm.NewSwarm(t, testEnv)
   137  	defer d.Stop(t)
   138  	client := d.NewClientT(t)
   139  	defer client.Close()
   140  
   141  	ctx := context.Background()
   142  
   143  	testName := "test_config-" + t.Name()
   144  
   145  	// This test case is ported from the original TestConfigsCreate
   146  	configID := createConfig(ctx, t, client, testName, []byte("TESTINGDATA"), nil)
   147  
   148  	insp, _, err := client.ConfigInspectWithRaw(ctx, configID)
   149  	assert.NilError(t, err)
   150  	assert.Check(t, is.Equal(insp.ID, configID))
   151  
   152  	// test UpdateConfig with full ID
   153  	insp.Spec.Labels = map[string]string{"test": "test1"}
   154  	err = client.ConfigUpdate(ctx, configID, insp.Version, insp.Spec)
   155  	assert.NilError(t, err)
   156  
   157  	insp, _, err = client.ConfigInspectWithRaw(ctx, configID)
   158  	assert.NilError(t, err)
   159  	assert.Check(t, is.Equal(insp.Spec.Labels["test"], "test1"))
   160  
   161  	// test UpdateConfig with full name
   162  	insp.Spec.Labels = map[string]string{"test": "test2"}
   163  	err = client.ConfigUpdate(ctx, testName, insp.Version, insp.Spec)
   164  	assert.NilError(t, err)
   165  
   166  	insp, _, err = client.ConfigInspectWithRaw(ctx, configID)
   167  	assert.NilError(t, err)
   168  	assert.Check(t, is.Equal(insp.Spec.Labels["test"], "test2"))
   169  
   170  	// test UpdateConfig with prefix ID
   171  	insp.Spec.Labels = map[string]string{"test": "test3"}
   172  	err = client.ConfigUpdate(ctx, configID[:1], insp.Version, insp.Spec)
   173  	assert.NilError(t, err)
   174  
   175  	insp, _, err = client.ConfigInspectWithRaw(ctx, configID)
   176  	assert.NilError(t, err)
   177  	assert.Check(t, is.Equal(insp.Spec.Labels["test"], "test3"))
   178  
   179  	// test UpdateConfig in updating Data which is not supported in daemon
   180  	// this test will produce an error in func UpdateConfig
   181  	insp.Spec.Data = []byte("TESTINGDATA2")
   182  	err = client.ConfigUpdate(ctx, configID, insp.Version, insp.Spec)
   183  	assert.Check(t, is.ErrorContains(err, "only updates to Labels are allowed"))
   184  }
   185  
   186  func TestTemplatedConfig(t *testing.T) {
   187  	skip.If(t, testEnv.DaemonInfo.OSType == "windows")
   188  	d := swarm.NewSwarm(t, testEnv)
   189  	defer d.Stop(t)
   190  	client := d.NewClientT(t)
   191  	defer client.Close()
   192  	ctx := context.Background()
   193  
   194  	referencedSecretName := "referencedsecret-" + t.Name()
   195  	referencedSecretSpec := swarmtypes.SecretSpec{
   196  		Annotations: swarmtypes.Annotations{
   197  			Name: referencedSecretName,
   198  		},
   199  		Data: []byte("this is a secret"),
   200  	}
   201  	referencedSecret, err := client.SecretCreate(ctx, referencedSecretSpec)
   202  	assert.Check(t, err)
   203  
   204  	referencedConfigName := "referencedconfig-" + t.Name()
   205  	referencedConfigSpec := swarmtypes.ConfigSpec{
   206  		Annotations: swarmtypes.Annotations{
   207  			Name: referencedConfigName,
   208  		},
   209  		Data: []byte("this is a config"),
   210  	}
   211  	referencedConfig, err := client.ConfigCreate(ctx, referencedConfigSpec)
   212  	assert.Check(t, err)
   213  
   214  	templatedConfigName := "templated_config-" + t.Name()
   215  	configSpec := swarmtypes.ConfigSpec{
   216  		Annotations: swarmtypes.Annotations{
   217  			Name: templatedConfigName,
   218  		},
   219  		Templating: &swarmtypes.Driver{
   220  			Name: "golang",
   221  		},
   222  		Data: []byte("SERVICE_NAME={{.Service.Name}}\n" +
   223  			"{{secret \"referencedsecrettarget\"}}\n" +
   224  			"{{config \"referencedconfigtarget\"}}\n"),
   225  	}
   226  
   227  	templatedConfig, err := client.ConfigCreate(ctx, configSpec)
   228  	assert.Check(t, err)
   229  
   230  	serviceID := swarm.CreateService(t, d,
   231  		swarm.ServiceWithConfig(
   232  			&swarmtypes.ConfigReference{
   233  				File: &swarmtypes.ConfigReferenceFileTarget{
   234  					Name: "/" + templatedConfigName,
   235  					UID:  "0",
   236  					GID:  "0",
   237  					Mode: 0600,
   238  				},
   239  				ConfigID:   templatedConfig.ID,
   240  				ConfigName: templatedConfigName,
   241  			},
   242  		),
   243  		swarm.ServiceWithConfig(
   244  			&swarmtypes.ConfigReference{
   245  				File: &swarmtypes.ConfigReferenceFileTarget{
   246  					Name: "referencedconfigtarget",
   247  					UID:  "0",
   248  					GID:  "0",
   249  					Mode: 0600,
   250  				},
   251  				ConfigID:   referencedConfig.ID,
   252  				ConfigName: referencedConfigName,
   253  			},
   254  		),
   255  		swarm.ServiceWithSecret(
   256  			&swarmtypes.SecretReference{
   257  				File: &swarmtypes.SecretReferenceFileTarget{
   258  					Name: "referencedsecrettarget",
   259  					UID:  "0",
   260  					GID:  "0",
   261  					Mode: 0600,
   262  				},
   263  				SecretID:   referencedSecret.ID,
   264  				SecretName: referencedSecretName,
   265  			},
   266  		),
   267  		swarm.ServiceWithName("svc"),
   268  	)
   269  
   270  	var tasks []swarmtypes.Task
   271  	waitAndAssert(t, 60*time.Second, func(t *testing.T) bool {
   272  		tasks = swarm.GetRunningTasks(t, d, serviceID)
   273  		return len(tasks) > 0
   274  	})
   275  
   276  	task := tasks[0]
   277  	waitAndAssert(t, 60*time.Second, func(t *testing.T) bool {
   278  		if task.NodeID == "" || (task.Status.ContainerStatus == nil || task.Status.ContainerStatus.ContainerID == "") {
   279  			task, _, _ = client.TaskInspectWithRaw(context.Background(), task.ID)
   280  		}
   281  		return task.NodeID != "" && task.Status.ContainerStatus != nil && task.Status.ContainerStatus.ContainerID != ""
   282  	})
   283  
   284  	attach := swarm.ExecTask(t, d, task, types.ExecConfig{
   285  		Cmd:          []string{"/bin/cat", "/" + templatedConfigName},
   286  		AttachStdout: true,
   287  		AttachStderr: true,
   288  	})
   289  
   290  	expect := "SERVICE_NAME=svc\n" +
   291  		"this is a secret\n" +
   292  		"this is a config\n"
   293  	assertAttachedStream(t, attach, expect)
   294  
   295  	attach = swarm.ExecTask(t, d, task, types.ExecConfig{
   296  		Cmd:          []string{"mount"},
   297  		AttachStdout: true,
   298  		AttachStderr: true,
   299  	})
   300  	assertAttachedStream(t, attach, "tmpfs on /"+templatedConfigName+" type tmpfs")
   301  }
   302  
   303  func assertAttachedStream(t *testing.T, attach types.HijackedResponse, expect string) {
   304  	buf := bytes.NewBuffer(nil)
   305  	_, err := stdcopy.StdCopy(buf, buf, attach.Reader)
   306  	assert.NilError(t, err)
   307  	assert.Check(t, is.Contains(buf.String(), expect))
   308  }
   309  
   310  func waitAndAssert(t *testing.T, timeout time.Duration, f func(*testing.T) bool) {
   311  	t.Helper()
   312  	after := time.After(timeout)
   313  	for {
   314  		select {
   315  		case <-after:
   316  			t.Fatalf("timed out waiting for condition")
   317  		default:
   318  		}
   319  		if f(t) {
   320  			return
   321  		}
   322  		time.Sleep(100 * time.Millisecond)
   323  	}
   324  }
   325  
   326  func TestConfigInspect(t *testing.T) {
   327  	skip.If(t, testEnv.DaemonInfo.OSType == "windows")
   328  
   329  	defer setupTest(t)()
   330  	d := swarm.NewSwarm(t, testEnv)
   331  	defer d.Stop(t)
   332  	client := d.NewClientT(t)
   333  	defer client.Close()
   334  
   335  	ctx := context.Background()
   336  
   337  	testName := t.Name()
   338  	configID := createConfig(ctx, t, client, testName, []byte("TESTINGDATA"), nil)
   339  
   340  	insp, body, err := client.ConfigInspectWithRaw(ctx, configID)
   341  	assert.NilError(t, err)
   342  	assert.Check(t, is.Equal(insp.Spec.Name, testName))
   343  
   344  	var config swarmtypes.Config
   345  	err = json.Unmarshal(body, &config)
   346  	assert.NilError(t, err)
   347  	assert.Check(t, is.DeepEqual(config, insp))
   348  }
   349  
   350  func TestConfigCreateWithLabels(t *testing.T) {
   351  	skip.If(t, testEnv.DaemonInfo.OSType != "linux")
   352  
   353  	defer setupTest(t)()
   354  	d := swarm.NewSwarm(t, testEnv)
   355  	defer d.Stop(t)
   356  	client := d.NewClientT(t)
   357  	defer client.Close()
   358  
   359  	ctx := context.Background()
   360  
   361  	labels := map[string]string{
   362  		"key1": "value1",
   363  		"key2": "value2",
   364  	}
   365  	testName := t.Name()
   366  	configID := createConfig(ctx, t, client, testName, []byte("TESTINGDATA"), labels)
   367  
   368  	insp, _, err := client.ConfigInspectWithRaw(ctx, configID)
   369  	assert.NilError(t, err)
   370  	assert.Check(t, is.Equal(insp.Spec.Name, testName))
   371  	assert.Check(t, is.Equal(2, len(insp.Spec.Labels)))
   372  	assert.Check(t, is.Equal("value1", insp.Spec.Labels["key1"]))
   373  	assert.Check(t, is.Equal("value2", insp.Spec.Labels["key2"]))
   374  }
   375  
   376  // Test case for 28884
   377  func TestConfigCreateResolve(t *testing.T) {
   378  	skip.If(t, testEnv.DaemonInfo.OSType != "linux")
   379  
   380  	defer setupTest(t)()
   381  	d := swarm.NewSwarm(t, testEnv)
   382  	defer d.Stop(t)
   383  	client := d.NewClientT(t)
   384  	defer client.Close()
   385  
   386  	ctx := context.Background()
   387  
   388  	configName := "test_config_" + t.Name()
   389  
   390  	configID := createConfig(ctx, t, client, configName, []byte("foo"), nil)
   391  	fakeName := configID
   392  	fakeID := createConfig(ctx, t, client, fakeName, []byte("fake foo"), nil)
   393  
   394  	entries, err := client.ConfigList(ctx, types.ConfigListOptions{})
   395  	assert.NilError(t, err)
   396  	assert.Assert(t, is.Contains(configNamesFromList(entries), configName))
   397  	assert.Assert(t, is.Contains(configNamesFromList(entries), fakeName))
   398  
   399  	err = client.ConfigRemove(ctx, configID)
   400  	assert.NilError(t, err)
   401  
   402  	// Fake one will remain
   403  	entries, err = client.ConfigList(ctx, types.ConfigListOptions{})
   404  	assert.NilError(t, err)
   405  	assert.Assert(t, is.DeepEqual(configNamesFromList(entries), []string{fakeName}))
   406  
   407  	// Remove based on name prefix of the fake one
   408  	// (which is the same as the ID of foo one) should not work
   409  	// as search is only done based on:
   410  	// - Full ID
   411  	// - Full Name
   412  	// - Partial ID (prefix)
   413  	err = client.ConfigRemove(ctx, configID[:5])
   414  	assert.Assert(t, nil != err)
   415  	entries, err = client.ConfigList(ctx, types.ConfigListOptions{})
   416  	assert.NilError(t, err)
   417  	assert.Assert(t, is.DeepEqual(configNamesFromList(entries), []string{fakeName}))
   418  
   419  	// Remove based on ID prefix of the fake one should succeed
   420  	err = client.ConfigRemove(ctx, fakeID[:5])
   421  	assert.NilError(t, err)
   422  	entries, err = client.ConfigList(ctx, types.ConfigListOptions{})
   423  	assert.NilError(t, err)
   424  	assert.Assert(t, is.Equal(0, len(entries)))
   425  }
   426  
   427  func configNamesFromList(entries []swarmtypes.Config) []string {
   428  	var values []string
   429  	for _, entry := range entries {
   430  		values = append(values, entry.Spec.Name)
   431  	}
   432  	sort.Strings(values)
   433  	return values
   434  }