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