docker_api_swarm_test.go 33 KB

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