2018-02-02 22:23:12 +00:00
|
|
|
package swarm
|
|
|
|
|
|
|
|
import (
|
2017-06-15 19:06:08 +00:00
|
|
|
"context"
|
2018-02-02 22:23:12 +00:00
|
|
|
"fmt"
|
|
|
|
"testing"
|
|
|
|
|
2017-06-15 19:06:08 +00:00
|
|
|
"github.com/docker/docker/api/types"
|
|
|
|
"github.com/docker/docker/api/types/filters"
|
2018-02-02 22:23:12 +00:00
|
|
|
swarmtypes "github.com/docker/docker/api/types/swarm"
|
2017-06-15 19:06:08 +00:00
|
|
|
"github.com/docker/docker/client"
|
2018-02-02 22:23:12 +00:00
|
|
|
"github.com/docker/docker/integration-cli/daemon"
|
|
|
|
"github.com/docker/docker/internal/test/environment"
|
2018-03-13 19:28:34 +00:00
|
|
|
"github.com/gotestyourself/gotestyourself/assert"
|
2018-03-14 10:21:21 +00:00
|
|
|
"github.com/gotestyourself/gotestyourself/skip"
|
2018-02-02 22:23:12 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
dockerdBinary = "dockerd"
|
|
|
|
defaultSwarmPort = 2477
|
|
|
|
)
|
|
|
|
|
2018-02-02 22:36:59 +00:00
|
|
|
// NewSwarm creates a swarm daemon for testing
|
2018-02-02 22:23:12 +00:00
|
|
|
func NewSwarm(t *testing.T, testEnv *environment.Execution) *daemon.Swarm {
|
2018-03-14 10:21:21 +00:00
|
|
|
skip.IfCondition(t, testEnv.IsRemoteDaemon())
|
2018-02-02 22:23:12 +00:00
|
|
|
d := &daemon.Swarm{
|
|
|
|
Daemon: daemon.New(t, "", dockerdBinary, daemon.Config{
|
|
|
|
Experimental: testEnv.DaemonInfo.ExperimentalBuild,
|
|
|
|
}),
|
|
|
|
// TODO: better method of finding an unused port
|
|
|
|
Port: defaultSwarmPort,
|
|
|
|
}
|
|
|
|
// TODO: move to a NewSwarm constructor
|
|
|
|
d.ListenAddr = fmt.Sprintf("0.0.0.0:%d", d.Port)
|
|
|
|
|
|
|
|
// avoid networking conflicts
|
|
|
|
args := []string{"--iptables=false", "--swarm-default-advertise-addr=lo"}
|
|
|
|
d.StartWithBusybox(t, args...)
|
|
|
|
|
2018-03-13 19:28:34 +00:00
|
|
|
assert.NilError(t, d.Init(swarmtypes.InitRequest{}))
|
2018-02-02 22:23:12 +00:00
|
|
|
return d
|
|
|
|
}
|
2017-06-15 19:06:08 +00:00
|
|
|
|
|
|
|
// ServiceSpecOpt is used with `CreateService` to pass in service spec modifiers
|
|
|
|
type ServiceSpecOpt func(*swarmtypes.ServiceSpec)
|
|
|
|
|
|
|
|
// CreateService creates a service on the passed in swarm daemon.
|
|
|
|
func CreateService(t *testing.T, d *daemon.Swarm, opts ...ServiceSpecOpt) string {
|
|
|
|
spec := defaultServiceSpec()
|
|
|
|
for _, o := range opts {
|
|
|
|
o(&spec)
|
|
|
|
}
|
|
|
|
|
|
|
|
client := GetClient(t, d)
|
|
|
|
|
|
|
|
resp, err := client.ServiceCreate(context.Background(), spec, types.ServiceCreateOptions{})
|
2018-03-13 19:28:34 +00:00
|
|
|
assert.NilError(t, err, "error creating service")
|
2017-06-15 19:06:08 +00:00
|
|
|
return resp.ID
|
|
|
|
}
|
|
|
|
|
|
|
|
func defaultServiceSpec() swarmtypes.ServiceSpec {
|
|
|
|
var spec swarmtypes.ServiceSpec
|
|
|
|
ServiceWithImage("busybox:latest")(&spec)
|
|
|
|
ServiceWithCommand([]string{"/bin/top"})(&spec)
|
|
|
|
ServiceWithReplicas(1)(&spec)
|
|
|
|
return spec
|
|
|
|
}
|
|
|
|
|
|
|
|
// ServiceWithImage sets the image to use for the service
|
|
|
|
func ServiceWithImage(image string) func(*swarmtypes.ServiceSpec) {
|
|
|
|
return func(spec *swarmtypes.ServiceSpec) {
|
|
|
|
ensureContainerSpec(spec)
|
|
|
|
spec.TaskTemplate.ContainerSpec.Image = image
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ServiceWithCommand sets the command to use for the service
|
|
|
|
func ServiceWithCommand(cmd []string) ServiceSpecOpt {
|
|
|
|
return func(spec *swarmtypes.ServiceSpec) {
|
|
|
|
ensureContainerSpec(spec)
|
|
|
|
spec.TaskTemplate.ContainerSpec.Command = cmd
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ServiceWithConfig adds the config reference to the service
|
|
|
|
func ServiceWithConfig(configRef *swarmtypes.ConfigReference) ServiceSpecOpt {
|
|
|
|
return func(spec *swarmtypes.ServiceSpec) {
|
|
|
|
ensureContainerSpec(spec)
|
|
|
|
spec.TaskTemplate.ContainerSpec.Configs = append(spec.TaskTemplate.ContainerSpec.Configs, configRef)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ServiceWithSecret adds the secret reference to the service
|
|
|
|
func ServiceWithSecret(secretRef *swarmtypes.SecretReference) ServiceSpecOpt {
|
|
|
|
return func(spec *swarmtypes.ServiceSpec) {
|
|
|
|
ensureContainerSpec(spec)
|
|
|
|
spec.TaskTemplate.ContainerSpec.Secrets = append(spec.TaskTemplate.ContainerSpec.Secrets, secretRef)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ServiceWithReplicas sets the replicas for the service
|
|
|
|
func ServiceWithReplicas(n uint64) ServiceSpecOpt {
|
|
|
|
return func(spec *swarmtypes.ServiceSpec) {
|
|
|
|
spec.Mode = swarmtypes.ServiceMode{
|
|
|
|
Replicated: &swarmtypes.ReplicatedService{
|
|
|
|
Replicas: &n,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ServiceWithName sets the name of the service
|
|
|
|
func ServiceWithName(name string) ServiceSpecOpt {
|
|
|
|
return func(spec *swarmtypes.ServiceSpec) {
|
|
|
|
spec.Annotations.Name = name
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetRunningTasks gets the list of running tasks for a service
|
|
|
|
func GetRunningTasks(t *testing.T, d *daemon.Swarm, serviceID string) []swarmtypes.Task {
|
|
|
|
client := GetClient(t, d)
|
|
|
|
|
|
|
|
filterArgs := filters.NewArgs()
|
|
|
|
filterArgs.Add("desired-state", "running")
|
|
|
|
filterArgs.Add("service", serviceID)
|
|
|
|
|
|
|
|
options := types.TaskListOptions{
|
|
|
|
Filters: filterArgs,
|
|
|
|
}
|
|
|
|
tasks, err := client.TaskList(context.Background(), options)
|
2018-03-13 19:28:34 +00:00
|
|
|
assert.NilError(t, err)
|
2017-06-15 19:06:08 +00:00
|
|
|
return tasks
|
|
|
|
}
|
|
|
|
|
|
|
|
// ExecTask runs the passed in exec config on the given task
|
|
|
|
func ExecTask(t *testing.T, d *daemon.Swarm, task swarmtypes.Task, config types.ExecConfig) types.HijackedResponse {
|
|
|
|
client := GetClient(t, d)
|
|
|
|
|
|
|
|
ctx := context.Background()
|
|
|
|
resp, err := client.ContainerExecCreate(ctx, task.Status.ContainerStatus.ContainerID, config)
|
2018-03-13 19:28:34 +00:00
|
|
|
assert.NilError(t, err, "error creating exec")
|
2017-06-15 19:06:08 +00:00
|
|
|
|
|
|
|
startCheck := types.ExecStartCheck{}
|
|
|
|
attach, err := client.ContainerExecAttach(ctx, resp.ID, startCheck)
|
2018-03-13 19:28:34 +00:00
|
|
|
assert.NilError(t, err, "error attaching to exec")
|
2017-06-15 19:06:08 +00:00
|
|
|
return attach
|
|
|
|
}
|
|
|
|
|
|
|
|
func ensureContainerSpec(spec *swarmtypes.ServiceSpec) {
|
|
|
|
if spec.TaskTemplate.ContainerSpec == nil {
|
|
|
|
spec.TaskTemplate.ContainerSpec = &swarmtypes.ContainerSpec{}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetClient creates a new client for the passed in swarm daemon.
|
|
|
|
func GetClient(t *testing.T, d *daemon.Swarm) client.APIClient {
|
|
|
|
client, err := client.NewClientWithOpts(client.WithHost((d.Sock())))
|
2018-03-13 19:28:34 +00:00
|
|
|
assert.NilError(t, err)
|
2017-06-15 19:06:08 +00:00
|
|
|
return client
|
|
|
|
}
|