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