docker_api_swarm_test.go 27 KB

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