github.com/demonoid81/moby@v0.0.0-20200517203328-62dd8e17c460/testutil/daemon/swarm.go (about) 1 package daemon 2 3 import ( 4 "context" 5 "fmt" 6 "testing" 7 8 "github.com/demonoid81/moby/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 }