e8dc902781
Integration tests will now configure clients to propagate traces as well as create spans for all tests. Some extra changes were needed (or desired for trace propagation) in the test helpers to pass through tracing spans via context. Signed-off-by: Brian Goff <cpuguy83@gmail.com>
399 lines
12 KiB
Go
399 lines
12 KiB
Go
package config // import "github.com/docker/docker/integration/config"
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"sort"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/docker/docker/api/types"
|
|
"github.com/docker/docker/api/types/filters"
|
|
swarmtypes "github.com/docker/docker/api/types/swarm"
|
|
"github.com/docker/docker/client"
|
|
"github.com/docker/docker/errdefs"
|
|
"github.com/docker/docker/integration/internal/swarm"
|
|
"github.com/docker/docker/pkg/stdcopy"
|
|
"github.com/docker/docker/testutil"
|
|
"gotest.tools/v3/assert"
|
|
is "gotest.tools/v3/assert/cmp"
|
|
"gotest.tools/v3/poll"
|
|
"gotest.tools/v3/skip"
|
|
)
|
|
|
|
func TestConfigInspect(t *testing.T) {
|
|
skip.If(t, testEnv.DaemonInfo.OSType == "windows")
|
|
|
|
ctx := setupTest(t)
|
|
|
|
d := swarm.NewSwarm(ctx, t, testEnv)
|
|
defer d.Stop(t)
|
|
c := d.NewClientT(t)
|
|
defer c.Close()
|
|
|
|
testName := t.Name()
|
|
configID := createConfig(ctx, t, c, testName, []byte("TESTINGDATA"), nil)
|
|
|
|
insp, body, err := c.ConfigInspectWithRaw(ctx, configID)
|
|
assert.NilError(t, err)
|
|
assert.Check(t, is.Equal(insp.Spec.Name, testName))
|
|
|
|
var config swarmtypes.Config
|
|
err = json.Unmarshal(body, &config)
|
|
assert.NilError(t, err)
|
|
assert.Check(t, is.DeepEqual(config, insp))
|
|
}
|
|
|
|
func TestConfigList(t *testing.T) {
|
|
skip.If(t, testEnv.DaemonInfo.OSType == "windows")
|
|
|
|
ctx := setupTest(t)
|
|
|
|
d := swarm.NewSwarm(ctx, t, testEnv)
|
|
defer d.Stop(t)
|
|
c := d.NewClientT(t)
|
|
defer c.Close()
|
|
|
|
// This test case is ported from the original TestConfigsEmptyList
|
|
configs, err := c.ConfigList(ctx, types.ConfigListOptions{})
|
|
assert.NilError(t, err)
|
|
assert.Check(t, is.Equal(len(configs), 0))
|
|
|
|
testName0 := "test0-" + t.Name()
|
|
testName1 := "test1-" + t.Name()
|
|
testNames := []string{testName0, testName1}
|
|
sort.Strings(testNames)
|
|
|
|
// create config test0
|
|
createConfig(ctx, t, c, testName0, []byte("TESTINGDATA0"), map[string]string{"type": "test"})
|
|
|
|
config1ID := createConfig(ctx, t, c, testName1, []byte("TESTINGDATA1"), map[string]string{"type": "production"})
|
|
|
|
// test by `config ls`
|
|
entries, err := c.ConfigList(ctx, types.ConfigListOptions{})
|
|
assert.NilError(t, err)
|
|
assert.Check(t, is.DeepEqual(configNamesFromList(entries), testNames))
|
|
|
|
testCases := []struct {
|
|
desc string
|
|
filters filters.Args
|
|
expected []string
|
|
}{
|
|
{
|
|
desc: "test filter by name",
|
|
filters: filters.NewArgs(filters.Arg("name", testName0)),
|
|
expected: []string{testName0},
|
|
},
|
|
{
|
|
desc: "test filter by id",
|
|
filters: filters.NewArgs(filters.Arg("id", config1ID)),
|
|
expected: []string{testName1},
|
|
},
|
|
{
|
|
desc: "test filter by label key only",
|
|
filters: filters.NewArgs(filters.Arg("label", "type")),
|
|
expected: testNames,
|
|
},
|
|
{
|
|
desc: "test filter by label key=value " + testName0,
|
|
filters: filters.NewArgs(filters.Arg("label", "type=test")),
|
|
expected: []string{testName0},
|
|
},
|
|
{
|
|
desc: "test filter by label key=value " + testName1,
|
|
filters: filters.NewArgs(filters.Arg("label", "type=production")),
|
|
expected: []string{testName1},
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
tc := tc
|
|
t.Run(tc.desc, func(t *testing.T) {
|
|
ctx := testutil.StartSpan(ctx, t)
|
|
entries, err = c.ConfigList(ctx, types.ConfigListOptions{
|
|
Filters: tc.filters,
|
|
})
|
|
assert.NilError(t, err)
|
|
assert.Check(t, is.DeepEqual(configNamesFromList(entries), tc.expected))
|
|
})
|
|
}
|
|
}
|
|
|
|
func createConfig(ctx context.Context, t *testing.T, client client.APIClient, name string, data []byte, labels map[string]string) string {
|
|
config, err := client.ConfigCreate(ctx, swarmtypes.ConfigSpec{
|
|
Annotations: swarmtypes.Annotations{
|
|
Name: name,
|
|
Labels: labels,
|
|
},
|
|
Data: data,
|
|
})
|
|
assert.NilError(t, err)
|
|
assert.Check(t, config.ID != "")
|
|
return config.ID
|
|
}
|
|
|
|
func TestConfigsCreateAndDelete(t *testing.T) {
|
|
skip.If(t, testEnv.DaemonInfo.OSType == "windows")
|
|
|
|
ctx := setupTest(t)
|
|
d := swarm.NewSwarm(ctx, t, testEnv)
|
|
defer d.Stop(t)
|
|
c := d.NewClientT(t)
|
|
defer c.Close()
|
|
|
|
testName := "test_config-" + t.Name()
|
|
configID := createConfig(ctx, t, c, testName, []byte("TESTINGDATA"), nil)
|
|
|
|
err := c.ConfigRemove(ctx, configID)
|
|
assert.NilError(t, err)
|
|
|
|
_, _, err = c.ConfigInspectWithRaw(ctx, configID)
|
|
assert.Check(t, errdefs.IsNotFound(err))
|
|
assert.Check(t, is.ErrorContains(err, configID))
|
|
|
|
err = c.ConfigRemove(ctx, "non-existing")
|
|
assert.Check(t, errdefs.IsNotFound(err))
|
|
assert.Check(t, is.ErrorContains(err, "non-existing"))
|
|
|
|
testName = "test_secret_with_labels_" + t.Name()
|
|
configID = createConfig(ctx, t, c, testName, []byte("TESTINGDATA"), map[string]string{
|
|
"key1": "value1",
|
|
"key2": "value2",
|
|
})
|
|
|
|
insp, _, err := c.ConfigInspectWithRaw(ctx, configID)
|
|
assert.NilError(t, err)
|
|
assert.Check(t, is.Equal(insp.Spec.Name, testName))
|
|
assert.Check(t, is.Equal(len(insp.Spec.Labels), 2))
|
|
assert.Check(t, is.Equal(insp.Spec.Labels["key1"], "value1"))
|
|
assert.Check(t, is.Equal(insp.Spec.Labels["key2"], "value2"))
|
|
}
|
|
|
|
func TestConfigsUpdate(t *testing.T) {
|
|
skip.If(t, testEnv.DaemonInfo.OSType == "windows")
|
|
|
|
ctx := setupTest(t)
|
|
|
|
d := swarm.NewSwarm(ctx, t, testEnv)
|
|
defer d.Stop(t)
|
|
c := d.NewClientT(t)
|
|
defer c.Close()
|
|
|
|
testName := "test_config-" + t.Name()
|
|
configID := createConfig(ctx, t, c, testName, []byte("TESTINGDATA"), nil)
|
|
|
|
insp, _, err := c.ConfigInspectWithRaw(ctx, configID)
|
|
assert.NilError(t, err)
|
|
assert.Check(t, is.Equal(insp.ID, configID))
|
|
|
|
// test UpdateConfig with full ID
|
|
insp.Spec.Labels = map[string]string{"test": "test1"}
|
|
err = c.ConfigUpdate(ctx, configID, insp.Version, insp.Spec)
|
|
assert.NilError(t, err)
|
|
|
|
insp, _, err = c.ConfigInspectWithRaw(ctx, configID)
|
|
assert.NilError(t, err)
|
|
assert.Check(t, is.Equal(insp.Spec.Labels["test"], "test1"))
|
|
|
|
// test UpdateConfig with full name
|
|
insp.Spec.Labels = map[string]string{"test": "test2"}
|
|
err = c.ConfigUpdate(ctx, testName, insp.Version, insp.Spec)
|
|
assert.NilError(t, err)
|
|
|
|
insp, _, err = c.ConfigInspectWithRaw(ctx, configID)
|
|
assert.NilError(t, err)
|
|
assert.Check(t, is.Equal(insp.Spec.Labels["test"], "test2"))
|
|
|
|
// test UpdateConfig with prefix ID
|
|
insp.Spec.Labels = map[string]string{"test": "test3"}
|
|
err = c.ConfigUpdate(ctx, configID[:1], insp.Version, insp.Spec)
|
|
assert.NilError(t, err)
|
|
|
|
insp, _, err = c.ConfigInspectWithRaw(ctx, configID)
|
|
assert.NilError(t, err)
|
|
assert.Check(t, is.Equal(insp.Spec.Labels["test"], "test3"))
|
|
|
|
// test UpdateConfig in updating Data which is not supported in daemon
|
|
// this test will produce an error in func UpdateConfig
|
|
insp.Spec.Data = []byte("TESTINGDATA2")
|
|
err = c.ConfigUpdate(ctx, configID, insp.Version, insp.Spec)
|
|
assert.Check(t, errdefs.IsInvalidParameter(err))
|
|
assert.Check(t, is.ErrorContains(err, "only updates to Labels are allowed"))
|
|
}
|
|
|
|
func TestTemplatedConfig(t *testing.T) {
|
|
skip.If(t, testEnv.DaemonInfo.OSType == "windows")
|
|
ctx := testutil.StartSpan(baseContext, t)
|
|
|
|
d := swarm.NewSwarm(ctx, t, testEnv)
|
|
defer d.Stop(t)
|
|
c := d.NewClientT(t)
|
|
defer c.Close()
|
|
|
|
referencedSecretName := "referencedsecret-" + t.Name()
|
|
referencedSecretSpec := swarmtypes.SecretSpec{
|
|
Annotations: swarmtypes.Annotations{
|
|
Name: referencedSecretName,
|
|
},
|
|
Data: []byte("this is a secret"),
|
|
}
|
|
referencedSecret, err := c.SecretCreate(ctx, referencedSecretSpec)
|
|
assert.Check(t, err)
|
|
|
|
referencedConfigName := "referencedconfig-" + t.Name()
|
|
referencedConfigSpec := swarmtypes.ConfigSpec{
|
|
Annotations: swarmtypes.Annotations{
|
|
Name: referencedConfigName,
|
|
},
|
|
Data: []byte("this is a config"),
|
|
}
|
|
referencedConfig, err := c.ConfigCreate(ctx, referencedConfigSpec)
|
|
assert.Check(t, err)
|
|
|
|
templatedConfigName := "templated_config-" + t.Name()
|
|
configSpec := swarmtypes.ConfigSpec{
|
|
Annotations: swarmtypes.Annotations{
|
|
Name: templatedConfigName,
|
|
},
|
|
Templating: &swarmtypes.Driver{
|
|
Name: "golang",
|
|
},
|
|
Data: []byte(`SERVICE_NAME={{.Service.Name}}
|
|
{{secret "referencedsecrettarget"}}
|
|
{{config "referencedconfigtarget"}}
|
|
`),
|
|
}
|
|
|
|
templatedConfig, err := c.ConfigCreate(ctx, configSpec)
|
|
assert.Check(t, err)
|
|
|
|
serviceName := "svc_" + t.Name()
|
|
serviceID := swarm.CreateService(ctx, t, d,
|
|
swarm.ServiceWithConfig(
|
|
&swarmtypes.ConfigReference{
|
|
File: &swarmtypes.ConfigReferenceFileTarget{
|
|
Name: "templated_config",
|
|
UID: "0",
|
|
GID: "0",
|
|
Mode: 0o600,
|
|
},
|
|
ConfigID: templatedConfig.ID,
|
|
ConfigName: templatedConfigName,
|
|
},
|
|
),
|
|
swarm.ServiceWithConfig(
|
|
&swarmtypes.ConfigReference{
|
|
File: &swarmtypes.ConfigReferenceFileTarget{
|
|
Name: "referencedconfigtarget",
|
|
UID: "0",
|
|
GID: "0",
|
|
Mode: 0o600,
|
|
},
|
|
ConfigID: referencedConfig.ID,
|
|
ConfigName: referencedConfigName,
|
|
},
|
|
),
|
|
swarm.ServiceWithSecret(
|
|
&swarmtypes.SecretReference{
|
|
File: &swarmtypes.SecretReferenceFileTarget{
|
|
Name: "referencedsecrettarget",
|
|
UID: "0",
|
|
GID: "0",
|
|
Mode: 0o600,
|
|
},
|
|
SecretID: referencedSecret.ID,
|
|
SecretName: referencedSecretName,
|
|
},
|
|
),
|
|
swarm.ServiceWithName(serviceName),
|
|
)
|
|
|
|
poll.WaitOn(t, swarm.RunningTasksCount(ctx, c, serviceID, 1), swarm.ServicePoll, poll.WithTimeout(1*time.Minute))
|
|
|
|
tasks := swarm.GetRunningTasks(ctx, t, c, serviceID)
|
|
assert.Assert(t, len(tasks) > 0, "no running tasks found for service %s", serviceID)
|
|
|
|
attach := swarm.ExecTask(ctx, t, d, tasks[0], types.ExecConfig{
|
|
Cmd: []string{"/bin/cat", "/templated_config"},
|
|
AttachStdout: true,
|
|
AttachStderr: true,
|
|
})
|
|
|
|
expect := "SERVICE_NAME=" + serviceName + "\n" +
|
|
"this is a secret\n" +
|
|
"this is a config\n"
|
|
assertAttachedStream(t, attach, expect)
|
|
|
|
attach = swarm.ExecTask(ctx, t, d, tasks[0], types.ExecConfig{
|
|
Cmd: []string{"mount"},
|
|
AttachStdout: true,
|
|
AttachStderr: true,
|
|
})
|
|
assertAttachedStream(t, attach, "tmpfs on /templated_config type tmpfs")
|
|
}
|
|
|
|
// Test case for 28884
|
|
func TestConfigCreateResolve(t *testing.T) {
|
|
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
|
|
|
|
ctx := setupTest(t)
|
|
|
|
d := swarm.NewSwarm(ctx, t, testEnv)
|
|
defer d.Stop(t)
|
|
c := d.NewClientT(t)
|
|
defer c.Close()
|
|
|
|
configName := "test_config_" + t.Name()
|
|
configID := createConfig(ctx, t, c, configName, []byte("foo"), nil)
|
|
|
|
fakeName := configID
|
|
fakeID := createConfig(ctx, t, c, fakeName, []byte("fake foo"), nil)
|
|
|
|
entries, err := c.ConfigList(ctx, types.ConfigListOptions{})
|
|
assert.NilError(t, err)
|
|
assert.Assert(t, is.Contains(configNamesFromList(entries), configName))
|
|
assert.Assert(t, is.Contains(configNamesFromList(entries), fakeName))
|
|
|
|
err = c.ConfigRemove(ctx, configID)
|
|
assert.NilError(t, err)
|
|
|
|
// Fake one will remain
|
|
entries, err = c.ConfigList(ctx, types.ConfigListOptions{})
|
|
assert.NilError(t, err)
|
|
assert.Assert(t, is.DeepEqual(configNamesFromList(entries), []string{fakeName}))
|
|
|
|
// Remove based on name prefix of the fake one
|
|
// (which is the same as the ID of foo one) should not work
|
|
// as search is only done based on:
|
|
// - Full ID
|
|
// - Full Name
|
|
// - Partial ID (prefix)
|
|
err = c.ConfigRemove(ctx, configID[:5])
|
|
assert.Assert(t, nil != err)
|
|
entries, err = c.ConfigList(ctx, types.ConfigListOptions{})
|
|
assert.NilError(t, err)
|
|
assert.Assert(t, is.DeepEqual(configNamesFromList(entries), []string{fakeName}))
|
|
|
|
// Remove based on ID prefix of the fake one should succeed
|
|
err = c.ConfigRemove(ctx, fakeID[:5])
|
|
assert.NilError(t, err)
|
|
entries, err = c.ConfigList(ctx, types.ConfigListOptions{})
|
|
assert.NilError(t, err)
|
|
assert.Assert(t, is.Equal(0, len(entries)))
|
|
}
|
|
|
|
func assertAttachedStream(t *testing.T, attach types.HijackedResponse, expect string) {
|
|
buf := bytes.NewBuffer(nil)
|
|
_, err := stdcopy.StdCopy(buf, buf, attach.Reader)
|
|
assert.NilError(t, err)
|
|
assert.Check(t, is.Contains(buf.String(), expect))
|
|
}
|
|
|
|
func configNamesFromList(entries []swarmtypes.Config) []string {
|
|
var values []string
|
|
for _, entry := range entries {
|
|
values = append(values, entry.Spec.Name)
|
|
}
|
|
sort.Strings(values)
|
|
return values
|
|
}
|