github.com/docker/docker@v299999999.0.0-20200612211812-aaf470eca7b5+incompatible/testutil/daemon/swarm.go (about)

     1  package daemon
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"testing"
     7  
     8  	"github.com/docker/docker/api/types/swarm"
     9  	"github.com/pkg/errors"
    10  	"gotest.tools/v3/assert"
    11  )
    12  
    13  const (
    14  	// DefaultSwarmPort is the default port use for swarm in the tests
    15  	DefaultSwarmPort       = 2477
    16  	defaultSwarmListenAddr = "0.0.0.0"
    17  )
    18  
    19  var (
    20  	startArgs = []string{"--iptables=false", "--swarm-default-advertise-addr=lo"}
    21  )
    22  
    23  // StartNode (re)starts the daemon
    24  func (d *Daemon) StartNode(t testing.TB) {
    25  	t.Helper()
    26  	d.Start(t, startArgs...)
    27  }
    28  
    29  // StartNodeWithBusybox starts daemon to be used as a swarm node, and loads the busybox image
    30  func (d *Daemon) StartNodeWithBusybox(t testing.TB) {
    31  	t.Helper()
    32  	d.StartWithBusybox(t, startArgs...)
    33  }
    34  
    35  // RestartNode restarts a daemon to be used as a swarm node
    36  func (d *Daemon) RestartNode(t testing.TB) {
    37  	t.Helper()
    38  	// avoid networking conflicts
    39  	d.Stop(t)
    40  	d.Start(t, startArgs...)
    41  }
    42  
    43  // StartAndSwarmInit starts the daemon (with busybox) and init the swarm
    44  func (d *Daemon) StartAndSwarmInit(t testing.TB) {
    45  	d.StartNodeWithBusybox(t)
    46  	d.SwarmInit(t, swarm.InitRequest{})
    47  }
    48  
    49  // StartAndSwarmJoin starts the daemon (with busybox) and join the specified swarm as worker or manager
    50  func (d *Daemon) StartAndSwarmJoin(t testing.TB, leader *Daemon, manager bool) {
    51  	t.Helper()
    52  	d.StartNodeWithBusybox(t)
    53  
    54  	tokens := leader.JoinTokens(t)
    55  	token := tokens.Worker
    56  	if manager {
    57  		token = tokens.Manager
    58  	}
    59  	t.Logf("[%s] joining swarm manager [%s]@%s, swarm listen addr %s", d.id, leader.id, leader.SwarmListenAddr(), d.SwarmListenAddr())
    60  	d.SwarmJoin(t, swarm.JoinRequest{
    61  		RemoteAddrs: []string{leader.SwarmListenAddr()},
    62  		JoinToken:   token,
    63  	})
    64  }
    65  
    66  // SpecConstructor defines a swarm spec constructor
    67  type SpecConstructor func(*swarm.Spec)
    68  
    69  // SwarmListenAddr returns the listen-addr used for the daemon
    70  func (d *Daemon) SwarmListenAddr() string {
    71  	return fmt.Sprintf("%s:%d", d.swarmListenAddr, d.SwarmPort)
    72  }
    73  
    74  // NodeID returns the swarm mode node ID
    75  func (d *Daemon) NodeID() string {
    76  	return d.CachedInfo.Swarm.NodeID
    77  }
    78  
    79  // SwarmInit initializes a new swarm cluster.
    80  func (d *Daemon) SwarmInit(t testing.TB, req swarm.InitRequest) {
    81  	t.Helper()
    82  	if req.ListenAddr == "" {
    83  		req.ListenAddr = fmt.Sprintf("%s:%d", d.swarmListenAddr, d.SwarmPort)
    84  	}
    85  	if req.DefaultAddrPool == nil {
    86  		req.DefaultAddrPool = d.DefaultAddrPool
    87  		req.SubnetSize = d.SubnetSize
    88  	}
    89  	if d.DataPathPort > 0 {
    90  		req.DataPathPort = d.DataPathPort
    91  	}
    92  	cli := d.NewClientT(t)
    93  	defer cli.Close()
    94  	_, err := cli.SwarmInit(context.Background(), req)
    95  	assert.NilError(t, err, "initializing swarm")
    96  	d.CachedInfo = d.Info(t)
    97  }
    98  
    99  // SwarmJoin joins a daemon to an existing cluster.
   100  func (d *Daemon) SwarmJoin(t testing.TB, req swarm.JoinRequest) {
   101  	t.Helper()
   102  	if req.ListenAddr == "" {
   103  		req.ListenAddr = fmt.Sprintf("%s:%d", d.swarmListenAddr, d.SwarmPort)
   104  	}
   105  	cli := d.NewClientT(t)
   106  	defer cli.Close()
   107  	err := cli.SwarmJoin(context.Background(), req)
   108  	assert.NilError(t, err, "[%s] joining swarm", d.id)
   109  	d.CachedInfo = d.Info(t)
   110  }
   111  
   112  // SwarmLeave forces daemon to leave current cluster.
   113  //
   114  // The passed in testing.TB is only used to validate that the client was successfully created
   115  // Some tests rely on error checking the result of the actual unlock, so allow
   116  // the error to be returned.
   117  func (d *Daemon) SwarmLeave(t testing.TB, force bool) error {
   118  	cli := d.NewClientT(t)
   119  	defer cli.Close()
   120  	return cli.SwarmLeave(context.Background(), force)
   121  }
   122  
   123  // SwarmInfo returns the swarm information of the daemon
   124  func (d *Daemon) SwarmInfo(t testing.TB) swarm.Info {
   125  	t.Helper()
   126  	cli := d.NewClientT(t)
   127  	info, err := cli.Info(context.Background())
   128  	assert.NilError(t, err, "get swarm info")
   129  	return info.Swarm
   130  }
   131  
   132  // SwarmUnlock tries to unlock a locked swarm
   133  //
   134  // The passed in testing.TB is only used to validate that the client was successfully created
   135  // Some tests rely on error checking the result of the actual unlock, so allow
   136  // the error to be returned.
   137  func (d *Daemon) SwarmUnlock(t testing.TB, req swarm.UnlockRequest) error {
   138  	cli := d.NewClientT(t)
   139  	defer cli.Close()
   140  
   141  	err := cli.SwarmUnlock(context.Background(), req)
   142  	if err != nil {
   143  		err = errors.Wrap(err, "unlocking swarm")
   144  	}
   145  	return err
   146  }
   147  
   148  // GetSwarm returns the current swarm object
   149  func (d *Daemon) GetSwarm(t testing.TB) swarm.Swarm {
   150  	t.Helper()
   151  	cli := d.NewClientT(t)
   152  	defer cli.Close()
   153  
   154  	sw, err := cli.SwarmInspect(context.Background())
   155  	assert.NilError(t, err)
   156  	return sw
   157  }
   158  
   159  // UpdateSwarm updates the current swarm object with the specified spec constructors
   160  func (d *Daemon) UpdateSwarm(t testing.TB, f ...SpecConstructor) {
   161  	t.Helper()
   162  	cli := d.NewClientT(t)
   163  	defer cli.Close()
   164  
   165  	sw := d.GetSwarm(t)
   166  	for _, fn := range f {
   167  		fn(&sw.Spec)
   168  	}
   169  
   170  	err := cli.SwarmUpdate(context.Background(), sw.Version, sw.Spec, swarm.UpdateFlags{})
   171  	assert.NilError(t, err)
   172  }
   173  
   174  // RotateTokens update the swarm to rotate tokens
   175  func (d *Daemon) RotateTokens(t testing.TB) {
   176  	t.Helper()
   177  	cli := d.NewClientT(t)
   178  	defer cli.Close()
   179  
   180  	sw, err := cli.SwarmInspect(context.Background())
   181  	assert.NilError(t, err)
   182  
   183  	flags := swarm.UpdateFlags{
   184  		RotateManagerToken: true,
   185  		RotateWorkerToken:  true,
   186  	}
   187  
   188  	err = cli.SwarmUpdate(context.Background(), sw.Version, sw.Spec, flags)
   189  	assert.NilError(t, err)
   190  }
   191  
   192  // JoinTokens returns the current swarm join tokens
   193  func (d *Daemon) JoinTokens(t testing.TB) swarm.JoinTokens {
   194  	t.Helper()
   195  	cli := d.NewClientT(t)
   196  	defer cli.Close()
   197  
   198  	sw, err := cli.SwarmInspect(context.Background())
   199  	assert.NilError(t, err)
   200  	return sw.JoinTokens
   201  }