Browse code

Merge pull request #36826 from vdemeester/integration-daemon-swarm-refactoring

Make internal/test/daemon.Daemon swarm aware

Sebastiaan van Stijn authored on 2018/04/12 01:33:58
Showing 18 changed files
... ...
@@ -311,7 +311,7 @@ func init() {
311 311
 type DockerSwarmSuite struct {
312 312
 	server      *httptest.Server
313 313
 	ds          *DockerSuite
314
-	daemons     []*daemon.Swarm
314
+	daemons     []*daemon.Daemon
315 315
 	daemonsLock sync.Mutex // protect access to daemons
316 316
 	portIndex   int
317 317
 }
... ...
@@ -328,14 +328,10 @@ func (s *DockerSwarmSuite) SetUpTest(c *check.C) {
328 328
 	testRequires(c, DaemonIsLinux, SameHostDaemon)
329 329
 }
330 330
 
331
-func (s *DockerSwarmSuite) AddDaemon(c *check.C, joinSwarm, manager bool) *daemon.Swarm {
332
-	d := &daemon.Swarm{
333
-		Daemon: daemon.New(c, dockerBinary, dockerdBinary, daemon.Config{
334
-			Experimental: testEnv.DaemonInfo.ExperimentalBuild,
335
-		}),
336
-		Port: defaultSwarmPort + s.portIndex,
337
-	}
338
-	d.ListenAddr = fmt.Sprintf("0.0.0.0:%d", d.Port)
331
+func (s *DockerSwarmSuite) AddDaemon(c *check.C, joinSwarm, manager bool) *daemon.Daemon {
332
+	d := daemon.New(c, dockerBinary, dockerdBinary, daemon.Config{
333
+		Experimental: testEnv.DaemonInfo.ExperimentalBuild,
334
+	}, testdaemon.WithSwarmPort(defaultSwarmPort+s.portIndex))
339 335
 	args := []string{"--iptables=false", "--swarm-default-advertise-addr=lo"} // avoid networking conflicts
340 336
 	d.StartWithBusybox(c, args...)
341 337
 
... ...
@@ -346,12 +342,12 @@ func (s *DockerSwarmSuite) AddDaemon(c *check.C, joinSwarm, manager bool) *daemo
346 346
 			if manager {
347 347
 				token = tokens.Manager
348 348
 			}
349
-			c.Assert(d.Join(swarm.JoinRequest{
350
-				RemoteAddrs: []string{s.daemons[0].ListenAddr},
349
+			d.SwarmJoin(c, swarm.JoinRequest{
350
+				RemoteAddrs: []string{s.daemons[0].SwarmListenAddr()},
351 351
 				JoinToken:   token,
352
-			}), check.IsNil)
352
+			})
353 353
 		} else {
354
-			c.Assert(d.Init(swarm.InitRequest{}), check.IsNil)
354
+			d.SwarmInit(c, swarm.InitRequest{})
355 355
 		}
356 356
 	}
357 357
 
... ...
@@ -38,10 +38,8 @@ type Config struct {
38 38
 // New returns a Daemon instance to be used for testing.
39 39
 // This will create a directory such as d123456789 in the folder specified by $DOCKER_INTEGRATION_DAEMON_DEST or $DEST.
40 40
 // The daemon will not automatically start.
41
-func New(t testingT, dockerBinary string, dockerdBinary string, config Config) *Daemon {
42
-	ops := []func(*daemon.Daemon){
43
-		daemon.WithDockerdBinary(dockerdBinary),
44
-	}
41
+func New(t testingT, dockerBinary string, dockerdBinary string, config Config, ops ...func(*daemon.Daemon)) *Daemon {
42
+	ops = append(ops, daemon.WithDockerdBinary(dockerdBinary))
45 43
 	if config.Experimental {
46 44
 		ops = append(ops, daemon.WithExperimental)
47 45
 	}
... ...
@@ -150,6 +148,21 @@ func (d *Daemon) WaitRun(contID string) error {
150 150
 	return WaitInspectWithArgs(d.dockerBinary, contID, "{{.State.Running}}", "true", 10*time.Second, args...)
151 151
 }
152 152
 
153
+// CmdRetryOutOfSequence tries the specified command against the current daemon for 10 times
154
+func (d *Daemon) CmdRetryOutOfSequence(args ...string) (string, error) {
155
+	for i := 0; ; i++ {
156
+		out, err := d.Cmd(args...)
157
+		if err != nil {
158
+			if strings.Contains(out, "update out of sequence") {
159
+				if i < 10 {
160
+					continue
161
+				}
162
+			}
163
+		}
164
+		return out, err
165
+	}
166
+}
167
+
153 168
 // WaitInspectWithArgs waits for the specified expression to be equals to the specified expected string in the given time.
154 169
 // Deprecated: use cli.WaitCmd instead
155 170
 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"
3 3
 import (
4 4
 	"fmt"
5 5
 	"strings"
6
-	"time"
7 6
 
8 7
 	"github.com/docker/docker/api/types"
9 8
 	"github.com/docker/docker/api/types/filters"
... ...
@@ -12,178 +11,12 @@ import (
12 12
 	"github.com/docker/docker/integration-cli/checker"
13 13
 	"github.com/go-check/check"
14 14
 	"github.com/gotestyourself/gotestyourself/assert"
15
-	"github.com/pkg/errors"
16 15
 	"golang.org/x/net/context"
17 16
 )
18 17
 
19
-// Swarm is a test daemon with helpers for participating in a swarm.
20
-type Swarm struct {
21
-	*Daemon
22
-	swarm.Info
23
-	Port       int
24
-	ListenAddr string
25
-}
26
-
27
-// Init initializes a new swarm cluster.
28
-func (d *Swarm) Init(req swarm.InitRequest) error {
29
-	if req.ListenAddr == "" {
30
-		req.ListenAddr = d.ListenAddr
31
-	}
32
-	cli, err := d.NewClient()
33
-	if err != nil {
34
-		return fmt.Errorf("initializing swarm: failed to create client %v", err)
35
-	}
36
-	defer cli.Close()
37
-	_, err = cli.SwarmInit(context.Background(), req)
38
-	if err != nil {
39
-		return fmt.Errorf("initializing swarm: %v", err)
40
-	}
41
-	info, err := d.SwarmInfo()
42
-	if err != nil {
43
-		return err
44
-	}
45
-	d.Info = info
46
-	return nil
47
-}
48
-
49
-// Join joins a daemon to an existing cluster.
50
-func (d *Swarm) Join(req swarm.JoinRequest) error {
51
-	if req.ListenAddr == "" {
52
-		req.ListenAddr = d.ListenAddr
53
-	}
54
-	cli, err := d.NewClient()
55
-	if err != nil {
56
-		return fmt.Errorf("joining swarm: failed to create client %v", err)
57
-	}
58
-	defer cli.Close()
59
-	err = cli.SwarmJoin(context.Background(), req)
60
-	if err != nil {
61
-		return fmt.Errorf("joining swarm: %v", err)
62
-	}
63
-	info, err := d.SwarmInfo()
64
-	if err != nil {
65
-		return err
66
-	}
67
-	d.Info = info
68
-	return nil
69
-}
70
-
71
-// Leave forces daemon to leave current cluster.
72
-func (d *Swarm) Leave(force bool) error {
73
-	cli, err := d.NewClient()
74
-	if err != nil {
75
-		return fmt.Errorf("leaving swarm: failed to create client %v", err)
76
-	}
77
-	defer cli.Close()
78
-	err = cli.SwarmLeave(context.Background(), force)
79
-	if err != nil {
80
-		err = fmt.Errorf("leaving swarm: %v", err)
81
-	}
82
-	return err
83
-}
84
-
85
-// SwarmInfo returns the swarm information of the daemon
86
-func (d *Swarm) SwarmInfo() (swarm.Info, error) {
87
-	cli, err := d.NewClient()
88
-	if err != nil {
89
-		return swarm.Info{}, fmt.Errorf("get swarm info: %v", err)
90
-	}
91
-
92
-	info, err := cli.Info(context.Background())
93
-	if err != nil {
94
-		return swarm.Info{}, fmt.Errorf("get swarm info: %v", err)
95
-	}
96
-
97
-	return info.Swarm, nil
98
-}
99
-
100
-// Unlock tries to unlock a locked swarm
101
-func (d *Swarm) Unlock(req swarm.UnlockRequest) error {
102
-	cli, err := d.NewClient()
103
-	if err != nil {
104
-		return fmt.Errorf("unlocking swarm: failed to create client %v", err)
105
-	}
106
-	defer cli.Close()
107
-	err = cli.SwarmUnlock(context.Background(), req)
108
-	if err != nil {
109
-		err = errors.Wrap(err, "unlocking swarm")
110
-	}
111
-	return err
112
-}
113
-
114
-// ServiceConstructor defines a swarm service constructor function
115
-type ServiceConstructor func(*swarm.Service)
116
-
117
-// NodeConstructor defines a swarm node constructor
118
-type NodeConstructor func(*swarm.Node)
119
-
120
-// SecretConstructor defines a swarm secret constructor
121
-type SecretConstructor func(*swarm.Secret)
122
-
123
-// ConfigConstructor defines a swarm config constructor
124
-type ConfigConstructor func(*swarm.Config)
125
-
126
-// SpecConstructor defines a swarm spec constructor
127
-type SpecConstructor func(*swarm.Spec)
128
-
129
-// CreateServiceWithOptions creates a swarm service given the specified service constructors
130
-// and auth config
131
-func (d *Swarm) CreateServiceWithOptions(c *check.C, opts types.ServiceCreateOptions, f ...ServiceConstructor) string {
132
-	var service swarm.Service
133
-	for _, fn := range f {
134
-		fn(&service)
135
-	}
136
-
137
-	cli, err := d.NewClient()
138
-	c.Assert(err, checker.IsNil)
139
-	defer cli.Close()
140
-
141
-	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
142
-	defer cancel()
143
-
144
-	res, err := cli.ServiceCreate(ctx, service.Spec, opts)
145
-	c.Assert(err, checker.IsNil)
146
-	return res.ID
147
-}
148
-
149
-// CreateService creates a swarm service given the specified service constructor
150
-func (d *Swarm) CreateService(c *check.C, f ...ServiceConstructor) string {
151
-	return d.CreateServiceWithOptions(c, types.ServiceCreateOptions{}, f...)
152
-}
153
-
154
-// GetService returns the swarm service corresponding to the specified id
155
-func (d *Swarm) GetService(c *check.C, id string) *swarm.Service {
156
-	cli, err := d.NewClient()
157
-	c.Assert(err, checker.IsNil)
158
-	defer cli.Close()
159
-
160
-	service, _, err := cli.ServiceInspectWithRaw(context.Background(), id, types.ServiceInspectOptions{})
161
-	c.Assert(err, checker.IsNil)
162
-	return &service
163
-}
164
-
165
-// GetServiceTasks returns the swarm tasks for the specified service
166
-func (d *Swarm) GetServiceTasks(c *check.C, service string) []swarm.Task {
167
-	cli, err := d.NewClient()
168
-	c.Assert(err, checker.IsNil)
169
-	defer cli.Close()
170
-
171
-	filterArgs := filters.NewArgs()
172
-	filterArgs.Add("desired-state", "running")
173
-	filterArgs.Add("service", service)
174
-
175
-	options := types.TaskListOptions{
176
-		Filters: filterArgs,
177
-	}
178
-
179
-	tasks, err := cli.TaskList(context.Background(), options)
180
-	c.Assert(err, checker.IsNil)
181
-	return tasks
182
-}
183
-
184 18
 // CheckServiceTasksInState returns the number of tasks with a matching state,
185 19
 // and optional message substring.
186
-func (d *Swarm) CheckServiceTasksInState(service string, state swarm.TaskState, message string) func(*check.C) (interface{}, check.CommentInterface) {
20
+func (d *Daemon) CheckServiceTasksInState(service string, state swarm.TaskState, message string) func(*check.C) (interface{}, check.CommentInterface) {
187 21
 	return func(c *check.C) (interface{}, check.CommentInterface) {
188 22
 		tasks := d.GetServiceTasks(c, service)
189 23
 		var count int
... ...
@@ -200,7 +33,7 @@ func (d *Swarm) CheckServiceTasksInState(service string, state swarm.TaskState,
200 200
 
201 201
 // CheckServiceTasksInStateWithError returns the number of tasks with a matching state,
202 202
 // and optional message substring.
203
-func (d *Swarm) CheckServiceTasksInStateWithError(service string, state swarm.TaskState, errorMessage string) func(*check.C) (interface{}, check.CommentInterface) {
203
+func (d *Daemon) CheckServiceTasksInStateWithError(service string, state swarm.TaskState, errorMessage string) func(*check.C) (interface{}, check.CommentInterface) {
204 204
 	return func(c *check.C) (interface{}, check.CommentInterface) {
205 205
 		tasks := d.GetServiceTasks(c, service)
206 206
 		var count int
... ...
@@ -216,12 +49,12 @@ func (d *Swarm) CheckServiceTasksInStateWithError(service string, state swarm.Ta
216 216
 }
217 217
 
218 218
 // CheckServiceRunningTasks returns the number of running tasks for the specified service
219
-func (d *Swarm) CheckServiceRunningTasks(service string) func(*check.C) (interface{}, check.CommentInterface) {
219
+func (d *Daemon) CheckServiceRunningTasks(service string) func(*check.C) (interface{}, check.CommentInterface) {
220 220
 	return d.CheckServiceTasksInState(service, swarm.TaskStateRunning, "")
221 221
 }
222 222
 
223 223
 // CheckServiceUpdateState returns the current update state for the specified service
224
-func (d *Swarm) CheckServiceUpdateState(service string) func(*check.C) (interface{}, check.CommentInterface) {
224
+func (d *Daemon) CheckServiceUpdateState(service string) func(*check.C) (interface{}, check.CommentInterface) {
225 225
 	return func(c *check.C) (interface{}, check.CommentInterface) {
226 226
 		service := d.GetService(c, service)
227 227
 		if service.UpdateStatus == nil {
... ...
@@ -232,7 +65,7 @@ func (d *Swarm) CheckServiceUpdateState(service string) func(*check.C) (interfac
232 232
 }
233 233
 
234 234
 // CheckPluginRunning returns the runtime state of the plugin
235
-func (d *Swarm) CheckPluginRunning(plugin string) func(c *check.C) (interface{}, check.CommentInterface) {
235
+func (d *Daemon) CheckPluginRunning(plugin string) func(c *check.C) (interface{}, check.CommentInterface) {
236 236
 	return func(c *check.C) (interface{}, check.CommentInterface) {
237 237
 		apiclient, err := d.NewClient()
238 238
 		assert.NilError(c, err)
... ...
@@ -246,7 +79,7 @@ func (d *Swarm) CheckPluginRunning(plugin string) func(c *check.C) (interface{},
246 246
 }
247 247
 
248 248
 // CheckPluginImage returns the runtime state of the plugin
249
-func (d *Swarm) CheckPluginImage(plugin string) func(c *check.C) (interface{}, check.CommentInterface) {
249
+func (d *Daemon) CheckPluginImage(plugin string) func(c *check.C) (interface{}, check.CommentInterface) {
250 250
 	return func(c *check.C) (interface{}, check.CommentInterface) {
251 251
 		apiclient, err := d.NewClient()
252 252
 		assert.NilError(c, err)
... ...
@@ -260,7 +93,7 @@ func (d *Swarm) CheckPluginImage(plugin string) func(c *check.C) (interface{}, c
260 260
 }
261 261
 
262 262
 // CheckServiceTasks returns the number of tasks for the specified service
263
-func (d *Swarm) CheckServiceTasks(service string) func(*check.C) (interface{}, check.CommentInterface) {
263
+func (d *Daemon) CheckServiceTasks(service string) func(*check.C) (interface{}, check.CommentInterface) {
264 264
 	return func(c *check.C) (interface{}, check.CommentInterface) {
265 265
 		tasks := d.GetServiceTasks(c, service)
266 266
 		return len(tasks), nil
... ...
@@ -268,7 +101,7 @@ func (d *Swarm) CheckServiceTasks(service string) func(*check.C) (interface{}, c
268 268
 }
269 269
 
270 270
 // CheckRunningTaskNetworks returns the number of times each network is referenced from a task.
271
-func (d *Swarm) CheckRunningTaskNetworks(c *check.C) (interface{}, check.CommentInterface) {
271
+func (d *Daemon) CheckRunningTaskNetworks(c *check.C) (interface{}, check.CommentInterface) {
272 272
 	cli, err := d.NewClient()
273 273
 	c.Assert(err, checker.IsNil)
274 274
 	defer cli.Close()
... ...
@@ -293,7 +126,7 @@ func (d *Swarm) CheckRunningTaskNetworks(c *check.C) (interface{}, check.Comment
293 293
 }
294 294
 
295 295
 // CheckRunningTaskImages returns the times each image is running as a task.
296
-func (d *Swarm) CheckRunningTaskImages(c *check.C) (interface{}, check.CommentInterface) {
296
+func (d *Daemon) CheckRunningTaskImages(c *check.C) (interface{}, check.CommentInterface) {
297 297
 	cli, err := d.NewClient()
298 298
 	c.Assert(err, checker.IsNil)
299 299
 	defer cli.Close()
... ...
@@ -318,7 +151,7 @@ func (d *Swarm) CheckRunningTaskImages(c *check.C) (interface{}, check.CommentIn
318 318
 }
319 319
 
320 320
 // CheckNodeReadyCount returns the number of ready node on the swarm
321
-func (d *Swarm) CheckNodeReadyCount(c *check.C) (interface{}, check.CommentInterface) {
321
+func (d *Daemon) CheckNodeReadyCount(c *check.C) (interface{}, check.CommentInterface) {
322 322
 	nodes := d.ListNodes(c)
323 323
 	var readyCount int
324 324
 	for _, node := range nodes {
... ...
@@ -329,303 +162,21 @@ func (d *Swarm) CheckNodeReadyCount(c *check.C) (interface{}, check.CommentInter
329 329
 	return readyCount, nil
330 330
 }
331 331
 
332
-// GetTask returns the swarm task identified by the specified id
333
-func (d *Swarm) GetTask(c *check.C, id string) swarm.Task {
334
-	cli, err := d.NewClient()
335
-	c.Assert(err, checker.IsNil)
336
-	defer cli.Close()
337
-
338
-	task, _, err := cli.TaskInspectWithRaw(context.Background(), id)
339
-	c.Assert(err, checker.IsNil)
340
-	return task
341
-}
342
-
343
-// UpdateService updates a swarm service with the specified service constructor
344
-func (d *Swarm) UpdateService(c *check.C, service *swarm.Service, f ...ServiceConstructor) {
345
-	cli, err := d.NewClient()
346
-	c.Assert(err, checker.IsNil)
347
-	defer cli.Close()
348
-
349
-	for _, fn := range f {
350
-		fn(service)
351
-	}
352
-
353
-	_, err = cli.ServiceUpdate(context.Background(), service.ID, service.Version, service.Spec, types.ServiceUpdateOptions{})
354
-	c.Assert(err, checker.IsNil)
355
-}
356
-
357
-// RemoveService removes the specified service
358
-func (d *Swarm) RemoveService(c *check.C, id string) {
359
-	cli, err := d.NewClient()
360
-	c.Assert(err, checker.IsNil)
361
-	defer cli.Close()
362
-
363
-	err = cli.ServiceRemove(context.Background(), id)
364
-	c.Assert(err, checker.IsNil)
365
-}
366
-
367
-// GetNode returns a swarm node identified by the specified id
368
-func (d *Swarm) GetNode(c *check.C, id string) *swarm.Node {
369
-	cli, err := d.NewClient()
370
-	c.Assert(err, checker.IsNil)
371
-	defer cli.Close()
372
-
373
-	node, _, err := cli.NodeInspectWithRaw(context.Background(), id)
374
-	c.Assert(err, checker.IsNil)
375
-	c.Assert(node.ID, checker.Equals, id)
376
-	return &node
377
-}
378
-
379
-// RemoveNode removes the specified node
380
-func (d *Swarm) RemoveNode(c *check.C, id string, force bool) {
381
-	cli, err := d.NewClient()
382
-	c.Assert(err, checker.IsNil)
383
-	defer cli.Close()
384
-
385
-	options := types.NodeRemoveOptions{
386
-		Force: force,
387
-	}
388
-	err = cli.NodeRemove(context.Background(), id, options)
389
-	c.Assert(err, checker.IsNil)
390
-}
391
-
392
-// UpdateNode updates a swarm node with the specified node constructor
393
-func (d *Swarm) UpdateNode(c *check.C, id string, f ...NodeConstructor) {
394
-	cli, err := d.NewClient()
395
-	c.Assert(err, checker.IsNil)
396
-	defer cli.Close()
397
-
398
-	for i := 0; ; i++ {
399
-		node := d.GetNode(c, id)
400
-		for _, fn := range f {
401
-			fn(node)
402
-		}
403
-
404
-		err = cli.NodeUpdate(context.Background(), node.ID, node.Version, node.Spec)
405
-		if i < 10 && err != nil && strings.Contains(err.Error(), "update out of sequence") {
406
-			time.Sleep(100 * time.Millisecond)
407
-			continue
408
-		}
409
-		c.Assert(err, checker.IsNil)
410
-		return
411
-	}
412
-}
413
-
414
-// ListNodes returns the list of the current swarm nodes
415
-func (d *Swarm) ListNodes(c *check.C) []swarm.Node {
416
-	cli, err := d.NewClient()
417
-	c.Assert(err, checker.IsNil)
418
-	defer cli.Close()
419
-
420
-	nodes, err := cli.NodeList(context.Background(), types.NodeListOptions{})
421
-	c.Assert(err, checker.IsNil)
422
-
423
-	return nodes
424
-}
425
-
426
-// ListServices returns the list of the current swarm services
427
-func (d *Swarm) ListServices(c *check.C) []swarm.Service {
428
-	cli, err := d.NewClient()
429
-	c.Assert(err, checker.IsNil)
430
-	defer cli.Close()
431
-
432
-	services, err := cli.ServiceList(context.Background(), types.ServiceListOptions{})
433
-	c.Assert(err, checker.IsNil)
434
-	return services
435
-}
436
-
437
-// CreateSecret creates a secret given the specified spec
438
-func (d *Swarm) CreateSecret(c *check.C, secretSpec swarm.SecretSpec) string {
439
-	cli, err := d.NewClient()
440
-	c.Assert(err, checker.IsNil)
441
-	defer cli.Close()
442
-
443
-	scr, err := cli.SecretCreate(context.Background(), secretSpec)
444
-	c.Assert(err, checker.IsNil)
445
-
446
-	return scr.ID
447
-}
448
-
449
-// ListSecrets returns the list of the current swarm secrets
450
-func (d *Swarm) ListSecrets(c *check.C) []swarm.Secret {
451
-	cli, err := d.NewClient()
452
-	c.Assert(err, checker.IsNil)
453
-	defer cli.Close()
454
-
455
-	secrets, err := cli.SecretList(context.Background(), types.SecretListOptions{})
456
-	c.Assert(err, checker.IsNil)
457
-	return secrets
458
-}
459
-
460
-// GetSecret returns a swarm secret identified by the specified id
461
-func (d *Swarm) GetSecret(c *check.C, id string) *swarm.Secret {
462
-	cli, err := d.NewClient()
463
-	c.Assert(err, checker.IsNil)
464
-	defer cli.Close()
465
-
466
-	secret, _, err := cli.SecretInspectWithRaw(context.Background(), id)
467
-	c.Assert(err, checker.IsNil)
468
-	return &secret
469
-}
470
-
471
-// DeleteSecret removes the swarm secret identified by the specified id
472
-func (d *Swarm) DeleteSecret(c *check.C, id string) {
473
-	cli, err := d.NewClient()
474
-	c.Assert(err, checker.IsNil)
475
-	defer cli.Close()
476
-
477
-	err = cli.SecretRemove(context.Background(), id)
478
-	c.Assert(err, checker.IsNil)
479
-}
480
-
481
-// UpdateSecret updates the swarm secret identified by the specified id
482
-// Currently, only label update is supported.
483
-func (d *Swarm) UpdateSecret(c *check.C, id string, f ...SecretConstructor) {
484
-	cli, err := d.NewClient()
485
-	c.Assert(err, checker.IsNil)
486
-	defer cli.Close()
487
-
488
-	secret := d.GetSecret(c, id)
489
-	for _, fn := range f {
490
-		fn(secret)
491
-	}
492
-
493
-	err = cli.SecretUpdate(context.Background(), secret.ID, secret.Version, secret.Spec)
494
-
495
-	c.Assert(err, checker.IsNil)
496
-}
497
-
498
-// CreateConfig creates a config given the specified spec
499
-func (d *Swarm) CreateConfig(c *check.C, configSpec swarm.ConfigSpec) string {
500
-	cli, err := d.NewClient()
501
-	c.Assert(err, checker.IsNil)
502
-	defer cli.Close()
503
-
504
-	scr, err := cli.ConfigCreate(context.Background(), configSpec)
505
-	c.Assert(err, checker.IsNil)
506
-	return scr.ID
507
-}
508
-
509
-// ListConfigs returns the list of the current swarm configs
510
-func (d *Swarm) ListConfigs(c *check.C) []swarm.Config {
511
-	cli, err := d.NewClient()
512
-	c.Assert(err, checker.IsNil)
513
-	defer cli.Close()
514
-
515
-	configs, err := cli.ConfigList(context.Background(), types.ConfigListOptions{})
516
-	c.Assert(err, checker.IsNil)
517
-	return configs
518
-}
519
-
520
-// GetConfig returns a swarm config identified by the specified id
521
-func (d *Swarm) GetConfig(c *check.C, id string) *swarm.Config {
522
-	cli, err := d.NewClient()
523
-	c.Assert(err, checker.IsNil)
524
-	defer cli.Close()
525
-
526
-	config, _, err := cli.ConfigInspectWithRaw(context.Background(), id)
527
-	c.Assert(err, checker.IsNil)
528
-	return &config
529
-}
530
-
531
-// DeleteConfig removes the swarm config identified by the specified id
532
-func (d *Swarm) DeleteConfig(c *check.C, id string) {
533
-	cli, err := d.NewClient()
534
-	c.Assert(err, checker.IsNil)
535
-	defer cli.Close()
536
-
537
-	err = cli.ConfigRemove(context.Background(), id)
538
-	c.Assert(err, checker.IsNil)
539
-}
540
-
541
-// UpdateConfig updates the swarm config identified by the specified id
542
-// Currently, only label update is supported.
543
-func (d *Swarm) UpdateConfig(c *check.C, id string, f ...ConfigConstructor) {
544
-	cli, err := d.NewClient()
545
-	c.Assert(err, checker.IsNil)
546
-	defer cli.Close()
547
-
548
-	config := d.GetConfig(c, id)
549
-	for _, fn := range f {
550
-		fn(config)
551
-	}
552
-
553
-	err = cli.ConfigUpdate(context.Background(), config.ID, config.Version, config.Spec)
554
-	c.Assert(err, checker.IsNil)
555
-}
556
-
557
-// GetSwarm returns the current swarm object
558
-func (d *Swarm) GetSwarm(c *check.C) swarm.Swarm {
559
-	cli, err := d.NewClient()
560
-	c.Assert(err, checker.IsNil)
561
-	defer cli.Close()
562
-
563
-	sw, err := cli.SwarmInspect(context.Background())
564
-	c.Assert(err, checker.IsNil)
565
-	return sw
566
-}
567
-
568
-// UpdateSwarm updates the current swarm object with the specified spec constructors
569
-func (d *Swarm) UpdateSwarm(c *check.C, f ...SpecConstructor) {
570
-	cli, err := d.NewClient()
571
-	c.Assert(err, checker.IsNil)
572
-	defer cli.Close()
573
-
574
-	sw := d.GetSwarm(c)
575
-	for _, fn := range f {
576
-		fn(&sw.Spec)
577
-	}
578
-
579
-	err = cli.SwarmUpdate(context.Background(), sw.Version, sw.Spec, swarm.UpdateFlags{})
580
-	c.Assert(err, checker.IsNil)
581
-}
582
-
583
-// RotateTokens update the swarm to rotate tokens
584
-func (d *Swarm) RotateTokens(c *check.C) {
585
-	cli, err := d.NewClient()
586
-	c.Assert(err, checker.IsNil)
587
-	defer cli.Close()
588
-
589
-	sw, err := cli.SwarmInspect(context.Background())
590
-	c.Assert(err, checker.IsNil)
591
-
592
-	flags := swarm.UpdateFlags{
593
-		RotateManagerToken: true,
594
-		RotateWorkerToken:  true,
595
-	}
596
-
597
-	err = cli.SwarmUpdate(context.Background(), sw.Version, sw.Spec, flags)
598
-	c.Assert(err, checker.IsNil)
599
-}
600
-
601
-// JoinTokens returns the current swarm join tokens
602
-func (d *Swarm) JoinTokens(c *check.C) swarm.JoinTokens {
603
-	cli, err := d.NewClient()
604
-	c.Assert(err, checker.IsNil)
605
-	defer cli.Close()
606
-
607
-	sw, err := cli.SwarmInspect(context.Background())
608
-	c.Assert(err, checker.IsNil)
609
-	return sw.JoinTokens
610
-}
611
-
612 332
 // CheckLocalNodeState returns the current swarm node state
613
-func (d *Swarm) CheckLocalNodeState(c *check.C) (interface{}, check.CommentInterface) {
614
-	info, err := d.SwarmInfo()
615
-	c.Assert(err, checker.IsNil)
333
+func (d *Daemon) CheckLocalNodeState(c *check.C) (interface{}, check.CommentInterface) {
334
+	info := d.SwarmInfo(c)
616 335
 	return info.LocalNodeState, nil
617 336
 }
618 337
 
619 338
 // CheckControlAvailable returns the current swarm control available
620
-func (d *Swarm) CheckControlAvailable(c *check.C) (interface{}, check.CommentInterface) {
621
-	info, err := d.SwarmInfo()
622
-	c.Assert(err, checker.IsNil)
339
+func (d *Daemon) CheckControlAvailable(c *check.C) (interface{}, check.CommentInterface) {
340
+	info := d.SwarmInfo(c)
623 341
 	c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
624 342
 	return info.ControlAvailable, nil
625 343
 }
626 344
 
627 345
 // CheckLeader returns whether there is a leader on the swarm or not
628
-func (d *Swarm) CheckLeader(c *check.C) (interface{}, check.CommentInterface) {
346
+func (d *Daemon) CheckLeader(c *check.C) (interface{}, check.CommentInterface) {
629 347
 	cli, err := d.NewClient()
630 348
 	c.Assert(err, checker.IsNil)
631 349
 	defer cli.Close()
... ...
@@ -5,11 +5,11 @@ import (
5 5
 	"github.com/go-check/check"
6 6
 )
7 7
 
8
-func (s *DockerSwarmSuite) getDaemon(c *check.C, nodeID string) *daemon.Swarm {
8
+func (s *DockerSwarmSuite) getDaemon(c *check.C, nodeID string) *daemon.Daemon {
9 9
 	s.daemonsLock.Lock()
10 10
 	defer s.daemonsLock.Unlock()
11 11
 	for _, d := range s.daemons {
12
-		if d.NodeID == nodeID {
12
+		if d.NodeID() == nodeID {
13 13
 			return d
14 14
 		}
15 15
 	}
... ...
@@ -21,8 +21,8 @@ func (s *DockerSwarmSuite) TestAPISwarmListNodes(c *check.C) {
21 21
 
22 22
 loop0:
23 23
 	for _, n := range nodes {
24
-		for _, d := range []*daemon.Swarm{d1, d2, d3} {
25
-			if n.ID == d.NodeID {
24
+		for _, d := range []*daemon.Daemon{d1, d2, d3} {
25
+			if n.ID == d.NodeID() {
26 26
 				continue loop0
27 27
 			}
28 28
 		}
... ...
@@ -53,8 +53,7 @@ func (s *DockerSwarmSuite) TestAPISwarmNodeRemove(c *check.C) {
53 53
 	c.Assert(len(nodes), checker.Equals, 3, check.Commentf("nodes: %#v", nodes))
54 54
 
55 55
 	// Getting the info so we can take the NodeID
56
-	d2Info, err := d2.SwarmInfo()
57
-	c.Assert(err, checker.IsNil)
56
+	d2Info := d2.SwarmInfo(c)
58 57
 
59 58
 	// forceful removal of d2 should work
60 59
 	d1.RemoveNode(c, d2Info.NodeID, true)
... ...
@@ -88,14 +87,14 @@ func (s *DockerSwarmSuite) TestAPISwarmNodeDrainPause(c *check.C) {
88 88
 	waitAndAssert(c, defaultReconciliationTimeout, reducedCheck(sumAsIntegers, d1.CheckActiveContainerCount, d2.CheckActiveContainerCount), checker.Equals, instances)
89 89
 
90 90
 	// drain d2, all containers should move to d1
91
-	d1.UpdateNode(c, d2.NodeID, func(n *swarm.Node) {
91
+	d1.UpdateNode(c, d2.NodeID(), func(n *swarm.Node) {
92 92
 		n.Spec.Availability = swarm.NodeAvailabilityDrain
93 93
 	})
94 94
 	waitAndAssert(c, defaultReconciliationTimeout, d1.CheckActiveContainerCount, checker.Equals, instances)
95 95
 	waitAndAssert(c, defaultReconciliationTimeout, d2.CheckActiveContainerCount, checker.Equals, 0)
96 96
 
97 97
 	// set d2 back to active
98
-	d1.UpdateNode(c, d2.NodeID, func(n *swarm.Node) {
98
+	d1.UpdateNode(c, d2.NodeID(), func(n *swarm.Node) {
99 99
 		n.Spec.Availability = swarm.NodeAvailabilityActive
100 100
 	})
101 101
 
... ...
@@ -115,7 +114,7 @@ func (s *DockerSwarmSuite) TestAPISwarmNodeDrainPause(c *check.C) {
115 115
 	d2ContainerCount := len(d2.ActiveContainers())
116 116
 
117 117
 	// set d2 to paused, scale service up, only d1 gets new tasks
118
-	d1.UpdateNode(c, d2.NodeID, func(n *swarm.Node) {
118
+	d1.UpdateNode(c, d2.NodeID(), func(n *swarm.Node) {
119 119
 		n.Spec.Availability = swarm.NodeAvailabilityPause
120 120
 	})
121 121
 
... ...
@@ -15,12 +15,13 @@ import (
15 15
 	"github.com/docker/docker/integration-cli/checker"
16 16
 	"github.com/docker/docker/integration-cli/daemon"
17 17
 	"github.com/docker/docker/integration-cli/fixtures/plugin"
18
+	testdaemon "github.com/docker/docker/internal/test/daemon"
18 19
 	"github.com/go-check/check"
19 20
 	"golang.org/x/net/context"
20 21
 	"golang.org/x/sys/unix"
21 22
 )
22 23
 
23
-func setPortConfig(portConfig []swarm.PortConfig) daemon.ServiceConstructor {
24
+func setPortConfig(portConfig []swarm.PortConfig) testdaemon.ServiceConstructor {
24 25
 	return func(s *swarm.Service) {
25 26
 		if s.Spec.EndpointSpec == nil {
26 27
 			s.Spec.EndpointSpec = &swarm.EndpointSpec{}
... ...
@@ -140,7 +141,7 @@ func (s *DockerSwarmSuite) TestAPISwarmServicesCreateGlobal(c *check.C) {
140 140
 
141 141
 func (s *DockerSwarmSuite) TestAPISwarmServicesUpdate(c *check.C) {
142 142
 	const nodeCount = 3
143
-	var daemons [nodeCount]*daemon.Swarm
143
+	var daemons [nodeCount]*daemon.Daemon
144 144
 	for i := 0; i < nodeCount; i++ {
145 145
 		daemons[i] = s.AddDaemon(c, true, i == 0)
146 146
 	}
... ...
@@ -309,7 +310,7 @@ func (s *DockerSwarmSuite) TestAPISwarmServicesUpdateStartFirst(c *check.C) {
309 309
 
310 310
 func (s *DockerSwarmSuite) TestAPISwarmServicesFailedUpdate(c *check.C) {
311 311
 	const nodeCount = 3
312
-	var daemons [nodeCount]*daemon.Swarm
312
+	var daemons [nodeCount]*daemon.Daemon
313 313
 	for i := 0; i < nodeCount; i++ {
314 314
 		daemons[i] = s.AddDaemon(c, true, i == 0)
315 315
 	}
... ...
@@ -349,7 +350,7 @@ func (s *DockerSwarmSuite) TestAPISwarmServicesFailedUpdate(c *check.C) {
349 349
 
350 350
 func (s *DockerSwarmSuite) TestAPISwarmServiceConstraintRole(c *check.C) {
351 351
 	const nodeCount = 3
352
-	var daemons [nodeCount]*daemon.Swarm
352
+	var daemons [nodeCount]*daemon.Daemon
353 353
 	for i := 0; i < nodeCount; i++ {
354 354
 		daemons[i] = s.AddDaemon(c, true, i == 0)
355 355
 	}
... ...
@@ -401,7 +402,7 @@ func (s *DockerSwarmSuite) TestAPISwarmServiceConstraintRole(c *check.C) {
401 401
 
402 402
 func (s *DockerSwarmSuite) TestAPISwarmServiceConstraintLabel(c *check.C) {
403 403
 	const nodeCount = 3
404
-	var daemons [nodeCount]*daemon.Swarm
404
+	var daemons [nodeCount]*daemon.Daemon
405 405
 	for i := 0; i < nodeCount; i++ {
406 406
 		daemons[i] = s.AddDaemon(c, true, i == 0)
407 407
 	}
... ...
@@ -496,7 +497,7 @@ func (s *DockerSwarmSuite) TestAPISwarmServiceConstraintLabel(c *check.C) {
496 496
 
497 497
 func (s *DockerSwarmSuite) TestAPISwarmServicePlacementPrefs(c *check.C) {
498 498
 	const nodeCount = 3
499
-	var daemons [nodeCount]*daemon.Swarm
499
+	var daemons [nodeCount]*daemon.Daemon
500 500
 	for i := 0; i < nodeCount; i++ {
501 501
 		daemons[i] = s.AddDaemon(c, true, i == 0)
502 502
 	}
... ...
@@ -551,9 +552,9 @@ func (s *DockerSwarmSuite) TestAPISwarmServicesStateReporting(c *check.C) {
551 551
 
552 552
 	waitAndAssert(c, defaultReconciliationTimeout, reducedCheck(sumAsIntegers, d1.CheckActiveContainerCount, d2.CheckActiveContainerCount, d3.CheckActiveContainerCount), checker.Equals, instances)
553 553
 
554
-	getContainers := func() map[string]*daemon.Swarm {
555
-		m := make(map[string]*daemon.Swarm)
556
-		for _, d := range []*daemon.Swarm{d1, d2, d3} {
554
+	getContainers := func() map[string]*daemon.Daemon {
555
+		m := make(map[string]*daemon.Daemon)
556
+		for _, d := range []*daemon.Daemon{d1, d2, d3} {
557 557
 			for _, id := range d.ActiveContainers() {
558 558
 				m[id] = d
559 559
 			}
... ...
@@ -23,6 +23,7 @@ import (
23 23
 	"github.com/docker/docker/integration-cli/checker"
24 24
 	"github.com/docker/docker/integration-cli/daemon"
25 25
 	"github.com/docker/docker/integration-cli/request"
26
+	testdaemon "github.com/docker/docker/internal/test/daemon"
26 27
 	"github.com/docker/swarmkit/ca"
27 28
 	"github.com/go-check/check"
28 29
 	"github.com/gotestyourself/gotestyourself/assert"
... ...
@@ -35,30 +36,30 @@ var defaultReconciliationTimeout = 30 * time.Second
35 35
 func (s *DockerSwarmSuite) TestAPISwarmInit(c *check.C) {
36 36
 	// todo: should find a better way to verify that components are running than /info
37 37
 	d1 := s.AddDaemon(c, true, true)
38
-	info, err := d1.SwarmInfo()
39
-	c.Assert(err, checker.IsNil)
38
+	info := d1.SwarmInfo(c)
40 39
 	c.Assert(info.ControlAvailable, checker.True)
41 40
 	c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
42 41
 	c.Assert(info.Cluster.RootRotationInProgress, checker.False)
43 42
 
44 43
 	d2 := s.AddDaemon(c, true, false)
45
-	info, err = d2.SwarmInfo()
46
-	c.Assert(err, checker.IsNil)
44
+	info = d2.SwarmInfo(c)
47 45
 	c.Assert(info.ControlAvailable, checker.False)
48 46
 	c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
49 47
 
50 48
 	// Leaving cluster
51
-	c.Assert(d2.Leave(false), checker.IsNil)
49
+	c.Assert(d2.SwarmLeave(false), checker.IsNil)
52 50
 
53
-	info, err = d2.SwarmInfo()
54
-	c.Assert(err, checker.IsNil)
51
+	info = d2.SwarmInfo(c)
55 52
 	c.Assert(info.ControlAvailable, checker.False)
56 53
 	c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateInactive)
57 54
 
58
-	c.Assert(d2.Join(swarm.JoinRequest{JoinToken: d1.JoinTokens(c).Worker, RemoteAddrs: []string{d1.ListenAddr}}), checker.IsNil)
55
+	d2.SwarmJoin(c, swarm.JoinRequest{
56
+		ListenAddr:  d1.SwarmListenAddr(),
57
+		JoinToken:   d1.JoinTokens(c).Worker,
58
+		RemoteAddrs: []string{d1.SwarmListenAddr()},
59
+	})
59 60
 
60
-	info, err = d2.SwarmInfo()
61
-	c.Assert(err, checker.IsNil)
61
+	info = d2.SwarmInfo(c)
62 62
 	c.Assert(info.ControlAvailable, checker.False)
63 63
 	c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
64 64
 
... ...
@@ -69,93 +70,100 @@ func (s *DockerSwarmSuite) TestAPISwarmInit(c *check.C) {
69 69
 	d1.Start(c)
70 70
 	d2.Start(c)
71 71
 
72
-	info, err = d1.SwarmInfo()
73
-	c.Assert(err, checker.IsNil)
72
+	info = d1.SwarmInfo(c)
74 73
 	c.Assert(info.ControlAvailable, checker.True)
75 74
 	c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
76 75
 
77
-	info, err = d2.SwarmInfo()
78
-	c.Assert(err, checker.IsNil)
76
+	info = d2.SwarmInfo(c)
79 77
 	c.Assert(info.ControlAvailable, checker.False)
80 78
 	c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
81 79
 }
82 80
 
83 81
 func (s *DockerSwarmSuite) TestAPISwarmJoinToken(c *check.C) {
84 82
 	d1 := s.AddDaemon(c, false, false)
85
-	c.Assert(d1.Init(swarm.InitRequest{}), checker.IsNil)
83
+	d1.SwarmInit(c, swarm.InitRequest{})
86 84
 
87 85
 	// todo: error message differs depending if some components of token are valid
88 86
 
89 87
 	d2 := s.AddDaemon(c, false, false)
90
-	err := d2.Join(swarm.JoinRequest{RemoteAddrs: []string{d1.ListenAddr}})
88
+	c2 := d2.NewClientT(c)
89
+	err := c2.SwarmJoin(context.Background(), swarm.JoinRequest{
90
+		ListenAddr:  d2.SwarmListenAddr(),
91
+		RemoteAddrs: []string{d1.SwarmListenAddr()},
92
+	})
91 93
 	c.Assert(err, checker.NotNil)
92 94
 	c.Assert(err.Error(), checker.Contains, "join token is necessary")
93
-	info, err := d2.SwarmInfo()
94
-	c.Assert(err, checker.IsNil)
95
+	info := d2.SwarmInfo(c)
95 96
 	c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateInactive)
96 97
 
97
-	err = d2.Join(swarm.JoinRequest{JoinToken: "foobaz", RemoteAddrs: []string{d1.ListenAddr}})
98
+	err = c2.SwarmJoin(context.Background(), swarm.JoinRequest{
99
+		ListenAddr:  d2.SwarmListenAddr(),
100
+		JoinToken:   "foobaz",
101
+		RemoteAddrs: []string{d1.SwarmListenAddr()},
102
+	})
98 103
 	c.Assert(err, checker.NotNil)
99 104
 	c.Assert(err.Error(), checker.Contains, "invalid join token")
100
-	info, err = d2.SwarmInfo()
101
-	c.Assert(err, checker.IsNil)
105
+	info = d2.SwarmInfo(c)
102 106
 	c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateInactive)
103 107
 
104 108
 	workerToken := d1.JoinTokens(c).Worker
105 109
 
106
-	c.Assert(d2.Join(swarm.JoinRequest{JoinToken: workerToken, RemoteAddrs: []string{d1.ListenAddr}}), checker.IsNil)
107
-	info, err = d2.SwarmInfo()
108
-	c.Assert(err, checker.IsNil)
110
+	d2.SwarmJoin(c, swarm.JoinRequest{
111
+		ListenAddr:  d2.SwarmListenAddr(),
112
+		JoinToken:   workerToken,
113
+		RemoteAddrs: []string{d1.SwarmListenAddr()},
114
+	})
115
+	info = d2.SwarmInfo(c)
109 116
 	c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
110
-	c.Assert(d2.Leave(false), checker.IsNil)
111
-	info, err = d2.SwarmInfo()
112
-	c.Assert(err, checker.IsNil)
117
+	c.Assert(d2.SwarmLeave(false), checker.IsNil)
118
+	info = d2.SwarmInfo(c)
113 119
 	c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateInactive)
114 120
 
115 121
 	// change tokens
116 122
 	d1.RotateTokens(c)
117 123
 
118
-	err = d2.Join(swarm.JoinRequest{JoinToken: workerToken, RemoteAddrs: []string{d1.ListenAddr}})
124
+	err = c2.SwarmJoin(context.Background(), swarm.JoinRequest{
125
+		ListenAddr:  d2.SwarmListenAddr(),
126
+		JoinToken:   workerToken,
127
+		RemoteAddrs: []string{d1.SwarmListenAddr()},
128
+	})
119 129
 	c.Assert(err, checker.NotNil)
120 130
 	c.Assert(err.Error(), checker.Contains, "join token is necessary")
121
-	info, err = d2.SwarmInfo()
122
-	c.Assert(err, checker.IsNil)
131
+	info = d2.SwarmInfo(c)
123 132
 	c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateInactive)
124 133
 
125 134
 	workerToken = d1.JoinTokens(c).Worker
126 135
 
127
-	c.Assert(d2.Join(swarm.JoinRequest{JoinToken: workerToken, RemoteAddrs: []string{d1.ListenAddr}}), checker.IsNil)
128
-	info, err = d2.SwarmInfo()
129
-	c.Assert(err, checker.IsNil)
136
+	d2.SwarmJoin(c, swarm.JoinRequest{JoinToken: workerToken, RemoteAddrs: []string{d1.SwarmListenAddr()}})
137
+	info = d2.SwarmInfo(c)
130 138
 	c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
131
-	c.Assert(d2.Leave(false), checker.IsNil)
132
-	info, err = d2.SwarmInfo()
133
-	c.Assert(err, checker.IsNil)
139
+	c.Assert(d2.SwarmLeave(false), checker.IsNil)
140
+	info = d2.SwarmInfo(c)
134 141
 	c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateInactive)
135 142
 
136 143
 	// change spec, don't change tokens
137 144
 	d1.UpdateSwarm(c, func(s *swarm.Spec) {})
138 145
 
139
-	err = d2.Join(swarm.JoinRequest{RemoteAddrs: []string{d1.ListenAddr}})
146
+	err = c2.SwarmJoin(context.Background(), swarm.JoinRequest{
147
+		ListenAddr:  d2.SwarmListenAddr(),
148
+		RemoteAddrs: []string{d1.SwarmListenAddr()},
149
+	})
140 150
 	c.Assert(err, checker.NotNil)
141 151
 	c.Assert(err.Error(), checker.Contains, "join token is necessary")
142
-	info, err = d2.SwarmInfo()
143
-	c.Assert(err, checker.IsNil)
152
+	info = d2.SwarmInfo(c)
144 153
 	c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateInactive)
145 154
 
146
-	c.Assert(d2.Join(swarm.JoinRequest{JoinToken: workerToken, RemoteAddrs: []string{d1.ListenAddr}}), checker.IsNil)
147
-	info, err = d2.SwarmInfo()
148
-	c.Assert(err, checker.IsNil)
155
+	d2.SwarmJoin(c, swarm.JoinRequest{JoinToken: workerToken, RemoteAddrs: []string{d1.SwarmListenAddr()}})
156
+	info = d2.SwarmInfo(c)
149 157
 	c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
150
-	c.Assert(d2.Leave(false), checker.IsNil)
151
-	info, err = d2.SwarmInfo()
152
-	c.Assert(err, checker.IsNil)
158
+	c.Assert(d2.SwarmLeave(false), checker.IsNil)
159
+	info = d2.SwarmInfo(c)
153 160
 	c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateInactive)
154 161
 }
155 162
 
156 163
 func (s *DockerSwarmSuite) TestUpdateSwarmAddExternalCA(c *check.C) {
157 164
 	d1 := s.AddDaemon(c, false, false)
158
-	c.Assert(d1.Init(swarm.InitRequest{}), checker.IsNil)
165
+	d1.SwarmInit(c, swarm.InitRequest{})
159 166
 	d1.UpdateSwarm(c, func(s *swarm.Spec) {
160 167
 		s.CAConfig.ExternalCAs = []*swarm.ExternalCA{
161 168
 			{
... ...
@@ -169,8 +177,7 @@ func (s *DockerSwarmSuite) TestUpdateSwarmAddExternalCA(c *check.C) {
169 169
 			},
170 170
 		}
171 171
 	})
172
-	info, err := d1.SwarmInfo()
173
-	c.Assert(err, checker.IsNil)
172
+	info := d1.SwarmInfo(c)
174 173
 	c.Assert(info.Cluster.Spec.CAConfig.ExternalCAs, checker.HasLen, 2)
175 174
 	c.Assert(info.Cluster.Spec.CAConfig.ExternalCAs[0].CACert, checker.Equals, "")
176 175
 	c.Assert(info.Cluster.Spec.CAConfig.ExternalCAs[1].CACert, checker.Equals, "cacert")
... ...
@@ -182,28 +189,32 @@ func (s *DockerSwarmSuite) TestAPISwarmCAHash(c *check.C) {
182 182
 	splitToken := strings.Split(d1.JoinTokens(c).Worker, "-")
183 183
 	splitToken[2] = "1kxftv4ofnc6mt30lmgipg6ngf9luhwqopfk1tz6bdmnkubg0e"
184 184
 	replacementToken := strings.Join(splitToken, "-")
185
-	err := d2.Join(swarm.JoinRequest{JoinToken: replacementToken, RemoteAddrs: []string{d1.ListenAddr}})
185
+	c2 := d2.NewClientT(c)
186
+	err := c2.SwarmJoin(context.Background(), swarm.JoinRequest{
187
+		ListenAddr:  d2.SwarmListenAddr(),
188
+		JoinToken:   replacementToken,
189
+		RemoteAddrs: []string{d1.SwarmListenAddr()},
190
+	})
186 191
 	c.Assert(err, checker.NotNil)
187 192
 	c.Assert(err.Error(), checker.Contains, "remote CA does not match fingerprint")
188 193
 }
189 194
 
190 195
 func (s *DockerSwarmSuite) TestAPISwarmPromoteDemote(c *check.C) {
191 196
 	d1 := s.AddDaemon(c, false, false)
192
-	c.Assert(d1.Init(swarm.InitRequest{}), checker.IsNil)
197
+	d1.SwarmInit(c, swarm.InitRequest{})
193 198
 	d2 := s.AddDaemon(c, true, false)
194 199
 
195
-	info, err := d2.SwarmInfo()
196
-	c.Assert(err, checker.IsNil)
200
+	info := d2.SwarmInfo(c)
197 201
 	c.Assert(info.ControlAvailable, checker.False)
198 202
 	c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
199 203
 
200
-	d1.UpdateNode(c, d2.NodeID, func(n *swarm.Node) {
204
+	d1.UpdateNode(c, d2.NodeID(), func(n *swarm.Node) {
201 205
 		n.Spec.Role = swarm.NodeRoleManager
202 206
 	})
203 207
 
204 208
 	waitAndAssert(c, defaultReconciliationTimeout, d2.CheckControlAvailable, checker.True)
205 209
 
206
-	d1.UpdateNode(c, d2.NodeID, func(n *swarm.Node) {
210
+	d1.UpdateNode(c, d2.NodeID(), func(n *swarm.Node) {
207 211
 		n.Spec.Role = swarm.NodeRoleWorker
208 212
 	})
209 213
 
... ...
@@ -228,7 +239,7 @@ func (s *DockerSwarmSuite) TestAPISwarmPromoteDemote(c *check.C) {
228 228
 	}, checker.Equals, "swarm-worker")
229 229
 
230 230
 	// Demoting last node should fail
231
-	node := d1.GetNode(c, d1.NodeID)
231
+	node := d1.GetNode(c, d1.NodeID())
232 232
 	node.Spec.Role = swarm.NodeRoleWorker
233 233
 	url := fmt.Sprintf("/nodes/%s/update?version=%d", node.ID, node.Version.Index)
234 234
 	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) {
246 246
 	if !strings.Contains(string(b), "last manager of the swarm") {
247 247
 		c.Assert(string(b), checker.Contains, "this would result in a loss of quorum")
248 248
 	}
249
-	info, err = d1.SwarmInfo()
250
-	c.Assert(err, checker.IsNil)
249
+	info = d1.SwarmInfo(c)
251 250
 	c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
252 251
 	c.Assert(info.ControlAvailable, checker.True)
253 252
 
254 253
 	// Promote already demoted node
255
-	d1.UpdateNode(c, d2.NodeID, func(n *swarm.Node) {
254
+	d1.UpdateNode(c, d2.NodeID(), func(n *swarm.Node) {
256 255
 		n.Spec.Role = swarm.NodeRoleManager
257 256
 	})
258 257
 
... ...
@@ -278,7 +288,7 @@ func (s *DockerSwarmSuite) TestAPISwarmLeaderProxy(c *check.C) {
278 278
 
279 279
 	// 3 services should be started now, because the requests were proxied to leader
280 280
 	// query each node and make sure it returns 3 services
281
-	for _, d := range []*daemon.Swarm{d1, d2, d3} {
281
+	for _, d := range []*daemon.Daemon{d1, d2, d3} {
282 282
 		services := d.ListServices(c)
283 283
 		c.Assert(services, checker.HasLen, 3)
284 284
 	}
... ...
@@ -291,23 +301,23 @@ func (s *DockerSwarmSuite) TestAPISwarmLeaderElection(c *check.C) {
291 291
 	d3 := s.AddDaemon(c, true, true)
292 292
 
293 293
 	// assert that the first node we made is the leader, and the other two are followers
294
-	c.Assert(d1.GetNode(c, d1.NodeID).ManagerStatus.Leader, checker.True)
295
-	c.Assert(d1.GetNode(c, d2.NodeID).ManagerStatus.Leader, checker.False)
296
-	c.Assert(d1.GetNode(c, d3.NodeID).ManagerStatus.Leader, checker.False)
294
+	c.Assert(d1.GetNode(c, d1.NodeID()).ManagerStatus.Leader, checker.True)
295
+	c.Assert(d1.GetNode(c, d2.NodeID()).ManagerStatus.Leader, checker.False)
296
+	c.Assert(d1.GetNode(c, d3.NodeID()).ManagerStatus.Leader, checker.False)
297 297
 
298 298
 	d1.Stop(c)
299 299
 
300 300
 	var (
301
-		leader    *daemon.Swarm   // keep track of leader
302
-		followers []*daemon.Swarm // keep track of followers
301
+		leader    *daemon.Daemon   // keep track of leader
302
+		followers []*daemon.Daemon // keep track of followers
303 303
 	)
304
-	checkLeader := func(nodes ...*daemon.Swarm) checkF {
304
+	checkLeader := func(nodes ...*daemon.Daemon) checkF {
305 305
 		return func(c *check.C) (interface{}, check.CommentInterface) {
306 306
 			// clear these out before each run
307 307
 			leader = nil
308 308
 			followers = nil
309 309
 			for _, d := range nodes {
310
-				if d.GetNode(c, d.NodeID).ManagerStatus.Leader {
310
+				if d.GetNode(c, d.NodeID()).ManagerStatus.Leader {
311 311
 					leader = d
312 312
 				} else {
313 313
 					followers = append(followers, d)
... ...
@@ -344,7 +354,7 @@ func (s *DockerSwarmSuite) TestAPISwarmLeaderElection(c *check.C) {
344 344
 	c.Assert(leader, checker.NotNil)
345 345
 	c.Assert(followers, checker.HasLen, 2)
346 346
 	// and that after we added d1 back, the leader hasn't changed
347
-	c.Assert(leader.NodeID, checker.Equals, stableleader.NodeID)
347
+	c.Assert(leader.NodeID(), checker.Equals, stableleader.NodeID())
348 348
 }
349 349
 
350 350
 func (s *DockerSwarmSuite) TestAPISwarmRaftQuorum(c *check.C) {
... ...
@@ -400,8 +410,8 @@ func (s *DockerSwarmSuite) TestAPISwarmLeaveRemovesContainer(c *check.C) {
400 400
 
401 401
 	waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, instances+1)
402 402
 
403
-	c.Assert(d.Leave(false), checker.NotNil)
404
-	c.Assert(d.Leave(true), checker.IsNil)
403
+	c.Assert(d.SwarmLeave(false), checker.NotNil)
404
+	c.Assert(d.SwarmLeave(true), checker.IsNil)
405 405
 
406 406
 	waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1)
407 407
 
... ...
@@ -420,17 +430,18 @@ func (s *DockerSwarmSuite) TestAPISwarmLeaveOnPendingJoin(c *check.C) {
420 420
 	c.Assert(err, checker.IsNil)
421 421
 	id = strings.TrimSpace(id)
422 422
 
423
-	err = d2.Join(swarm.JoinRequest{
423
+	c2 := d2.NewClientT(c)
424
+	err = c2.SwarmJoin(context.Background(), swarm.JoinRequest{
425
+		ListenAddr:  d2.SwarmListenAddr(),
424 426
 		RemoteAddrs: []string{"123.123.123.123:1234"},
425 427
 	})
426 428
 	c.Assert(err, check.NotNil)
427 429
 	c.Assert(err.Error(), checker.Contains, "Timeout was reached")
428 430
 
429
-	info, err := d2.SwarmInfo()
430
-	c.Assert(err, checker.IsNil)
431
+	info := d2.SwarmInfo(c)
431 432
 	c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStatePending)
432 433
 
433
-	c.Assert(d2.Leave(true), checker.IsNil)
434
+	c.Assert(d2.SwarmLeave(true), checker.IsNil)
434 435
 
435 436
 	waitAndAssert(c, defaultReconciliationTimeout, d2.CheckActiveContainerCount, checker.Equals, 1)
436 437
 
... ...
@@ -443,7 +454,9 @@ func (s *DockerSwarmSuite) TestAPISwarmLeaveOnPendingJoin(c *check.C) {
443 443
 func (s *DockerSwarmSuite) TestAPISwarmRestoreOnPendingJoin(c *check.C) {
444 444
 	testRequires(c, Network)
445 445
 	d := s.AddDaemon(c, false, false)
446
-	err := d.Join(swarm.JoinRequest{
446
+	client := d.NewClientT(c)
447
+	err := client.SwarmJoin(context.Background(), swarm.JoinRequest{
448
+		ListenAddr:  d.SwarmListenAddr(),
447 449
 		RemoteAddrs: []string{"123.123.123.123:1234"},
448 450
 	})
449 451
 	c.Assert(err, check.NotNil)
... ...
@@ -454,8 +467,7 @@ func (s *DockerSwarmSuite) TestAPISwarmRestoreOnPendingJoin(c *check.C) {
454 454
 	d.Stop(c)
455 455
 	d.Start(c)
456 456
 
457
-	info, err := d.SwarmInfo()
458
-	c.Assert(err, checker.IsNil)
457
+	info := d.SwarmInfo(c)
459 458
 	c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateInactive)
460 459
 }
461 460
 
... ...
@@ -539,7 +551,7 @@ func (s *DockerSwarmSuite) TestAPISwarmForceNewCluster(c *check.C) {
539 539
 	waitAndAssert(c, defaultReconciliationTimeout, reducedCheck(sumAsIntegers, d1.CheckActiveContainerCount, d2.CheckActiveContainerCount), checker.Equals, instances)
540 540
 
541 541
 	// drain d2, all containers should move to d1
542
-	d1.UpdateNode(c, d2.NodeID, func(n *swarm.Node) {
542
+	d1.UpdateNode(c, d2.NodeID(), func(n *swarm.Node) {
543 543
 		n.Spec.Availability = swarm.NodeAvailabilityDrain
544 544
 	})
545 545
 	waitAndAssert(c, defaultReconciliationTimeout, d1.CheckActiveContainerCount, checker.Equals, instances)
... ...
@@ -547,16 +559,15 @@ func (s *DockerSwarmSuite) TestAPISwarmForceNewCluster(c *check.C) {
547 547
 
548 548
 	d2.Stop(c)
549 549
 
550
-	c.Assert(d1.Init(swarm.InitRequest{
550
+	d1.SwarmInit(c, swarm.InitRequest{
551 551
 		ForceNewCluster: true,
552 552
 		Spec:            swarm.Spec{},
553
-	}), checker.IsNil)
553
+	})
554 554
 
555 555
 	waitAndAssert(c, defaultReconciliationTimeout, d1.CheckActiveContainerCount, checker.Equals, instances)
556 556
 
557 557
 	d3 := s.AddDaemon(c, true, true)
558
-	info, err := d3.SwarmInfo()
559
-	c.Assert(err, checker.IsNil)
558
+	info := d3.SwarmInfo(c)
560 559
 	c.Assert(info.ControlAvailable, checker.True)
561 560
 	c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
562 561
 
... ...
@@ -622,7 +633,7 @@ func serviceForUpdate(s *swarm.Service) {
622 622
 	s.Spec.Name = "updatetest"
623 623
 }
624 624
 
625
-func setInstances(replicas int) daemon.ServiceConstructor {
625
+func setInstances(replicas int) testdaemon.ServiceConstructor {
626 626
 	ureplicas := uint64(replicas)
627 627
 	return func(s *swarm.Service) {
628 628
 		s.Spec.Mode = swarm.ServiceMode{
... ...
@@ -633,7 +644,7 @@ func setInstances(replicas int) daemon.ServiceConstructor {
633 633
 	}
634 634
 }
635 635
 
636
-func setUpdateOrder(order string) daemon.ServiceConstructor {
636
+func setUpdateOrder(order string) testdaemon.ServiceConstructor {
637 637
 	return func(s *swarm.Service) {
638 638
 		if s.Spec.UpdateConfig == nil {
639 639
 			s.Spec.UpdateConfig = &swarm.UpdateConfig{}
... ...
@@ -642,7 +653,7 @@ func setUpdateOrder(order string) daemon.ServiceConstructor {
642 642
 	}
643 643
 }
644 644
 
645
-func setRollbackOrder(order string) daemon.ServiceConstructor {
645
+func setRollbackOrder(order string) testdaemon.ServiceConstructor {
646 646
 	return func(s *swarm.Service) {
647 647
 		if s.Spec.RollbackConfig == nil {
648 648
 			s.Spec.RollbackConfig = &swarm.UpdateConfig{}
... ...
@@ -651,7 +662,7 @@ func setRollbackOrder(order string) daemon.ServiceConstructor {
651 651
 	}
652 652
 }
653 653
 
654
-func setImage(image string) daemon.ServiceConstructor {
654
+func setImage(image string) testdaemon.ServiceConstructor {
655 655
 	return func(s *swarm.Service) {
656 656
 		if s.Spec.TaskTemplate.ContainerSpec == nil {
657 657
 			s.Spec.TaskTemplate.ContainerSpec = &swarm.ContainerSpec{}
... ...
@@ -660,25 +671,25 @@ func setImage(image string) daemon.ServiceConstructor {
660 660
 	}
661 661
 }
662 662
 
663
-func setFailureAction(failureAction string) daemon.ServiceConstructor {
663
+func setFailureAction(failureAction string) testdaemon.ServiceConstructor {
664 664
 	return func(s *swarm.Service) {
665 665
 		s.Spec.UpdateConfig.FailureAction = failureAction
666 666
 	}
667 667
 }
668 668
 
669
-func setMaxFailureRatio(maxFailureRatio float32) daemon.ServiceConstructor {
669
+func setMaxFailureRatio(maxFailureRatio float32) testdaemon.ServiceConstructor {
670 670
 	return func(s *swarm.Service) {
671 671
 		s.Spec.UpdateConfig.MaxFailureRatio = maxFailureRatio
672 672
 	}
673 673
 }
674 674
 
675
-func setParallelism(parallelism uint64) daemon.ServiceConstructor {
675
+func setParallelism(parallelism uint64) testdaemon.ServiceConstructor {
676 676
 	return func(s *swarm.Service) {
677 677
 		s.Spec.UpdateConfig.Parallelism = parallelism
678 678
 	}
679 679
 }
680 680
 
681
-func setConstraints(constraints []string) daemon.ServiceConstructor {
681
+func setConstraints(constraints []string) testdaemon.ServiceConstructor {
682 682
 	return func(s *swarm.Service) {
683 683
 		if s.Spec.TaskTemplate.Placement == nil {
684 684
 			s.Spec.TaskTemplate.Placement = &swarm.Placement{}
... ...
@@ -687,7 +698,7 @@ func setConstraints(constraints []string) daemon.ServiceConstructor {
687 687
 	}
688 688
 }
689 689
 
690
-func setPlacementPrefs(prefs []swarm.PlacementPreference) daemon.ServiceConstructor {
690
+func setPlacementPrefs(prefs []swarm.PlacementPreference) testdaemon.ServiceConstructor {
691 691
 	return func(s *swarm.Service) {
692 692
 		if s.Spec.TaskTemplate.Placement == nil {
693 693
 			s.Spec.TaskTemplate.Placement = &swarm.Placement{}
... ...
@@ -702,18 +713,19 @@ func setGlobalMode(s *swarm.Service) {
702 702
 	}
703 703
 }
704 704
 
705
-func checkClusterHealth(c *check.C, cl []*daemon.Swarm, managerCount, workerCount int) {
705
+func checkClusterHealth(c *check.C, cl []*daemon.Daemon, managerCount, workerCount int) {
706 706
 	var totalMCount, totalWCount int
707 707
 
708 708
 	for _, d := range cl {
709 709
 		var (
710 710
 			info swarm.Info
711
-			err  error
712 711
 		)
713 712
 
714 713
 		// check info in a waitAndAssert, because if the cluster doesn't have a leader, `info` will return an error
715 714
 		checkInfo := func(c *check.C) (interface{}, check.CommentInterface) {
716
-			info, err = d.SwarmInfo()
715
+			client := d.NewClientT(c)
716
+			daemonInfo, err := client.Info(context.Background())
717
+			info = daemonInfo.Swarm
717 718
 			return err, check.Commentf("cluster not ready in time")
718 719
 		}
719 720
 		waitAndAssert(c, defaultReconciliationTimeout, checkInfo, checker.IsNil)
... ...
@@ -733,7 +745,7 @@ func checkClusterHealth(c *check.C, cl []*daemon.Swarm, managerCount, workerCoun
733 733
 				}
734 734
 				nn := d.GetNode(c, n.ID)
735 735
 				n = *nn
736
-				return n.Status.State == swarm.NodeStateReady, check.Commentf("state of node %s, reported by %s", n.ID, d.Info.NodeID)
736
+				return n.Status.State == swarm.NodeStateReady, check.Commentf("state of node %s, reported by %s", n.ID, d.NodeID())
737 737
 			}
738 738
 			waitAndAssert(c, defaultReconciliationTimeout, waitReady, checker.True)
739 739
 
... ...
@@ -743,18 +755,18 @@ func checkClusterHealth(c *check.C, cl []*daemon.Swarm, managerCount, workerCoun
743 743
 				}
744 744
 				nn := d.GetNode(c, n.ID)
745 745
 				n = *nn
746
-				return n.Spec.Availability == swarm.NodeAvailabilityActive, check.Commentf("availability of node %s, reported by %s", n.ID, d.Info.NodeID)
746
+				return n.Spec.Availability == swarm.NodeAvailabilityActive, check.Commentf("availability of node %s, reported by %s", n.ID, d.NodeID())
747 747
 			}
748 748
 			waitAndAssert(c, defaultReconciliationTimeout, waitActive, checker.True)
749 749
 
750 750
 			if n.Spec.Role == swarm.NodeRoleManager {
751
-				c.Assert(n.ManagerStatus, checker.NotNil, check.Commentf("manager status of node %s (manager), reported by %s", n.ID, d.Info.NodeID))
751
+				c.Assert(n.ManagerStatus, checker.NotNil, check.Commentf("manager status of node %s (manager), reported by %s", n.ID, d.NodeID()))
752 752
 				if n.ManagerStatus.Leader {
753 753
 					leaderFound = true
754 754
 				}
755 755
 				mCount++
756 756
 			} else {
757
-				c.Assert(n.ManagerStatus, checker.IsNil, check.Commentf("manager status of node %s (worker), reported by %s", n.ID, d.Info.NodeID))
757
+				c.Assert(n.ManagerStatus, checker.IsNil, check.Commentf("manager status of node %s (worker), reported by %s", n.ID, d.NodeID()))
758 758
 				wCount++
759 759
 			}
760 760
 		}
... ...
@@ -769,11 +781,10 @@ func checkClusterHealth(c *check.C, cl []*daemon.Swarm, managerCount, workerCoun
769 769
 func (s *DockerSwarmSuite) TestAPISwarmRestartCluster(c *check.C) {
770 770
 	mCount, wCount := 5, 1
771 771
 
772
-	var nodes []*daemon.Swarm
772
+	var nodes []*daemon.Daemon
773 773
 	for i := 0; i < mCount; i++ {
774 774
 		manager := s.AddDaemon(c, true, true)
775
-		info, err := manager.SwarmInfo()
776
-		c.Assert(err, checker.IsNil)
775
+		info := manager.SwarmInfo(c)
777 776
 		c.Assert(info.ControlAvailable, checker.True)
778 777
 		c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
779 778
 		nodes = append(nodes, manager)
... ...
@@ -781,8 +792,7 @@ func (s *DockerSwarmSuite) TestAPISwarmRestartCluster(c *check.C) {
781 781
 
782 782
 	for i := 0; i < wCount; i++ {
783 783
 		worker := s.AddDaemon(c, true, false)
784
-		info, err := worker.SwarmInfo()
785
-		c.Assert(err, checker.IsNil)
784
+		info := worker.SwarmInfo(c)
786 785
 		c.Assert(info.ControlAvailable, checker.False)
787 786
 		c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
788 787
 		nodes = append(nodes, worker)
... ...
@@ -795,7 +805,7 @@ func (s *DockerSwarmSuite) TestAPISwarmRestartCluster(c *check.C) {
795 795
 		errs := make(chan error, len(nodes))
796 796
 
797 797
 		for _, d := range nodes {
798
-			go func(daemon *daemon.Swarm) {
798
+			go func(daemon *daemon.Daemon) {
799 799
 				defer wg.Done()
800 800
 				if err := daemon.StopWithError(); err != nil {
801 801
 					errs <- err
... ...
@@ -820,7 +830,7 @@ func (s *DockerSwarmSuite) TestAPISwarmRestartCluster(c *check.C) {
820 820
 		errs := make(chan error, len(nodes))
821 821
 
822 822
 		for _, d := range nodes {
823
-			go func(daemon *daemon.Swarm) {
823
+			go func(daemon *daemon.Daemon) {
824 824
 				defer wg.Done()
825 825
 				if err := daemon.StartWithError("--iptables=false"); err != nil {
826 826
 					errs <- err
... ...
@@ -859,7 +869,7 @@ func (s *DockerSwarmSuite) TestAPISwarmServicesUpdateWithName(c *check.C) {
859 859
 // Unlocking an unlocked swarm results in an error
860 860
 func (s *DockerSwarmSuite) TestAPISwarmUnlockNotLocked(c *check.C) {
861 861
 	d := s.AddDaemon(c, true, true)
862
-	err := d.Unlock(swarm.UnlockRequest{UnlockKey: "wrong-key"})
862
+	err := d.SwarmUnlock(swarm.UnlockRequest{UnlockKey: "wrong-key"})
863 863
 	c.Assert(err, checker.NotNil)
864 864
 	c.Assert(err.Error(), checker.Contains, "swarm is not locked")
865 865
 }
... ...
@@ -870,7 +880,10 @@ func (s *DockerSwarmSuite) TestAPISwarmErrorHandling(c *check.C) {
870 870
 	c.Assert(err, checker.IsNil)
871 871
 	defer ln.Close()
872 872
 	d := s.AddDaemon(c, false, false)
873
-	err = d.Init(swarm.InitRequest{})
873
+	client := d.NewClientT(c)
874
+	_, err = client.SwarmInit(context.Background(), swarm.InitRequest{
875
+		ListenAddr: d.SwarmListenAddr(),
876
+	})
874 877
 	c.Assert(err, checker.NotNil)
875 878
 	c.Assert(err.Error(), checker.Contains, "address already in use")
876 879
 }
... ...
@@ -940,13 +953,13 @@ func (s *DockerSwarmSuite) TestSwarmRepeatedRootRotation(c *check.C) {
940 940
 	m := s.AddDaemon(c, true, true)
941 941
 	w := s.AddDaemon(c, true, false)
942 942
 
943
-	info, err := m.SwarmInfo()
944
-	c.Assert(err, checker.IsNil)
943
+	info := m.SwarmInfo(c)
945 944
 
946 945
 	currentTrustRoot := info.Cluster.TLSInfo.TrustRoot
947 946
 
948 947
 	// rotate multiple times
949 948
 	for i := 0; i < 4; i++ {
949
+		var err error
950 950
 		var cert, key []byte
951 951
 		if i%2 != 0 {
952 952
 			cert, _, key, err = initca.New(&csr.CertificateRequest{
... ...
@@ -966,8 +979,7 @@ func (s *DockerSwarmSuite) TestSwarmRepeatedRootRotation(c *check.C) {
966 966
 		// poll to make sure update succeeds
967 967
 		var clusterTLSInfo swarm.TLSInfo
968 968
 		for j := 0; j < 18; j++ {
969
-			info, err := m.SwarmInfo()
970
-			c.Assert(err, checker.IsNil)
969
+			info := m.SwarmInfo(c)
971 970
 
972 971
 			// the desired CA cert and key is always redacted
973 972
 			c.Assert(info.Cluster.Spec.CAConfig.SigningCAKey, checker.Equals, "")
... ...
@@ -989,8 +1001,8 @@ func (s *DockerSwarmSuite) TestSwarmRepeatedRootRotation(c *check.C) {
989 989
 		// could take another second or two for the nodes to trust the new roots after they've all gotten
990 990
 		// new TLS certificates
991 991
 		for j := 0; j < 18; j++ {
992
-			mInfo := m.GetNode(c, m.NodeID).Description.TLSInfo
993
-			wInfo := m.GetNode(c, w.NodeID).Description.TLSInfo
992
+			mInfo := m.GetNode(c, m.NodeID()).Description.TLSInfo
993
+			wInfo := m.GetNode(c, w.NodeID()).Description.TLSInfo
994 994
 
995 995
 			if mInfo.TrustRoot == clusterTLSInfo.TrustRoot && wInfo.TrustRoot == clusterTLSInfo.TrustRoot {
996 996
 				break
... ...
@@ -1000,8 +1012,8 @@ func (s *DockerSwarmSuite) TestSwarmRepeatedRootRotation(c *check.C) {
1000 1000
 			time.Sleep(250 * time.Millisecond)
1001 1001
 		}
1002 1002
 
1003
-		c.Assert(m.GetNode(c, m.NodeID).Description.TLSInfo, checker.DeepEquals, clusterTLSInfo)
1004
-		c.Assert(m.GetNode(c, w.NodeID).Description.TLSInfo, checker.DeepEquals, clusterTLSInfo)
1003
+		c.Assert(m.GetNode(c, m.NodeID()).Description.TLSInfo, checker.DeepEquals, clusterTLSInfo)
1004
+		c.Assert(m.GetNode(c, w.NodeID()).Description.TLSInfo, checker.DeepEquals, clusterTLSInfo)
1005 1005
 		currentTrustRoot = clusterTLSInfo.TrustRoot
1006 1006
 	}
1007 1007
 }
... ...
@@ -16,7 +16,7 @@ import (
16 16
 	"github.com/go-check/check"
17 17
 )
18 18
 
19
-func pruneNetworkAndVerify(c *check.C, d *daemon.Swarm, kept, pruned []string) {
19
+func pruneNetworkAndVerify(c *check.C, d *daemon.Daemon, kept, pruned []string) {
20 20
 	_, err := d.Cmd("network", "prune", "--force")
21 21
 	c.Assert(err, checker.IsNil)
22 22
 
... ...
@@ -53,7 +53,7 @@ func (s *DockerSwarmSuite) TestServiceLogs(c *check.C) {
53 53
 // countLogLines returns a closure that can be used with waitAndAssert to
54 54
 // verify that a minimum number of expected container log messages have been
55 55
 // output.
56
-func countLogLines(d *daemon.Swarm, name string) func(*check.C) (interface{}, check.CommentInterface) {
56
+func countLogLines(d *daemon.Daemon, name string) func(*check.C) (interface{}, check.CommentInterface) {
57 57
 	return func(c *check.C) (interface{}, check.CommentInterface) {
58 58
 		result := icmd.RunCmd(d.Command("service", "logs", "-t", "--raw", name))
59 59
 		result.Assert(c, icmd.Expected{})
... ...
@@ -57,7 +57,7 @@ func (s *DockerSwarmSuite) TestSwarmUpdate(c *check.C) {
57 57
 	// passing an external CA (this is without starting a root rotation) does not fail
58 58
 	cli.Docker(cli.Args("swarm", "update", "--external-ca", "protocol=cfssl,url=https://something.org",
59 59
 		"--external-ca", "protocol=cfssl,url=https://somethingelse.org,cacert=fixtures/https/ca.pem"),
60
-		cli.Daemon(d.Daemon)).Assert(c, icmd.Success)
60
+		cli.Daemon(d)).Assert(c, icmd.Success)
61 61
 
62 62
 	expected, err := ioutil.ReadFile("fixtures/https/ca.pem")
63 63
 	c.Assert(err, checker.IsNil)
... ...
@@ -73,7 +73,7 @@ func (s *DockerSwarmSuite) TestSwarmUpdate(c *check.C) {
73 73
 
74 74
 	result := cli.Docker(cli.Args("swarm", "update",
75 75
 		"--external-ca", fmt.Sprintf("protocol=cfssl,url=https://something.org,cacert=%s", tempFile.Path())),
76
-		cli.Daemon(d.Daemon))
76
+		cli.Daemon(d))
77 77
 	result.Assert(c, icmd.Expected{
78 78
 		ExitCode: 125,
79 79
 		Err:      "must be in PEM format",
... ...
@@ -94,7 +94,7 @@ func (s *DockerSwarmSuite) TestSwarmInit(c *check.C) {
94 94
 
95 95
 	result := cli.Docker(cli.Args("swarm", "init", "--cert-expiry", "30h", "--dispatcher-heartbeat", "11s",
96 96
 		"--external-ca", fmt.Sprintf("protocol=cfssl,url=https://somethingelse.org,cacert=%s", tempFile.Path())),
97
-		cli.Daemon(d.Daemon))
97
+		cli.Daemon(d))
98 98
 	result.Assert(c, icmd.Expected{
99 99
 		ExitCode: 125,
100 100
 		Err:      "must be in PEM format",
... ...
@@ -103,7 +103,7 @@ func (s *DockerSwarmSuite) TestSwarmInit(c *check.C) {
103 103
 	cli.Docker(cli.Args("swarm", "init", "--cert-expiry", "30h", "--dispatcher-heartbeat", "11s",
104 104
 		"--external-ca", "protocol=cfssl,url=https://something.org",
105 105
 		"--external-ca", "protocol=cfssl,url=https://somethingelse.org,cacert=fixtures/https/ca.pem"),
106
-		cli.Daemon(d.Daemon)).Assert(c, icmd.Success)
106
+		cli.Daemon(d)).Assert(c, icmd.Success)
107 107
 
108 108
 	expected, err := ioutil.ReadFile("fixtures/https/ca.pem")
109 109
 	c.Assert(err, checker.IsNil)
... ...
@@ -115,8 +115,8 @@ func (s *DockerSwarmSuite) TestSwarmInit(c *check.C) {
115 115
 	c.Assert(spec.CAConfig.ExternalCAs[0].CACert, checker.Equals, "")
116 116
 	c.Assert(spec.CAConfig.ExternalCAs[1].CACert, checker.Equals, string(expected))
117 117
 
118
-	c.Assert(d.Leave(true), checker.IsNil)
119
-	cli.Docker(cli.Args("swarm", "init"), cli.Daemon(d.Daemon)).Assert(c, icmd.Success)
118
+	c.Assert(d.SwarmLeave(true), checker.IsNil)
119
+	cli.Docker(cli.Args("swarm", "init"), cli.Daemon(d)).Assert(c, icmd.Success)
120 120
 
121 121
 	spec = getSpec()
122 122
 	c.Assert(spec.CAConfig.NodeCertExpiry, checker.Equals, 90*24*time.Hour)
... ...
@@ -126,12 +126,12 @@ func (s *DockerSwarmSuite) TestSwarmInit(c *check.C) {
126 126
 func (s *DockerSwarmSuite) TestSwarmInitIPv6(c *check.C) {
127 127
 	testRequires(c, IPv6)
128 128
 	d1 := s.AddDaemon(c, false, false)
129
-	cli.Docker(cli.Args("swarm", "init", "--listen-add", "::1"), cli.Daemon(d1.Daemon)).Assert(c, icmd.Success)
129
+	cli.Docker(cli.Args("swarm", "init", "--listen-add", "::1"), cli.Daemon(d1)).Assert(c, icmd.Success)
130 130
 
131 131
 	d2 := s.AddDaemon(c, false, false)
132
-	cli.Docker(cli.Args("swarm", "join", "::1"), cli.Daemon(d2.Daemon)).Assert(c, icmd.Success)
132
+	cli.Docker(cli.Args("swarm", "join", "::1"), cli.Daemon(d2)).Assert(c, icmd.Success)
133 133
 
134
-	out := cli.Docker(cli.Args("info"), cli.Daemon(d2.Daemon)).Assert(c, icmd.Success).Combined()
134
+	out := cli.Docker(cli.Args("info"), cli.Daemon(d2)).Assert(c, icmd.Success).Combined()
135 135
 	c.Assert(out, checker.Contains, "Swarm: active")
136 136
 }
137 137
 
... ...
@@ -145,13 +145,12 @@ func (s *DockerSwarmSuite) TestSwarmInitUnspecifiedAdvertiseAddr(c *check.C) {
145 145
 func (s *DockerSwarmSuite) TestSwarmIncompatibleDaemon(c *check.C) {
146 146
 	// init swarm mode and stop a daemon
147 147
 	d := s.AddDaemon(c, true, true)
148
-	info, err := d.SwarmInfo()
149
-	c.Assert(err, checker.IsNil)
148
+	info := d.SwarmInfo(c)
150 149
 	c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
151 150
 	d.Stop(c)
152 151
 
153 152
 	// start a daemon with --cluster-store and --cluster-advertise
154
-	err = d.StartWithError("--cluster-store=consul://consuladdr:consulport/some/path", "--cluster-advertise=1.1.1.1:2375")
153
+	err := d.StartWithError("--cluster-store=consul://consuladdr:consulport/some/path", "--cluster-advertise=1.1.1.1:2375")
155 154
 	c.Assert(err, checker.NotNil)
156 155
 	content, err := d.ReadLogFile()
157 156
 	c.Assert(err, checker.IsNil)
... ...
@@ -426,7 +425,7 @@ func (s *DockerSwarmSuite) TestOverlayAttachableOnSwarmLeave(c *check.C) {
426 426
 	c.Assert(err, checker.IsNil, check.Commentf(out))
427 427
 
428 428
 	// Leave the swarm
429
-	err = d.Leave(true)
429
+	err = d.SwarmLeave(true)
430 430
 	c.Assert(err, checker.IsNil)
431 431
 
432 432
 	// Check the container is disconnected
... ...
@@ -989,13 +988,12 @@ func (s *DockerSwarmSuite) TestDNSConfigUpdate(c *check.C) {
989 989
 	c.Assert(strings.TrimSpace(out), checker.Equals, "{[1.2.3.4] [example.com] [timeout:3]}")
990 990
 }
991 991
 
992
-func getNodeStatus(c *check.C, d *daemon.Swarm) swarm.LocalNodeState {
993
-	info, err := d.SwarmInfo()
994
-	c.Assert(err, checker.IsNil)
992
+func getNodeStatus(c *check.C, d *daemon.Daemon) swarm.LocalNodeState {
993
+	info := d.SwarmInfo(c)
995 994
 	return info.LocalNodeState
996 995
 }
997 996
 
998
-func checkKeyIsEncrypted(d *daemon.Swarm) func(*check.C) (interface{}, check.CommentInterface) {
997
+func checkKeyIsEncrypted(d *daemon.Daemon) func(*check.C) (interface{}, check.CommentInterface) {
999 998
 	return func(c *check.C) (interface{}, check.CommentInterface) {
1000 999
 		keyBytes, err := ioutil.ReadFile(filepath.Join(d.Folder, "root", "swarm", "certificates", "swarm-node.key"))
1001 1000
 		if err != nil {
... ...
@@ -1011,7 +1009,7 @@ func checkKeyIsEncrypted(d *daemon.Swarm) func(*check.C) (interface{}, check.Com
1011 1011
 	}
1012 1012
 }
1013 1013
 
1014
-func checkSwarmLockedToUnlocked(c *check.C, d *daemon.Swarm, unlockKey string) {
1014
+func checkSwarmLockedToUnlocked(c *check.C, d *daemon.Daemon, unlockKey string) {
1015 1015
 	// Wait for the PEM file to become unencrypted
1016 1016
 	waitAndAssert(c, defaultReconciliationTimeout, checkKeyIsEncrypted(d), checker.Equals, false)
1017 1017
 
... ...
@@ -1019,7 +1017,7 @@ func checkSwarmLockedToUnlocked(c *check.C, d *daemon.Swarm, unlockKey string) {
1019 1019
 	c.Assert(getNodeStatus(c, d), checker.Equals, swarm.LocalNodeStateActive)
1020 1020
 }
1021 1021
 
1022
-func checkSwarmUnlockedToLocked(c *check.C, d *daemon.Swarm) {
1022
+func checkSwarmUnlockedToLocked(c *check.C, d *daemon.Daemon) {
1023 1023
 	// Wait for the PEM file to become encrypted
1024 1024
 	waitAndAssert(c, defaultReconciliationTimeout, checkKeyIsEncrypted(d), checker.Equals, true)
1025 1025
 
... ...
@@ -1117,8 +1115,7 @@ func (s *DockerSwarmSuite) TestSwarmLeaveLocked(c *check.C) {
1117 1117
 	// It starts off locked
1118 1118
 	d.Restart(c, "--swarm-default-advertise-addr=lo")
1119 1119
 
1120
-	info, err := d.SwarmInfo()
1121
-	c.Assert(err, checker.IsNil)
1120
+	info := d.SwarmInfo(c)
1122 1121
 	c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateLocked)
1123 1122
 
1124 1123
 	outs, _ = d.Cmd("node", "ls")
... ...
@@ -1132,15 +1129,13 @@ func (s *DockerSwarmSuite) TestSwarmLeaveLocked(c *check.C) {
1132 1132
 	outs, err = d.Cmd("swarm", "leave", "--force")
1133 1133
 	c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs))
1134 1134
 
1135
-	info, err = d.SwarmInfo()
1136
-	c.Assert(err, checker.IsNil)
1135
+	info = d.SwarmInfo(c)
1137 1136
 	c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateInactive)
1138 1137
 
1139 1138
 	outs, err = d.Cmd("swarm", "init")
1140 1139
 	c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs))
1141 1140
 
1142
-	info, err = d.SwarmInfo()
1143
-	c.Assert(err, checker.IsNil)
1141
+	info = d.SwarmInfo(c)
1144 1142
 	c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
1145 1143
 }
1146 1144
 
... ...
@@ -1176,7 +1171,7 @@ func (s *DockerSwarmSuite) TestSwarmLockUnlockCluster(c *check.C) {
1176 1176
 	c.Assert(outs, checker.Equals, unlockKey+"\n")
1177 1177
 
1178 1178
 	// The ones that got the cluster update should be set to locked
1179
-	for _, d := range []*daemon.Swarm{d1, d3} {
1179
+	for _, d := range []*daemon.Daemon{d1, d3} {
1180 1180
 		checkSwarmUnlockedToLocked(c, d)
1181 1181
 
1182 1182
 		cmd := d.Command("swarm", "unlock")
... ...
@@ -1197,7 +1192,7 @@ func (s *DockerSwarmSuite) TestSwarmLockUnlockCluster(c *check.C) {
1197 1197
 	c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs))
1198 1198
 
1199 1199
 	// the ones that got the update are now set to unlocked
1200
-	for _, d := range []*daemon.Swarm{d1, d3} {
1200
+	for _, d := range []*daemon.Daemon{d1, d3} {
1201 1201
 		checkSwarmLockedToUnlocked(c, d, unlockKey)
1202 1202
 	}
1203 1203
 
... ...
@@ -1247,7 +1242,7 @@ func (s *DockerSwarmSuite) TestSwarmJoinPromoteLocked(c *check.C) {
1247 1247
 	c.Assert(getNodeStatus(c, d2), checker.Equals, swarm.LocalNodeStateActive)
1248 1248
 
1249 1249
 	// promote worker
1250
-	outs, err = d1.Cmd("node", "promote", d2.Info.NodeID)
1250
+	outs, err = d1.Cmd("node", "promote", d2.NodeID())
1251 1251
 	c.Assert(err, checker.IsNil)
1252 1252
 	c.Assert(outs, checker.Contains, "promoted to a manager in the swarm")
1253 1253
 
... ...
@@ -1255,7 +1250,7 @@ func (s *DockerSwarmSuite) TestSwarmJoinPromoteLocked(c *check.C) {
1255 1255
 	d3 := s.AddDaemon(c, true, true)
1256 1256
 
1257 1257
 	// both new nodes are locked
1258
-	for _, d := range []*daemon.Swarm{d2, d3} {
1258
+	for _, d := range []*daemon.Daemon{d2, d3} {
1259 1259
 		checkSwarmUnlockedToLocked(c, d)
1260 1260
 
1261 1261
 		cmd := d.Command("swarm", "unlock")
... ...
@@ -1265,7 +1260,7 @@ func (s *DockerSwarmSuite) TestSwarmJoinPromoteLocked(c *check.C) {
1265 1265
 	}
1266 1266
 
1267 1267
 	// demote manager back to worker - workers are not locked
1268
-	outs, err = d1.Cmd("node", "demote", d3.Info.NodeID)
1268
+	outs, err = d1.Cmd("node", "demote", d3.NodeID())
1269 1269
 	c.Assert(err, checker.IsNil)
1270 1270
 	c.Assert(outs, checker.Contains, "demoted in the swarm")
1271 1271
 
... ...
@@ -1409,7 +1404,7 @@ func (s *DockerSwarmSuite) TestSwarmClusterRotateUnlockKey(c *check.C) {
1409 1409
 		d2.Restart(c)
1410 1410
 		d3.Restart(c)
1411 1411
 
1412
-		for _, d := range []*daemon.Swarm{d2, d3} {
1412
+		for _, d := range []*daemon.Daemon{d2, d3} {
1413 1413
 			c.Assert(getNodeStatus(c, d), checker.Equals, swarm.LocalNodeStateLocked)
1414 1414
 
1415 1415
 			outs, _ := d.Cmd("node", "ls")
... ...
@@ -1521,7 +1516,7 @@ func (s *DockerSwarmSuite) TestSwarmManagerAddress(c *check.C) {
1521 1521
 	d3 := s.AddDaemon(c, true, false)
1522 1522
 
1523 1523
 	// Manager Addresses will always show Node 1's address
1524
-	expectedOutput := fmt.Sprintf("Manager Addresses:\n  127.0.0.1:%d\n", d1.Port)
1524
+	expectedOutput := fmt.Sprintf("Manager Addresses:\n  127.0.0.1:%d\n", d1.SwarmPort)
1525 1525
 
1526 1526
 	out, err := d1.Cmd("info")
1527 1527
 	c.Assert(err, checker.IsNil)
... ...
@@ -1641,7 +1636,7 @@ func (s *DockerSwarmSuite) TestSwarmJoinWithDrain(c *check.C) {
1641 1641
 
1642 1642
 	d1 := s.AddDaemon(c, false, false)
1643 1643
 
1644
-	out, err = d1.Cmd("swarm", "join", "--availability=drain", "--token", token, d.ListenAddr)
1644
+	out, err = d1.Cmd("swarm", "join", "--availability=drain", "--token", token, d.SwarmListenAddr())
1645 1645
 	c.Assert(err, checker.IsNil)
1646 1646
 	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
1647 1647
 
... ...
@@ -1835,7 +1830,7 @@ func (s *DockerSwarmSuite) TestSwarmJoinLeave(c *check.C) {
1835 1835
 	// Verify that back to back join/leave does not cause panics
1836 1836
 	d1 := s.AddDaemon(c, false, false)
1837 1837
 	for i := 0; i < 10; i++ {
1838
-		out, err = d1.Cmd("swarm", "join", "--token", token, d.ListenAddr)
1838
+		out, err = d1.Cmd("swarm", "join", "--token", token, d.SwarmListenAddr())
1839 1839
 		c.Assert(err, checker.IsNil)
1840 1840
 		c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
1841 1841
 
... ...
@@ -1846,7 +1841,7 @@ func (s *DockerSwarmSuite) TestSwarmJoinLeave(c *check.C) {
1846 1846
 
1847 1847
 const defaultRetryCount = 10
1848 1848
 
1849
-func waitForEvent(c *check.C, d *daemon.Swarm, since string, filter string, event string, retry int) string {
1849
+func waitForEvent(c *check.C, d *daemon.Daemon, since string, filter string, event string, retry int) string {
1850 1850
 	if retry < 1 {
1851 1851
 		c.Fatalf("retry count %d is invalid. It should be no less than 1", retry)
1852 1852
 		return ""
... ...
@@ -1982,7 +1977,7 @@ func (s *DockerSwarmSuite) TestSwarmClusterEventsNode(c *check.C) {
1982 1982
 	s.AddDaemon(c, true, true)
1983 1983
 	d3 := s.AddDaemon(c, true, true)
1984 1984
 
1985
-	d3ID := d3.NodeID
1985
+	d3ID := d3.NodeID()
1986 1986
 	waitForEvent(c, d1, "0", "-f scope=swarm", "node create "+d3ID, defaultRetryCount)
1987 1987
 
1988 1988
 	t1 := daemonUnixTime(c)
... ...
@@ -2,7 +2,6 @@ package swarm
2 2
 
3 3
 import (
4 4
 	"context"
5
-	"fmt"
6 5
 	"runtime"
7 6
 	"testing"
8 7
 	"time"
... ...
@@ -11,18 +10,13 @@ import (
11 11
 	"github.com/docker/docker/api/types/filters"
12 12
 	swarmtypes "github.com/docker/docker/api/types/swarm"
13 13
 	"github.com/docker/docker/client"
14
-	"github.com/docker/docker/integration-cli/daemon"
14
+	"github.com/docker/docker/internal/test/daemon"
15 15
 	"github.com/docker/docker/internal/test/environment"
16 16
 	"github.com/gotestyourself/gotestyourself/assert"
17 17
 	"github.com/gotestyourself/gotestyourself/poll"
18 18
 	"github.com/gotestyourself/gotestyourself/skip"
19 19
 )
20 20
 
21
-const (
22
-	dockerdBinary    = "dockerd"
23
-	defaultSwarmPort = 2477
24
-)
25
-
26 21
 // ServicePoll tweaks the pollSettings for `service`
27 22
 func ServicePoll(config *poll.Settings) {
28 23
 	// Override the default pollSettings for `service` resource here ...
... ...
@@ -55,23 +49,17 @@ func ContainerPoll(config *poll.Settings) {
55 55
 }
56 56
 
57 57
 // NewSwarm creates a swarm daemon for testing
58
-func NewSwarm(t *testing.T, testEnv *environment.Execution) *daemon.Swarm {
58
+func NewSwarm(t *testing.T, testEnv *environment.Execution, ops ...func(*daemon.Daemon)) *daemon.Daemon {
59 59
 	skip.IfCondition(t, testEnv.IsRemoteDaemon())
60
-	d := &daemon.Swarm{
61
-		Daemon: daemon.New(t, "", dockerdBinary, daemon.Config{
62
-			Experimental: testEnv.DaemonInfo.ExperimentalBuild,
63
-		}),
64
-		// TODO: better method of finding an unused port
65
-		Port: defaultSwarmPort,
60
+	if testEnv.DaemonInfo.ExperimentalBuild {
61
+		ops = append(ops, daemon.WithExperimental)
66 62
 	}
67
-	// TODO: move to a NewSwarm constructor
68
-	d.ListenAddr = fmt.Sprintf("0.0.0.0:%d", d.Port)
69
-
63
+	d := daemon.New(t, ops...)
70 64
 	// avoid networking conflicts
71 65
 	args := []string{"--iptables=false", "--swarm-default-advertise-addr=lo"}
72 66
 	d.StartWithBusybox(t, args...)
73 67
 
74
-	assert.NilError(t, d.Init(swarmtypes.InitRequest{}))
68
+	d.SwarmInit(t, swarmtypes.InitRequest{})
75 69
 	return d
76 70
 }
77 71
 
... ...
@@ -79,7 +67,7 @@ func NewSwarm(t *testing.T, testEnv *environment.Execution) *daemon.Swarm {
79 79
 type ServiceSpecOpt func(*swarmtypes.ServiceSpec)
80 80
 
81 81
 // CreateService creates a service on the passed in swarm daemon.
82
-func CreateService(t *testing.T, d *daemon.Swarm, opts ...ServiceSpecOpt) string {
82
+func CreateService(t *testing.T, d *daemon.Daemon, opts ...ServiceSpecOpt) string {
83 83
 	spec := defaultServiceSpec()
84 84
 	for _, o := range opts {
85 85
 		o(&spec)
... ...
@@ -151,7 +139,7 @@ func ServiceWithName(name string) ServiceSpecOpt {
151 151
 }
152 152
 
153 153
 // GetRunningTasks gets the list of running tasks for a service
154
-func GetRunningTasks(t *testing.T, d *daemon.Swarm, serviceID string) []swarmtypes.Task {
154
+func GetRunningTasks(t *testing.T, d *daemon.Daemon, serviceID string) []swarmtypes.Task {
155 155
 	client := GetClient(t, d)
156 156
 
157 157
 	filterArgs := filters.NewArgs()
... ...
@@ -167,7 +155,7 @@ func GetRunningTasks(t *testing.T, d *daemon.Swarm, serviceID string) []swarmtyp
167 167
 }
168 168
 
169 169
 // ExecTask runs the passed in exec config on the given task
170
-func ExecTask(t *testing.T, d *daemon.Swarm, task swarmtypes.Task, config types.ExecConfig) types.HijackedResponse {
170
+func ExecTask(t *testing.T, d *daemon.Daemon, task swarmtypes.Task, config types.ExecConfig) types.HijackedResponse {
171 171
 	client := GetClient(t, d)
172 172
 
173 173
 	ctx := context.Background()
... ...
@@ -187,7 +175,7 @@ func ensureContainerSpec(spec *swarmtypes.ServiceSpec) {
187 187
 }
188 188
 
189 189
 // GetClient creates a new client for the passed in swarm daemon.
190
-func GetClient(t *testing.T, d *daemon.Swarm) client.APIClient {
190
+func GetClient(t *testing.T, d *daemon.Daemon) client.APIClient {
191 191
 	client, err := client.NewClientWithOpts(client.WithHost((d.Sock())))
192 192
 	assert.NilError(t, err)
193 193
 	return client
194 194
new file mode 100644
... ...
@@ -0,0 +1,66 @@
0
+package daemon
1
+
2
+import (
3
+	"context"
4
+
5
+	"github.com/docker/docker/api/types"
6
+	"github.com/docker/docker/api/types/swarm"
7
+	"github.com/gotestyourself/gotestyourself/assert"
8
+)
9
+
10
+// ConfigConstructor defines a swarm config constructor
11
+type ConfigConstructor func(*swarm.Config)
12
+
13
+// CreateConfig creates a config given the specified spec
14
+func (d *Daemon) CreateConfig(t assert.TestingT, configSpec swarm.ConfigSpec) string {
15
+	cli := d.NewClientT(t)
16
+	defer cli.Close()
17
+
18
+	scr, err := cli.ConfigCreate(context.Background(), configSpec)
19
+	assert.NilError(t, err)
20
+	return scr.ID
21
+}
22
+
23
+// ListConfigs returns the list of the current swarm configs
24
+func (d *Daemon) ListConfigs(t assert.TestingT) []swarm.Config {
25
+	cli := d.NewClientT(t)
26
+	defer cli.Close()
27
+
28
+	configs, err := cli.ConfigList(context.Background(), types.ConfigListOptions{})
29
+	assert.NilError(t, err)
30
+	return configs
31
+}
32
+
33
+// GetConfig returns a swarm config identified by the specified id
34
+func (d *Daemon) GetConfig(t assert.TestingT, id string) *swarm.Config {
35
+	cli := d.NewClientT(t)
36
+	defer cli.Close()
37
+
38
+	config, _, err := cli.ConfigInspectWithRaw(context.Background(), id)
39
+	assert.NilError(t, err)
40
+	return &config
41
+}
42
+
43
+// DeleteConfig removes the swarm config identified by the specified id
44
+func (d *Daemon) DeleteConfig(t assert.TestingT, id string) {
45
+	cli := d.NewClientT(t)
46
+	defer cli.Close()
47
+
48
+	err := cli.ConfigRemove(context.Background(), id)
49
+	assert.NilError(t, err)
50
+}
51
+
52
+// UpdateConfig updates the swarm config identified by the specified id
53
+// Currently, only label update is supported.
54
+func (d *Daemon) UpdateConfig(t assert.TestingT, id string, f ...ConfigConstructor) {
55
+	cli := d.NewClientT(t)
56
+	defer cli.Close()
57
+
58
+	config := d.GetConfig(t, id)
59
+	for _, fn := range f {
60
+		fn(config)
61
+	}
62
+
63
+	err := cli.ConfigUpdate(context.Background(), config.ID, config.Version, config.Spec)
64
+	assert.NilError(t, err)
65
+}
... ...
@@ -67,6 +67,13 @@ type Daemon struct {
67 67
 	experimental  bool
68 68
 	dockerdBinary string
69 69
 	log           logT
70
+
71
+	// swarm related field
72
+	swarmListenAddr string
73
+	SwarmPort       int // FIXME(vdemeester) should probably not be exported
74
+
75
+	// cached information
76
+	CachedInfo types.Info
70 77
 }
71 78
 
72 79
 // New returns a Daemon instance to be used for testing.
... ...
@@ -98,14 +105,16 @@ func New(t testingT, ops ...func(*Daemon)) *Daemon {
98 98
 		}
99 99
 	}
100 100
 	d := &Daemon{
101
-		id:            id,
102
-		Folder:        daemonFolder,
103
-		Root:          daemonRoot,
104
-		storageDriver: storageDriver,
105
-		userlandProxy: userlandProxy,
106
-		execRoot:      filepath.Join(os.TempDir(), "docker-execroot", id),
107
-		dockerdBinary: defaultDockerdBinary,
108
-		log:           t,
101
+		id:              id,
102
+		Folder:          daemonFolder,
103
+		Root:            daemonRoot,
104
+		storageDriver:   storageDriver,
105
+		userlandProxy:   userlandProxy,
106
+		execRoot:        filepath.Join(os.TempDir(), "docker-execroot", id),
107
+		dockerdBinary:   defaultDockerdBinary,
108
+		swarmListenAddr: defaultSwarmListenAddr,
109
+		SwarmPort:       defaultSwarmPort,
110
+		log:             t,
109 111
 	}
110 112
 
111 113
 	for _, op := range ops {
... ...
@@ -150,12 +159,23 @@ func (d *Daemon) ReadLogFile() ([]byte, error) {
150 150
 }
151 151
 
152 152
 // NewClient creates new client based on daemon's socket path
153
+// FIXME(vdemeester): replace NewClient with NewClientT
153 154
 func (d *Daemon) NewClient() (*client.Client, error) {
154 155
 	return client.NewClientWithOpts(
155 156
 		client.FromEnv,
156 157
 		client.WithHost(d.Sock()))
157 158
 }
158 159
 
160
+// NewClientT creates new client based on daemon's socket path
161
+// FIXME(vdemeester): replace NewClient with NewClientT
162
+func (d *Daemon) NewClientT(t assert.TestingT) *client.Client {
163
+	c, err := client.NewClientWithOpts(
164
+		client.FromEnv,
165
+		client.WithHost(d.Sock()))
166
+	assert.NilError(t, err, "cannot create daemon client")
167
+	return c
168
+}
169
+
159 170
 // CleanupExecRoot cleans the daemon exec root (network namespaces, ...)
160 171
 func (d *Daemon) CleanupExecRoot(t testingT) {
161 172
 	cleanupExecRoot(t, d.execRoot)
... ...
@@ -610,7 +630,7 @@ func (d *Daemon) queryRootDir() (string, error) {
610 610
 
611 611
 // Info returns the info struct for this daemon
612 612
 func (d *Daemon) Info(t assert.TestingT) types.Info {
613
-	apiclient, err := client.NewClientWithOpts(client.WithHost((d.Sock())))
613
+	apiclient, err := d.NewClient()
614 614
 	assert.NilError(t, err)
615 615
 	info, err := apiclient.Info(context.Background())
616 616
 	assert.NilError(t, err)
617 617
new file mode 100644
... ...
@@ -0,0 +1,69 @@
0
+package daemon
1
+
2
+import (
3
+	"context"
4
+	"strings"
5
+	"time"
6
+
7
+	"github.com/docker/docker/api/types"
8
+	"github.com/docker/docker/api/types/swarm"
9
+	"github.com/gotestyourself/gotestyourself/assert"
10
+)
11
+
12
+// NodeConstructor defines a swarm node constructor
13
+type NodeConstructor func(*swarm.Node)
14
+
15
+// GetNode returns a swarm node identified by the specified id
16
+func (d *Daemon) GetNode(t assert.TestingT, id string) *swarm.Node {
17
+	cli := d.NewClientT(t)
18
+	defer cli.Close()
19
+
20
+	node, _, err := cli.NodeInspectWithRaw(context.Background(), id)
21
+	assert.NilError(t, err)
22
+	assert.Check(t, node.ID == id)
23
+	return &node
24
+}
25
+
26
+// RemoveNode removes the specified node
27
+func (d *Daemon) RemoveNode(t assert.TestingT, id string, force bool) {
28
+	cli := d.NewClientT(t)
29
+	defer cli.Close()
30
+
31
+	options := types.NodeRemoveOptions{
32
+		Force: force,
33
+	}
34
+	err := cli.NodeRemove(context.Background(), id, options)
35
+	assert.NilError(t, err)
36
+}
37
+
38
+// UpdateNode updates a swarm node with the specified node constructor
39
+func (d *Daemon) UpdateNode(t assert.TestingT, id string, f ...NodeConstructor) {
40
+	cli := d.NewClientT(t)
41
+	defer cli.Close()
42
+
43
+	for i := 0; ; i++ {
44
+		node := d.GetNode(t, id)
45
+		for _, fn := range f {
46
+			fn(node)
47
+		}
48
+
49
+		err := cli.NodeUpdate(context.Background(), node.ID, node.Version, node.Spec)
50
+		if i < 10 && err != nil && strings.Contains(err.Error(), "update out of sequence") {
51
+			time.Sleep(100 * time.Millisecond)
52
+			continue
53
+		}
54
+		assert.NilError(t, err)
55
+		return
56
+	}
57
+}
58
+
59
+// ListNodes returns the list of the current swarm nodes
60
+func (d *Daemon) ListNodes(t assert.TestingT) []swarm.Node {
61
+	cli := d.NewClientT(t)
62
+	defer cli.Close()
63
+
64
+	nodes, err := cli.NodeList(context.Background(), types.NodeListOptions{})
65
+	assert.NilError(t, err)
66
+
67
+	return nodes
68
+}
... ...
@@ -11,3 +11,17 @@ func WithDockerdBinary(dockerdBinary string) func(*Daemon) {
11 11
 		d.dockerdBinary = dockerdBinary
12 12
 	}
13 13
 }
14
+
15
+// WithSwarmPort sets the swarm port to use for swarm mode
16
+func WithSwarmPort(port int) func(*Daemon) {
17
+	return func(d *Daemon) {
18
+		d.SwarmPort = port
19
+	}
20
+}
21
+
22
+// WithSwarmListenAddr sets the swarm listen addr to use for swarm mode
23
+func WithSwarmListenAddr(listenAddr string) func(*Daemon) {
24
+	return func(d *Daemon) {
25
+		d.swarmListenAddr = listenAddr
26
+	}
27
+}
14 28
new file mode 100644
... ...
@@ -0,0 +1,68 @@
0
+package daemon
1
+
2
+import (
3
+	"context"
4
+
5
+	"github.com/docker/docker/api/types"
6
+	"github.com/docker/docker/api/types/swarm"
7
+	"github.com/gotestyourself/gotestyourself/assert"
8
+)
9
+
10
+// SecretConstructor defines a swarm secret constructor
11
+type SecretConstructor func(*swarm.Secret)
12
+
13
+// CreateSecret creates a secret given the specified spec
14
+func (d *Daemon) CreateSecret(t assert.TestingT, secretSpec swarm.SecretSpec) string {
15
+	cli := d.NewClientT(t)
16
+	defer cli.Close()
17
+
18
+	scr, err := cli.SecretCreate(context.Background(), secretSpec)
19
+	assert.NilError(t, err)
20
+
21
+	return scr.ID
22
+}
23
+
24
+// ListSecrets returns the list of the current swarm secrets
25
+func (d *Daemon) ListSecrets(t assert.TestingT) []swarm.Secret {
26
+	cli := d.NewClientT(t)
27
+	defer cli.Close()
28
+
29
+	secrets, err := cli.SecretList(context.Background(), types.SecretListOptions{})
30
+	assert.NilError(t, err)
31
+	return secrets
32
+}
33
+
34
+// GetSecret returns a swarm secret identified by the specified id
35
+func (d *Daemon) GetSecret(t assert.TestingT, id string) *swarm.Secret {
36
+	cli := d.NewClientT(t)
37
+	defer cli.Close()
38
+
39
+	secret, _, err := cli.SecretInspectWithRaw(context.Background(), id)
40
+	assert.NilError(t, err)
41
+	return &secret
42
+}
43
+
44
+// DeleteSecret removes the swarm secret identified by the specified id
45
+func (d *Daemon) DeleteSecret(t assert.TestingT, id string) {
46
+	cli := d.NewClientT(t)
47
+	defer cli.Close()
48
+
49
+	err := cli.SecretRemove(context.Background(), id)
50
+	assert.NilError(t, err)
51
+}
52
+
53
+// UpdateSecret updates the swarm secret identified by the specified id
54
+// Currently, only label update is supported.
55
+func (d *Daemon) UpdateSecret(t assert.TestingT, id string, f ...SecretConstructor) {
56
+	cli := d.NewClientT(t)
57
+	defer cli.Close()
58
+
59
+	secret := d.GetSecret(t, id)
60
+	for _, fn := range f {
61
+		fn(secret)
62
+	}
63
+
64
+	err := cli.SecretUpdate(context.Background(), secret.ID, secret.Version, secret.Spec)
65
+
66
+	assert.NilError(t, err)
67
+}
0 68
new file mode 100644
... ...
@@ -0,0 +1,108 @@
0
+package daemon
1
+
2
+import (
3
+	"context"
4
+	"time"
5
+
6
+	"github.com/docker/docker/api/types"
7
+	"github.com/docker/docker/api/types/filters"
8
+	"github.com/docker/docker/api/types/swarm"
9
+	"github.com/gotestyourself/gotestyourself/assert"
10
+)
11
+
12
+// ServiceConstructor defines a swarm service constructor function
13
+type ServiceConstructor func(*swarm.Service)
14
+
15
+// CreateServiceWithOptions creates a swarm service given the specified service constructors
16
+// and auth config
17
+func (d *Daemon) CreateServiceWithOptions(t assert.TestingT, opts types.ServiceCreateOptions, f ...ServiceConstructor) string {
18
+	var service swarm.Service
19
+	for _, fn := range f {
20
+		fn(&service)
21
+	}
22
+
23
+	cli := d.NewClientT(t)
24
+	defer cli.Close()
25
+
26
+	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
27
+	defer cancel()
28
+
29
+	res, err := cli.ServiceCreate(ctx, service.Spec, opts)
30
+	assert.NilError(t, err)
31
+	return res.ID
32
+}
33
+
34
+// CreateService creates a swarm service given the specified service constructor
35
+func (d *Daemon) CreateService(t assert.TestingT, f ...ServiceConstructor) string {
36
+	return d.CreateServiceWithOptions(t, types.ServiceCreateOptions{}, f...)
37
+}
38
+
39
+// GetService returns the swarm service corresponding to the specified id
40
+func (d *Daemon) GetService(t assert.TestingT, id string) *swarm.Service {
41
+	cli := d.NewClientT(t)
42
+	defer cli.Close()
43
+
44
+	service, _, err := cli.ServiceInspectWithRaw(context.Background(), id, types.ServiceInspectOptions{})
45
+	assert.NilError(t, err)
46
+	return &service
47
+}
48
+
49
+// GetServiceTasks returns the swarm tasks for the specified service
50
+func (d *Daemon) GetServiceTasks(t assert.TestingT, service string) []swarm.Task {
51
+	cli := d.NewClientT(t)
52
+	defer cli.Close()
53
+
54
+	filterArgs := filters.NewArgs()
55
+	filterArgs.Add("desired-state", "running")
56
+	filterArgs.Add("service", service)
57
+
58
+	options := types.TaskListOptions{
59
+		Filters: filterArgs,
60
+	}
61
+
62
+	tasks, err := cli.TaskList(context.Background(), options)
63
+	assert.NilError(t, err)
64
+	return tasks
65
+}
66
+
67
+// UpdateService updates a swarm service with the specified service constructor
68
+func (d *Daemon) UpdateService(t assert.TestingT, service *swarm.Service, f ...ServiceConstructor) {
69
+	cli := d.NewClientT(t)
70
+	defer cli.Close()
71
+
72
+	for _, fn := range f {
73
+		fn(service)
74
+	}
75
+
76
+	_, err := cli.ServiceUpdate(context.Background(), service.ID, service.Version, service.Spec, types.ServiceUpdateOptions{})
77
+	assert.NilError(t, err)
78
+}
79
+
80
+// RemoveService removes the specified service
81
+func (d *Daemon) RemoveService(t assert.TestingT, id string) {
82
+	cli := d.NewClientT(t)
83
+	defer cli.Close()
84
+
85
+	err := cli.ServiceRemove(context.Background(), id)
86
+	assert.NilError(t, err)
87
+}
88
+
89
+// ListServices returns the list of the current swarm services
90
+func (d *Daemon) ListServices(t assert.TestingT) []swarm.Service {
91
+	cli := d.NewClientT(t)
92
+	defer cli.Close()
93
+
94
+	services, err := cli.ServiceList(context.Background(), types.ServiceListOptions{})
95
+	assert.NilError(t, err)
96
+	return services
97
+}
98
+
99
+// GetTask returns the swarm task identified by the specified id
100
+func (d *Daemon) GetTask(t assert.TestingT, id string) swarm.Task {
101
+	cli := d.NewClientT(t)
102
+	defer cli.Close()
103
+
104
+	task, _, err := cli.TaskInspectWithRaw(context.Background(), id)
105
+	assert.NilError(t, err)
106
+	return task
107
+}
0 108
new file mode 100644
... ...
@@ -0,0 +1,139 @@
0
+package daemon
1
+
2
+import (
3
+	"context"
4
+	"fmt"
5
+
6
+	"github.com/docker/docker/api/types/swarm"
7
+	"github.com/gotestyourself/gotestyourself/assert"
8
+	"github.com/pkg/errors"
9
+)
10
+
11
+const (
12
+	defaultSwarmPort       = 2477
13
+	defaultSwarmListenAddr = "0.0.0.0"
14
+)
15
+
16
+// SpecConstructor defines a swarm spec constructor
17
+type SpecConstructor func(*swarm.Spec)
18
+
19
+// SwarmListenAddr returns the listen-addr used for the daemon
20
+func (d *Daemon) SwarmListenAddr() string {
21
+	return fmt.Sprintf("%s:%d", d.swarmListenAddr, d.SwarmPort)
22
+}
23
+
24
+// NodeID returns the swarm mode node ID
25
+func (d *Daemon) NodeID() string {
26
+	return d.CachedInfo.Swarm.NodeID
27
+}
28
+
29
+// SwarmInit initializes a new swarm cluster.
30
+func (d *Daemon) SwarmInit(t assert.TestingT, req swarm.InitRequest) {
31
+	if req.ListenAddr == "" {
32
+		req.ListenAddr = fmt.Sprintf("%s:%d", d.swarmListenAddr, d.SwarmPort)
33
+	}
34
+	cli := d.NewClientT(t)
35
+	defer cli.Close()
36
+	_, err := cli.SwarmInit(context.Background(), req)
37
+	assert.NilError(t, err, "initializing swarm")
38
+	d.CachedInfo = d.Info(t)
39
+}
40
+
41
+// SwarmJoin joins a daemon to an existing cluster.
42
+func (d *Daemon) SwarmJoin(t assert.TestingT, req swarm.JoinRequest) {
43
+	if req.ListenAddr == "" {
44
+		req.ListenAddr = fmt.Sprintf("%s:%d", d.swarmListenAddr, d.SwarmPort)
45
+	}
46
+	cli := d.NewClientT(t)
47
+	defer cli.Close()
48
+	err := cli.SwarmJoin(context.Background(), req)
49
+	assert.NilError(t, err, "initializing swarm")
50
+	d.CachedInfo = d.Info(t)
51
+}
52
+
53
+// SwarmLeave forces daemon to leave current cluster.
54
+func (d *Daemon) SwarmLeave(force bool) error {
55
+	cli, err := d.NewClient()
56
+	if err != nil {
57
+		return fmt.Errorf("leaving swarm: failed to create client %v", err)
58
+	}
59
+	defer cli.Close()
60
+	err = cli.SwarmLeave(context.Background(), force)
61
+	if err != nil {
62
+		err = fmt.Errorf("leaving swarm: %v", err)
63
+	}
64
+	return err
65
+}
66
+
67
+// SwarmInfo returns the swarm information of the daemon
68
+func (d *Daemon) SwarmInfo(t assert.TestingT) swarm.Info {
69
+	cli := d.NewClientT(t)
70
+	info, err := cli.Info(context.Background())
71
+	assert.NilError(t, err, "get swarm info")
72
+	return info.Swarm
73
+}
74
+
75
+// SwarmUnlock tries to unlock a locked swarm
76
+func (d *Daemon) SwarmUnlock(req swarm.UnlockRequest) error {
77
+	cli, err := d.NewClient()
78
+	if err != nil {
79
+		return fmt.Errorf("unlocking swarm: failed to create client %v", err)
80
+	}
81
+	defer cli.Close()
82
+	err = cli.SwarmUnlock(context.Background(), req)
83
+	if err != nil {
84
+		err = errors.Wrap(err, "unlocking swarm")
85
+	}
86
+	return err
87
+}
88
+
89
+// GetSwarm returns the current swarm object
90
+func (d *Daemon) GetSwarm(t assert.TestingT) swarm.Swarm {
91
+	cli := d.NewClientT(t)
92
+	defer cli.Close()
93
+
94
+	sw, err := cli.SwarmInspect(context.Background())
95
+	assert.NilError(t, err)
96
+	return sw
97
+}
98
+
99
+// UpdateSwarm updates the current swarm object with the specified spec constructors
100
+func (d *Daemon) UpdateSwarm(t assert.TestingT, f ...SpecConstructor) {
101
+	cli := d.NewClientT(t)
102
+	defer cli.Close()
103
+
104
+	sw := d.GetSwarm(t)
105
+	for _, fn := range f {
106
+		fn(&sw.Spec)
107
+	}
108
+
109
+	err := cli.SwarmUpdate(context.Background(), sw.Version, sw.Spec, swarm.UpdateFlags{})
110
+	assert.NilError(t, err)
111
+}
112
+
113
+// RotateTokens update the swarm to rotate tokens
114
+func (d *Daemon) RotateTokens(t assert.TestingT) {
115
+	cli := d.NewClientT(t)
116
+	defer cli.Close()
117
+
118
+	sw, err := cli.SwarmInspect(context.Background())
119
+	assert.NilError(t, err)
120
+
121
+	flags := swarm.UpdateFlags{
122
+		RotateManagerToken: true,
123
+		RotateWorkerToken:  true,
124
+	}
125
+
126
+	err = cli.SwarmUpdate(context.Background(), sw.Version, sw.Spec, flags)
127
+	assert.NilError(t, err)
128
+}
129
+
130
+// JoinTokens returns the current swarm join tokens
131
+func (d *Daemon) JoinTokens(t assert.TestingT) swarm.JoinTokens {
132
+	cli := d.NewClientT(t)
133
+	defer cli.Close()
134
+
135
+	sw, err := cli.SwarmInspect(context.Background())
136
+	assert.NilError(t, err)
137
+	return sw.JoinTokens
138
+}