Make internal/test/daemon.Daemon swarm aware

This remove the daemon.Swarm construction by make the new test Daemon
struct aware of swarm.

Signed-off-by: Vincent Demeester <vincent@sbr.pm>
This commit is contained in:
Vincent Demeester 2018-04-11 12:10:17 +02:00
parent f0d277fe84
commit 83d18cf4e3
No known key found for this signature in database
GPG Key ID: 083CC6FD6EB699A3
18 changed files with 721 additions and 697 deletions

View File

@ -311,7 +311,7 @@ func init() {
type DockerSwarmSuite struct {
server *httptest.Server
ds *DockerSuite
daemons []*daemon.Swarm
daemons []*daemon.Daemon
daemonsLock sync.Mutex // protect access to daemons
portIndex int
}
@ -328,14 +328,10 @@ func (s *DockerSwarmSuite) SetUpTest(c *check.C) {
testRequires(c, DaemonIsLinux, SameHostDaemon)
}
func (s *DockerSwarmSuite) AddDaemon(c *check.C, joinSwarm, manager bool) *daemon.Swarm {
d := &daemon.Swarm{
Daemon: daemon.New(c, dockerBinary, dockerdBinary, daemon.Config{
Experimental: testEnv.DaemonInfo.ExperimentalBuild,
}),
Port: defaultSwarmPort + s.portIndex,
}
d.ListenAddr = fmt.Sprintf("0.0.0.0:%d", d.Port)
func (s *DockerSwarmSuite) AddDaemon(c *check.C, joinSwarm, manager bool) *daemon.Daemon {
d := daemon.New(c, dockerBinary, dockerdBinary, daemon.Config{
Experimental: testEnv.DaemonInfo.ExperimentalBuild,
}, testdaemon.WithSwarmPort(defaultSwarmPort+s.portIndex))
args := []string{"--iptables=false", "--swarm-default-advertise-addr=lo"} // avoid networking conflicts
d.StartWithBusybox(c, args...)
@ -346,12 +342,12 @@ func (s *DockerSwarmSuite) AddDaemon(c *check.C, joinSwarm, manager bool) *daemo
if manager {
token = tokens.Manager
}
c.Assert(d.Join(swarm.JoinRequest{
RemoteAddrs: []string{s.daemons[0].ListenAddr},
d.SwarmJoin(c, swarm.JoinRequest{
RemoteAddrs: []string{s.daemons[0].SwarmListenAddr()},
JoinToken: token,
}), check.IsNil)
})
} else {
c.Assert(d.Init(swarm.InitRequest{}), check.IsNil)
d.SwarmInit(c, swarm.InitRequest{})
}
}

View File

@ -38,10 +38,8 @@ type Config struct {
// New returns a Daemon instance to be used for testing.
// This will create a directory such as d123456789 in the folder specified by $DOCKER_INTEGRATION_DAEMON_DEST or $DEST.
// The daemon will not automatically start.
func New(t testingT, dockerBinary string, dockerdBinary string, config Config) *Daemon {
ops := []func(*daemon.Daemon){
daemon.WithDockerdBinary(dockerdBinary),
}
func New(t testingT, dockerBinary string, dockerdBinary string, config Config, ops ...func(*daemon.Daemon)) *Daemon {
ops = append(ops, daemon.WithDockerdBinary(dockerdBinary))
if config.Experimental {
ops = append(ops, daemon.WithExperimental)
}
@ -150,6 +148,21 @@ func (d *Daemon) WaitRun(contID string) error {
return WaitInspectWithArgs(d.dockerBinary, contID, "{{.State.Running}}", "true", 10*time.Second, args...)
}
// CmdRetryOutOfSequence tries the specified command against the current daemon for 10 times
func (d *Daemon) CmdRetryOutOfSequence(args ...string) (string, error) {
for i := 0; ; i++ {
out, err := d.Cmd(args...)
if err != nil {
if strings.Contains(out, "update out of sequence") {
if i < 10 {
continue
}
}
}
return out, err
}
}
// WaitInspectWithArgs waits for the specified expression to be equals to the specified expected string in the given time.
// Deprecated: use cli.WaitCmd instead
func WaitInspectWithArgs(dockerBinary, name, expr, expected string, timeout time.Duration, arg ...string) error {

View File

@ -3,7 +3,6 @@ package daemon // import "github.com/docker/docker/integration-cli/daemon"
import (
"fmt"
"strings"
"time"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
@ -12,178 +11,12 @@ import (
"github.com/docker/docker/integration-cli/checker"
"github.com/go-check/check"
"github.com/gotestyourself/gotestyourself/assert"
"github.com/pkg/errors"
"golang.org/x/net/context"
)
// Swarm is a test daemon with helpers for participating in a swarm.
type Swarm struct {
*Daemon
swarm.Info
Port int
ListenAddr string
}
// Init initializes a new swarm cluster.
func (d *Swarm) Init(req swarm.InitRequest) error {
if req.ListenAddr == "" {
req.ListenAddr = d.ListenAddr
}
cli, err := d.NewClient()
if err != nil {
return fmt.Errorf("initializing swarm: failed to create client %v", err)
}
defer cli.Close()
_, err = cli.SwarmInit(context.Background(), req)
if err != nil {
return fmt.Errorf("initializing swarm: %v", err)
}
info, err := d.SwarmInfo()
if err != nil {
return err
}
d.Info = info
return nil
}
// Join joins a daemon to an existing cluster.
func (d *Swarm) Join(req swarm.JoinRequest) error {
if req.ListenAddr == "" {
req.ListenAddr = d.ListenAddr
}
cli, err := d.NewClient()
if err != nil {
return fmt.Errorf("joining swarm: failed to create client %v", err)
}
defer cli.Close()
err = cli.SwarmJoin(context.Background(), req)
if err != nil {
return fmt.Errorf("joining swarm: %v", err)
}
info, err := d.SwarmInfo()
if err != nil {
return err
}
d.Info = info
return nil
}
// Leave forces daemon to leave current cluster.
func (d *Swarm) Leave(force bool) error {
cli, err := d.NewClient()
if err != nil {
return fmt.Errorf("leaving swarm: failed to create client %v", err)
}
defer cli.Close()
err = cli.SwarmLeave(context.Background(), force)
if err != nil {
err = fmt.Errorf("leaving swarm: %v", err)
}
return err
}
// SwarmInfo returns the swarm information of the daemon
func (d *Swarm) SwarmInfo() (swarm.Info, error) {
cli, err := d.NewClient()
if err != nil {
return swarm.Info{}, fmt.Errorf("get swarm info: %v", err)
}
info, err := cli.Info(context.Background())
if err != nil {
return swarm.Info{}, fmt.Errorf("get swarm info: %v", err)
}
return info.Swarm, nil
}
// Unlock tries to unlock a locked swarm
func (d *Swarm) Unlock(req swarm.UnlockRequest) error {
cli, err := d.NewClient()
if err != nil {
return fmt.Errorf("unlocking swarm: failed to create client %v", err)
}
defer cli.Close()
err = cli.SwarmUnlock(context.Background(), req)
if err != nil {
err = errors.Wrap(err, "unlocking swarm")
}
return err
}
// ServiceConstructor defines a swarm service constructor function
type ServiceConstructor func(*swarm.Service)
// NodeConstructor defines a swarm node constructor
type NodeConstructor func(*swarm.Node)
// SecretConstructor defines a swarm secret constructor
type SecretConstructor func(*swarm.Secret)
// ConfigConstructor defines a swarm config constructor
type ConfigConstructor func(*swarm.Config)
// SpecConstructor defines a swarm spec constructor
type SpecConstructor func(*swarm.Spec)
// CreateServiceWithOptions creates a swarm service given the specified service constructors
// and auth config
func (d *Swarm) CreateServiceWithOptions(c *check.C, opts types.ServiceCreateOptions, f ...ServiceConstructor) string {
var service swarm.Service
for _, fn := range f {
fn(&service)
}
cli, err := d.NewClient()
c.Assert(err, checker.IsNil)
defer cli.Close()
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
res, err := cli.ServiceCreate(ctx, service.Spec, opts)
c.Assert(err, checker.IsNil)
return res.ID
}
// CreateService creates a swarm service given the specified service constructor
func (d *Swarm) CreateService(c *check.C, f ...ServiceConstructor) string {
return d.CreateServiceWithOptions(c, types.ServiceCreateOptions{}, f...)
}
// GetService returns the swarm service corresponding to the specified id
func (d *Swarm) GetService(c *check.C, id string) *swarm.Service {
cli, err := d.NewClient()
c.Assert(err, checker.IsNil)
defer cli.Close()
service, _, err := cli.ServiceInspectWithRaw(context.Background(), id, types.ServiceInspectOptions{})
c.Assert(err, checker.IsNil)
return &service
}
// GetServiceTasks returns the swarm tasks for the specified service
func (d *Swarm) GetServiceTasks(c *check.C, service string) []swarm.Task {
cli, err := d.NewClient()
c.Assert(err, checker.IsNil)
defer cli.Close()
filterArgs := filters.NewArgs()
filterArgs.Add("desired-state", "running")
filterArgs.Add("service", service)
options := types.TaskListOptions{
Filters: filterArgs,
}
tasks, err := cli.TaskList(context.Background(), options)
c.Assert(err, checker.IsNil)
return tasks
}
// CheckServiceTasksInState returns the number of tasks with a matching state,
// and optional message substring.
func (d *Swarm) CheckServiceTasksInState(service string, state swarm.TaskState, message string) func(*check.C) (interface{}, check.CommentInterface) {
func (d *Daemon) CheckServiceTasksInState(service string, state swarm.TaskState, message string) func(*check.C) (interface{}, check.CommentInterface) {
return func(c *check.C) (interface{}, check.CommentInterface) {
tasks := d.GetServiceTasks(c, service)
var count int
@ -200,7 +33,7 @@ func (d *Swarm) CheckServiceTasksInState(service string, state swarm.TaskState,
// CheckServiceTasksInStateWithError returns the number of tasks with a matching state,
// and optional message substring.
func (d *Swarm) CheckServiceTasksInStateWithError(service string, state swarm.TaskState, errorMessage string) func(*check.C) (interface{}, check.CommentInterface) {
func (d *Daemon) CheckServiceTasksInStateWithError(service string, state swarm.TaskState, errorMessage string) func(*check.C) (interface{}, check.CommentInterface) {
return func(c *check.C) (interface{}, check.CommentInterface) {
tasks := d.GetServiceTasks(c, service)
var count int
@ -216,12 +49,12 @@ func (d *Swarm) CheckServiceTasksInStateWithError(service string, state swarm.Ta
}
// CheckServiceRunningTasks returns the number of running tasks for the specified service
func (d *Swarm) CheckServiceRunningTasks(service string) func(*check.C) (interface{}, check.CommentInterface) {
func (d *Daemon) CheckServiceRunningTasks(service string) func(*check.C) (interface{}, check.CommentInterface) {
return d.CheckServiceTasksInState(service, swarm.TaskStateRunning, "")
}
// CheckServiceUpdateState returns the current update state for the specified service
func (d *Swarm) CheckServiceUpdateState(service string) func(*check.C) (interface{}, check.CommentInterface) {
func (d *Daemon) CheckServiceUpdateState(service string) func(*check.C) (interface{}, check.CommentInterface) {
return func(c *check.C) (interface{}, check.CommentInterface) {
service := d.GetService(c, service)
if service.UpdateStatus == nil {
@ -232,7 +65,7 @@ func (d *Swarm) CheckServiceUpdateState(service string) func(*check.C) (interfac
}
// CheckPluginRunning returns the runtime state of the plugin
func (d *Swarm) CheckPluginRunning(plugin string) func(c *check.C) (interface{}, check.CommentInterface) {
func (d *Daemon) CheckPluginRunning(plugin string) func(c *check.C) (interface{}, check.CommentInterface) {
return func(c *check.C) (interface{}, check.CommentInterface) {
apiclient, err := d.NewClient()
assert.NilError(c, err)
@ -246,7 +79,7 @@ func (d *Swarm) CheckPluginRunning(plugin string) func(c *check.C) (interface{},
}
// CheckPluginImage returns the runtime state of the plugin
func (d *Swarm) CheckPluginImage(plugin string) func(c *check.C) (interface{}, check.CommentInterface) {
func (d *Daemon) CheckPluginImage(plugin string) func(c *check.C) (interface{}, check.CommentInterface) {
return func(c *check.C) (interface{}, check.CommentInterface) {
apiclient, err := d.NewClient()
assert.NilError(c, err)
@ -260,7 +93,7 @@ func (d *Swarm) CheckPluginImage(plugin string) func(c *check.C) (interface{}, c
}
// CheckServiceTasks returns the number of tasks for the specified service
func (d *Swarm) CheckServiceTasks(service string) func(*check.C) (interface{}, check.CommentInterface) {
func (d *Daemon) CheckServiceTasks(service string) func(*check.C) (interface{}, check.CommentInterface) {
return func(c *check.C) (interface{}, check.CommentInterface) {
tasks := d.GetServiceTasks(c, service)
return len(tasks), nil
@ -268,7 +101,7 @@ func (d *Swarm) CheckServiceTasks(service string) func(*check.C) (interface{}, c
}
// CheckRunningTaskNetworks returns the number of times each network is referenced from a task.
func (d *Swarm) CheckRunningTaskNetworks(c *check.C) (interface{}, check.CommentInterface) {
func (d *Daemon) CheckRunningTaskNetworks(c *check.C) (interface{}, check.CommentInterface) {
cli, err := d.NewClient()
c.Assert(err, checker.IsNil)
defer cli.Close()
@ -293,7 +126,7 @@ func (d *Swarm) CheckRunningTaskNetworks(c *check.C) (interface{}, check.Comment
}
// CheckRunningTaskImages returns the times each image is running as a task.
func (d *Swarm) CheckRunningTaskImages(c *check.C) (interface{}, check.CommentInterface) {
func (d *Daemon) CheckRunningTaskImages(c *check.C) (interface{}, check.CommentInterface) {
cli, err := d.NewClient()
c.Assert(err, checker.IsNil)
defer cli.Close()
@ -318,7 +151,7 @@ func (d *Swarm) CheckRunningTaskImages(c *check.C) (interface{}, check.CommentIn
}
// CheckNodeReadyCount returns the number of ready node on the swarm
func (d *Swarm) CheckNodeReadyCount(c *check.C) (interface{}, check.CommentInterface) {
func (d *Daemon) CheckNodeReadyCount(c *check.C) (interface{}, check.CommentInterface) {
nodes := d.ListNodes(c)
var readyCount int
for _, node := range nodes {
@ -329,303 +162,21 @@ func (d *Swarm) CheckNodeReadyCount(c *check.C) (interface{}, check.CommentInter
return readyCount, nil
}
// GetTask returns the swarm task identified by the specified id
func (d *Swarm) GetTask(c *check.C, id string) swarm.Task {
cli, err := d.NewClient()
c.Assert(err, checker.IsNil)
defer cli.Close()
task, _, err := cli.TaskInspectWithRaw(context.Background(), id)
c.Assert(err, checker.IsNil)
return task
}
// UpdateService updates a swarm service with the specified service constructor
func (d *Swarm) UpdateService(c *check.C, service *swarm.Service, f ...ServiceConstructor) {
cli, err := d.NewClient()
c.Assert(err, checker.IsNil)
defer cli.Close()
for _, fn := range f {
fn(service)
}
_, err = cli.ServiceUpdate(context.Background(), service.ID, service.Version, service.Spec, types.ServiceUpdateOptions{})
c.Assert(err, checker.IsNil)
}
// RemoveService removes the specified service
func (d *Swarm) RemoveService(c *check.C, id string) {
cli, err := d.NewClient()
c.Assert(err, checker.IsNil)
defer cli.Close()
err = cli.ServiceRemove(context.Background(), id)
c.Assert(err, checker.IsNil)
}
// GetNode returns a swarm node identified by the specified id
func (d *Swarm) GetNode(c *check.C, id string) *swarm.Node {
cli, err := d.NewClient()
c.Assert(err, checker.IsNil)
defer cli.Close()
node, _, err := cli.NodeInspectWithRaw(context.Background(), id)
c.Assert(err, checker.IsNil)
c.Assert(node.ID, checker.Equals, id)
return &node
}
// RemoveNode removes the specified node
func (d *Swarm) RemoveNode(c *check.C, id string, force bool) {
cli, err := d.NewClient()
c.Assert(err, checker.IsNil)
defer cli.Close()
options := types.NodeRemoveOptions{
Force: force,
}
err = cli.NodeRemove(context.Background(), id, options)
c.Assert(err, checker.IsNil)
}
// UpdateNode updates a swarm node with the specified node constructor
func (d *Swarm) UpdateNode(c *check.C, id string, f ...NodeConstructor) {
cli, err := d.NewClient()
c.Assert(err, checker.IsNil)
defer cli.Close()
for i := 0; ; i++ {
node := d.GetNode(c, id)
for _, fn := range f {
fn(node)
}
err = cli.NodeUpdate(context.Background(), node.ID, node.Version, node.Spec)
if i < 10 && err != nil && strings.Contains(err.Error(), "update out of sequence") {
time.Sleep(100 * time.Millisecond)
continue
}
c.Assert(err, checker.IsNil)
return
}
}
// ListNodes returns the list of the current swarm nodes
func (d *Swarm) ListNodes(c *check.C) []swarm.Node {
cli, err := d.NewClient()
c.Assert(err, checker.IsNil)
defer cli.Close()
nodes, err := cli.NodeList(context.Background(), types.NodeListOptions{})
c.Assert(err, checker.IsNil)
return nodes
}
// ListServices returns the list of the current swarm services
func (d *Swarm) ListServices(c *check.C) []swarm.Service {
cli, err := d.NewClient()
c.Assert(err, checker.IsNil)
defer cli.Close()
services, err := cli.ServiceList(context.Background(), types.ServiceListOptions{})
c.Assert(err, checker.IsNil)
return services
}
// CreateSecret creates a secret given the specified spec
func (d *Swarm) CreateSecret(c *check.C, secretSpec swarm.SecretSpec) string {
cli, err := d.NewClient()
c.Assert(err, checker.IsNil)
defer cli.Close()
scr, err := cli.SecretCreate(context.Background(), secretSpec)
c.Assert(err, checker.IsNil)
return scr.ID
}
// ListSecrets returns the list of the current swarm secrets
func (d *Swarm) ListSecrets(c *check.C) []swarm.Secret {
cli, err := d.NewClient()
c.Assert(err, checker.IsNil)
defer cli.Close()
secrets, err := cli.SecretList(context.Background(), types.SecretListOptions{})
c.Assert(err, checker.IsNil)
return secrets
}
// GetSecret returns a swarm secret identified by the specified id
func (d *Swarm) GetSecret(c *check.C, id string) *swarm.Secret {
cli, err := d.NewClient()
c.Assert(err, checker.IsNil)
defer cli.Close()
secret, _, err := cli.SecretInspectWithRaw(context.Background(), id)
c.Assert(err, checker.IsNil)
return &secret
}
// DeleteSecret removes the swarm secret identified by the specified id
func (d *Swarm) DeleteSecret(c *check.C, id string) {
cli, err := d.NewClient()
c.Assert(err, checker.IsNil)
defer cli.Close()
err = cli.SecretRemove(context.Background(), id)
c.Assert(err, checker.IsNil)
}
// UpdateSecret updates the swarm secret identified by the specified id
// Currently, only label update is supported.
func (d *Swarm) UpdateSecret(c *check.C, id string, f ...SecretConstructor) {
cli, err := d.NewClient()
c.Assert(err, checker.IsNil)
defer cli.Close()
secret := d.GetSecret(c, id)
for _, fn := range f {
fn(secret)
}
err = cli.SecretUpdate(context.Background(), secret.ID, secret.Version, secret.Spec)
c.Assert(err, checker.IsNil)
}
// CreateConfig creates a config given the specified spec
func (d *Swarm) CreateConfig(c *check.C, configSpec swarm.ConfigSpec) string {
cli, err := d.NewClient()
c.Assert(err, checker.IsNil)
defer cli.Close()
scr, err := cli.ConfigCreate(context.Background(), configSpec)
c.Assert(err, checker.IsNil)
return scr.ID
}
// ListConfigs returns the list of the current swarm configs
func (d *Swarm) ListConfigs(c *check.C) []swarm.Config {
cli, err := d.NewClient()
c.Assert(err, checker.IsNil)
defer cli.Close()
configs, err := cli.ConfigList(context.Background(), types.ConfigListOptions{})
c.Assert(err, checker.IsNil)
return configs
}
// GetConfig returns a swarm config identified by the specified id
func (d *Swarm) GetConfig(c *check.C, id string) *swarm.Config {
cli, err := d.NewClient()
c.Assert(err, checker.IsNil)
defer cli.Close()
config, _, err := cli.ConfigInspectWithRaw(context.Background(), id)
c.Assert(err, checker.IsNil)
return &config
}
// DeleteConfig removes the swarm config identified by the specified id
func (d *Swarm) DeleteConfig(c *check.C, id string) {
cli, err := d.NewClient()
c.Assert(err, checker.IsNil)
defer cli.Close()
err = cli.ConfigRemove(context.Background(), id)
c.Assert(err, checker.IsNil)
}
// UpdateConfig updates the swarm config identified by the specified id
// Currently, only label update is supported.
func (d *Swarm) UpdateConfig(c *check.C, id string, f ...ConfigConstructor) {
cli, err := d.NewClient()
c.Assert(err, checker.IsNil)
defer cli.Close()
config := d.GetConfig(c, id)
for _, fn := range f {
fn(config)
}
err = cli.ConfigUpdate(context.Background(), config.ID, config.Version, config.Spec)
c.Assert(err, checker.IsNil)
}
// GetSwarm returns the current swarm object
func (d *Swarm) GetSwarm(c *check.C) swarm.Swarm {
cli, err := d.NewClient()
c.Assert(err, checker.IsNil)
defer cli.Close()
sw, err := cli.SwarmInspect(context.Background())
c.Assert(err, checker.IsNil)
return sw
}
// UpdateSwarm updates the current swarm object with the specified spec constructors
func (d *Swarm) UpdateSwarm(c *check.C, f ...SpecConstructor) {
cli, err := d.NewClient()
c.Assert(err, checker.IsNil)
defer cli.Close()
sw := d.GetSwarm(c)
for _, fn := range f {
fn(&sw.Spec)
}
err = cli.SwarmUpdate(context.Background(), sw.Version, sw.Spec, swarm.UpdateFlags{})
c.Assert(err, checker.IsNil)
}
// RotateTokens update the swarm to rotate tokens
func (d *Swarm) RotateTokens(c *check.C) {
cli, err := d.NewClient()
c.Assert(err, checker.IsNil)
defer cli.Close()
sw, err := cli.SwarmInspect(context.Background())
c.Assert(err, checker.IsNil)
flags := swarm.UpdateFlags{
RotateManagerToken: true,
RotateWorkerToken: true,
}
err = cli.SwarmUpdate(context.Background(), sw.Version, sw.Spec, flags)
c.Assert(err, checker.IsNil)
}
// JoinTokens returns the current swarm join tokens
func (d *Swarm) JoinTokens(c *check.C) swarm.JoinTokens {
cli, err := d.NewClient()
c.Assert(err, checker.IsNil)
defer cli.Close()
sw, err := cli.SwarmInspect(context.Background())
c.Assert(err, checker.IsNil)
return sw.JoinTokens
}
// CheckLocalNodeState returns the current swarm node state
func (d *Swarm) CheckLocalNodeState(c *check.C) (interface{}, check.CommentInterface) {
info, err := d.SwarmInfo()
c.Assert(err, checker.IsNil)
func (d *Daemon) CheckLocalNodeState(c *check.C) (interface{}, check.CommentInterface) {
info := d.SwarmInfo(c)
return info.LocalNodeState, nil
}
// CheckControlAvailable returns the current swarm control available
func (d *Swarm) CheckControlAvailable(c *check.C) (interface{}, check.CommentInterface) {
info, err := d.SwarmInfo()
c.Assert(err, checker.IsNil)
func (d *Daemon) CheckControlAvailable(c *check.C) (interface{}, check.CommentInterface) {
info := d.SwarmInfo(c)
c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
return info.ControlAvailable, nil
}
// CheckLeader returns whether there is a leader on the swarm or not
func (d *Swarm) CheckLeader(c *check.C) (interface{}, check.CommentInterface) {
func (d *Daemon) CheckLeader(c *check.C) (interface{}, check.CommentInterface) {
cli, err := d.NewClient()
c.Assert(err, checker.IsNil)
defer cli.Close()
@ -644,18 +195,3 @@ func (d *Swarm) CheckLeader(c *check.C) (interface{}, check.CommentInterface) {
}
return fmt.Errorf("no leader"), check.Commentf("could not find leader")
}
// CmdRetryOutOfSequence tries the specified command against the current daemon for 10 times
func (d *Swarm) CmdRetryOutOfSequence(args ...string) (string, error) {
for i := 0; ; i++ {
out, err := d.Cmd(args...)
if err != nil {
if strings.Contains(out, "update out of sequence") {
if i < 10 {
continue
}
}
}
return out, err
}
}

View File

@ -5,11 +5,11 @@ import (
"github.com/go-check/check"
)
func (s *DockerSwarmSuite) getDaemon(c *check.C, nodeID string) *daemon.Swarm {
func (s *DockerSwarmSuite) getDaemon(c *check.C, nodeID string) *daemon.Daemon {
s.daemonsLock.Lock()
defer s.daemonsLock.Unlock()
for _, d := range s.daemons {
if d.NodeID == nodeID {
if d.NodeID() == nodeID {
return d
}
}

View File

@ -21,8 +21,8 @@ func (s *DockerSwarmSuite) TestAPISwarmListNodes(c *check.C) {
loop0:
for _, n := range nodes {
for _, d := range []*daemon.Swarm{d1, d2, d3} {
if n.ID == d.NodeID {
for _, d := range []*daemon.Daemon{d1, d2, d3} {
if n.ID == d.NodeID() {
continue loop0
}
}
@ -53,8 +53,7 @@ func (s *DockerSwarmSuite) TestAPISwarmNodeRemove(c *check.C) {
c.Assert(len(nodes), checker.Equals, 3, check.Commentf("nodes: %#v", nodes))
// Getting the info so we can take the NodeID
d2Info, err := d2.SwarmInfo()
c.Assert(err, checker.IsNil)
d2Info := d2.SwarmInfo(c)
// forceful removal of d2 should work
d1.RemoveNode(c, d2Info.NodeID, true)
@ -88,14 +87,14 @@ func (s *DockerSwarmSuite) TestAPISwarmNodeDrainPause(c *check.C) {
waitAndAssert(c, defaultReconciliationTimeout, reducedCheck(sumAsIntegers, d1.CheckActiveContainerCount, d2.CheckActiveContainerCount), checker.Equals, instances)
// drain d2, all containers should move to d1
d1.UpdateNode(c, d2.NodeID, func(n *swarm.Node) {
d1.UpdateNode(c, d2.NodeID(), func(n *swarm.Node) {
n.Spec.Availability = swarm.NodeAvailabilityDrain
})
waitAndAssert(c, defaultReconciliationTimeout, d1.CheckActiveContainerCount, checker.Equals, instances)
waitAndAssert(c, defaultReconciliationTimeout, d2.CheckActiveContainerCount, checker.Equals, 0)
// set d2 back to active
d1.UpdateNode(c, d2.NodeID, func(n *swarm.Node) {
d1.UpdateNode(c, d2.NodeID(), func(n *swarm.Node) {
n.Spec.Availability = swarm.NodeAvailabilityActive
})
@ -115,7 +114,7 @@ func (s *DockerSwarmSuite) TestAPISwarmNodeDrainPause(c *check.C) {
d2ContainerCount := len(d2.ActiveContainers())
// set d2 to paused, scale service up, only d1 gets new tasks
d1.UpdateNode(c, d2.NodeID, func(n *swarm.Node) {
d1.UpdateNode(c, d2.NodeID(), func(n *swarm.Node) {
n.Spec.Availability = swarm.NodeAvailabilityPause
})

View File

@ -15,12 +15,13 @@ import (
"github.com/docker/docker/integration-cli/checker"
"github.com/docker/docker/integration-cli/daemon"
"github.com/docker/docker/integration-cli/fixtures/plugin"
testdaemon "github.com/docker/docker/internal/test/daemon"
"github.com/go-check/check"
"golang.org/x/net/context"
"golang.org/x/sys/unix"
)
func setPortConfig(portConfig []swarm.PortConfig) daemon.ServiceConstructor {
func setPortConfig(portConfig []swarm.PortConfig) testdaemon.ServiceConstructor {
return func(s *swarm.Service) {
if s.Spec.EndpointSpec == nil {
s.Spec.EndpointSpec = &swarm.EndpointSpec{}
@ -140,7 +141,7 @@ func (s *DockerSwarmSuite) TestAPISwarmServicesCreateGlobal(c *check.C) {
func (s *DockerSwarmSuite) TestAPISwarmServicesUpdate(c *check.C) {
const nodeCount = 3
var daemons [nodeCount]*daemon.Swarm
var daemons [nodeCount]*daemon.Daemon
for i := 0; i < nodeCount; i++ {
daemons[i] = s.AddDaemon(c, true, i == 0)
}
@ -309,7 +310,7 @@ func (s *DockerSwarmSuite) TestAPISwarmServicesUpdateStartFirst(c *check.C) {
func (s *DockerSwarmSuite) TestAPISwarmServicesFailedUpdate(c *check.C) {
const nodeCount = 3
var daemons [nodeCount]*daemon.Swarm
var daemons [nodeCount]*daemon.Daemon
for i := 0; i < nodeCount; i++ {
daemons[i] = s.AddDaemon(c, true, i == 0)
}
@ -349,7 +350,7 @@ func (s *DockerSwarmSuite) TestAPISwarmServicesFailedUpdate(c *check.C) {
func (s *DockerSwarmSuite) TestAPISwarmServiceConstraintRole(c *check.C) {
const nodeCount = 3
var daemons [nodeCount]*daemon.Swarm
var daemons [nodeCount]*daemon.Daemon
for i := 0; i < nodeCount; i++ {
daemons[i] = s.AddDaemon(c, true, i == 0)
}
@ -401,7 +402,7 @@ func (s *DockerSwarmSuite) TestAPISwarmServiceConstraintRole(c *check.C) {
func (s *DockerSwarmSuite) TestAPISwarmServiceConstraintLabel(c *check.C) {
const nodeCount = 3
var daemons [nodeCount]*daemon.Swarm
var daemons [nodeCount]*daemon.Daemon
for i := 0; i < nodeCount; i++ {
daemons[i] = s.AddDaemon(c, true, i == 0)
}
@ -496,7 +497,7 @@ func (s *DockerSwarmSuite) TestAPISwarmServiceConstraintLabel(c *check.C) {
func (s *DockerSwarmSuite) TestAPISwarmServicePlacementPrefs(c *check.C) {
const nodeCount = 3
var daemons [nodeCount]*daemon.Swarm
var daemons [nodeCount]*daemon.Daemon
for i := 0; i < nodeCount; i++ {
daemons[i] = s.AddDaemon(c, true, i == 0)
}
@ -551,9 +552,9 @@ func (s *DockerSwarmSuite) TestAPISwarmServicesStateReporting(c *check.C) {
waitAndAssert(c, defaultReconciliationTimeout, reducedCheck(sumAsIntegers, d1.CheckActiveContainerCount, d2.CheckActiveContainerCount, d3.CheckActiveContainerCount), checker.Equals, instances)
getContainers := func() map[string]*daemon.Swarm {
m := make(map[string]*daemon.Swarm)
for _, d := range []*daemon.Swarm{d1, d2, d3} {
getContainers := func() map[string]*daemon.Daemon {
m := make(map[string]*daemon.Daemon)
for _, d := range []*daemon.Daemon{d1, d2, d3} {
for _, id := range d.ActiveContainers() {
m[id] = d
}

View File

@ -23,6 +23,7 @@ import (
"github.com/docker/docker/integration-cli/checker"
"github.com/docker/docker/integration-cli/daemon"
"github.com/docker/docker/integration-cli/request"
testdaemon "github.com/docker/docker/internal/test/daemon"
"github.com/docker/swarmkit/ca"
"github.com/go-check/check"
"github.com/gotestyourself/gotestyourself/assert"
@ -35,30 +36,30 @@ var defaultReconciliationTimeout = 30 * time.Second
func (s *DockerSwarmSuite) TestAPISwarmInit(c *check.C) {
// todo: should find a better way to verify that components are running than /info
d1 := s.AddDaemon(c, true, true)
info, err := d1.SwarmInfo()
c.Assert(err, checker.IsNil)
info := d1.SwarmInfo(c)
c.Assert(info.ControlAvailable, checker.True)
c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
c.Assert(info.Cluster.RootRotationInProgress, checker.False)
d2 := s.AddDaemon(c, true, false)
info, err = d2.SwarmInfo()
c.Assert(err, checker.IsNil)
info = d2.SwarmInfo(c)
c.Assert(info.ControlAvailable, checker.False)
c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
// Leaving cluster
c.Assert(d2.Leave(false), checker.IsNil)
c.Assert(d2.SwarmLeave(false), checker.IsNil)
info, err = d2.SwarmInfo()
c.Assert(err, checker.IsNil)
info = d2.SwarmInfo(c)
c.Assert(info.ControlAvailable, checker.False)
c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateInactive)
c.Assert(d2.Join(swarm.JoinRequest{JoinToken: d1.JoinTokens(c).Worker, RemoteAddrs: []string{d1.ListenAddr}}), checker.IsNil)
d2.SwarmJoin(c, swarm.JoinRequest{
ListenAddr: d1.SwarmListenAddr(),
JoinToken: d1.JoinTokens(c).Worker,
RemoteAddrs: []string{d1.SwarmListenAddr()},
})
info, err = d2.SwarmInfo()
c.Assert(err, checker.IsNil)
info = d2.SwarmInfo(c)
c.Assert(info.ControlAvailable, checker.False)
c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
@ -69,93 +70,100 @@ func (s *DockerSwarmSuite) TestAPISwarmInit(c *check.C) {
d1.Start(c)
d2.Start(c)
info, err = d1.SwarmInfo()
c.Assert(err, checker.IsNil)
info = d1.SwarmInfo(c)
c.Assert(info.ControlAvailable, checker.True)
c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
info, err = d2.SwarmInfo()
c.Assert(err, checker.IsNil)
info = d2.SwarmInfo(c)
c.Assert(info.ControlAvailable, checker.False)
c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
}
func (s *DockerSwarmSuite) TestAPISwarmJoinToken(c *check.C) {
d1 := s.AddDaemon(c, false, false)
c.Assert(d1.Init(swarm.InitRequest{}), checker.IsNil)
d1.SwarmInit(c, swarm.InitRequest{})
// todo: error message differs depending if some components of token are valid
d2 := s.AddDaemon(c, false, false)
err := d2.Join(swarm.JoinRequest{RemoteAddrs: []string{d1.ListenAddr}})
c2 := d2.NewClientT(c)
err := c2.SwarmJoin(context.Background(), swarm.JoinRequest{
ListenAddr: d2.SwarmListenAddr(),
RemoteAddrs: []string{d1.SwarmListenAddr()},
})
c.Assert(err, checker.NotNil)
c.Assert(err.Error(), checker.Contains, "join token is necessary")
info, err := d2.SwarmInfo()
c.Assert(err, checker.IsNil)
info := d2.SwarmInfo(c)
c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateInactive)
err = d2.Join(swarm.JoinRequest{JoinToken: "foobaz", RemoteAddrs: []string{d1.ListenAddr}})
err = c2.SwarmJoin(context.Background(), swarm.JoinRequest{
ListenAddr: d2.SwarmListenAddr(),
JoinToken: "foobaz",
RemoteAddrs: []string{d1.SwarmListenAddr()},
})
c.Assert(err, checker.NotNil)
c.Assert(err.Error(), checker.Contains, "invalid join token")
info, err = d2.SwarmInfo()
c.Assert(err, checker.IsNil)
info = d2.SwarmInfo(c)
c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateInactive)
workerToken := d1.JoinTokens(c).Worker
c.Assert(d2.Join(swarm.JoinRequest{JoinToken: workerToken, RemoteAddrs: []string{d1.ListenAddr}}), checker.IsNil)
info, err = d2.SwarmInfo()
c.Assert(err, checker.IsNil)
d2.SwarmJoin(c, swarm.JoinRequest{
ListenAddr: d2.SwarmListenAddr(),
JoinToken: workerToken,
RemoteAddrs: []string{d1.SwarmListenAddr()},
})
info = d2.SwarmInfo(c)
c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
c.Assert(d2.Leave(false), checker.IsNil)
info, err = d2.SwarmInfo()
c.Assert(err, checker.IsNil)
c.Assert(d2.SwarmLeave(false), checker.IsNil)
info = d2.SwarmInfo(c)
c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateInactive)
// change tokens
d1.RotateTokens(c)
err = d2.Join(swarm.JoinRequest{JoinToken: workerToken, RemoteAddrs: []string{d1.ListenAddr}})
err = c2.SwarmJoin(context.Background(), swarm.JoinRequest{
ListenAddr: d2.SwarmListenAddr(),
JoinToken: workerToken,
RemoteAddrs: []string{d1.SwarmListenAddr()},
})
c.Assert(err, checker.NotNil)
c.Assert(err.Error(), checker.Contains, "join token is necessary")
info, err = d2.SwarmInfo()
c.Assert(err, checker.IsNil)
info = d2.SwarmInfo(c)
c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateInactive)
workerToken = d1.JoinTokens(c).Worker
c.Assert(d2.Join(swarm.JoinRequest{JoinToken: workerToken, RemoteAddrs: []string{d1.ListenAddr}}), checker.IsNil)
info, err = d2.SwarmInfo()
c.Assert(err, checker.IsNil)
d2.SwarmJoin(c, swarm.JoinRequest{JoinToken: workerToken, RemoteAddrs: []string{d1.SwarmListenAddr()}})
info = d2.SwarmInfo(c)
c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
c.Assert(d2.Leave(false), checker.IsNil)
info, err = d2.SwarmInfo()
c.Assert(err, checker.IsNil)
c.Assert(d2.SwarmLeave(false), checker.IsNil)
info = d2.SwarmInfo(c)
c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateInactive)
// change spec, don't change tokens
d1.UpdateSwarm(c, func(s *swarm.Spec) {})
err = d2.Join(swarm.JoinRequest{RemoteAddrs: []string{d1.ListenAddr}})
err = c2.SwarmJoin(context.Background(), swarm.JoinRequest{
ListenAddr: d2.SwarmListenAddr(),
RemoteAddrs: []string{d1.SwarmListenAddr()},
})
c.Assert(err, checker.NotNil)
c.Assert(err.Error(), checker.Contains, "join token is necessary")
info, err = d2.SwarmInfo()
c.Assert(err, checker.IsNil)
info = d2.SwarmInfo(c)
c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateInactive)
c.Assert(d2.Join(swarm.JoinRequest{JoinToken: workerToken, RemoteAddrs: []string{d1.ListenAddr}}), checker.IsNil)
info, err = d2.SwarmInfo()
c.Assert(err, checker.IsNil)
d2.SwarmJoin(c, swarm.JoinRequest{JoinToken: workerToken, RemoteAddrs: []string{d1.SwarmListenAddr()}})
info = d2.SwarmInfo(c)
c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
c.Assert(d2.Leave(false), checker.IsNil)
info, err = d2.SwarmInfo()
c.Assert(err, checker.IsNil)
c.Assert(d2.SwarmLeave(false), checker.IsNil)
info = d2.SwarmInfo(c)
c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateInactive)
}
func (s *DockerSwarmSuite) TestUpdateSwarmAddExternalCA(c *check.C) {
d1 := s.AddDaemon(c, false, false)
c.Assert(d1.Init(swarm.InitRequest{}), checker.IsNil)
d1.SwarmInit(c, swarm.InitRequest{})
d1.UpdateSwarm(c, func(s *swarm.Spec) {
s.CAConfig.ExternalCAs = []*swarm.ExternalCA{
{
@ -169,8 +177,7 @@ func (s *DockerSwarmSuite) TestUpdateSwarmAddExternalCA(c *check.C) {
},
}
})
info, err := d1.SwarmInfo()
c.Assert(err, checker.IsNil)
info := d1.SwarmInfo(c)
c.Assert(info.Cluster.Spec.CAConfig.ExternalCAs, checker.HasLen, 2)
c.Assert(info.Cluster.Spec.CAConfig.ExternalCAs[0].CACert, checker.Equals, "")
c.Assert(info.Cluster.Spec.CAConfig.ExternalCAs[1].CACert, checker.Equals, "cacert")
@ -182,28 +189,32 @@ func (s *DockerSwarmSuite) TestAPISwarmCAHash(c *check.C) {
splitToken := strings.Split(d1.JoinTokens(c).Worker, "-")
splitToken[2] = "1kxftv4ofnc6mt30lmgipg6ngf9luhwqopfk1tz6bdmnkubg0e"
replacementToken := strings.Join(splitToken, "-")
err := d2.Join(swarm.JoinRequest{JoinToken: replacementToken, RemoteAddrs: []string{d1.ListenAddr}})
c2 := d2.NewClientT(c)
err := c2.SwarmJoin(context.Background(), swarm.JoinRequest{
ListenAddr: d2.SwarmListenAddr(),
JoinToken: replacementToken,
RemoteAddrs: []string{d1.SwarmListenAddr()},
})
c.Assert(err, checker.NotNil)
c.Assert(err.Error(), checker.Contains, "remote CA does not match fingerprint")
}
func (s *DockerSwarmSuite) TestAPISwarmPromoteDemote(c *check.C) {
d1 := s.AddDaemon(c, false, false)
c.Assert(d1.Init(swarm.InitRequest{}), checker.IsNil)
d1.SwarmInit(c, swarm.InitRequest{})
d2 := s.AddDaemon(c, true, false)
info, err := d2.SwarmInfo()
c.Assert(err, checker.IsNil)
info := d2.SwarmInfo(c)
c.Assert(info.ControlAvailable, checker.False)
c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
d1.UpdateNode(c, d2.NodeID, func(n *swarm.Node) {
d1.UpdateNode(c, d2.NodeID(), func(n *swarm.Node) {
n.Spec.Role = swarm.NodeRoleManager
})
waitAndAssert(c, defaultReconciliationTimeout, d2.CheckControlAvailable, checker.True)
d1.UpdateNode(c, d2.NodeID, func(n *swarm.Node) {
d1.UpdateNode(c, d2.NodeID(), func(n *swarm.Node) {
n.Spec.Role = swarm.NodeRoleWorker
})
@ -228,7 +239,7 @@ func (s *DockerSwarmSuite) TestAPISwarmPromoteDemote(c *check.C) {
}, checker.Equals, "swarm-worker")
// Demoting last node should fail
node := d1.GetNode(c, d1.NodeID)
node := d1.GetNode(c, d1.NodeID())
node.Spec.Role = swarm.NodeRoleWorker
url := fmt.Sprintf("/nodes/%s/update?version=%d", node.ID, node.Version.Index)
res, body, err := request.DoOnHost(d1.Sock(), url, request.Method("POST"), request.JSONBody(node.Spec))
@ -246,13 +257,12 @@ func (s *DockerSwarmSuite) TestAPISwarmPromoteDemote(c *check.C) {
if !strings.Contains(string(b), "last manager of the swarm") {
c.Assert(string(b), checker.Contains, "this would result in a loss of quorum")
}
info, err = d1.SwarmInfo()
c.Assert(err, checker.IsNil)
info = d1.SwarmInfo(c)
c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
c.Assert(info.ControlAvailable, checker.True)
// Promote already demoted node
d1.UpdateNode(c, d2.NodeID, func(n *swarm.Node) {
d1.UpdateNode(c, d2.NodeID(), func(n *swarm.Node) {
n.Spec.Role = swarm.NodeRoleManager
})
@ -278,7 +288,7 @@ func (s *DockerSwarmSuite) TestAPISwarmLeaderProxy(c *check.C) {
// 3 services should be started now, because the requests were proxied to leader
// query each node and make sure it returns 3 services
for _, d := range []*daemon.Swarm{d1, d2, d3} {
for _, d := range []*daemon.Daemon{d1, d2, d3} {
services := d.ListServices(c)
c.Assert(services, checker.HasLen, 3)
}
@ -291,23 +301,23 @@ func (s *DockerSwarmSuite) TestAPISwarmLeaderElection(c *check.C) {
d3 := s.AddDaemon(c, true, true)
// assert that the first node we made is the leader, and the other two are followers
c.Assert(d1.GetNode(c, d1.NodeID).ManagerStatus.Leader, checker.True)
c.Assert(d1.GetNode(c, d2.NodeID).ManagerStatus.Leader, checker.False)
c.Assert(d1.GetNode(c, d3.NodeID).ManagerStatus.Leader, checker.False)
c.Assert(d1.GetNode(c, d1.NodeID()).ManagerStatus.Leader, checker.True)
c.Assert(d1.GetNode(c, d2.NodeID()).ManagerStatus.Leader, checker.False)
c.Assert(d1.GetNode(c, d3.NodeID()).ManagerStatus.Leader, checker.False)
d1.Stop(c)
var (
leader *daemon.Swarm // keep track of leader
followers []*daemon.Swarm // keep track of followers
leader *daemon.Daemon // keep track of leader
followers []*daemon.Daemon // keep track of followers
)
checkLeader := func(nodes ...*daemon.Swarm) checkF {
checkLeader := func(nodes ...*daemon.Daemon) checkF {
return func(c *check.C) (interface{}, check.CommentInterface) {
// clear these out before each run
leader = nil
followers = nil
for _, d := range nodes {
if d.GetNode(c, d.NodeID).ManagerStatus.Leader {
if d.GetNode(c, d.NodeID()).ManagerStatus.Leader {
leader = d
} else {
followers = append(followers, d)
@ -344,7 +354,7 @@ func (s *DockerSwarmSuite) TestAPISwarmLeaderElection(c *check.C) {
c.Assert(leader, checker.NotNil)
c.Assert(followers, checker.HasLen, 2)
// and that after we added d1 back, the leader hasn't changed
c.Assert(leader.NodeID, checker.Equals, stableleader.NodeID)
c.Assert(leader.NodeID(), checker.Equals, stableleader.NodeID())
}
func (s *DockerSwarmSuite) TestAPISwarmRaftQuorum(c *check.C) {
@ -400,8 +410,8 @@ func (s *DockerSwarmSuite) TestAPISwarmLeaveRemovesContainer(c *check.C) {
waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, instances+1)
c.Assert(d.Leave(false), checker.NotNil)
c.Assert(d.Leave(true), checker.IsNil)
c.Assert(d.SwarmLeave(false), checker.NotNil)
c.Assert(d.SwarmLeave(true), checker.IsNil)
waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1)
@ -420,17 +430,18 @@ func (s *DockerSwarmSuite) TestAPISwarmLeaveOnPendingJoin(c *check.C) {
c.Assert(err, checker.IsNil)
id = strings.TrimSpace(id)
err = d2.Join(swarm.JoinRequest{
c2 := d2.NewClientT(c)
err = c2.SwarmJoin(context.Background(), swarm.JoinRequest{
ListenAddr: d2.SwarmListenAddr(),
RemoteAddrs: []string{"123.123.123.123:1234"},
})
c.Assert(err, check.NotNil)
c.Assert(err.Error(), checker.Contains, "Timeout was reached")
info, err := d2.SwarmInfo()
c.Assert(err, checker.IsNil)
info := d2.SwarmInfo(c)
c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStatePending)
c.Assert(d2.Leave(true), checker.IsNil)
c.Assert(d2.SwarmLeave(true), checker.IsNil)
waitAndAssert(c, defaultReconciliationTimeout, d2.CheckActiveContainerCount, checker.Equals, 1)
@ -443,7 +454,9 @@ func (s *DockerSwarmSuite) TestAPISwarmLeaveOnPendingJoin(c *check.C) {
func (s *DockerSwarmSuite) TestAPISwarmRestoreOnPendingJoin(c *check.C) {
testRequires(c, Network)
d := s.AddDaemon(c, false, false)
err := d.Join(swarm.JoinRequest{
client := d.NewClientT(c)
err := client.SwarmJoin(context.Background(), swarm.JoinRequest{
ListenAddr: d.SwarmListenAddr(),
RemoteAddrs: []string{"123.123.123.123:1234"},
})
c.Assert(err, check.NotNil)
@ -454,8 +467,7 @@ func (s *DockerSwarmSuite) TestAPISwarmRestoreOnPendingJoin(c *check.C) {
d.Stop(c)
d.Start(c)
info, err := d.SwarmInfo()
c.Assert(err, checker.IsNil)
info := d.SwarmInfo(c)
c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateInactive)
}
@ -539,7 +551,7 @@ func (s *DockerSwarmSuite) TestAPISwarmForceNewCluster(c *check.C) {
waitAndAssert(c, defaultReconciliationTimeout, reducedCheck(sumAsIntegers, d1.CheckActiveContainerCount, d2.CheckActiveContainerCount), checker.Equals, instances)
// drain d2, all containers should move to d1
d1.UpdateNode(c, d2.NodeID, func(n *swarm.Node) {
d1.UpdateNode(c, d2.NodeID(), func(n *swarm.Node) {
n.Spec.Availability = swarm.NodeAvailabilityDrain
})
waitAndAssert(c, defaultReconciliationTimeout, d1.CheckActiveContainerCount, checker.Equals, instances)
@ -547,16 +559,15 @@ func (s *DockerSwarmSuite) TestAPISwarmForceNewCluster(c *check.C) {
d2.Stop(c)
c.Assert(d1.Init(swarm.InitRequest{
d1.SwarmInit(c, swarm.InitRequest{
ForceNewCluster: true,
Spec: swarm.Spec{},
}), checker.IsNil)
})
waitAndAssert(c, defaultReconciliationTimeout, d1.CheckActiveContainerCount, checker.Equals, instances)
d3 := s.AddDaemon(c, true, true)
info, err := d3.SwarmInfo()
c.Assert(err, checker.IsNil)
info := d3.SwarmInfo(c)
c.Assert(info.ControlAvailable, checker.True)
c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
@ -622,7 +633,7 @@ func serviceForUpdate(s *swarm.Service) {
s.Spec.Name = "updatetest"
}
func setInstances(replicas int) daemon.ServiceConstructor {
func setInstances(replicas int) testdaemon.ServiceConstructor {
ureplicas := uint64(replicas)
return func(s *swarm.Service) {
s.Spec.Mode = swarm.ServiceMode{
@ -633,7 +644,7 @@ func setInstances(replicas int) daemon.ServiceConstructor {
}
}
func setUpdateOrder(order string) daemon.ServiceConstructor {
func setUpdateOrder(order string) testdaemon.ServiceConstructor {
return func(s *swarm.Service) {
if s.Spec.UpdateConfig == nil {
s.Spec.UpdateConfig = &swarm.UpdateConfig{}
@ -642,7 +653,7 @@ func setUpdateOrder(order string) daemon.ServiceConstructor {
}
}
func setRollbackOrder(order string) daemon.ServiceConstructor {
func setRollbackOrder(order string) testdaemon.ServiceConstructor {
return func(s *swarm.Service) {
if s.Spec.RollbackConfig == nil {
s.Spec.RollbackConfig = &swarm.UpdateConfig{}
@ -651,7 +662,7 @@ func setRollbackOrder(order string) daemon.ServiceConstructor {
}
}
func setImage(image string) daemon.ServiceConstructor {
func setImage(image string) testdaemon.ServiceConstructor {
return func(s *swarm.Service) {
if s.Spec.TaskTemplate.ContainerSpec == nil {
s.Spec.TaskTemplate.ContainerSpec = &swarm.ContainerSpec{}
@ -660,25 +671,25 @@ func setImage(image string) daemon.ServiceConstructor {
}
}
func setFailureAction(failureAction string) daemon.ServiceConstructor {
func setFailureAction(failureAction string) testdaemon.ServiceConstructor {
return func(s *swarm.Service) {
s.Spec.UpdateConfig.FailureAction = failureAction
}
}
func setMaxFailureRatio(maxFailureRatio float32) daemon.ServiceConstructor {
func setMaxFailureRatio(maxFailureRatio float32) testdaemon.ServiceConstructor {
return func(s *swarm.Service) {
s.Spec.UpdateConfig.MaxFailureRatio = maxFailureRatio
}
}
func setParallelism(parallelism uint64) daemon.ServiceConstructor {
func setParallelism(parallelism uint64) testdaemon.ServiceConstructor {
return func(s *swarm.Service) {
s.Spec.UpdateConfig.Parallelism = parallelism
}
}
func setConstraints(constraints []string) daemon.ServiceConstructor {
func setConstraints(constraints []string) testdaemon.ServiceConstructor {
return func(s *swarm.Service) {
if s.Spec.TaskTemplate.Placement == nil {
s.Spec.TaskTemplate.Placement = &swarm.Placement{}
@ -687,7 +698,7 @@ func setConstraints(constraints []string) daemon.ServiceConstructor {
}
}
func setPlacementPrefs(prefs []swarm.PlacementPreference) daemon.ServiceConstructor {
func setPlacementPrefs(prefs []swarm.PlacementPreference) testdaemon.ServiceConstructor {
return func(s *swarm.Service) {
if s.Spec.TaskTemplate.Placement == nil {
s.Spec.TaskTemplate.Placement = &swarm.Placement{}
@ -702,18 +713,19 @@ func setGlobalMode(s *swarm.Service) {
}
}
func checkClusterHealth(c *check.C, cl []*daemon.Swarm, managerCount, workerCount int) {
func checkClusterHealth(c *check.C, cl []*daemon.Daemon, managerCount, workerCount int) {
var totalMCount, totalWCount int
for _, d := range cl {
var (
info swarm.Info
err error
)
// check info in a waitAndAssert, because if the cluster doesn't have a leader, `info` will return an error
checkInfo := func(c *check.C) (interface{}, check.CommentInterface) {
info, err = d.SwarmInfo()
client := d.NewClientT(c)
daemonInfo, err := client.Info(context.Background())
info = daemonInfo.Swarm
return err, check.Commentf("cluster not ready in time")
}
waitAndAssert(c, defaultReconciliationTimeout, checkInfo, checker.IsNil)
@ -733,7 +745,7 @@ func checkClusterHealth(c *check.C, cl []*daemon.Swarm, managerCount, workerCoun
}
nn := d.GetNode(c, n.ID)
n = *nn
return n.Status.State == swarm.NodeStateReady, check.Commentf("state of node %s, reported by %s", n.ID, d.Info.NodeID)
return n.Status.State == swarm.NodeStateReady, check.Commentf("state of node %s, reported by %s", n.ID, d.NodeID())
}
waitAndAssert(c, defaultReconciliationTimeout, waitReady, checker.True)
@ -743,18 +755,18 @@ func checkClusterHealth(c *check.C, cl []*daemon.Swarm, managerCount, workerCoun
}
nn := d.GetNode(c, n.ID)
n = *nn
return n.Spec.Availability == swarm.NodeAvailabilityActive, check.Commentf("availability of node %s, reported by %s", n.ID, d.Info.NodeID)
return n.Spec.Availability == swarm.NodeAvailabilityActive, check.Commentf("availability of node %s, reported by %s", n.ID, d.NodeID())
}
waitAndAssert(c, defaultReconciliationTimeout, waitActive, checker.True)
if n.Spec.Role == swarm.NodeRoleManager {
c.Assert(n.ManagerStatus, checker.NotNil, check.Commentf("manager status of node %s (manager), reported by %s", n.ID, d.Info.NodeID))
c.Assert(n.ManagerStatus, checker.NotNil, check.Commentf("manager status of node %s (manager), reported by %s", n.ID, d.NodeID()))
if n.ManagerStatus.Leader {
leaderFound = true
}
mCount++
} else {
c.Assert(n.ManagerStatus, checker.IsNil, check.Commentf("manager status of node %s (worker), reported by %s", n.ID, d.Info.NodeID))
c.Assert(n.ManagerStatus, checker.IsNil, check.Commentf("manager status of node %s (worker), reported by %s", n.ID, d.NodeID()))
wCount++
}
}
@ -769,11 +781,10 @@ func checkClusterHealth(c *check.C, cl []*daemon.Swarm, managerCount, workerCoun
func (s *DockerSwarmSuite) TestAPISwarmRestartCluster(c *check.C) {
mCount, wCount := 5, 1
var nodes []*daemon.Swarm
var nodes []*daemon.Daemon
for i := 0; i < mCount; i++ {
manager := s.AddDaemon(c, true, true)
info, err := manager.SwarmInfo()
c.Assert(err, checker.IsNil)
info := manager.SwarmInfo(c)
c.Assert(info.ControlAvailable, checker.True)
c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
nodes = append(nodes, manager)
@ -781,8 +792,7 @@ func (s *DockerSwarmSuite) TestAPISwarmRestartCluster(c *check.C) {
for i := 0; i < wCount; i++ {
worker := s.AddDaemon(c, true, false)
info, err := worker.SwarmInfo()
c.Assert(err, checker.IsNil)
info := worker.SwarmInfo(c)
c.Assert(info.ControlAvailable, checker.False)
c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
nodes = append(nodes, worker)
@ -795,7 +805,7 @@ func (s *DockerSwarmSuite) TestAPISwarmRestartCluster(c *check.C) {
errs := make(chan error, len(nodes))
for _, d := range nodes {
go func(daemon *daemon.Swarm) {
go func(daemon *daemon.Daemon) {
defer wg.Done()
if err := daemon.StopWithError(); err != nil {
errs <- err
@ -820,7 +830,7 @@ func (s *DockerSwarmSuite) TestAPISwarmRestartCluster(c *check.C) {
errs := make(chan error, len(nodes))
for _, d := range nodes {
go func(daemon *daemon.Swarm) {
go func(daemon *daemon.Daemon) {
defer wg.Done()
if err := daemon.StartWithError("--iptables=false"); err != nil {
errs <- err
@ -859,7 +869,7 @@ func (s *DockerSwarmSuite) TestAPISwarmServicesUpdateWithName(c *check.C) {
// Unlocking an unlocked swarm results in an error
func (s *DockerSwarmSuite) TestAPISwarmUnlockNotLocked(c *check.C) {
d := s.AddDaemon(c, true, true)
err := d.Unlock(swarm.UnlockRequest{UnlockKey: "wrong-key"})
err := d.SwarmUnlock(swarm.UnlockRequest{UnlockKey: "wrong-key"})
c.Assert(err, checker.NotNil)
c.Assert(err.Error(), checker.Contains, "swarm is not locked")
}
@ -870,7 +880,10 @@ func (s *DockerSwarmSuite) TestAPISwarmErrorHandling(c *check.C) {
c.Assert(err, checker.IsNil)
defer ln.Close()
d := s.AddDaemon(c, false, false)
err = d.Init(swarm.InitRequest{})
client := d.NewClientT(c)
_, err = client.SwarmInit(context.Background(), swarm.InitRequest{
ListenAddr: d.SwarmListenAddr(),
})
c.Assert(err, checker.NotNil)
c.Assert(err.Error(), checker.Contains, "address already in use")
}
@ -940,13 +953,13 @@ func (s *DockerSwarmSuite) TestSwarmRepeatedRootRotation(c *check.C) {
m := s.AddDaemon(c, true, true)
w := s.AddDaemon(c, true, false)
info, err := m.SwarmInfo()
c.Assert(err, checker.IsNil)
info := m.SwarmInfo(c)
currentTrustRoot := info.Cluster.TLSInfo.TrustRoot
// rotate multiple times
for i := 0; i < 4; i++ {
var err error
var cert, key []byte
if i%2 != 0 {
cert, _, key, err = initca.New(&csr.CertificateRequest{
@ -966,8 +979,7 @@ func (s *DockerSwarmSuite) TestSwarmRepeatedRootRotation(c *check.C) {
// poll to make sure update succeeds
var clusterTLSInfo swarm.TLSInfo
for j := 0; j < 18; j++ {
info, err := m.SwarmInfo()
c.Assert(err, checker.IsNil)
info := m.SwarmInfo(c)
// the desired CA cert and key is always redacted
c.Assert(info.Cluster.Spec.CAConfig.SigningCAKey, checker.Equals, "")
@ -989,8 +1001,8 @@ func (s *DockerSwarmSuite) TestSwarmRepeatedRootRotation(c *check.C) {
// could take another second or two for the nodes to trust the new roots after they've all gotten
// new TLS certificates
for j := 0; j < 18; j++ {
mInfo := m.GetNode(c, m.NodeID).Description.TLSInfo
wInfo := m.GetNode(c, w.NodeID).Description.TLSInfo
mInfo := m.GetNode(c, m.NodeID()).Description.TLSInfo
wInfo := m.GetNode(c, w.NodeID()).Description.TLSInfo
if mInfo.TrustRoot == clusterTLSInfo.TrustRoot && wInfo.TrustRoot == clusterTLSInfo.TrustRoot {
break
@ -1000,8 +1012,8 @@ func (s *DockerSwarmSuite) TestSwarmRepeatedRootRotation(c *check.C) {
time.Sleep(250 * time.Millisecond)
}
c.Assert(m.GetNode(c, m.NodeID).Description.TLSInfo, checker.DeepEquals, clusterTLSInfo)
c.Assert(m.GetNode(c, w.NodeID).Description.TLSInfo, checker.DeepEquals, clusterTLSInfo)
c.Assert(m.GetNode(c, m.NodeID()).Description.TLSInfo, checker.DeepEquals, clusterTLSInfo)
c.Assert(m.GetNode(c, w.NodeID()).Description.TLSInfo, checker.DeepEquals, clusterTLSInfo)
currentTrustRoot = clusterTLSInfo.TrustRoot
}
}

View File

@ -16,7 +16,7 @@ import (
"github.com/go-check/check"
)
func pruneNetworkAndVerify(c *check.C, d *daemon.Swarm, kept, pruned []string) {
func pruneNetworkAndVerify(c *check.C, d *daemon.Daemon, kept, pruned []string) {
_, err := d.Cmd("network", "prune", "--force")
c.Assert(err, checker.IsNil)

View File

@ -53,7 +53,7 @@ func (s *DockerSwarmSuite) TestServiceLogs(c *check.C) {
// countLogLines returns a closure that can be used with waitAndAssert to
// verify that a minimum number of expected container log messages have been
// output.
func countLogLines(d *daemon.Swarm, name string) func(*check.C) (interface{}, check.CommentInterface) {
func countLogLines(d *daemon.Daemon, name string) func(*check.C) (interface{}, check.CommentInterface) {
return func(c *check.C) (interface{}, check.CommentInterface) {
result := icmd.RunCmd(d.Command("service", "logs", "-t", "--raw", name))
result.Assert(c, icmd.Expected{})

View File

@ -57,7 +57,7 @@ func (s *DockerSwarmSuite) TestSwarmUpdate(c *check.C) {
// passing an external CA (this is without starting a root rotation) does not fail
cli.Docker(cli.Args("swarm", "update", "--external-ca", "protocol=cfssl,url=https://something.org",
"--external-ca", "protocol=cfssl,url=https://somethingelse.org,cacert=fixtures/https/ca.pem"),
cli.Daemon(d.Daemon)).Assert(c, icmd.Success)
cli.Daemon(d)).Assert(c, icmd.Success)
expected, err := ioutil.ReadFile("fixtures/https/ca.pem")
c.Assert(err, checker.IsNil)
@ -73,7 +73,7 @@ func (s *DockerSwarmSuite) TestSwarmUpdate(c *check.C) {
result := cli.Docker(cli.Args("swarm", "update",
"--external-ca", fmt.Sprintf("protocol=cfssl,url=https://something.org,cacert=%s", tempFile.Path())),
cli.Daemon(d.Daemon))
cli.Daemon(d))
result.Assert(c, icmd.Expected{
ExitCode: 125,
Err: "must be in PEM format",
@ -94,7 +94,7 @@ func (s *DockerSwarmSuite) TestSwarmInit(c *check.C) {
result := cli.Docker(cli.Args("swarm", "init", "--cert-expiry", "30h", "--dispatcher-heartbeat", "11s",
"--external-ca", fmt.Sprintf("protocol=cfssl,url=https://somethingelse.org,cacert=%s", tempFile.Path())),
cli.Daemon(d.Daemon))
cli.Daemon(d))
result.Assert(c, icmd.Expected{
ExitCode: 125,
Err: "must be in PEM format",
@ -103,7 +103,7 @@ func (s *DockerSwarmSuite) TestSwarmInit(c *check.C) {
cli.Docker(cli.Args("swarm", "init", "--cert-expiry", "30h", "--dispatcher-heartbeat", "11s",
"--external-ca", "protocol=cfssl,url=https://something.org",
"--external-ca", "protocol=cfssl,url=https://somethingelse.org,cacert=fixtures/https/ca.pem"),
cli.Daemon(d.Daemon)).Assert(c, icmd.Success)
cli.Daemon(d)).Assert(c, icmd.Success)
expected, err := ioutil.ReadFile("fixtures/https/ca.pem")
c.Assert(err, checker.IsNil)
@ -115,8 +115,8 @@ func (s *DockerSwarmSuite) TestSwarmInit(c *check.C) {
c.Assert(spec.CAConfig.ExternalCAs[0].CACert, checker.Equals, "")
c.Assert(spec.CAConfig.ExternalCAs[1].CACert, checker.Equals, string(expected))
c.Assert(d.Leave(true), checker.IsNil)
cli.Docker(cli.Args("swarm", "init"), cli.Daemon(d.Daemon)).Assert(c, icmd.Success)
c.Assert(d.SwarmLeave(true), checker.IsNil)
cli.Docker(cli.Args("swarm", "init"), cli.Daemon(d)).Assert(c, icmd.Success)
spec = getSpec()
c.Assert(spec.CAConfig.NodeCertExpiry, checker.Equals, 90*24*time.Hour)
@ -126,12 +126,12 @@ func (s *DockerSwarmSuite) TestSwarmInit(c *check.C) {
func (s *DockerSwarmSuite) TestSwarmInitIPv6(c *check.C) {
testRequires(c, IPv6)
d1 := s.AddDaemon(c, false, false)
cli.Docker(cli.Args("swarm", "init", "--listen-add", "::1"), cli.Daemon(d1.Daemon)).Assert(c, icmd.Success)
cli.Docker(cli.Args("swarm", "init", "--listen-add", "::1"), cli.Daemon(d1)).Assert(c, icmd.Success)
d2 := s.AddDaemon(c, false, false)
cli.Docker(cli.Args("swarm", "join", "::1"), cli.Daemon(d2.Daemon)).Assert(c, icmd.Success)
cli.Docker(cli.Args("swarm", "join", "::1"), cli.Daemon(d2)).Assert(c, icmd.Success)
out := cli.Docker(cli.Args("info"), cli.Daemon(d2.Daemon)).Assert(c, icmd.Success).Combined()
out := cli.Docker(cli.Args("info"), cli.Daemon(d2)).Assert(c, icmd.Success).Combined()
c.Assert(out, checker.Contains, "Swarm: active")
}
@ -145,13 +145,12 @@ func (s *DockerSwarmSuite) TestSwarmInitUnspecifiedAdvertiseAddr(c *check.C) {
func (s *DockerSwarmSuite) TestSwarmIncompatibleDaemon(c *check.C) {
// init swarm mode and stop a daemon
d := s.AddDaemon(c, true, true)
info, err := d.SwarmInfo()
c.Assert(err, checker.IsNil)
info := d.SwarmInfo(c)
c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
d.Stop(c)
// start a daemon with --cluster-store and --cluster-advertise
err = d.StartWithError("--cluster-store=consul://consuladdr:consulport/some/path", "--cluster-advertise=1.1.1.1:2375")
err := d.StartWithError("--cluster-store=consul://consuladdr:consulport/some/path", "--cluster-advertise=1.1.1.1:2375")
c.Assert(err, checker.NotNil)
content, err := d.ReadLogFile()
c.Assert(err, checker.IsNil)
@ -426,7 +425,7 @@ func (s *DockerSwarmSuite) TestOverlayAttachableOnSwarmLeave(c *check.C) {
c.Assert(err, checker.IsNil, check.Commentf(out))
// Leave the swarm
err = d.Leave(true)
err = d.SwarmLeave(true)
c.Assert(err, checker.IsNil)
// Check the container is disconnected
@ -989,13 +988,12 @@ func (s *DockerSwarmSuite) TestDNSConfigUpdate(c *check.C) {
c.Assert(strings.TrimSpace(out), checker.Equals, "{[1.2.3.4] [example.com] [timeout:3]}")
}
func getNodeStatus(c *check.C, d *daemon.Swarm) swarm.LocalNodeState {
info, err := d.SwarmInfo()
c.Assert(err, checker.IsNil)
func getNodeStatus(c *check.C, d *daemon.Daemon) swarm.LocalNodeState {
info := d.SwarmInfo(c)
return info.LocalNodeState
}
func checkKeyIsEncrypted(d *daemon.Swarm) func(*check.C) (interface{}, check.CommentInterface) {
func checkKeyIsEncrypted(d *daemon.Daemon) func(*check.C) (interface{}, check.CommentInterface) {
return func(c *check.C) (interface{}, check.CommentInterface) {
keyBytes, err := ioutil.ReadFile(filepath.Join(d.Folder, "root", "swarm", "certificates", "swarm-node.key"))
if err != nil {
@ -1011,7 +1009,7 @@ func checkKeyIsEncrypted(d *daemon.Swarm) func(*check.C) (interface{}, check.Com
}
}
func checkSwarmLockedToUnlocked(c *check.C, d *daemon.Swarm, unlockKey string) {
func checkSwarmLockedToUnlocked(c *check.C, d *daemon.Daemon, unlockKey string) {
// Wait for the PEM file to become unencrypted
waitAndAssert(c, defaultReconciliationTimeout, checkKeyIsEncrypted(d), checker.Equals, false)
@ -1019,7 +1017,7 @@ func checkSwarmLockedToUnlocked(c *check.C, d *daemon.Swarm, unlockKey string) {
c.Assert(getNodeStatus(c, d), checker.Equals, swarm.LocalNodeStateActive)
}
func checkSwarmUnlockedToLocked(c *check.C, d *daemon.Swarm) {
func checkSwarmUnlockedToLocked(c *check.C, d *daemon.Daemon) {
// Wait for the PEM file to become encrypted
waitAndAssert(c, defaultReconciliationTimeout, checkKeyIsEncrypted(d), checker.Equals, true)
@ -1117,8 +1115,7 @@ func (s *DockerSwarmSuite) TestSwarmLeaveLocked(c *check.C) {
// It starts off locked
d.Restart(c, "--swarm-default-advertise-addr=lo")
info, err := d.SwarmInfo()
c.Assert(err, checker.IsNil)
info := d.SwarmInfo(c)
c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateLocked)
outs, _ = d.Cmd("node", "ls")
@ -1132,15 +1129,13 @@ func (s *DockerSwarmSuite) TestSwarmLeaveLocked(c *check.C) {
outs, err = d.Cmd("swarm", "leave", "--force")
c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs))
info, err = d.SwarmInfo()
c.Assert(err, checker.IsNil)
info = d.SwarmInfo(c)
c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateInactive)
outs, err = d.Cmd("swarm", "init")
c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs))
info, err = d.SwarmInfo()
c.Assert(err, checker.IsNil)
info = d.SwarmInfo(c)
c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
}
@ -1176,7 +1171,7 @@ func (s *DockerSwarmSuite) TestSwarmLockUnlockCluster(c *check.C) {
c.Assert(outs, checker.Equals, unlockKey+"\n")
// The ones that got the cluster update should be set to locked
for _, d := range []*daemon.Swarm{d1, d3} {
for _, d := range []*daemon.Daemon{d1, d3} {
checkSwarmUnlockedToLocked(c, d)
cmd := d.Command("swarm", "unlock")
@ -1197,7 +1192,7 @@ func (s *DockerSwarmSuite) TestSwarmLockUnlockCluster(c *check.C) {
c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs))
// the ones that got the update are now set to unlocked
for _, d := range []*daemon.Swarm{d1, d3} {
for _, d := range []*daemon.Daemon{d1, d3} {
checkSwarmLockedToUnlocked(c, d, unlockKey)
}
@ -1247,7 +1242,7 @@ func (s *DockerSwarmSuite) TestSwarmJoinPromoteLocked(c *check.C) {
c.Assert(getNodeStatus(c, d2), checker.Equals, swarm.LocalNodeStateActive)
// promote worker
outs, err = d1.Cmd("node", "promote", d2.Info.NodeID)
outs, err = d1.Cmd("node", "promote", d2.NodeID())
c.Assert(err, checker.IsNil)
c.Assert(outs, checker.Contains, "promoted to a manager in the swarm")
@ -1255,7 +1250,7 @@ func (s *DockerSwarmSuite) TestSwarmJoinPromoteLocked(c *check.C) {
d3 := s.AddDaemon(c, true, true)
// both new nodes are locked
for _, d := range []*daemon.Swarm{d2, d3} {
for _, d := range []*daemon.Daemon{d2, d3} {
checkSwarmUnlockedToLocked(c, d)
cmd := d.Command("swarm", "unlock")
@ -1265,7 +1260,7 @@ func (s *DockerSwarmSuite) TestSwarmJoinPromoteLocked(c *check.C) {
}
// demote manager back to worker - workers are not locked
outs, err = d1.Cmd("node", "demote", d3.Info.NodeID)
outs, err = d1.Cmd("node", "demote", d3.NodeID())
c.Assert(err, checker.IsNil)
c.Assert(outs, checker.Contains, "demoted in the swarm")
@ -1409,7 +1404,7 @@ func (s *DockerSwarmSuite) TestSwarmClusterRotateUnlockKey(c *check.C) {
d2.Restart(c)
d3.Restart(c)
for _, d := range []*daemon.Swarm{d2, d3} {
for _, d := range []*daemon.Daemon{d2, d3} {
c.Assert(getNodeStatus(c, d), checker.Equals, swarm.LocalNodeStateLocked)
outs, _ := d.Cmd("node", "ls")
@ -1521,7 +1516,7 @@ func (s *DockerSwarmSuite) TestSwarmManagerAddress(c *check.C) {
d3 := s.AddDaemon(c, true, false)
// Manager Addresses will always show Node 1's address
expectedOutput := fmt.Sprintf("Manager Addresses:\n 127.0.0.1:%d\n", d1.Port)
expectedOutput := fmt.Sprintf("Manager Addresses:\n 127.0.0.1:%d\n", d1.SwarmPort)
out, err := d1.Cmd("info")
c.Assert(err, checker.IsNil)
@ -1641,7 +1636,7 @@ func (s *DockerSwarmSuite) TestSwarmJoinWithDrain(c *check.C) {
d1 := s.AddDaemon(c, false, false)
out, err = d1.Cmd("swarm", "join", "--availability=drain", "--token", token, d.ListenAddr)
out, err = d1.Cmd("swarm", "join", "--availability=drain", "--token", token, d.SwarmListenAddr())
c.Assert(err, checker.IsNil)
c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
@ -1835,7 +1830,7 @@ func (s *DockerSwarmSuite) TestSwarmJoinLeave(c *check.C) {
// Verify that back to back join/leave does not cause panics
d1 := s.AddDaemon(c, false, false)
for i := 0; i < 10; i++ {
out, err = d1.Cmd("swarm", "join", "--token", token, d.ListenAddr)
out, err = d1.Cmd("swarm", "join", "--token", token, d.SwarmListenAddr())
c.Assert(err, checker.IsNil)
c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
@ -1846,7 +1841,7 @@ func (s *DockerSwarmSuite) TestSwarmJoinLeave(c *check.C) {
const defaultRetryCount = 10
func waitForEvent(c *check.C, d *daemon.Swarm, since string, filter string, event string, retry int) string {
func waitForEvent(c *check.C, d *daemon.Daemon, since string, filter string, event string, retry int) string {
if retry < 1 {
c.Fatalf("retry count %d is invalid. It should be no less than 1", retry)
return ""
@ -1982,7 +1977,7 @@ func (s *DockerSwarmSuite) TestSwarmClusterEventsNode(c *check.C) {
s.AddDaemon(c, true, true)
d3 := s.AddDaemon(c, true, true)
d3ID := d3.NodeID
d3ID := d3.NodeID()
waitForEvent(c, d1, "0", "-f scope=swarm", "node create "+d3ID, defaultRetryCount)
t1 := daemonUnixTime(c)

View File

@ -2,7 +2,6 @@ package swarm
import (
"context"
"fmt"
"runtime"
"testing"
"time"
@ -11,18 +10,13 @@ import (
"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-cli/daemon"
"github.com/docker/docker/internal/test/daemon"
"github.com/docker/docker/internal/test/environment"
"github.com/gotestyourself/gotestyourself/assert"
"github.com/gotestyourself/gotestyourself/poll"
"github.com/gotestyourself/gotestyourself/skip"
)
const (
dockerdBinary = "dockerd"
defaultSwarmPort = 2477
)
// ServicePoll tweaks the pollSettings for `service`
func ServicePoll(config *poll.Settings) {
// Override the default pollSettings for `service` resource here ...
@ -55,23 +49,17 @@ func ContainerPoll(config *poll.Settings) {
}
// NewSwarm creates a swarm daemon for testing
func NewSwarm(t *testing.T, testEnv *environment.Execution) *daemon.Swarm {
func NewSwarm(t *testing.T, testEnv *environment.Execution, ops ...func(*daemon.Daemon)) *daemon.Daemon {
skip.IfCondition(t, testEnv.IsRemoteDaemon())
d := &daemon.Swarm{
Daemon: daemon.New(t, "", dockerdBinary, daemon.Config{
Experimental: testEnv.DaemonInfo.ExperimentalBuild,
}),
// TODO: better method of finding an unused port
Port: defaultSwarmPort,
if testEnv.DaemonInfo.ExperimentalBuild {
ops = append(ops, daemon.WithExperimental)
}
// TODO: move to a NewSwarm constructor
d.ListenAddr = fmt.Sprintf("0.0.0.0:%d", d.Port)
d := daemon.New(t, ops...)
// avoid networking conflicts
args := []string{"--iptables=false", "--swarm-default-advertise-addr=lo"}
d.StartWithBusybox(t, args...)
assert.NilError(t, d.Init(swarmtypes.InitRequest{}))
d.SwarmInit(t, swarmtypes.InitRequest{})
return d
}
@ -79,7 +67,7 @@ func NewSwarm(t *testing.T, testEnv *environment.Execution) *daemon.Swarm {
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 {
func CreateService(t *testing.T, d *daemon.Daemon, opts ...ServiceSpecOpt) string {
spec := defaultServiceSpec()
for _, o := range opts {
o(&spec)
@ -151,7 +139,7 @@ func ServiceWithName(name string) ServiceSpecOpt {
}
// GetRunningTasks gets the list of running tasks for a service
func GetRunningTasks(t *testing.T, d *daemon.Swarm, serviceID string) []swarmtypes.Task {
func GetRunningTasks(t *testing.T, d *daemon.Daemon, serviceID string) []swarmtypes.Task {
client := GetClient(t, d)
filterArgs := filters.NewArgs()
@ -167,7 +155,7 @@ func GetRunningTasks(t *testing.T, d *daemon.Swarm, serviceID string) []swarmtyp
}
// 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 {
func ExecTask(t *testing.T, d *daemon.Daemon, task swarmtypes.Task, config types.ExecConfig) types.HijackedResponse {
client := GetClient(t, d)
ctx := context.Background()
@ -187,7 +175,7 @@ func ensureContainerSpec(spec *swarmtypes.ServiceSpec) {
}
// GetClient creates a new client for the passed in swarm daemon.
func GetClient(t *testing.T, d *daemon.Swarm) client.APIClient {
func GetClient(t *testing.T, d *daemon.Daemon) client.APIClient {
client, err := client.NewClientWithOpts(client.WithHost((d.Sock())))
assert.NilError(t, err)
return client

View File

@ -0,0 +1,66 @@
package daemon
import (
"context"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
"github.com/gotestyourself/gotestyourself/assert"
)
// ConfigConstructor defines a swarm config constructor
type ConfigConstructor func(*swarm.Config)
// CreateConfig creates a config given the specified spec
func (d *Daemon) CreateConfig(t assert.TestingT, configSpec swarm.ConfigSpec) string {
cli := d.NewClientT(t)
defer cli.Close()
scr, err := cli.ConfigCreate(context.Background(), configSpec)
assert.NilError(t, err)
return scr.ID
}
// ListConfigs returns the list of the current swarm configs
func (d *Daemon) ListConfigs(t assert.TestingT) []swarm.Config {
cli := d.NewClientT(t)
defer cli.Close()
configs, err := cli.ConfigList(context.Background(), types.ConfigListOptions{})
assert.NilError(t, err)
return configs
}
// GetConfig returns a swarm config identified by the specified id
func (d *Daemon) GetConfig(t assert.TestingT, id string) *swarm.Config {
cli := d.NewClientT(t)
defer cli.Close()
config, _, err := cli.ConfigInspectWithRaw(context.Background(), id)
assert.NilError(t, err)
return &config
}
// DeleteConfig removes the swarm config identified by the specified id
func (d *Daemon) DeleteConfig(t assert.TestingT, id string) {
cli := d.NewClientT(t)
defer cli.Close()
err := cli.ConfigRemove(context.Background(), id)
assert.NilError(t, err)
}
// UpdateConfig updates the swarm config identified by the specified id
// Currently, only label update is supported.
func (d *Daemon) UpdateConfig(t assert.TestingT, id string, f ...ConfigConstructor) {
cli := d.NewClientT(t)
defer cli.Close()
config := d.GetConfig(t, id)
for _, fn := range f {
fn(config)
}
err := cli.ConfigUpdate(context.Background(), config.ID, config.Version, config.Spec)
assert.NilError(t, err)
}

View File

@ -67,6 +67,13 @@ type Daemon struct {
experimental bool
dockerdBinary string
log logT
// swarm related field
swarmListenAddr string
SwarmPort int // FIXME(vdemeester) should probably not be exported
// cached information
CachedInfo types.Info
}
// New returns a Daemon instance to be used for testing.
@ -98,14 +105,16 @@ func New(t testingT, ops ...func(*Daemon)) *Daemon {
}
}
d := &Daemon{
id: id,
Folder: daemonFolder,
Root: daemonRoot,
storageDriver: storageDriver,
userlandProxy: userlandProxy,
execRoot: filepath.Join(os.TempDir(), "docker-execroot", id),
dockerdBinary: defaultDockerdBinary,
log: t,
id: id,
Folder: daemonFolder,
Root: daemonRoot,
storageDriver: storageDriver,
userlandProxy: userlandProxy,
execRoot: filepath.Join(os.TempDir(), "docker-execroot", id),
dockerdBinary: defaultDockerdBinary,
swarmListenAddr: defaultSwarmListenAddr,
SwarmPort: defaultSwarmPort,
log: t,
}
for _, op := range ops {
@ -150,12 +159,23 @@ func (d *Daemon) ReadLogFile() ([]byte, error) {
}
// NewClient creates new client based on daemon's socket path
// FIXME(vdemeester): replace NewClient with NewClientT
func (d *Daemon) NewClient() (*client.Client, error) {
return client.NewClientWithOpts(
client.FromEnv,
client.WithHost(d.Sock()))
}
// NewClientT creates new client based on daemon's socket path
// FIXME(vdemeester): replace NewClient with NewClientT
func (d *Daemon) NewClientT(t assert.TestingT) *client.Client {
c, err := client.NewClientWithOpts(
client.FromEnv,
client.WithHost(d.Sock()))
assert.NilError(t, err, "cannot create daemon client")
return c
}
// CleanupExecRoot cleans the daemon exec root (network namespaces, ...)
func (d *Daemon) CleanupExecRoot(t testingT) {
cleanupExecRoot(t, d.execRoot)
@ -610,7 +630,7 @@ func (d *Daemon) queryRootDir() (string, error) {
// Info returns the info struct for this daemon
func (d *Daemon) Info(t assert.TestingT) types.Info {
apiclient, err := client.NewClientWithOpts(client.WithHost((d.Sock())))
apiclient, err := d.NewClient()
assert.NilError(t, err)
info, err := apiclient.Info(context.Background())
assert.NilError(t, err)

View File

@ -0,0 +1,69 @@
package daemon
import (
"context"
"strings"
"time"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
"github.com/gotestyourself/gotestyourself/assert"
)
// NodeConstructor defines a swarm node constructor
type NodeConstructor func(*swarm.Node)
// GetNode returns a swarm node identified by the specified id
func (d *Daemon) GetNode(t assert.TestingT, id string) *swarm.Node {
cli := d.NewClientT(t)
defer cli.Close()
node, _, err := cli.NodeInspectWithRaw(context.Background(), id)
assert.NilError(t, err)
assert.Check(t, node.ID == id)
return &node
}
// RemoveNode removes the specified node
func (d *Daemon) RemoveNode(t assert.TestingT, id string, force bool) {
cli := d.NewClientT(t)
defer cli.Close()
options := types.NodeRemoveOptions{
Force: force,
}
err := cli.NodeRemove(context.Background(), id, options)
assert.NilError(t, err)
}
// UpdateNode updates a swarm node with the specified node constructor
func (d *Daemon) UpdateNode(t assert.TestingT, id string, f ...NodeConstructor) {
cli := d.NewClientT(t)
defer cli.Close()
for i := 0; ; i++ {
node := d.GetNode(t, id)
for _, fn := range f {
fn(node)
}
err := cli.NodeUpdate(context.Background(), node.ID, node.Version, node.Spec)
if i < 10 && err != nil && strings.Contains(err.Error(), "update out of sequence") {
time.Sleep(100 * time.Millisecond)
continue
}
assert.NilError(t, err)
return
}
}
// ListNodes returns the list of the current swarm nodes
func (d *Daemon) ListNodes(t assert.TestingT) []swarm.Node {
cli := d.NewClientT(t)
defer cli.Close()
nodes, err := cli.NodeList(context.Background(), types.NodeListOptions{})
assert.NilError(t, err)
return nodes
}

View File

@ -11,3 +11,17 @@ func WithDockerdBinary(dockerdBinary string) func(*Daemon) {
d.dockerdBinary = dockerdBinary
}
}
// WithSwarmPort sets the swarm port to use for swarm mode
func WithSwarmPort(port int) func(*Daemon) {
return func(d *Daemon) {
d.SwarmPort = port
}
}
// WithSwarmListenAddr sets the swarm listen addr to use for swarm mode
func WithSwarmListenAddr(listenAddr string) func(*Daemon) {
return func(d *Daemon) {
d.swarmListenAddr = listenAddr
}
}

View File

@ -0,0 +1,68 @@
package daemon
import (
"context"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
"github.com/gotestyourself/gotestyourself/assert"
)
// SecretConstructor defines a swarm secret constructor
type SecretConstructor func(*swarm.Secret)
// CreateSecret creates a secret given the specified spec
func (d *Daemon) CreateSecret(t assert.TestingT, secretSpec swarm.SecretSpec) string {
cli := d.NewClientT(t)
defer cli.Close()
scr, err := cli.SecretCreate(context.Background(), secretSpec)
assert.NilError(t, err)
return scr.ID
}
// ListSecrets returns the list of the current swarm secrets
func (d *Daemon) ListSecrets(t assert.TestingT) []swarm.Secret {
cli := d.NewClientT(t)
defer cli.Close()
secrets, err := cli.SecretList(context.Background(), types.SecretListOptions{})
assert.NilError(t, err)
return secrets
}
// GetSecret returns a swarm secret identified by the specified id
func (d *Daemon) GetSecret(t assert.TestingT, id string) *swarm.Secret {
cli := d.NewClientT(t)
defer cli.Close()
secret, _, err := cli.SecretInspectWithRaw(context.Background(), id)
assert.NilError(t, err)
return &secret
}
// DeleteSecret removes the swarm secret identified by the specified id
func (d *Daemon) DeleteSecret(t assert.TestingT, id string) {
cli := d.NewClientT(t)
defer cli.Close()
err := cli.SecretRemove(context.Background(), id)
assert.NilError(t, err)
}
// UpdateSecret updates the swarm secret identified by the specified id
// Currently, only label update is supported.
func (d *Daemon) UpdateSecret(t assert.TestingT, id string, f ...SecretConstructor) {
cli := d.NewClientT(t)
defer cli.Close()
secret := d.GetSecret(t, id)
for _, fn := range f {
fn(secret)
}
err := cli.SecretUpdate(context.Background(), secret.ID, secret.Version, secret.Spec)
assert.NilError(t, err)
}

View File

@ -0,0 +1,108 @@
package daemon
import (
"context"
"time"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/swarm"
"github.com/gotestyourself/gotestyourself/assert"
)
// ServiceConstructor defines a swarm service constructor function
type ServiceConstructor func(*swarm.Service)
// CreateServiceWithOptions creates a swarm service given the specified service constructors
// and auth config
func (d *Daemon) CreateServiceWithOptions(t assert.TestingT, opts types.ServiceCreateOptions, f ...ServiceConstructor) string {
var service swarm.Service
for _, fn := range f {
fn(&service)
}
cli := d.NewClientT(t)
defer cli.Close()
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
res, err := cli.ServiceCreate(ctx, service.Spec, opts)
assert.NilError(t, err)
return res.ID
}
// CreateService creates a swarm service given the specified service constructor
func (d *Daemon) CreateService(t assert.TestingT, f ...ServiceConstructor) string {
return d.CreateServiceWithOptions(t, types.ServiceCreateOptions{}, f...)
}
// GetService returns the swarm service corresponding to the specified id
func (d *Daemon) GetService(t assert.TestingT, id string) *swarm.Service {
cli := d.NewClientT(t)
defer cli.Close()
service, _, err := cli.ServiceInspectWithRaw(context.Background(), id, types.ServiceInspectOptions{})
assert.NilError(t, err)
return &service
}
// GetServiceTasks returns the swarm tasks for the specified service
func (d *Daemon) GetServiceTasks(t assert.TestingT, service string) []swarm.Task {
cli := d.NewClientT(t)
defer cli.Close()
filterArgs := filters.NewArgs()
filterArgs.Add("desired-state", "running")
filterArgs.Add("service", service)
options := types.TaskListOptions{
Filters: filterArgs,
}
tasks, err := cli.TaskList(context.Background(), options)
assert.NilError(t, err)
return tasks
}
// UpdateService updates a swarm service with the specified service constructor
func (d *Daemon) UpdateService(t assert.TestingT, service *swarm.Service, f ...ServiceConstructor) {
cli := d.NewClientT(t)
defer cli.Close()
for _, fn := range f {
fn(service)
}
_, err := cli.ServiceUpdate(context.Background(), service.ID, service.Version, service.Spec, types.ServiceUpdateOptions{})
assert.NilError(t, err)
}
// RemoveService removes the specified service
func (d *Daemon) RemoveService(t assert.TestingT, id string) {
cli := d.NewClientT(t)
defer cli.Close()
err := cli.ServiceRemove(context.Background(), id)
assert.NilError(t, err)
}
// ListServices returns the list of the current swarm services
func (d *Daemon) ListServices(t assert.TestingT) []swarm.Service {
cli := d.NewClientT(t)
defer cli.Close()
services, err := cli.ServiceList(context.Background(), types.ServiceListOptions{})
assert.NilError(t, err)
return services
}
// GetTask returns the swarm task identified by the specified id
func (d *Daemon) GetTask(t assert.TestingT, id string) swarm.Task {
cli := d.NewClientT(t)
defer cli.Close()
task, _, err := cli.TaskInspectWithRaw(context.Background(), id)
assert.NilError(t, err)
return task
}

View File

@ -0,0 +1,139 @@
package daemon
import (
"context"
"fmt"
"github.com/docker/docker/api/types/swarm"
"github.com/gotestyourself/gotestyourself/assert"
"github.com/pkg/errors"
)
const (
defaultSwarmPort = 2477
defaultSwarmListenAddr = "0.0.0.0"
)
// SpecConstructor defines a swarm spec constructor
type SpecConstructor func(*swarm.Spec)
// SwarmListenAddr returns the listen-addr used for the daemon
func (d *Daemon) SwarmListenAddr() string {
return fmt.Sprintf("%s:%d", d.swarmListenAddr, d.SwarmPort)
}
// NodeID returns the swarm mode node ID
func (d *Daemon) NodeID() string {
return d.CachedInfo.Swarm.NodeID
}
// SwarmInit initializes a new swarm cluster.
func (d *Daemon) SwarmInit(t assert.TestingT, req swarm.InitRequest) {
if req.ListenAddr == "" {
req.ListenAddr = fmt.Sprintf("%s:%d", d.swarmListenAddr, d.SwarmPort)
}
cli := d.NewClientT(t)
defer cli.Close()
_, err := cli.SwarmInit(context.Background(), req)
assert.NilError(t, err, "initializing swarm")
d.CachedInfo = d.Info(t)
}
// SwarmJoin joins a daemon to an existing cluster.
func (d *Daemon) SwarmJoin(t assert.TestingT, req swarm.JoinRequest) {
if req.ListenAddr == "" {
req.ListenAddr = fmt.Sprintf("%s:%d", d.swarmListenAddr, d.SwarmPort)
}
cli := d.NewClientT(t)
defer cli.Close()
err := cli.SwarmJoin(context.Background(), req)
assert.NilError(t, err, "initializing swarm")
d.CachedInfo = d.Info(t)
}
// SwarmLeave forces daemon to leave current cluster.
func (d *Daemon) SwarmLeave(force bool) error {
cli, err := d.NewClient()
if err != nil {
return fmt.Errorf("leaving swarm: failed to create client %v", err)
}
defer cli.Close()
err = cli.SwarmLeave(context.Background(), force)
if err != nil {
err = fmt.Errorf("leaving swarm: %v", err)
}
return err
}
// SwarmInfo returns the swarm information of the daemon
func (d *Daemon) SwarmInfo(t assert.TestingT) swarm.Info {
cli := d.NewClientT(t)
info, err := cli.Info(context.Background())
assert.NilError(t, err, "get swarm info")
return info.Swarm
}
// SwarmUnlock tries to unlock a locked swarm
func (d *Daemon) SwarmUnlock(req swarm.UnlockRequest) error {
cli, err := d.NewClient()
if err != nil {
return fmt.Errorf("unlocking swarm: failed to create client %v", err)
}
defer cli.Close()
err = cli.SwarmUnlock(context.Background(), req)
if err != nil {
err = errors.Wrap(err, "unlocking swarm")
}
return err
}
// GetSwarm returns the current swarm object
func (d *Daemon) GetSwarm(t assert.TestingT) swarm.Swarm {
cli := d.NewClientT(t)
defer cli.Close()
sw, err := cli.SwarmInspect(context.Background())
assert.NilError(t, err)
return sw
}
// UpdateSwarm updates the current swarm object with the specified spec constructors
func (d *Daemon) UpdateSwarm(t assert.TestingT, f ...SpecConstructor) {
cli := d.NewClientT(t)
defer cli.Close()
sw := d.GetSwarm(t)
for _, fn := range f {
fn(&sw.Spec)
}
err := cli.SwarmUpdate(context.Background(), sw.Version, sw.Spec, swarm.UpdateFlags{})
assert.NilError(t, err)
}
// RotateTokens update the swarm to rotate tokens
func (d *Daemon) RotateTokens(t assert.TestingT) {
cli := d.NewClientT(t)
defer cli.Close()
sw, err := cli.SwarmInspect(context.Background())
assert.NilError(t, err)
flags := swarm.UpdateFlags{
RotateManagerToken: true,
RotateWorkerToken: true,
}
err = cli.SwarmUpdate(context.Background(), sw.Version, sw.Spec, flags)
assert.NilError(t, err)
}
// JoinTokens returns the current swarm join tokens
func (d *Daemon) JoinTokens(t assert.TestingT) swarm.JoinTokens {
cli := d.NewClientT(t)
defer cli.Close()
sw, err := cli.SwarmInspect(context.Background())
assert.NilError(t, err)
return sw.JoinTokens
}