713c7d49a1
This removes various skips that accounted for running the integration tests
against older versions of the daemon before 20.10 (API version v1.41). Those
versions are EOL, and we don't run tests against them.
This reverts most of e440831802
, and similar
PRs.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
379 lines
13 KiB
Go
379 lines
13 KiB
Go
package service // import "github.com/docker/docker/integration/service"
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"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/integration/internal/network"
|
|
"github.com/docker/docker/integration/internal/swarm"
|
|
"github.com/docker/docker/testutil"
|
|
"gotest.tools/v3/assert"
|
|
is "gotest.tools/v3/assert/cmp"
|
|
"gotest.tools/v3/poll"
|
|
"gotest.tools/v3/skip"
|
|
)
|
|
|
|
func TestServiceUpdateLabel(t *testing.T) {
|
|
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
|
|
ctx := setupTest(t)
|
|
|
|
d := swarm.NewSwarm(ctx, t, testEnv)
|
|
defer d.Stop(t)
|
|
cli := d.NewClientT(t)
|
|
defer cli.Close()
|
|
|
|
serviceName := "TestService_" + t.Name()
|
|
serviceID := swarm.CreateService(ctx, t, d, swarm.ServiceWithName(serviceName))
|
|
service := getService(ctx, t, cli, serviceID)
|
|
assert.Check(t, is.DeepEqual(service.Spec.Labels, map[string]string{}))
|
|
|
|
// add label to empty set
|
|
service.Spec.Labels["foo"] = "bar"
|
|
_, err := cli.ServiceUpdate(ctx, serviceID, service.Version, service.Spec, types.ServiceUpdateOptions{})
|
|
assert.NilError(t, err)
|
|
poll.WaitOn(t, serviceSpecIsUpdated(ctx, cli, serviceID, service.Version.Index), swarm.ServicePoll)
|
|
service = getService(ctx, t, cli, serviceID)
|
|
assert.Check(t, is.DeepEqual(service.Spec.Labels, map[string]string{"foo": "bar"}))
|
|
|
|
// add label to non-empty set
|
|
service.Spec.Labels["foo2"] = "bar"
|
|
_, err = cli.ServiceUpdate(ctx, serviceID, service.Version, service.Spec, types.ServiceUpdateOptions{})
|
|
assert.NilError(t, err)
|
|
poll.WaitOn(t, serviceSpecIsUpdated(ctx, cli, serviceID, service.Version.Index), swarm.ServicePoll)
|
|
service = getService(ctx, t, cli, serviceID)
|
|
assert.Check(t, is.DeepEqual(service.Spec.Labels, map[string]string{"foo": "bar", "foo2": "bar"}))
|
|
|
|
delete(service.Spec.Labels, "foo2")
|
|
_, err = cli.ServiceUpdate(ctx, serviceID, service.Version, service.Spec, types.ServiceUpdateOptions{})
|
|
assert.NilError(t, err)
|
|
poll.WaitOn(t, serviceSpecIsUpdated(ctx, cli, serviceID, service.Version.Index), swarm.ServicePoll)
|
|
service = getService(ctx, t, cli, serviceID)
|
|
assert.Check(t, is.DeepEqual(service.Spec.Labels, map[string]string{"foo": "bar"}))
|
|
|
|
delete(service.Spec.Labels, "foo")
|
|
_, err = cli.ServiceUpdate(ctx, serviceID, service.Version, service.Spec, types.ServiceUpdateOptions{})
|
|
assert.NilError(t, err)
|
|
poll.WaitOn(t, serviceSpecIsUpdated(ctx, cli, serviceID, service.Version.Index), swarm.ServicePoll)
|
|
service = getService(ctx, t, cli, serviceID)
|
|
assert.Check(t, is.DeepEqual(service.Spec.Labels, map[string]string{}))
|
|
|
|
// now make sure we can add again
|
|
service.Spec.Labels["foo"] = "bar"
|
|
_, err = cli.ServiceUpdate(ctx, serviceID, service.Version, service.Spec, types.ServiceUpdateOptions{})
|
|
assert.NilError(t, err)
|
|
poll.WaitOn(t, serviceSpecIsUpdated(ctx, cli, serviceID, service.Version.Index), swarm.ServicePoll)
|
|
service = getService(ctx, t, cli, serviceID)
|
|
assert.Check(t, is.DeepEqual(service.Spec.Labels, map[string]string{"foo": "bar"}))
|
|
|
|
err = cli.ServiceRemove(ctx, serviceID)
|
|
assert.NilError(t, err)
|
|
}
|
|
|
|
func TestServiceUpdateSecrets(t *testing.T) {
|
|
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
|
|
ctx := setupTest(t)
|
|
|
|
d := swarm.NewSwarm(ctx, t, testEnv)
|
|
defer d.Stop(t)
|
|
cli := d.NewClientT(t)
|
|
defer cli.Close()
|
|
|
|
secretName := "TestSecret_" + t.Name()
|
|
secretTarget := "targetName"
|
|
resp, err := cli.SecretCreate(ctx, swarmtypes.SecretSpec{
|
|
Annotations: swarmtypes.Annotations{
|
|
Name: secretName,
|
|
},
|
|
Data: []byte("TESTINGDATA"),
|
|
})
|
|
assert.NilError(t, err)
|
|
assert.Check(t, resp.ID != "")
|
|
|
|
serviceName := "TestService_" + t.Name()
|
|
serviceID := swarm.CreateService(ctx, t, d, swarm.ServiceWithName(serviceName))
|
|
service := getService(ctx, t, cli, serviceID)
|
|
|
|
// add secret
|
|
service.Spec.TaskTemplate.ContainerSpec.Secrets = append(service.Spec.TaskTemplate.ContainerSpec.Secrets,
|
|
&swarmtypes.SecretReference{
|
|
File: &swarmtypes.SecretReferenceFileTarget{
|
|
Name: secretTarget,
|
|
UID: "0",
|
|
GID: "0",
|
|
Mode: 0o600,
|
|
},
|
|
SecretID: resp.ID,
|
|
SecretName: secretName,
|
|
},
|
|
)
|
|
_, err = cli.ServiceUpdate(ctx, serviceID, service.Version, service.Spec, types.ServiceUpdateOptions{})
|
|
assert.NilError(t, err)
|
|
poll.WaitOn(t, serviceIsUpdated(ctx, cli, serviceID), swarm.ServicePoll)
|
|
|
|
service = getService(ctx, t, cli, serviceID)
|
|
secrets := service.Spec.TaskTemplate.ContainerSpec.Secrets
|
|
assert.Assert(t, is.Equal(1, len(secrets)))
|
|
|
|
secret := *secrets[0]
|
|
assert.Check(t, is.Equal(secretName, secret.SecretName))
|
|
assert.Check(t, nil != secret.File)
|
|
assert.Check(t, is.Equal(secretTarget, secret.File.Name))
|
|
|
|
// remove
|
|
service.Spec.TaskTemplate.ContainerSpec.Secrets = []*swarmtypes.SecretReference{}
|
|
_, err = cli.ServiceUpdate(ctx, serviceID, service.Version, service.Spec, types.ServiceUpdateOptions{})
|
|
assert.NilError(t, err)
|
|
poll.WaitOn(t, serviceIsUpdated(ctx, cli, serviceID), swarm.ServicePoll)
|
|
service = getService(ctx, t, cli, serviceID)
|
|
assert.Check(t, is.Equal(0, len(service.Spec.TaskTemplate.ContainerSpec.Secrets)))
|
|
|
|
err = cli.ServiceRemove(ctx, serviceID)
|
|
assert.NilError(t, err)
|
|
}
|
|
|
|
func TestServiceUpdateConfigs(t *testing.T) {
|
|
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
|
|
ctx := setupTest(t)
|
|
|
|
d := swarm.NewSwarm(ctx, t, testEnv)
|
|
defer d.Stop(t)
|
|
cli := d.NewClientT(t)
|
|
defer cli.Close()
|
|
|
|
configName := "TestConfig_" + t.Name()
|
|
configTarget := "targetName"
|
|
resp, err := cli.ConfigCreate(ctx, swarmtypes.ConfigSpec{
|
|
Annotations: swarmtypes.Annotations{
|
|
Name: configName,
|
|
},
|
|
Data: []byte("TESTINGDATA"),
|
|
})
|
|
assert.NilError(t, err)
|
|
assert.Check(t, resp.ID != "")
|
|
|
|
serviceName := "TestService_" + t.Name()
|
|
serviceID := swarm.CreateService(ctx, t, d, swarm.ServiceWithName(serviceName))
|
|
service := getService(ctx, t, cli, serviceID)
|
|
|
|
// add config
|
|
service.Spec.TaskTemplate.ContainerSpec.Configs = append(service.Spec.TaskTemplate.ContainerSpec.Configs,
|
|
&swarmtypes.ConfigReference{
|
|
File: &swarmtypes.ConfigReferenceFileTarget{
|
|
Name: configTarget,
|
|
UID: "0",
|
|
GID: "0",
|
|
Mode: 0o600,
|
|
},
|
|
ConfigID: resp.ID,
|
|
ConfigName: configName,
|
|
},
|
|
)
|
|
_, err = cli.ServiceUpdate(ctx, serviceID, service.Version, service.Spec, types.ServiceUpdateOptions{})
|
|
assert.NilError(t, err)
|
|
poll.WaitOn(t, serviceIsUpdated(ctx, cli, serviceID), swarm.ServicePoll)
|
|
|
|
service = getService(ctx, t, cli, serviceID)
|
|
configs := service.Spec.TaskTemplate.ContainerSpec.Configs
|
|
assert.Assert(t, is.Equal(1, len(configs)))
|
|
|
|
config := *configs[0]
|
|
assert.Check(t, is.Equal(configName, config.ConfigName))
|
|
assert.Check(t, nil != config.File)
|
|
assert.Check(t, is.Equal(configTarget, config.File.Name))
|
|
|
|
// remove
|
|
service.Spec.TaskTemplate.ContainerSpec.Configs = []*swarmtypes.ConfigReference{}
|
|
_, err = cli.ServiceUpdate(ctx, serviceID, service.Version, service.Spec, types.ServiceUpdateOptions{})
|
|
assert.NilError(t, err)
|
|
poll.WaitOn(t, serviceIsUpdated(ctx, cli, serviceID), swarm.ServicePoll)
|
|
service = getService(ctx, t, cli, serviceID)
|
|
assert.Check(t, is.Equal(0, len(service.Spec.TaskTemplate.ContainerSpec.Configs)))
|
|
|
|
err = cli.ServiceRemove(ctx, serviceID)
|
|
assert.NilError(t, err)
|
|
}
|
|
|
|
func TestServiceUpdateNetwork(t *testing.T) {
|
|
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
|
|
ctx := setupTest(t)
|
|
|
|
d := swarm.NewSwarm(ctx, t, testEnv)
|
|
defer d.Stop(t)
|
|
cli := d.NewClientT(t)
|
|
defer cli.Close()
|
|
|
|
// Create a overlay network
|
|
testNet := "testNet" + t.Name()
|
|
overlayID := network.CreateNoError(ctx, t, cli, testNet,
|
|
network.WithDriver("overlay"))
|
|
|
|
var instances uint64 = 1
|
|
// Create service with the overlay network
|
|
serviceName := "TestServiceUpdateNetworkRM_" + t.Name()
|
|
serviceID := swarm.CreateService(ctx, t, d,
|
|
swarm.ServiceWithReplicas(instances),
|
|
swarm.ServiceWithName(serviceName),
|
|
swarm.ServiceWithNetwork(testNet))
|
|
|
|
poll.WaitOn(t, swarm.RunningTasksCount(ctx, cli, serviceID, instances), swarm.ServicePoll)
|
|
service := getService(ctx, t, cli, serviceID)
|
|
netInfo, err := cli.NetworkInspect(ctx, testNet, types.NetworkInspectOptions{
|
|
Verbose: true,
|
|
Scope: "swarm",
|
|
})
|
|
assert.NilError(t, err)
|
|
assert.Assert(t, len(netInfo.Containers) == 2, "Expected 2 endpoints, one for container and one for LB Sandbox")
|
|
|
|
// Remove network from service
|
|
service.Spec.TaskTemplate.Networks = []swarmtypes.NetworkAttachmentConfig{}
|
|
_, err = cli.ServiceUpdate(ctx, serviceID, service.Version, service.Spec, types.ServiceUpdateOptions{})
|
|
assert.NilError(t, err)
|
|
poll.WaitOn(t, serviceIsUpdated(ctx, cli, serviceID), swarm.ServicePoll)
|
|
|
|
netInfo, err = cli.NetworkInspect(ctx, testNet, types.NetworkInspectOptions{
|
|
Verbose: true,
|
|
Scope: "swarm",
|
|
})
|
|
|
|
assert.NilError(t, err)
|
|
assert.Assert(t, len(netInfo.Containers) == 0, "Load balancing endpoint still exists in network")
|
|
|
|
err = cli.NetworkRemove(ctx, overlayID)
|
|
assert.NilError(t, err)
|
|
|
|
err = cli.ServiceRemove(ctx, serviceID)
|
|
assert.NilError(t, err)
|
|
}
|
|
|
|
// TestServiceUpdatePidsLimit tests creating and updating a service with PidsLimit
|
|
func TestServiceUpdatePidsLimit(t *testing.T) {
|
|
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
|
|
tests := []struct {
|
|
name string
|
|
pidsLimit int64
|
|
expected int64
|
|
}{
|
|
{
|
|
name: "create service with PidsLimit 300",
|
|
pidsLimit: 300,
|
|
expected: 300,
|
|
},
|
|
{
|
|
name: "unset PidsLimit to 0",
|
|
pidsLimit: 0,
|
|
expected: 0,
|
|
},
|
|
{
|
|
name: "update PidsLimit to 100",
|
|
pidsLimit: 100,
|
|
expected: 100,
|
|
},
|
|
}
|
|
|
|
ctx := setupTest(t)
|
|
|
|
d := swarm.NewSwarm(ctx, t, testEnv)
|
|
defer d.Stop(t)
|
|
cli := d.NewClientT(t)
|
|
defer func() { _ = cli.Close() }()
|
|
var (
|
|
serviceID string
|
|
service swarmtypes.Service
|
|
)
|
|
for i, tc := range tests {
|
|
tc := tc
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
ctx := testutil.StartSpan(ctx, t)
|
|
if i == 0 {
|
|
serviceID = swarm.CreateService(ctx, t, d, swarm.ServiceWithPidsLimit(tc.pidsLimit))
|
|
} else {
|
|
service = getService(ctx, t, cli, serviceID)
|
|
if service.Spec.TaskTemplate.Resources == nil {
|
|
service.Spec.TaskTemplate.Resources = &swarmtypes.ResourceRequirements{}
|
|
}
|
|
if service.Spec.TaskTemplate.Resources.Limits == nil {
|
|
service.Spec.TaskTemplate.Resources.Limits = &swarmtypes.Limit{}
|
|
}
|
|
service.Spec.TaskTemplate.Resources.Limits.Pids = tc.pidsLimit
|
|
_, err := cli.ServiceUpdate(ctx, serviceID, service.Version, service.Spec, types.ServiceUpdateOptions{})
|
|
assert.NilError(t, err)
|
|
poll.WaitOn(t, serviceIsUpdated(ctx, cli, serviceID), swarm.ServicePoll)
|
|
}
|
|
|
|
poll.WaitOn(t, swarm.RunningTasksCount(ctx, cli, serviceID, 1), swarm.ServicePoll)
|
|
service = getService(ctx, t, cli, serviceID)
|
|
container := getServiceTaskContainer(ctx, t, cli, serviceID)
|
|
assert.Equal(t, service.Spec.TaskTemplate.Resources.Limits.Pids, tc.expected)
|
|
if tc.expected == 0 {
|
|
if container.HostConfig.Resources.PidsLimit != nil {
|
|
t.Fatalf("Expected container.HostConfig.Resources.PidsLimit to be nil")
|
|
}
|
|
} else {
|
|
assert.Assert(t, container.HostConfig.Resources.PidsLimit != nil)
|
|
assert.Equal(t, *container.HostConfig.Resources.PidsLimit, tc.expected)
|
|
}
|
|
})
|
|
}
|
|
|
|
err := cli.ServiceRemove(ctx, serviceID)
|
|
assert.NilError(t, err)
|
|
}
|
|
|
|
func getServiceTaskContainer(ctx context.Context, t *testing.T, cli client.APIClient, serviceID string) types.ContainerJSON {
|
|
t.Helper()
|
|
tasks, err := cli.TaskList(ctx, types.TaskListOptions{
|
|
Filters: filters.NewArgs(
|
|
filters.Arg("service", serviceID),
|
|
filters.Arg("desired-state", "running"),
|
|
),
|
|
})
|
|
assert.NilError(t, err)
|
|
assert.Assert(t, len(tasks) > 0)
|
|
|
|
ctr, err := cli.ContainerInspect(ctx, tasks[0].Status.ContainerStatus.ContainerID)
|
|
assert.NilError(t, err)
|
|
assert.Equal(t, ctr.State.Running, true)
|
|
return ctr
|
|
}
|
|
|
|
func getService(ctx context.Context, t *testing.T, cli client.ServiceAPIClient, serviceID string) swarmtypes.Service {
|
|
t.Helper()
|
|
service, _, err := cli.ServiceInspectWithRaw(ctx, serviceID, types.ServiceInspectOptions{})
|
|
assert.NilError(t, err)
|
|
return service
|
|
}
|
|
|
|
func serviceIsUpdated(ctx context.Context, client client.ServiceAPIClient, serviceID string) func(log poll.LogT) poll.Result {
|
|
return func(log poll.LogT) poll.Result {
|
|
service, _, err := client.ServiceInspectWithRaw(ctx, serviceID, types.ServiceInspectOptions{})
|
|
switch {
|
|
case err != nil:
|
|
return poll.Error(err)
|
|
case service.UpdateStatus != nil && service.UpdateStatus.State == swarmtypes.UpdateStateCompleted:
|
|
return poll.Success()
|
|
default:
|
|
if service.UpdateStatus != nil {
|
|
return poll.Continue("waiting for service %s to be updated, state: %s, message: %s", serviceID, service.UpdateStatus.State, service.UpdateStatus.Message)
|
|
}
|
|
return poll.Continue("waiting for service %s to be updated", serviceID)
|
|
}
|
|
}
|
|
}
|
|
|
|
func serviceSpecIsUpdated(ctx context.Context, client client.ServiceAPIClient, serviceID string, serviceOldVersion uint64) func(log poll.LogT) poll.Result {
|
|
return func(log poll.LogT) poll.Result {
|
|
service, _, err := client.ServiceInspectWithRaw(ctx, serviceID, types.ServiceInspectOptions{})
|
|
switch {
|
|
case err != nil:
|
|
return poll.Error(err)
|
|
case service.Version.Index > serviceOldVersion:
|
|
return poll.Success()
|
|
default:
|
|
return poll.Continue("waiting for service %s to be updated", serviceID)
|
|
}
|
|
}
|
|
}
|