swarm.go 5.4 KB

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