mirror of
				https://github.com/moby/moby.git
				synced 2022-11-09 12:21:53 -05:00 
			
		
		
		
	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:
		
							parent
							
								
									f0d277fe84
								
							
						
					
					
						commit
						83d18cf4e3
					
				
					 18 changed files with 721 additions and 697 deletions
				
			
		| 
						 | 
				
			
			@ -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{})
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
			}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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{})
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										66
									
								
								internal/test/daemon/config.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								internal/test/daemon/config.go
									
										
									
									
									
										Normal 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)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										69
									
								
								internal/test/daemon/node.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								internal/test/daemon/node.go
									
										
									
									
									
										Normal 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
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										68
									
								
								internal/test/daemon/secret.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								internal/test/daemon/secret.go
									
										
									
									
									
										Normal 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)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										108
									
								
								internal/test/daemon/service.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								internal/test/daemon/service.go
									
										
									
									
									
										Normal 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
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										139
									
								
								internal/test/daemon/swarm.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								internal/test/daemon/swarm.go
									
										
									
									
									
										Normal 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
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue