github.com/LazyboyChen7/engine@v17.12.1-ce-rc2+incompatible/integration-cli/daemon/daemon_swarm.go (about)

     1  package daemon
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"net/http"
     7  	"strings"
     8  	"time"
     9  
    10  	"github.com/docker/docker/api/types"
    11  	"github.com/docker/docker/api/types/filters"
    12  	"github.com/docker/docker/api/types/swarm"
    13  	"github.com/docker/docker/integration-cli/checker"
    14  	"github.com/go-check/check"
    15  	"github.com/pkg/errors"
    16  	"golang.org/x/net/context"
    17  )
    18  
    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  // CheckServiceTasksInState returns the number of tasks with a matching state,
   185  // and optional message substring.
   186  func (d *Swarm) CheckServiceTasksInState(service string, state swarm.TaskState, message string) func(*check.C) (interface{}, check.CommentInterface) {
   187  	return func(c *check.C) (interface{}, check.CommentInterface) {
   188  		tasks := d.GetServiceTasks(c, service)
   189  		var count int
   190  		for _, task := range tasks {
   191  			if task.Status.State == state {
   192  				if message == "" || strings.Contains(task.Status.Message, message) {
   193  					count++
   194  				}
   195  			}
   196  		}
   197  		return count, nil
   198  	}
   199  }
   200  
   201  // CheckServiceTasksInStateWithError returns the number of tasks with a matching state,
   202  // and optional message substring.
   203  func (d *Swarm) CheckServiceTasksInStateWithError(service string, state swarm.TaskState, errorMessage string) func(*check.C) (interface{}, check.CommentInterface) {
   204  	return func(c *check.C) (interface{}, check.CommentInterface) {
   205  		tasks := d.GetServiceTasks(c, service)
   206  		var count int
   207  		for _, task := range tasks {
   208  			if task.Status.State == state {
   209  				if errorMessage == "" || strings.Contains(task.Status.Err, errorMessage) {
   210  					count++
   211  				}
   212  			}
   213  		}
   214  		return count, nil
   215  	}
   216  }
   217  
   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) {
   220  	return d.CheckServiceTasksInState(service, swarm.TaskStateRunning, "")
   221  }
   222  
   223  // CheckServiceUpdateState returns the current update state for the specified service
   224  func (d *Swarm) CheckServiceUpdateState(service string) func(*check.C) (interface{}, check.CommentInterface) {
   225  	return func(c *check.C) (interface{}, check.CommentInterface) {
   226  		service := d.GetService(c, service)
   227  		if service.UpdateStatus == nil {
   228  			return "", nil
   229  		}
   230  		return service.UpdateStatus.State, nil
   231  	}
   232  }
   233  
   234  // CheckPluginRunning returns the runtime state of the plugin
   235  func (d *Swarm) CheckPluginRunning(plugin string) func(c *check.C) (interface{}, check.CommentInterface) {
   236  	return func(c *check.C) (interface{}, check.CommentInterface) {
   237  		status, out, err := d.SockRequest("GET", "/plugins/"+plugin+"/json", nil)
   238  		c.Assert(err, checker.IsNil, check.Commentf(string(out)))
   239  		if status != http.StatusOK {
   240  			return false, nil
   241  		}
   242  
   243  		var p types.Plugin
   244  		c.Assert(json.Unmarshal(out, &p), checker.IsNil, check.Commentf(string(out)))
   245  
   246  		return p.Enabled, check.Commentf("%+v", p)
   247  	}
   248  }
   249  
   250  // CheckPluginImage returns the runtime state of the plugin
   251  func (d *Swarm) CheckPluginImage(plugin string) func(c *check.C) (interface{}, check.CommentInterface) {
   252  	return func(c *check.C) (interface{}, check.CommentInterface) {
   253  		status, out, err := d.SockRequest("GET", "/plugins/"+plugin+"/json", nil)
   254  		c.Assert(err, checker.IsNil, check.Commentf(string(out)))
   255  		if status != http.StatusOK {
   256  			return false, nil
   257  		}
   258  
   259  		var p types.Plugin
   260  		c.Assert(json.Unmarshal(out, &p), checker.IsNil, check.Commentf(string(out)))
   261  		return p.PluginReference, check.Commentf("%+v", p)
   262  	}
   263  }
   264  
   265  // CheckServiceTasks returns the number of tasks for the specified service
   266  func (d *Swarm) CheckServiceTasks(service string) func(*check.C) (interface{}, check.CommentInterface) {
   267  	return func(c *check.C) (interface{}, check.CommentInterface) {
   268  		tasks := d.GetServiceTasks(c, service)
   269  		return len(tasks), nil
   270  	}
   271  }
   272  
   273  // CheckRunningTaskNetworks returns the number of times each network is referenced from a task.
   274  func (d *Swarm) CheckRunningTaskNetworks(c *check.C) (interface{}, check.CommentInterface) {
   275  	cli, err := d.NewClient()
   276  	c.Assert(err, checker.IsNil)
   277  	defer cli.Close()
   278  
   279  	filterArgs := filters.NewArgs()
   280  	filterArgs.Add("desired-state", "running")
   281  
   282  	options := types.TaskListOptions{
   283  		Filters: filterArgs,
   284  	}
   285  
   286  	tasks, err := cli.TaskList(context.Background(), options)
   287  	c.Assert(err, checker.IsNil)
   288  
   289  	result := make(map[string]int)
   290  	for _, task := range tasks {
   291  		for _, network := range task.Spec.Networks {
   292  			result[network.Target]++
   293  		}
   294  	}
   295  	return result, nil
   296  }
   297  
   298  // CheckRunningTaskImages returns the times each image is running as a task.
   299  func (d *Swarm) CheckRunningTaskImages(c *check.C) (interface{}, check.CommentInterface) {
   300  	cli, err := d.NewClient()
   301  	c.Assert(err, checker.IsNil)
   302  	defer cli.Close()
   303  
   304  	filterArgs := filters.NewArgs()
   305  	filterArgs.Add("desired-state", "running")
   306  
   307  	options := types.TaskListOptions{
   308  		Filters: filterArgs,
   309  	}
   310  
   311  	tasks, err := cli.TaskList(context.Background(), options)
   312  	c.Assert(err, checker.IsNil)
   313  
   314  	result := make(map[string]int)
   315  	for _, task := range tasks {
   316  		if task.Status.State == swarm.TaskStateRunning && task.Spec.ContainerSpec != nil {
   317  			result[task.Spec.ContainerSpec.Image]++
   318  		}
   319  	}
   320  	return result, nil
   321  }
   322  
   323  // CheckNodeReadyCount returns the number of ready node on the swarm
   324  func (d *Swarm) CheckNodeReadyCount(c *check.C) (interface{}, check.CommentInterface) {
   325  	nodes := d.ListNodes(c)
   326  	var readyCount int
   327  	for _, node := range nodes {
   328  		if node.Status.State == swarm.NodeStateReady {
   329  			readyCount++
   330  		}
   331  	}
   332  	return readyCount, nil
   333  }
   334  
   335  // GetTask returns the swarm task identified by the specified id
   336  func (d *Swarm) GetTask(c *check.C, id string) swarm.Task {
   337  	cli, err := d.NewClient()
   338  	c.Assert(err, checker.IsNil)
   339  	defer cli.Close()
   340  
   341  	task, _, err := cli.TaskInspectWithRaw(context.Background(), id)
   342  	c.Assert(err, checker.IsNil)
   343  	return task
   344  }
   345  
   346  // UpdateService updates a swarm service with the specified service constructor
   347  func (d *Swarm) UpdateService(c *check.C, service *swarm.Service, f ...ServiceConstructor) {
   348  	cli, err := d.NewClient()
   349  	c.Assert(err, checker.IsNil)
   350  	defer cli.Close()
   351  
   352  	for _, fn := range f {
   353  		fn(service)
   354  	}
   355  
   356  	_, err = cli.ServiceUpdate(context.Background(), service.ID, service.Version, service.Spec, types.ServiceUpdateOptions{})
   357  	c.Assert(err, checker.IsNil)
   358  }
   359  
   360  // RemoveService removes the specified service
   361  func (d *Swarm) RemoveService(c *check.C, id string) {
   362  	cli, err := d.NewClient()
   363  	c.Assert(err, checker.IsNil)
   364  	defer cli.Close()
   365  
   366  	err = cli.ServiceRemove(context.Background(), id)
   367  	c.Assert(err, checker.IsNil)
   368  }
   369  
   370  // GetNode returns a swarm node identified by the specified id
   371  func (d *Swarm) GetNode(c *check.C, id string) *swarm.Node {
   372  	cli, err := d.NewClient()
   373  	c.Assert(err, checker.IsNil)
   374  	defer cli.Close()
   375  
   376  	node, _, err := cli.NodeInspectWithRaw(context.Background(), id)
   377  	c.Assert(err, checker.IsNil)
   378  	c.Assert(node.ID, checker.Equals, id)
   379  	return &node
   380  }
   381  
   382  // RemoveNode removes the specified node
   383  func (d *Swarm) RemoveNode(c *check.C, id string, force bool) {
   384  	cli, err := d.NewClient()
   385  	c.Assert(err, checker.IsNil)
   386  	defer cli.Close()
   387  
   388  	options := types.NodeRemoveOptions{
   389  		Force: force,
   390  	}
   391  	err = cli.NodeRemove(context.Background(), id, options)
   392  	c.Assert(err, checker.IsNil)
   393  }
   394  
   395  // UpdateNode updates a swarm node with the specified node constructor
   396  func (d *Swarm) UpdateNode(c *check.C, id string, f ...NodeConstructor) {
   397  	cli, err := d.NewClient()
   398  	c.Assert(err, checker.IsNil)
   399  	defer cli.Close()
   400  
   401  	for i := 0; ; i++ {
   402  		node := d.GetNode(c, id)
   403  		for _, fn := range f {
   404  			fn(node)
   405  		}
   406  
   407  		err = cli.NodeUpdate(context.Background(), node.ID, node.Version, node.Spec)
   408  		if i < 10 && err != nil && strings.Contains(err.Error(), "update out of sequence") {
   409  			time.Sleep(100 * time.Millisecond)
   410  			continue
   411  		}
   412  		c.Assert(err, checker.IsNil)
   413  		return
   414  	}
   415  }
   416  
   417  // ListNodes returns the list of the current swarm nodes
   418  func (d *Swarm) ListNodes(c *check.C) []swarm.Node {
   419  	cli, err := d.NewClient()
   420  	c.Assert(err, checker.IsNil)
   421  	defer cli.Close()
   422  
   423  	nodes, err := cli.NodeList(context.Background(), types.NodeListOptions{})
   424  	c.Assert(err, checker.IsNil)
   425  
   426  	return nodes
   427  }
   428  
   429  // ListServices returns the list of the current swarm services
   430  func (d *Swarm) ListServices(c *check.C) []swarm.Service {
   431  	cli, err := d.NewClient()
   432  	c.Assert(err, checker.IsNil)
   433  	defer cli.Close()
   434  
   435  	services, err := cli.ServiceList(context.Background(), types.ServiceListOptions{})
   436  	c.Assert(err, checker.IsNil)
   437  	return services
   438  }
   439  
   440  // CreateSecret creates a secret given the specified spec
   441  func (d *Swarm) CreateSecret(c *check.C, secretSpec swarm.SecretSpec) string {
   442  	cli, err := d.NewClient()
   443  	c.Assert(err, checker.IsNil)
   444  	defer cli.Close()
   445  
   446  	scr, err := cli.SecretCreate(context.Background(), secretSpec)
   447  	c.Assert(err, checker.IsNil)
   448  
   449  	return scr.ID
   450  }
   451  
   452  // ListSecrets returns the list of the current swarm secrets
   453  func (d *Swarm) ListSecrets(c *check.C) []swarm.Secret {
   454  	cli, err := d.NewClient()
   455  	c.Assert(err, checker.IsNil)
   456  	defer cli.Close()
   457  
   458  	secrets, err := cli.SecretList(context.Background(), types.SecretListOptions{})
   459  	c.Assert(err, checker.IsNil)
   460  	return secrets
   461  }
   462  
   463  // GetSecret returns a swarm secret identified by the specified id
   464  func (d *Swarm) GetSecret(c *check.C, id string) *swarm.Secret {
   465  	cli, err := d.NewClient()
   466  	c.Assert(err, checker.IsNil)
   467  	defer cli.Close()
   468  
   469  	secret, _, err := cli.SecretInspectWithRaw(context.Background(), id)
   470  	c.Assert(err, checker.IsNil)
   471  	return &secret
   472  }
   473  
   474  // DeleteSecret removes the swarm secret identified by the specified id
   475  func (d *Swarm) DeleteSecret(c *check.C, id string) {
   476  	cli, err := d.NewClient()
   477  	c.Assert(err, checker.IsNil)
   478  	defer cli.Close()
   479  
   480  	err = cli.SecretRemove(context.Background(), id)
   481  	c.Assert(err, checker.IsNil)
   482  }
   483  
   484  // UpdateSecret updates the swarm secret identified by the specified id
   485  // Currently, only label update is supported.
   486  func (d *Swarm) UpdateSecret(c *check.C, id string, f ...SecretConstructor) {
   487  	cli, err := d.NewClient()
   488  	c.Assert(err, checker.IsNil)
   489  	defer cli.Close()
   490  
   491  	secret := d.GetSecret(c, id)
   492  	for _, fn := range f {
   493  		fn(secret)
   494  	}
   495  
   496  	err = cli.SecretUpdate(context.Background(), secret.ID, secret.Version, secret.Spec)
   497  
   498  	c.Assert(err, checker.IsNil)
   499  }
   500  
   501  // CreateConfig creates a config given the specified spec
   502  func (d *Swarm) CreateConfig(c *check.C, configSpec swarm.ConfigSpec) string {
   503  	cli, err := d.NewClient()
   504  	c.Assert(err, checker.IsNil)
   505  	defer cli.Close()
   506  
   507  	scr, err := cli.ConfigCreate(context.Background(), configSpec)
   508  	c.Assert(err, checker.IsNil)
   509  	return scr.ID
   510  }
   511  
   512  // ListConfigs returns the list of the current swarm configs
   513  func (d *Swarm) ListConfigs(c *check.C) []swarm.Config {
   514  	cli, err := d.NewClient()
   515  	c.Assert(err, checker.IsNil)
   516  	defer cli.Close()
   517  
   518  	configs, err := cli.ConfigList(context.Background(), types.ConfigListOptions{})
   519  	c.Assert(err, checker.IsNil)
   520  	return configs
   521  }
   522  
   523  // GetConfig returns a swarm config identified by the specified id
   524  func (d *Swarm) GetConfig(c *check.C, id string) *swarm.Config {
   525  	cli, err := d.NewClient()
   526  	c.Assert(err, checker.IsNil)
   527  	defer cli.Close()
   528  
   529  	config, _, err := cli.ConfigInspectWithRaw(context.Background(), id)
   530  	c.Assert(err, checker.IsNil)
   531  	return &config
   532  }
   533  
   534  // DeleteConfig removes the swarm config identified by the specified id
   535  func (d *Swarm) DeleteConfig(c *check.C, id string) {
   536  	cli, err := d.NewClient()
   537  	c.Assert(err, checker.IsNil)
   538  	defer cli.Close()
   539  
   540  	err = cli.ConfigRemove(context.Background(), id)
   541  	c.Assert(err, checker.IsNil)
   542  }
   543  
   544  // UpdateConfig updates the swarm config identified by the specified id
   545  // Currently, only label update is supported.
   546  func (d *Swarm) UpdateConfig(c *check.C, id string, f ...ConfigConstructor) {
   547  	cli, err := d.NewClient()
   548  	c.Assert(err, checker.IsNil)
   549  	defer cli.Close()
   550  
   551  	config := d.GetConfig(c, id)
   552  	for _, fn := range f {
   553  		fn(config)
   554  	}
   555  
   556  	err = cli.ConfigUpdate(context.Background(), config.ID, config.Version, config.Spec)
   557  	c.Assert(err, checker.IsNil)
   558  }
   559  
   560  // GetSwarm returns the current swarm object
   561  func (d *Swarm) GetSwarm(c *check.C) swarm.Swarm {
   562  	cli, err := d.NewClient()
   563  	c.Assert(err, checker.IsNil)
   564  	defer cli.Close()
   565  
   566  	sw, err := cli.SwarmInspect(context.Background())
   567  	c.Assert(err, checker.IsNil)
   568  	return sw
   569  }
   570  
   571  // UpdateSwarm updates the current swarm object with the specified spec constructors
   572  func (d *Swarm) UpdateSwarm(c *check.C, f ...SpecConstructor) {
   573  	cli, err := d.NewClient()
   574  	c.Assert(err, checker.IsNil)
   575  	defer cli.Close()
   576  
   577  	sw := d.GetSwarm(c)
   578  	for _, fn := range f {
   579  		fn(&sw.Spec)
   580  	}
   581  
   582  	err = cli.SwarmUpdate(context.Background(), sw.Version, sw.Spec, swarm.UpdateFlags{})
   583  	c.Assert(err, checker.IsNil)
   584  }
   585  
   586  // RotateTokens update the swarm to rotate tokens
   587  func (d *Swarm) RotateTokens(c *check.C) {
   588  	cli, err := d.NewClient()
   589  	c.Assert(err, checker.IsNil)
   590  	defer cli.Close()
   591  
   592  	sw, err := cli.SwarmInspect(context.Background())
   593  	c.Assert(err, checker.IsNil)
   594  
   595  	flags := swarm.UpdateFlags{
   596  		RotateManagerToken: true,
   597  		RotateWorkerToken:  true,
   598  	}
   599  
   600  	err = cli.SwarmUpdate(context.Background(), sw.Version, sw.Spec, flags)
   601  	c.Assert(err, checker.IsNil)
   602  }
   603  
   604  // JoinTokens returns the current swarm join tokens
   605  func (d *Swarm) JoinTokens(c *check.C) swarm.JoinTokens {
   606  	cli, err := d.NewClient()
   607  	c.Assert(err, checker.IsNil)
   608  	defer cli.Close()
   609  
   610  	sw, err := cli.SwarmInspect(context.Background())
   611  	c.Assert(err, checker.IsNil)
   612  	return sw.JoinTokens
   613  }
   614  
   615  // CheckLocalNodeState returns the current swarm node state
   616  func (d *Swarm) CheckLocalNodeState(c *check.C) (interface{}, check.CommentInterface) {
   617  	info, err := d.SwarmInfo()
   618  	c.Assert(err, checker.IsNil)
   619  	return info.LocalNodeState, nil
   620  }
   621  
   622  // CheckControlAvailable returns the current swarm control available
   623  func (d *Swarm) CheckControlAvailable(c *check.C) (interface{}, check.CommentInterface) {
   624  	info, err := d.SwarmInfo()
   625  	c.Assert(err, checker.IsNil)
   626  	c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
   627  	return info.ControlAvailable, nil
   628  }
   629  
   630  // CheckLeader returns whether there is a leader on the swarm or not
   631  func (d *Swarm) CheckLeader(c *check.C) (interface{}, check.CommentInterface) {
   632  	cli, err := d.NewClient()
   633  	c.Assert(err, checker.IsNil)
   634  	defer cli.Close()
   635  
   636  	errList := check.Commentf("could not get node list")
   637  
   638  	ls, err := cli.NodeList(context.Background(), types.NodeListOptions{})
   639  	if err != nil {
   640  		return err, errList
   641  	}
   642  
   643  	for _, node := range ls {
   644  		if node.ManagerStatus != nil && node.ManagerStatus.Leader {
   645  			return nil, nil
   646  		}
   647  	}
   648  	return fmt.Errorf("no leader"), check.Commentf("could not find leader")
   649  }
   650  
   651  // CmdRetryOutOfSequence tries the specified command against the current daemon for 10 times
   652  func (d *Swarm) CmdRetryOutOfSequence(args ...string) (string, error) {
   653  	for i := 0; ; i++ {
   654  		out, err := d.Cmd(args...)
   655  		if err != nil {
   656  			if strings.Contains(out, "update out of sequence") {
   657  				if i < 10 {
   658  					continue
   659  				}
   660  			}
   661  		}
   662  		return out, err
   663  	}
   664  }