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