docker_api_swarm_test.go 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932
  1. // +build !windows
  2. package main
  3. import (
  4. "encoding/json"
  5. "fmt"
  6. "io/ioutil"
  7. "net"
  8. "net/http"
  9. "os"
  10. "path/filepath"
  11. "strings"
  12. "sync"
  13. "time"
  14. "github.com/cloudflare/cfssl/helpers"
  15. "github.com/docker/docker/api/types"
  16. "github.com/docker/docker/api/types/container"
  17. "github.com/docker/docker/api/types/swarm"
  18. "github.com/docker/docker/integration-cli/checker"
  19. "github.com/docker/docker/integration-cli/daemon"
  20. "github.com/go-check/check"
  21. )
  22. var defaultReconciliationTimeout = 30 * time.Second
  23. func (s *DockerSwarmSuite) TestAPISwarmInit(c *check.C) {
  24. // todo: should find a better way to verify that components are running than /info
  25. d1 := s.AddDaemon(c, true, true)
  26. info, err := d1.SwarmInfo()
  27. c.Assert(err, checker.IsNil)
  28. c.Assert(info.ControlAvailable, checker.True)
  29. c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
  30. c.Assert(info.Cluster.RootRotationInProgress, checker.False)
  31. d2 := s.AddDaemon(c, true, false)
  32. info, err = d2.SwarmInfo()
  33. c.Assert(err, checker.IsNil)
  34. c.Assert(info.ControlAvailable, checker.False)
  35. c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
  36. // Leaving cluster
  37. c.Assert(d2.Leave(false), checker.IsNil)
  38. info, err = d2.SwarmInfo()
  39. c.Assert(err, checker.IsNil)
  40. c.Assert(info.ControlAvailable, checker.False)
  41. c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateInactive)
  42. c.Assert(d2.Join(swarm.JoinRequest{JoinToken: d1.JoinTokens(c).Worker, RemoteAddrs: []string{d1.ListenAddr}}), checker.IsNil)
  43. info, err = d2.SwarmInfo()
  44. c.Assert(err, checker.IsNil)
  45. c.Assert(info.ControlAvailable, checker.False)
  46. c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
  47. // Current state restoring after restarts
  48. d1.Stop(c)
  49. d2.Stop(c)
  50. d1.Start(c)
  51. d2.Start(c)
  52. info, err = d1.SwarmInfo()
  53. c.Assert(err, checker.IsNil)
  54. c.Assert(info.ControlAvailable, checker.True)
  55. c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
  56. info, err = d2.SwarmInfo()
  57. c.Assert(err, checker.IsNil)
  58. c.Assert(info.ControlAvailable, checker.False)
  59. c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
  60. }
  61. func (s *DockerSwarmSuite) TestAPISwarmJoinToken(c *check.C) {
  62. d1 := s.AddDaemon(c, false, false)
  63. c.Assert(d1.Init(swarm.InitRequest{}), checker.IsNil)
  64. // todo: error message differs depending if some components of token are valid
  65. d2 := s.AddDaemon(c, false, false)
  66. err := d2.Join(swarm.JoinRequest{RemoteAddrs: []string{d1.ListenAddr}})
  67. c.Assert(err, checker.NotNil)
  68. c.Assert(err.Error(), checker.Contains, "join token is necessary")
  69. info, err := d2.SwarmInfo()
  70. c.Assert(err, checker.IsNil)
  71. c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateInactive)
  72. err = d2.Join(swarm.JoinRequest{JoinToken: "foobaz", RemoteAddrs: []string{d1.ListenAddr}})
  73. c.Assert(err, checker.NotNil)
  74. c.Assert(err.Error(), checker.Contains, "invalid join token")
  75. info, err = d2.SwarmInfo()
  76. c.Assert(err, checker.IsNil)
  77. c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateInactive)
  78. workerToken := d1.JoinTokens(c).Worker
  79. c.Assert(d2.Join(swarm.JoinRequest{JoinToken: workerToken, RemoteAddrs: []string{d1.ListenAddr}}), checker.IsNil)
  80. info, err = d2.SwarmInfo()
  81. c.Assert(err, checker.IsNil)
  82. c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
  83. c.Assert(d2.Leave(false), checker.IsNil)
  84. info, err = d2.SwarmInfo()
  85. c.Assert(err, checker.IsNil)
  86. c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateInactive)
  87. // change tokens
  88. d1.RotateTokens(c)
  89. err = d2.Join(swarm.JoinRequest{JoinToken: workerToken, RemoteAddrs: []string{d1.ListenAddr}})
  90. c.Assert(err, checker.NotNil)
  91. c.Assert(err.Error(), checker.Contains, "join token is necessary")
  92. info, err = d2.SwarmInfo()
  93. c.Assert(err, checker.IsNil)
  94. c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateInactive)
  95. workerToken = d1.JoinTokens(c).Worker
  96. c.Assert(d2.Join(swarm.JoinRequest{JoinToken: workerToken, RemoteAddrs: []string{d1.ListenAddr}}), checker.IsNil)
  97. info, err = d2.SwarmInfo()
  98. c.Assert(err, checker.IsNil)
  99. c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
  100. c.Assert(d2.Leave(false), checker.IsNil)
  101. info, err = d2.SwarmInfo()
  102. c.Assert(err, checker.IsNil)
  103. c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateInactive)
  104. // change spec, don't change tokens
  105. d1.UpdateSwarm(c, func(s *swarm.Spec) {})
  106. err = d2.Join(swarm.JoinRequest{RemoteAddrs: []string{d1.ListenAddr}})
  107. c.Assert(err, checker.NotNil)
  108. c.Assert(err.Error(), checker.Contains, "join token is necessary")
  109. info, err = d2.SwarmInfo()
  110. c.Assert(err, checker.IsNil)
  111. c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateInactive)
  112. c.Assert(d2.Join(swarm.JoinRequest{JoinToken: workerToken, RemoteAddrs: []string{d1.ListenAddr}}), checker.IsNil)
  113. info, err = d2.SwarmInfo()
  114. c.Assert(err, checker.IsNil)
  115. c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
  116. c.Assert(d2.Leave(false), checker.IsNil)
  117. info, err = d2.SwarmInfo()
  118. c.Assert(err, checker.IsNil)
  119. c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateInactive)
  120. }
  121. func (s *DockerSwarmSuite) TestUpdateSwarmAddExternalCA(c *check.C) {
  122. d1 := s.AddDaemon(c, false, false)
  123. c.Assert(d1.Init(swarm.InitRequest{}), checker.IsNil)
  124. d1.UpdateSwarm(c, func(s *swarm.Spec) {
  125. s.CAConfig.ExternalCAs = []*swarm.ExternalCA{
  126. {
  127. Protocol: swarm.ExternalCAProtocolCFSSL,
  128. URL: "https://thishasnoca.org",
  129. },
  130. {
  131. Protocol: swarm.ExternalCAProtocolCFSSL,
  132. URL: "https://thishasacacert.org",
  133. CACert: "cacert",
  134. },
  135. }
  136. })
  137. info, err := d1.SwarmInfo()
  138. c.Assert(err, checker.IsNil)
  139. c.Assert(info.Cluster.Spec.CAConfig.ExternalCAs, checker.HasLen, 2)
  140. c.Assert(info.Cluster.Spec.CAConfig.ExternalCAs[0].CACert, checker.Equals, "")
  141. c.Assert(info.Cluster.Spec.CAConfig.ExternalCAs[1].CACert, checker.Equals, "cacert")
  142. }
  143. func (s *DockerSwarmSuite) TestAPISwarmCAHash(c *check.C) {
  144. d1 := s.AddDaemon(c, true, true)
  145. d2 := s.AddDaemon(c, false, false)
  146. splitToken := strings.Split(d1.JoinTokens(c).Worker, "-")
  147. splitToken[2] = "1kxftv4ofnc6mt30lmgipg6ngf9luhwqopfk1tz6bdmnkubg0e"
  148. replacementToken := strings.Join(splitToken, "-")
  149. err := d2.Join(swarm.JoinRequest{JoinToken: replacementToken, RemoteAddrs: []string{d1.ListenAddr}})
  150. c.Assert(err, checker.NotNil)
  151. c.Assert(err.Error(), checker.Contains, "remote CA does not match fingerprint")
  152. }
  153. func (s *DockerSwarmSuite) TestAPISwarmPromoteDemote(c *check.C) {
  154. d1 := s.AddDaemon(c, false, false)
  155. c.Assert(d1.Init(swarm.InitRequest{}), checker.IsNil)
  156. d2 := s.AddDaemon(c, true, false)
  157. info, err := d2.SwarmInfo()
  158. c.Assert(err, checker.IsNil)
  159. c.Assert(info.ControlAvailable, checker.False)
  160. c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
  161. d1.UpdateNode(c, d2.NodeID, func(n *swarm.Node) {
  162. n.Spec.Role = swarm.NodeRoleManager
  163. })
  164. waitAndAssert(c, defaultReconciliationTimeout, d2.CheckControlAvailable, checker.True)
  165. d1.UpdateNode(c, d2.NodeID, func(n *swarm.Node) {
  166. n.Spec.Role = swarm.NodeRoleWorker
  167. })
  168. waitAndAssert(c, defaultReconciliationTimeout, d2.CheckControlAvailable, checker.False)
  169. // Wait for the role to change to worker in the cert. This is partially
  170. // done because it's something worth testing in its own right, and
  171. // partially because changing the role from manager to worker and then
  172. // back to manager quickly might cause the node to pause for awhile
  173. // while waiting for the role to change to worker, and the test can
  174. // time out during this interval.
  175. waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
  176. certBytes, err := ioutil.ReadFile(filepath.Join(d2.Folder, "root", "swarm", "certificates", "swarm-node.crt"))
  177. if err != nil {
  178. return "", check.Commentf("error: %v", err)
  179. }
  180. certs, err := helpers.ParseCertificatesPEM(certBytes)
  181. if err == nil && len(certs) > 0 && len(certs[0].Subject.OrganizationalUnit) > 0 {
  182. return certs[0].Subject.OrganizationalUnit[0], nil
  183. }
  184. return "", check.Commentf("could not get organizational unit from certificate")
  185. }, checker.Equals, "swarm-worker")
  186. // Demoting last node should fail
  187. node := d1.GetNode(c, d1.NodeID)
  188. node.Spec.Role = swarm.NodeRoleWorker
  189. url := fmt.Sprintf("/nodes/%s/update?version=%d", node.ID, node.Version.Index)
  190. status, out, err := d1.SockRequest("POST", url, node.Spec)
  191. c.Assert(err, checker.IsNil)
  192. c.Assert(status, checker.Equals, http.StatusInternalServerError, check.Commentf("output: %q", string(out)))
  193. // The warning specific to demoting the last manager is best-effort and
  194. // won't appear until the Role field of the demoted manager has been
  195. // updated.
  196. // Yes, I know this looks silly, but checker.Matches is broken, since
  197. // it anchors the regexp contrary to the documentation, and this makes
  198. // it impossible to match something that includes a line break.
  199. if !strings.Contains(string(out), "last manager of the swarm") {
  200. c.Assert(string(out), checker.Contains, "this would result in a loss of quorum")
  201. }
  202. info, err = d1.SwarmInfo()
  203. c.Assert(err, checker.IsNil)
  204. c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
  205. c.Assert(info.ControlAvailable, checker.True)
  206. // Promote already demoted node
  207. d1.UpdateNode(c, d2.NodeID, func(n *swarm.Node) {
  208. n.Spec.Role = swarm.NodeRoleManager
  209. })
  210. waitAndAssert(c, defaultReconciliationTimeout, d2.CheckControlAvailable, checker.True)
  211. }
  212. func (s *DockerSwarmSuite) TestAPISwarmLeaderProxy(c *check.C) {
  213. // add three managers, one of these is leader
  214. d1 := s.AddDaemon(c, true, true)
  215. d2 := s.AddDaemon(c, true, true)
  216. d3 := s.AddDaemon(c, true, true)
  217. // start a service by hitting each of the 3 managers
  218. d1.CreateService(c, simpleTestService, func(s *swarm.Service) {
  219. s.Spec.Name = "test1"
  220. })
  221. d2.CreateService(c, simpleTestService, func(s *swarm.Service) {
  222. s.Spec.Name = "test2"
  223. })
  224. d3.CreateService(c, simpleTestService, func(s *swarm.Service) {
  225. s.Spec.Name = "test3"
  226. })
  227. // 3 services should be started now, because the requests were proxied to leader
  228. // query each node and make sure it returns 3 services
  229. for _, d := range []*daemon.Swarm{d1, d2, d3} {
  230. services := d.ListServices(c)
  231. c.Assert(services, checker.HasLen, 3)
  232. }
  233. }
  234. func (s *DockerSwarmSuite) TestAPISwarmLeaderElection(c *check.C) {
  235. // Create 3 nodes
  236. d1 := s.AddDaemon(c, true, true)
  237. d2 := s.AddDaemon(c, true, true)
  238. d3 := s.AddDaemon(c, true, true)
  239. // assert that the first node we made is the leader, and the other two are followers
  240. c.Assert(d1.GetNode(c, d1.NodeID).ManagerStatus.Leader, checker.True)
  241. c.Assert(d1.GetNode(c, d2.NodeID).ManagerStatus.Leader, checker.False)
  242. c.Assert(d1.GetNode(c, d3.NodeID).ManagerStatus.Leader, checker.False)
  243. d1.Stop(c)
  244. var (
  245. leader *daemon.Swarm // keep track of leader
  246. followers []*daemon.Swarm // keep track of followers
  247. )
  248. checkLeader := func(nodes ...*daemon.Swarm) checkF {
  249. return func(c *check.C) (interface{}, check.CommentInterface) {
  250. // clear these out before each run
  251. leader = nil
  252. followers = nil
  253. for _, d := range nodes {
  254. if d.GetNode(c, d.NodeID).ManagerStatus.Leader {
  255. leader = d
  256. } else {
  257. followers = append(followers, d)
  258. }
  259. }
  260. if leader == nil {
  261. return false, check.Commentf("no leader elected")
  262. }
  263. return true, check.Commentf("elected %v", leader.ID())
  264. }
  265. }
  266. // wait for an election to occur
  267. waitAndAssert(c, defaultReconciliationTimeout, checkLeader(d2, d3), checker.True)
  268. // assert that we have a new leader
  269. c.Assert(leader, checker.NotNil)
  270. // Keep track of the current leader, since we want that to be chosen.
  271. stableleader := leader
  272. // add the d1, the initial leader, back
  273. d1.Start(c)
  274. // TODO(stevvooe): may need to wait for rejoin here
  275. // wait for possible election
  276. waitAndAssert(c, defaultReconciliationTimeout, checkLeader(d1, d2, d3), checker.True)
  277. // pick out the leader and the followers again
  278. // verify that we still only have 1 leader and 2 followers
  279. c.Assert(leader, checker.NotNil)
  280. c.Assert(followers, checker.HasLen, 2)
  281. // and that after we added d1 back, the leader hasn't changed
  282. c.Assert(leader.NodeID, checker.Equals, stableleader.NodeID)
  283. }
  284. func (s *DockerSwarmSuite) TestAPISwarmRaftQuorum(c *check.C) {
  285. d1 := s.AddDaemon(c, true, true)
  286. d2 := s.AddDaemon(c, true, true)
  287. d3 := s.AddDaemon(c, true, true)
  288. d1.CreateService(c, simpleTestService)
  289. d2.Stop(c)
  290. // make sure there is a leader
  291. waitAndAssert(c, defaultReconciliationTimeout, d1.CheckLeader, checker.IsNil)
  292. d1.CreateService(c, simpleTestService, func(s *swarm.Service) {
  293. s.Spec.Name = "top1"
  294. })
  295. d3.Stop(c)
  296. var service swarm.Service
  297. simpleTestService(&service)
  298. service.Spec.Name = "top2"
  299. status, out, err := d1.SockRequest("POST", "/services/create", service.Spec)
  300. c.Assert(err, checker.IsNil)
  301. c.Assert(status, checker.Equals, http.StatusInternalServerError, check.Commentf("deadline exceeded", string(out)))
  302. d2.Start(c)
  303. // make sure there is a leader
  304. waitAndAssert(c, defaultReconciliationTimeout, d1.CheckLeader, checker.IsNil)
  305. d1.CreateService(c, simpleTestService, func(s *swarm.Service) {
  306. s.Spec.Name = "top3"
  307. })
  308. }
  309. func (s *DockerSwarmSuite) TestAPISwarmLeaveRemovesContainer(c *check.C) {
  310. d := s.AddDaemon(c, true, true)
  311. instances := 2
  312. d.CreateService(c, simpleTestService, setInstances(instances))
  313. id, err := d.Cmd("run", "-d", "busybox", "top")
  314. c.Assert(err, checker.IsNil)
  315. id = strings.TrimSpace(id)
  316. waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, instances+1)
  317. c.Assert(d.Leave(false), checker.NotNil)
  318. c.Assert(d.Leave(true), checker.IsNil)
  319. waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1)
  320. id2, err := d.Cmd("ps", "-q")
  321. c.Assert(err, checker.IsNil)
  322. c.Assert(id, checker.HasPrefix, strings.TrimSpace(id2))
  323. }
  324. // #23629
  325. func (s *DockerSwarmSuite) TestAPISwarmLeaveOnPendingJoin(c *check.C) {
  326. testRequires(c, Network)
  327. s.AddDaemon(c, true, true)
  328. d2 := s.AddDaemon(c, false, false)
  329. id, err := d2.Cmd("run", "-d", "busybox", "top")
  330. c.Assert(err, checker.IsNil)
  331. id = strings.TrimSpace(id)
  332. err = d2.Join(swarm.JoinRequest{
  333. RemoteAddrs: []string{"123.123.123.123:1234"},
  334. })
  335. c.Assert(err, check.NotNil)
  336. c.Assert(err.Error(), checker.Contains, "Timeout was reached")
  337. info, err := d2.SwarmInfo()
  338. c.Assert(err, checker.IsNil)
  339. c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStatePending)
  340. c.Assert(d2.Leave(true), checker.IsNil)
  341. waitAndAssert(c, defaultReconciliationTimeout, d2.CheckActiveContainerCount, checker.Equals, 1)
  342. id2, err := d2.Cmd("ps", "-q")
  343. c.Assert(err, checker.IsNil)
  344. c.Assert(id, checker.HasPrefix, strings.TrimSpace(id2))
  345. }
  346. // #23705
  347. func (s *DockerSwarmSuite) TestAPISwarmRestoreOnPendingJoin(c *check.C) {
  348. testRequires(c, Network)
  349. d := s.AddDaemon(c, false, false)
  350. err := d.Join(swarm.JoinRequest{
  351. RemoteAddrs: []string{"123.123.123.123:1234"},
  352. })
  353. c.Assert(err, check.NotNil)
  354. c.Assert(err.Error(), checker.Contains, "Timeout was reached")
  355. waitAndAssert(c, defaultReconciliationTimeout, d.CheckLocalNodeState, checker.Equals, swarm.LocalNodeStatePending)
  356. d.Stop(c)
  357. d.Start(c)
  358. info, err := d.SwarmInfo()
  359. c.Assert(err, checker.IsNil)
  360. c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateInactive)
  361. }
  362. func (s *DockerSwarmSuite) TestAPISwarmManagerRestore(c *check.C) {
  363. d1 := s.AddDaemon(c, true, true)
  364. instances := 2
  365. id := d1.CreateService(c, simpleTestService, setInstances(instances))
  366. d1.GetService(c, id)
  367. d1.Stop(c)
  368. d1.Start(c)
  369. d1.GetService(c, id)
  370. d2 := s.AddDaemon(c, true, true)
  371. d2.GetService(c, id)
  372. d2.Stop(c)
  373. d2.Start(c)
  374. d2.GetService(c, id)
  375. d3 := s.AddDaemon(c, true, true)
  376. d3.GetService(c, id)
  377. d3.Stop(c)
  378. d3.Start(c)
  379. d3.GetService(c, id)
  380. d3.Kill()
  381. time.Sleep(1 * time.Second) // time to handle signal
  382. d3.Start(c)
  383. d3.GetService(c, id)
  384. }
  385. func (s *DockerSwarmSuite) TestAPISwarmScaleNoRollingUpdate(c *check.C) {
  386. d := s.AddDaemon(c, true, true)
  387. instances := 2
  388. id := d.CreateService(c, simpleTestService, setInstances(instances))
  389. waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, instances)
  390. containers := d.ActiveContainers()
  391. instances = 4
  392. d.UpdateService(c, d.GetService(c, id), setInstances(instances))
  393. waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, instances)
  394. containers2 := d.ActiveContainers()
  395. loop0:
  396. for _, c1 := range containers {
  397. for _, c2 := range containers2 {
  398. if c1 == c2 {
  399. continue loop0
  400. }
  401. }
  402. c.Errorf("container %v not found in new set %#v", c1, containers2)
  403. }
  404. }
  405. func (s *DockerSwarmSuite) TestAPISwarmInvalidAddress(c *check.C) {
  406. d := s.AddDaemon(c, false, false)
  407. req := swarm.InitRequest{
  408. ListenAddr: "",
  409. }
  410. status, _, err := d.SockRequest("POST", "/swarm/init", req)
  411. c.Assert(err, checker.IsNil)
  412. c.Assert(status, checker.Equals, http.StatusBadRequest)
  413. req2 := swarm.JoinRequest{
  414. ListenAddr: "0.0.0.0:2377",
  415. RemoteAddrs: []string{""},
  416. }
  417. status, _, err = d.SockRequest("POST", "/swarm/join", req2)
  418. c.Assert(err, checker.IsNil)
  419. c.Assert(status, checker.Equals, http.StatusBadRequest)
  420. }
  421. func (s *DockerSwarmSuite) TestAPISwarmForceNewCluster(c *check.C) {
  422. d1 := s.AddDaemon(c, true, true)
  423. d2 := s.AddDaemon(c, true, true)
  424. instances := 2
  425. id := d1.CreateService(c, simpleTestService, setInstances(instances))
  426. waitAndAssert(c, defaultReconciliationTimeout, reducedCheck(sumAsIntegers, d1.CheckActiveContainerCount, d2.CheckActiveContainerCount), checker.Equals, instances)
  427. // drain d2, all containers should move to d1
  428. d1.UpdateNode(c, d2.NodeID, func(n *swarm.Node) {
  429. n.Spec.Availability = swarm.NodeAvailabilityDrain
  430. })
  431. waitAndAssert(c, defaultReconciliationTimeout, d1.CheckActiveContainerCount, checker.Equals, instances)
  432. waitAndAssert(c, defaultReconciliationTimeout, d2.CheckActiveContainerCount, checker.Equals, 0)
  433. d2.Stop(c)
  434. c.Assert(d1.Init(swarm.InitRequest{
  435. ForceNewCluster: true,
  436. Spec: swarm.Spec{},
  437. }), checker.IsNil)
  438. waitAndAssert(c, defaultReconciliationTimeout, d1.CheckActiveContainerCount, checker.Equals, instances)
  439. d3 := s.AddDaemon(c, true, true)
  440. info, err := d3.SwarmInfo()
  441. c.Assert(err, checker.IsNil)
  442. c.Assert(info.ControlAvailable, checker.True)
  443. c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
  444. instances = 4
  445. d3.UpdateService(c, d3.GetService(c, id), setInstances(instances))
  446. waitAndAssert(c, defaultReconciliationTimeout, reducedCheck(sumAsIntegers, d1.CheckActiveContainerCount, d3.CheckActiveContainerCount), checker.Equals, instances)
  447. }
  448. func simpleTestService(s *swarm.Service) {
  449. ureplicas := uint64(1)
  450. restartDelay := time.Duration(100 * time.Millisecond)
  451. s.Spec = swarm.ServiceSpec{
  452. TaskTemplate: swarm.TaskSpec{
  453. ContainerSpec: swarm.ContainerSpec{
  454. Image: "busybox:latest",
  455. Command: []string{"/bin/top"},
  456. },
  457. RestartPolicy: &swarm.RestartPolicy{
  458. Delay: &restartDelay,
  459. },
  460. },
  461. Mode: swarm.ServiceMode{
  462. Replicated: &swarm.ReplicatedService{
  463. Replicas: &ureplicas,
  464. },
  465. },
  466. }
  467. s.Spec.Name = "top"
  468. }
  469. func serviceForUpdate(s *swarm.Service) {
  470. ureplicas := uint64(1)
  471. restartDelay := time.Duration(100 * time.Millisecond)
  472. s.Spec = swarm.ServiceSpec{
  473. TaskTemplate: swarm.TaskSpec{
  474. ContainerSpec: swarm.ContainerSpec{
  475. Image: "busybox:latest",
  476. Command: []string{"/bin/top"},
  477. },
  478. RestartPolicy: &swarm.RestartPolicy{
  479. Delay: &restartDelay,
  480. },
  481. },
  482. Mode: swarm.ServiceMode{
  483. Replicated: &swarm.ReplicatedService{
  484. Replicas: &ureplicas,
  485. },
  486. },
  487. UpdateConfig: &swarm.UpdateConfig{
  488. Parallelism: 2,
  489. Delay: 4 * time.Second,
  490. FailureAction: swarm.UpdateFailureActionContinue,
  491. },
  492. RollbackConfig: &swarm.UpdateConfig{
  493. Parallelism: 3,
  494. Delay: 4 * time.Second,
  495. FailureAction: swarm.UpdateFailureActionContinue,
  496. },
  497. }
  498. s.Spec.Name = "updatetest"
  499. }
  500. func setInstances(replicas int) daemon.ServiceConstructor {
  501. ureplicas := uint64(replicas)
  502. return func(s *swarm.Service) {
  503. s.Spec.Mode = swarm.ServiceMode{
  504. Replicated: &swarm.ReplicatedService{
  505. Replicas: &ureplicas,
  506. },
  507. }
  508. }
  509. }
  510. func setUpdateOrder(order string) daemon.ServiceConstructor {
  511. return func(s *swarm.Service) {
  512. if s.Spec.UpdateConfig == nil {
  513. s.Spec.UpdateConfig = &swarm.UpdateConfig{}
  514. }
  515. s.Spec.UpdateConfig.Order = order
  516. }
  517. }
  518. func setRollbackOrder(order string) daemon.ServiceConstructor {
  519. return func(s *swarm.Service) {
  520. if s.Spec.RollbackConfig == nil {
  521. s.Spec.RollbackConfig = &swarm.UpdateConfig{}
  522. }
  523. s.Spec.RollbackConfig.Order = order
  524. }
  525. }
  526. func setImage(image string) daemon.ServiceConstructor {
  527. return func(s *swarm.Service) {
  528. s.Spec.TaskTemplate.ContainerSpec.Image = image
  529. }
  530. }
  531. func setFailureAction(failureAction string) daemon.ServiceConstructor {
  532. return func(s *swarm.Service) {
  533. s.Spec.UpdateConfig.FailureAction = failureAction
  534. }
  535. }
  536. func setMaxFailureRatio(maxFailureRatio float32) daemon.ServiceConstructor {
  537. return func(s *swarm.Service) {
  538. s.Spec.UpdateConfig.MaxFailureRatio = maxFailureRatio
  539. }
  540. }
  541. func setParallelism(parallelism uint64) daemon.ServiceConstructor {
  542. return func(s *swarm.Service) {
  543. s.Spec.UpdateConfig.Parallelism = parallelism
  544. }
  545. }
  546. func setConstraints(constraints []string) daemon.ServiceConstructor {
  547. return func(s *swarm.Service) {
  548. if s.Spec.TaskTemplate.Placement == nil {
  549. s.Spec.TaskTemplate.Placement = &swarm.Placement{}
  550. }
  551. s.Spec.TaskTemplate.Placement.Constraints = constraints
  552. }
  553. }
  554. func setPlacementPrefs(prefs []swarm.PlacementPreference) daemon.ServiceConstructor {
  555. return func(s *swarm.Service) {
  556. if s.Spec.TaskTemplate.Placement == nil {
  557. s.Spec.TaskTemplate.Placement = &swarm.Placement{}
  558. }
  559. s.Spec.TaskTemplate.Placement.Preferences = prefs
  560. }
  561. }
  562. func setGlobalMode(s *swarm.Service) {
  563. s.Spec.Mode = swarm.ServiceMode{
  564. Global: &swarm.GlobalService{},
  565. }
  566. }
  567. func checkClusterHealth(c *check.C, cl []*daemon.Swarm, managerCount, workerCount int) {
  568. var totalMCount, totalWCount int
  569. for _, d := range cl {
  570. var (
  571. info swarm.Info
  572. err error
  573. )
  574. // check info in a waitAndAssert, because if the cluster doesn't have a leader, `info` will return an error
  575. checkInfo := func(c *check.C) (interface{}, check.CommentInterface) {
  576. info, err = d.SwarmInfo()
  577. return err, check.Commentf("cluster not ready in time")
  578. }
  579. waitAndAssert(c, defaultReconciliationTimeout, checkInfo, checker.IsNil)
  580. if !info.ControlAvailable {
  581. totalWCount++
  582. continue
  583. }
  584. var leaderFound bool
  585. totalMCount++
  586. var mCount, wCount int
  587. for _, n := range d.ListNodes(c) {
  588. waitReady := func(c *check.C) (interface{}, check.CommentInterface) {
  589. if n.Status.State == swarm.NodeStateReady {
  590. return true, nil
  591. }
  592. nn := d.GetNode(c, n.ID)
  593. n = *nn
  594. return n.Status.State == swarm.NodeStateReady, check.Commentf("state of node %s, reported by %s", n.ID, d.Info.NodeID)
  595. }
  596. waitAndAssert(c, defaultReconciliationTimeout, waitReady, checker.True)
  597. waitActive := func(c *check.C) (interface{}, check.CommentInterface) {
  598. if n.Spec.Availability == swarm.NodeAvailabilityActive {
  599. return true, nil
  600. }
  601. nn := d.GetNode(c, n.ID)
  602. n = *nn
  603. return n.Spec.Availability == swarm.NodeAvailabilityActive, check.Commentf("availability of node %s, reported by %s", n.ID, d.Info.NodeID)
  604. }
  605. waitAndAssert(c, defaultReconciliationTimeout, waitActive, checker.True)
  606. if n.Spec.Role == swarm.NodeRoleManager {
  607. c.Assert(n.ManagerStatus, checker.NotNil, check.Commentf("manager status of node %s (manager), reported by %s", n.ID, d.Info.NodeID))
  608. if n.ManagerStatus.Leader {
  609. leaderFound = true
  610. }
  611. mCount++
  612. } else {
  613. c.Assert(n.ManagerStatus, checker.IsNil, check.Commentf("manager status of node %s (worker), reported by %s", n.ID, d.Info.NodeID))
  614. wCount++
  615. }
  616. }
  617. c.Assert(leaderFound, checker.True, check.Commentf("lack of leader reported by node %s", info.NodeID))
  618. c.Assert(mCount, checker.Equals, managerCount, check.Commentf("managers count reported by node %s", info.NodeID))
  619. c.Assert(wCount, checker.Equals, workerCount, check.Commentf("workers count reported by node %s", info.NodeID))
  620. }
  621. c.Assert(totalMCount, checker.Equals, managerCount)
  622. c.Assert(totalWCount, checker.Equals, workerCount)
  623. }
  624. func (s *DockerSwarmSuite) TestAPISwarmRestartCluster(c *check.C) {
  625. mCount, wCount := 5, 1
  626. var nodes []*daemon.Swarm
  627. for i := 0; i < mCount; i++ {
  628. manager := s.AddDaemon(c, true, true)
  629. info, err := manager.SwarmInfo()
  630. c.Assert(err, checker.IsNil)
  631. c.Assert(info.ControlAvailable, checker.True)
  632. c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
  633. nodes = append(nodes, manager)
  634. }
  635. for i := 0; i < wCount; i++ {
  636. worker := s.AddDaemon(c, true, false)
  637. info, err := worker.SwarmInfo()
  638. c.Assert(err, checker.IsNil)
  639. c.Assert(info.ControlAvailable, checker.False)
  640. c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
  641. nodes = append(nodes, worker)
  642. }
  643. // stop whole cluster
  644. {
  645. var wg sync.WaitGroup
  646. wg.Add(len(nodes))
  647. errs := make(chan error, len(nodes))
  648. for _, d := range nodes {
  649. go func(daemon *daemon.Swarm) {
  650. defer wg.Done()
  651. if err := daemon.StopWithError(); err != nil {
  652. errs <- err
  653. }
  654. // FIXME(vdemeester) This is duplicated…
  655. if root := os.Getenv("DOCKER_REMAP_ROOT"); root != "" {
  656. daemon.Root = filepath.Dir(daemon.Root)
  657. }
  658. }(d)
  659. }
  660. wg.Wait()
  661. close(errs)
  662. for err := range errs {
  663. c.Assert(err, check.IsNil)
  664. }
  665. }
  666. // start whole cluster
  667. {
  668. var wg sync.WaitGroup
  669. wg.Add(len(nodes))
  670. errs := make(chan error, len(nodes))
  671. for _, d := range nodes {
  672. go func(daemon *daemon.Swarm) {
  673. defer wg.Done()
  674. if err := daemon.StartWithError("--iptables=false"); err != nil {
  675. errs <- err
  676. }
  677. }(d)
  678. }
  679. wg.Wait()
  680. close(errs)
  681. for err := range errs {
  682. c.Assert(err, check.IsNil)
  683. }
  684. }
  685. checkClusterHealth(c, nodes, mCount, wCount)
  686. }
  687. func (s *DockerSwarmSuite) TestAPISwarmServicesUpdateWithName(c *check.C) {
  688. d := s.AddDaemon(c, true, true)
  689. instances := 2
  690. id := d.CreateService(c, simpleTestService, setInstances(instances))
  691. waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, instances)
  692. service := d.GetService(c, id)
  693. instances = 5
  694. setInstances(instances)(service)
  695. url := fmt.Sprintf("/services/%s/update?version=%d", service.Spec.Name, service.Version.Index)
  696. status, out, err := d.SockRequest("POST", url, service.Spec)
  697. c.Assert(err, checker.IsNil)
  698. c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out)))
  699. waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, instances)
  700. }
  701. // Unlocking an unlocked swarm results in an error
  702. func (s *DockerSwarmSuite) TestAPISwarmUnlockNotLocked(c *check.C) {
  703. d := s.AddDaemon(c, true, true)
  704. err := d.Unlock(swarm.UnlockRequest{UnlockKey: "wrong-key"})
  705. c.Assert(err, checker.NotNil)
  706. c.Assert(err.Error(), checker.Contains, "swarm is not locked")
  707. }
  708. // #29885
  709. func (s *DockerSwarmSuite) TestAPISwarmErrorHandling(c *check.C) {
  710. ln, err := net.Listen("tcp", fmt.Sprintf(":%d", defaultSwarmPort))
  711. c.Assert(err, checker.IsNil)
  712. defer ln.Close()
  713. d := s.AddDaemon(c, false, false)
  714. err = d.Init(swarm.InitRequest{})
  715. c.Assert(err, checker.NotNil)
  716. c.Assert(err.Error(), checker.Contains, "address already in use")
  717. }
  718. // Test case for 30242, where duplicate networks, with different drivers `bridge` and `overlay`,
  719. // caused both scopes to be `swarm` for `docker network inspect` and `docker network ls`.
  720. // This test makes sure the fixes correctly output scopes instead.
  721. func (s *DockerSwarmSuite) TestAPIDuplicateNetworks(c *check.C) {
  722. d := s.AddDaemon(c, true, true)
  723. name := "foo"
  724. networkCreateRequest := types.NetworkCreateRequest{
  725. Name: name,
  726. NetworkCreate: types.NetworkCreate{
  727. CheckDuplicate: false,
  728. },
  729. }
  730. var n1 types.NetworkCreateResponse
  731. networkCreateRequest.NetworkCreate.Driver = "bridge"
  732. status, out, err := d.SockRequest("POST", "/networks/create", networkCreateRequest)
  733. c.Assert(err, checker.IsNil, check.Commentf(string(out)))
  734. c.Assert(status, checker.Equals, http.StatusCreated, check.Commentf(string(out)))
  735. c.Assert(json.Unmarshal(out, &n1), checker.IsNil)
  736. var n2 types.NetworkCreateResponse
  737. networkCreateRequest.NetworkCreate.Driver = "overlay"
  738. status, out, err = d.SockRequest("POST", "/networks/create", networkCreateRequest)
  739. c.Assert(err, checker.IsNil, check.Commentf(string(out)))
  740. c.Assert(status, checker.Equals, http.StatusCreated, check.Commentf(string(out)))
  741. c.Assert(json.Unmarshal(out, &n2), checker.IsNil)
  742. var r1 types.NetworkResource
  743. status, out, err = d.SockRequest("GET", "/networks/"+n1.ID, nil)
  744. c.Assert(err, checker.IsNil, check.Commentf(string(out)))
  745. c.Assert(status, checker.Equals, http.StatusOK, check.Commentf(string(out)))
  746. c.Assert(json.Unmarshal(out, &r1), checker.IsNil)
  747. c.Assert(r1.Scope, checker.Equals, "local")
  748. var r2 types.NetworkResource
  749. status, out, err = d.SockRequest("GET", "/networks/"+n2.ID, nil)
  750. c.Assert(err, checker.IsNil, check.Commentf(string(out)))
  751. c.Assert(status, checker.Equals, http.StatusOK, check.Commentf(string(out)))
  752. c.Assert(json.Unmarshal(out, &r2), checker.IsNil)
  753. c.Assert(r2.Scope, checker.Equals, "swarm")
  754. }
  755. // Test case for 30178
  756. func (s *DockerSwarmSuite) TestAPISwarmHealthcheckNone(c *check.C) {
  757. d := s.AddDaemon(c, true, true)
  758. out, err := d.Cmd("network", "create", "-d", "overlay", "lb")
  759. c.Assert(err, checker.IsNil, check.Commentf(out))
  760. instances := 1
  761. d.CreateService(c, simpleTestService, setInstances(instances), func(s *swarm.Service) {
  762. s.Spec.TaskTemplate.ContainerSpec.Healthcheck = &container.HealthConfig{}
  763. s.Spec.TaskTemplate.Networks = []swarm.NetworkAttachmentConfig{
  764. {Target: "lb"},
  765. }
  766. })
  767. waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, instances)
  768. containers := d.ActiveContainers()
  769. out, err = d.Cmd("exec", containers[0], "ping", "-c1", "-W3", "top")
  770. c.Assert(err, checker.IsNil, check.Commentf(out))
  771. }