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