docker_api_swarm_service_test.go 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598
  1. // +build !windows
  2. package main
  3. import (
  4. "fmt"
  5. "strconv"
  6. "strings"
  7. "syscall"
  8. "time"
  9. "github.com/docker/docker/api/types/swarm"
  10. "github.com/docker/docker/integration-cli/checker"
  11. "github.com/docker/docker/integration-cli/daemon"
  12. "github.com/go-check/check"
  13. )
  14. func setPortConfig(portConfig []swarm.PortConfig) daemon.ServiceConstructor {
  15. return func(s *swarm.Service) {
  16. if s.Spec.EndpointSpec == nil {
  17. s.Spec.EndpointSpec = &swarm.EndpointSpec{}
  18. }
  19. s.Spec.EndpointSpec.Ports = portConfig
  20. }
  21. }
  22. func (s *DockerSwarmSuite) TestAPIServiceUpdatePort(c *check.C) {
  23. d := s.AddDaemon(c, true, true)
  24. // Create a service with a port mapping of 8080:8081.
  25. portConfig := []swarm.PortConfig{{TargetPort: 8081, PublishedPort: 8080}}
  26. serviceID := d.CreateService(c, simpleTestService, setInstances(1), setPortConfig(portConfig))
  27. waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1)
  28. // Update the service: changed the port mapping from 8080:8081 to 8082:8083.
  29. updatedPortConfig := []swarm.PortConfig{{TargetPort: 8083, PublishedPort: 8082}}
  30. remoteService := d.GetService(c, serviceID)
  31. d.UpdateService(c, remoteService, setPortConfig(updatedPortConfig))
  32. // Inspect the service and verify port mapping.
  33. updatedService := d.GetService(c, serviceID)
  34. c.Assert(updatedService.Spec.EndpointSpec, check.NotNil)
  35. c.Assert(len(updatedService.Spec.EndpointSpec.Ports), check.Equals, 1)
  36. c.Assert(updatedService.Spec.EndpointSpec.Ports[0].TargetPort, check.Equals, uint32(8083))
  37. c.Assert(updatedService.Spec.EndpointSpec.Ports[0].PublishedPort, check.Equals, uint32(8082))
  38. }
  39. func (s *DockerSwarmSuite) TestAPISwarmServicesEmptyList(c *check.C) {
  40. d := s.AddDaemon(c, true, true)
  41. services := d.ListServices(c)
  42. c.Assert(services, checker.NotNil)
  43. c.Assert(len(services), checker.Equals, 0, check.Commentf("services: %#v", services))
  44. }
  45. func (s *DockerSwarmSuite) TestAPISwarmServicesCreate(c *check.C) {
  46. d := s.AddDaemon(c, true, true)
  47. instances := 2
  48. id := d.CreateService(c, simpleTestService, setInstances(instances))
  49. waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, instances)
  50. // insertDefaults inserts UpdateConfig when service is fetched by ID
  51. _, out, err := d.SockRequest("GET", "/services/"+id+"?insertDefaults=true", nil)
  52. c.Assert(err, checker.IsNil, check.Commentf("%s", out))
  53. c.Assert(string(out), checker.Contains, "UpdateConfig")
  54. // insertDefaults inserts UpdateConfig when service is fetched by ID
  55. _, out, err = d.SockRequest("GET", "/services/top?insertDefaults=true", nil)
  56. c.Assert(err, checker.IsNil, check.Commentf("%s", out))
  57. c.Assert(string(out), checker.Contains, "UpdateConfig")
  58. service := d.GetService(c, id)
  59. instances = 5
  60. d.UpdateService(c, service, setInstances(instances))
  61. waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, instances)
  62. d.RemoveService(c, service.ID)
  63. waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 0)
  64. }
  65. func (s *DockerSwarmSuite) TestAPISwarmServicesMultipleAgents(c *check.C) {
  66. d1 := s.AddDaemon(c, true, true)
  67. d2 := s.AddDaemon(c, true, false)
  68. d3 := s.AddDaemon(c, true, false)
  69. time.Sleep(1 * time.Second) // make sure all daemons are ready to accept tasks
  70. instances := 9
  71. id := d1.CreateService(c, simpleTestService, setInstances(instances))
  72. waitAndAssert(c, defaultReconciliationTimeout, d1.CheckActiveContainerCount, checker.GreaterThan, 0)
  73. waitAndAssert(c, defaultReconciliationTimeout, d2.CheckActiveContainerCount, checker.GreaterThan, 0)
  74. waitAndAssert(c, defaultReconciliationTimeout, d3.CheckActiveContainerCount, checker.GreaterThan, 0)
  75. waitAndAssert(c, defaultReconciliationTimeout, reducedCheck(sumAsIntegers, d1.CheckActiveContainerCount, d2.CheckActiveContainerCount, d3.CheckActiveContainerCount), checker.Equals, instances)
  76. // reconciliation on d2 node down
  77. d2.Stop(c)
  78. waitAndAssert(c, defaultReconciliationTimeout, reducedCheck(sumAsIntegers, d1.CheckActiveContainerCount, d3.CheckActiveContainerCount), checker.Equals, instances)
  79. // test downscaling
  80. instances = 5
  81. d1.UpdateService(c, d1.GetService(c, id), setInstances(instances))
  82. waitAndAssert(c, defaultReconciliationTimeout, reducedCheck(sumAsIntegers, d1.CheckActiveContainerCount, d3.CheckActiveContainerCount), checker.Equals, instances)
  83. }
  84. func (s *DockerSwarmSuite) TestAPISwarmServicesCreateGlobal(c *check.C) {
  85. d1 := s.AddDaemon(c, true, true)
  86. d2 := s.AddDaemon(c, true, false)
  87. d3 := s.AddDaemon(c, true, false)
  88. d1.CreateService(c, simpleTestService, setGlobalMode)
  89. waitAndAssert(c, defaultReconciliationTimeout, d1.CheckActiveContainerCount, checker.Equals, 1)
  90. waitAndAssert(c, defaultReconciliationTimeout, d2.CheckActiveContainerCount, checker.Equals, 1)
  91. waitAndAssert(c, defaultReconciliationTimeout, d3.CheckActiveContainerCount, checker.Equals, 1)
  92. d4 := s.AddDaemon(c, true, false)
  93. d5 := s.AddDaemon(c, true, false)
  94. waitAndAssert(c, defaultReconciliationTimeout, d4.CheckActiveContainerCount, checker.Equals, 1)
  95. waitAndAssert(c, defaultReconciliationTimeout, d5.CheckActiveContainerCount, checker.Equals, 1)
  96. }
  97. func (s *DockerSwarmSuite) TestAPISwarmServicesUpdate(c *check.C) {
  98. const nodeCount = 3
  99. var daemons [nodeCount]*daemon.Swarm
  100. for i := 0; i < nodeCount; i++ {
  101. daemons[i] = s.AddDaemon(c, true, i == 0)
  102. }
  103. // wait for nodes ready
  104. waitAndAssert(c, 5*time.Second, daemons[0].CheckNodeReadyCount, checker.Equals, nodeCount)
  105. // service image at start
  106. image1 := "busybox:latest"
  107. // target image in update
  108. image2 := "busybox:test"
  109. // create a different tag
  110. for _, d := range daemons {
  111. out, err := d.Cmd("tag", image1, image2)
  112. c.Assert(err, checker.IsNil, check.Commentf(out))
  113. }
  114. // create service
  115. instances := 5
  116. parallelism := 2
  117. rollbackParallelism := 3
  118. id := daemons[0].CreateService(c, serviceForUpdate, setInstances(instances))
  119. // wait for tasks ready
  120. waitAndAssert(c, defaultReconciliationTimeout, daemons[0].CheckRunningTaskImages, checker.DeepEquals,
  121. map[string]int{image1: instances})
  122. // issue service update
  123. service := daemons[0].GetService(c, id)
  124. daemons[0].UpdateService(c, service, setImage(image2))
  125. // first batch
  126. waitAndAssert(c, defaultReconciliationTimeout, daemons[0].CheckRunningTaskImages, checker.DeepEquals,
  127. map[string]int{image1: instances - parallelism, image2: parallelism})
  128. // 2nd batch
  129. waitAndAssert(c, defaultReconciliationTimeout, daemons[0].CheckRunningTaskImages, checker.DeepEquals,
  130. map[string]int{image1: instances - 2*parallelism, image2: 2 * parallelism})
  131. // 3nd batch
  132. waitAndAssert(c, defaultReconciliationTimeout, daemons[0].CheckRunningTaskImages, checker.DeepEquals,
  133. map[string]int{image2: instances})
  134. // Roll back to the previous version. This uses the CLI because
  135. // rollback used to be a client-side operation.
  136. out, err := daemons[0].Cmd("service", "update", "--rollback", id)
  137. c.Assert(err, checker.IsNil, check.Commentf(out))
  138. // first batch
  139. waitAndAssert(c, defaultReconciliationTimeout, daemons[0].CheckRunningTaskImages, checker.DeepEquals,
  140. map[string]int{image2: instances - rollbackParallelism, image1: rollbackParallelism})
  141. // 2nd batch
  142. waitAndAssert(c, defaultReconciliationTimeout, daemons[0].CheckRunningTaskImages, checker.DeepEquals,
  143. map[string]int{image1: instances})
  144. }
  145. func (s *DockerSwarmSuite) TestAPISwarmServicesUpdateStartFirst(c *check.C) {
  146. d := s.AddDaemon(c, true, true)
  147. // service image at start
  148. image1 := "busybox:latest"
  149. // target image in update
  150. image2 := "testhealth"
  151. // service started from this image won't pass health check
  152. _, _, err := d.BuildImageWithOut(image2,
  153. `FROM busybox
  154. HEALTHCHECK --interval=1s --timeout=30s --retries=1024 \
  155. CMD cat /status`,
  156. true)
  157. c.Check(err, check.IsNil)
  158. // create service
  159. instances := 5
  160. parallelism := 2
  161. rollbackParallelism := 3
  162. id := d.CreateService(c, serviceForUpdate, setInstances(instances), setUpdateOrder(swarm.UpdateOrderStartFirst), setRollbackOrder(swarm.UpdateOrderStartFirst))
  163. checkStartingTasks := func(expected int) []swarm.Task {
  164. var startingTasks []swarm.Task
  165. waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
  166. tasks := d.GetServiceTasks(c, id)
  167. startingTasks = nil
  168. for _, t := range tasks {
  169. if t.Status.State == swarm.TaskStateStarting {
  170. startingTasks = append(startingTasks, t)
  171. }
  172. }
  173. return startingTasks, nil
  174. }, checker.HasLen, expected)
  175. return startingTasks
  176. }
  177. makeTasksHealthy := func(tasks []swarm.Task) {
  178. for _, t := range tasks {
  179. containerID := t.Status.ContainerStatus.ContainerID
  180. d.Cmd("exec", containerID, "touch", "/status")
  181. }
  182. }
  183. // wait for tasks ready
  184. waitAndAssert(c, defaultReconciliationTimeout, d.CheckRunningTaskImages, checker.DeepEquals,
  185. map[string]int{image1: instances})
  186. // issue service update
  187. service := d.GetService(c, id)
  188. d.UpdateService(c, service, setImage(image2))
  189. // first batch
  190. // The old tasks should be running, and the new ones should be starting.
  191. startingTasks := checkStartingTasks(parallelism)
  192. waitAndAssert(c, defaultReconciliationTimeout, d.CheckRunningTaskImages, checker.DeepEquals,
  193. map[string]int{image1: instances})
  194. // make it healthy
  195. makeTasksHealthy(startingTasks)
  196. waitAndAssert(c, defaultReconciliationTimeout, d.CheckRunningTaskImages, checker.DeepEquals,
  197. map[string]int{image1: instances - parallelism, image2: parallelism})
  198. // 2nd batch
  199. // The old tasks should be running, and the new ones should be starting.
  200. startingTasks = checkStartingTasks(parallelism)
  201. waitAndAssert(c, defaultReconciliationTimeout, d.CheckRunningTaskImages, checker.DeepEquals,
  202. map[string]int{image1: instances - parallelism, image2: parallelism})
  203. // make it healthy
  204. makeTasksHealthy(startingTasks)
  205. waitAndAssert(c, defaultReconciliationTimeout, d.CheckRunningTaskImages, checker.DeepEquals,
  206. map[string]int{image1: instances - 2*parallelism, image2: 2 * parallelism})
  207. // 3nd batch
  208. // The old tasks should be running, and the new ones should be starting.
  209. startingTasks = checkStartingTasks(1)
  210. waitAndAssert(c, defaultReconciliationTimeout, d.CheckRunningTaskImages, checker.DeepEquals,
  211. map[string]int{image1: instances - 2*parallelism, image2: 2 * parallelism})
  212. // make it healthy
  213. makeTasksHealthy(startingTasks)
  214. waitAndAssert(c, defaultReconciliationTimeout, d.CheckRunningTaskImages, checker.DeepEquals,
  215. map[string]int{image2: instances})
  216. // Roll back to the previous version. This uses the CLI because
  217. // rollback is a client-side operation.
  218. out, err := d.Cmd("service", "update", "--rollback", id)
  219. c.Assert(err, checker.IsNil, check.Commentf(out))
  220. // first batch
  221. waitAndAssert(c, defaultReconciliationTimeout, d.CheckRunningTaskImages, checker.DeepEquals,
  222. map[string]int{image2: instances - rollbackParallelism, image1: rollbackParallelism})
  223. // 2nd batch
  224. waitAndAssert(c, defaultReconciliationTimeout, d.CheckRunningTaskImages, checker.DeepEquals,
  225. map[string]int{image1: instances})
  226. }
  227. func (s *DockerSwarmSuite) TestAPISwarmServicesFailedUpdate(c *check.C) {
  228. const nodeCount = 3
  229. var daemons [nodeCount]*daemon.Swarm
  230. for i := 0; i < nodeCount; i++ {
  231. daemons[i] = s.AddDaemon(c, true, i == 0)
  232. }
  233. // wait for nodes ready
  234. waitAndAssert(c, 5*time.Second, daemons[0].CheckNodeReadyCount, checker.Equals, nodeCount)
  235. // service image at start
  236. image1 := "busybox:latest"
  237. // target image in update
  238. image2 := "busybox:badtag"
  239. // create service
  240. instances := 5
  241. id := daemons[0].CreateService(c, serviceForUpdate, setInstances(instances))
  242. // wait for tasks ready
  243. waitAndAssert(c, defaultReconciliationTimeout, daemons[0].CheckRunningTaskImages, checker.DeepEquals,
  244. map[string]int{image1: instances})
  245. // issue service update
  246. service := daemons[0].GetService(c, id)
  247. daemons[0].UpdateService(c, service, setImage(image2), setFailureAction(swarm.UpdateFailureActionPause), setMaxFailureRatio(0.25), setParallelism(1))
  248. // should update 2 tasks and then pause
  249. waitAndAssert(c, defaultReconciliationTimeout, daemons[0].CheckServiceUpdateState(id), checker.Equals, swarm.UpdateStatePaused)
  250. v, _ := daemons[0].CheckServiceRunningTasks(id)(c)
  251. c.Assert(v, checker.Equals, instances-2)
  252. // Roll back to the previous version. This uses the CLI because
  253. // rollback used to be a client-side operation.
  254. out, err := daemons[0].Cmd("service", "update", "--rollback", id)
  255. c.Assert(err, checker.IsNil, check.Commentf(out))
  256. waitAndAssert(c, defaultReconciliationTimeout, daemons[0].CheckRunningTaskImages, checker.DeepEquals,
  257. map[string]int{image1: instances})
  258. }
  259. func (s *DockerSwarmSuite) TestAPISwarmServiceConstraintRole(c *check.C) {
  260. const nodeCount = 3
  261. var daemons [nodeCount]*daemon.Swarm
  262. for i := 0; i < nodeCount; i++ {
  263. daemons[i] = s.AddDaemon(c, true, i == 0)
  264. }
  265. // wait for nodes ready
  266. waitAndAssert(c, 5*time.Second, daemons[0].CheckNodeReadyCount, checker.Equals, nodeCount)
  267. // create service
  268. constraints := []string{"node.role==worker"}
  269. instances := 3
  270. id := daemons[0].CreateService(c, simpleTestService, setConstraints(constraints), setInstances(instances))
  271. // wait for tasks ready
  272. waitAndAssert(c, defaultReconciliationTimeout, daemons[0].CheckServiceRunningTasks(id), checker.Equals, instances)
  273. // validate tasks are running on worker nodes
  274. tasks := daemons[0].GetServiceTasks(c, id)
  275. for _, task := range tasks {
  276. node := daemons[0].GetNode(c, task.NodeID)
  277. c.Assert(node.Spec.Role, checker.Equals, swarm.NodeRoleWorker)
  278. }
  279. //remove service
  280. daemons[0].RemoveService(c, id)
  281. // create service
  282. constraints = []string{"node.role!=worker"}
  283. id = daemons[0].CreateService(c, simpleTestService, setConstraints(constraints), setInstances(instances))
  284. // wait for tasks ready
  285. waitAndAssert(c, defaultReconciliationTimeout, daemons[0].CheckServiceRunningTasks(id), checker.Equals, instances)
  286. tasks = daemons[0].GetServiceTasks(c, id)
  287. // validate tasks are running on manager nodes
  288. for _, task := range tasks {
  289. node := daemons[0].GetNode(c, task.NodeID)
  290. c.Assert(node.Spec.Role, checker.Equals, swarm.NodeRoleManager)
  291. }
  292. //remove service
  293. daemons[0].RemoveService(c, id)
  294. // create service
  295. constraints = []string{"node.role==nosuchrole"}
  296. id = daemons[0].CreateService(c, simpleTestService, setConstraints(constraints), setInstances(instances))
  297. // wait for tasks created
  298. waitAndAssert(c, defaultReconciliationTimeout, daemons[0].CheckServiceTasks(id), checker.Equals, instances)
  299. // let scheduler try
  300. time.Sleep(250 * time.Millisecond)
  301. // validate tasks are not assigned to any node
  302. tasks = daemons[0].GetServiceTasks(c, id)
  303. for _, task := range tasks {
  304. c.Assert(task.NodeID, checker.Equals, "")
  305. }
  306. }
  307. func (s *DockerSwarmSuite) TestAPISwarmServiceConstraintLabel(c *check.C) {
  308. const nodeCount = 3
  309. var daemons [nodeCount]*daemon.Swarm
  310. for i := 0; i < nodeCount; i++ {
  311. daemons[i] = s.AddDaemon(c, true, i == 0)
  312. }
  313. // wait for nodes ready
  314. waitAndAssert(c, 5*time.Second, daemons[0].CheckNodeReadyCount, checker.Equals, nodeCount)
  315. nodes := daemons[0].ListNodes(c)
  316. c.Assert(len(nodes), checker.Equals, nodeCount)
  317. // add labels to nodes
  318. daemons[0].UpdateNode(c, nodes[0].ID, func(n *swarm.Node) {
  319. n.Spec.Annotations.Labels = map[string]string{
  320. "security": "high",
  321. }
  322. })
  323. for i := 1; i < nodeCount; i++ {
  324. daemons[0].UpdateNode(c, nodes[i].ID, func(n *swarm.Node) {
  325. n.Spec.Annotations.Labels = map[string]string{
  326. "security": "low",
  327. }
  328. })
  329. }
  330. // create service
  331. instances := 3
  332. constraints := []string{"node.labels.security==high"}
  333. id := daemons[0].CreateService(c, simpleTestService, setConstraints(constraints), setInstances(instances))
  334. // wait for tasks ready
  335. waitAndAssert(c, defaultReconciliationTimeout, daemons[0].CheckServiceRunningTasks(id), checker.Equals, instances)
  336. tasks := daemons[0].GetServiceTasks(c, id)
  337. // validate all tasks are running on nodes[0]
  338. for _, task := range tasks {
  339. c.Assert(task.NodeID, checker.Equals, nodes[0].ID)
  340. }
  341. //remove service
  342. daemons[0].RemoveService(c, id)
  343. // create service
  344. constraints = []string{"node.labels.security!=high"}
  345. id = daemons[0].CreateService(c, simpleTestService, setConstraints(constraints), setInstances(instances))
  346. // wait for tasks ready
  347. waitAndAssert(c, defaultReconciliationTimeout, daemons[0].CheckServiceRunningTasks(id), checker.Equals, instances)
  348. tasks = daemons[0].GetServiceTasks(c, id)
  349. // validate all tasks are NOT running on nodes[0]
  350. for _, task := range tasks {
  351. c.Assert(task.NodeID, checker.Not(checker.Equals), nodes[0].ID)
  352. }
  353. //remove service
  354. daemons[0].RemoveService(c, id)
  355. constraints = []string{"node.labels.security==medium"}
  356. id = daemons[0].CreateService(c, simpleTestService, setConstraints(constraints), setInstances(instances))
  357. // wait for tasks created
  358. waitAndAssert(c, defaultReconciliationTimeout, daemons[0].CheckServiceTasks(id), checker.Equals, instances)
  359. // let scheduler try
  360. time.Sleep(250 * time.Millisecond)
  361. tasks = daemons[0].GetServiceTasks(c, id)
  362. // validate tasks are not assigned
  363. for _, task := range tasks {
  364. c.Assert(task.NodeID, checker.Equals, "")
  365. }
  366. //remove service
  367. daemons[0].RemoveService(c, id)
  368. // multiple constraints
  369. constraints = []string{
  370. "node.labels.security==high",
  371. fmt.Sprintf("node.id==%s", nodes[1].ID),
  372. }
  373. id = daemons[0].CreateService(c, simpleTestService, setConstraints(constraints), setInstances(instances))
  374. // wait for tasks created
  375. waitAndAssert(c, defaultReconciliationTimeout, daemons[0].CheckServiceTasks(id), checker.Equals, instances)
  376. // let scheduler try
  377. time.Sleep(250 * time.Millisecond)
  378. tasks = daemons[0].GetServiceTasks(c, id)
  379. // validate tasks are not assigned
  380. for _, task := range tasks {
  381. c.Assert(task.NodeID, checker.Equals, "")
  382. }
  383. // make nodes[1] fulfills the constraints
  384. daemons[0].UpdateNode(c, nodes[1].ID, func(n *swarm.Node) {
  385. n.Spec.Annotations.Labels = map[string]string{
  386. "security": "high",
  387. }
  388. })
  389. // wait for tasks ready
  390. waitAndAssert(c, defaultReconciliationTimeout, daemons[0].CheckServiceRunningTasks(id), checker.Equals, instances)
  391. tasks = daemons[0].GetServiceTasks(c, id)
  392. for _, task := range tasks {
  393. c.Assert(task.NodeID, checker.Equals, nodes[1].ID)
  394. }
  395. }
  396. func (s *DockerSwarmSuite) TestAPISwarmServicePlacementPrefs(c *check.C) {
  397. const nodeCount = 3
  398. var daemons [nodeCount]*daemon.Swarm
  399. for i := 0; i < nodeCount; i++ {
  400. daemons[i] = s.AddDaemon(c, true, i == 0)
  401. }
  402. // wait for nodes ready
  403. waitAndAssert(c, 5*time.Second, daemons[0].CheckNodeReadyCount, checker.Equals, nodeCount)
  404. nodes := daemons[0].ListNodes(c)
  405. c.Assert(len(nodes), checker.Equals, nodeCount)
  406. // add labels to nodes
  407. daemons[0].UpdateNode(c, nodes[0].ID, func(n *swarm.Node) {
  408. n.Spec.Annotations.Labels = map[string]string{
  409. "rack": "a",
  410. }
  411. })
  412. for i := 1; i < nodeCount; i++ {
  413. daemons[0].UpdateNode(c, nodes[i].ID, func(n *swarm.Node) {
  414. n.Spec.Annotations.Labels = map[string]string{
  415. "rack": "b",
  416. }
  417. })
  418. }
  419. // create service
  420. instances := 4
  421. prefs := []swarm.PlacementPreference{{Spread: &swarm.SpreadOver{SpreadDescriptor: "node.labels.rack"}}}
  422. id := daemons[0].CreateService(c, simpleTestService, setPlacementPrefs(prefs), setInstances(instances))
  423. // wait for tasks ready
  424. waitAndAssert(c, defaultReconciliationTimeout, daemons[0].CheckServiceRunningTasks(id), checker.Equals, instances)
  425. tasks := daemons[0].GetServiceTasks(c, id)
  426. // validate all tasks are running on nodes[0]
  427. tasksOnNode := make(map[string]int)
  428. for _, task := range tasks {
  429. tasksOnNode[task.NodeID]++
  430. }
  431. c.Assert(tasksOnNode[nodes[0].ID], checker.Equals, 2)
  432. c.Assert(tasksOnNode[nodes[1].ID], checker.Equals, 1)
  433. c.Assert(tasksOnNode[nodes[2].ID], checker.Equals, 1)
  434. }
  435. func (s *DockerSwarmSuite) TestAPISwarmServicesStateReporting(c *check.C) {
  436. testRequires(c, SameHostDaemon)
  437. testRequires(c, DaemonIsLinux)
  438. d1 := s.AddDaemon(c, true, true)
  439. d2 := s.AddDaemon(c, true, true)
  440. d3 := s.AddDaemon(c, true, false)
  441. time.Sleep(1 * time.Second) // make sure all daemons are ready to accept
  442. instances := 9
  443. d1.CreateService(c, simpleTestService, setInstances(instances))
  444. waitAndAssert(c, defaultReconciliationTimeout, reducedCheck(sumAsIntegers, d1.CheckActiveContainerCount, d2.CheckActiveContainerCount, d3.CheckActiveContainerCount), checker.Equals, instances)
  445. getContainers := func() map[string]*daemon.Swarm {
  446. m := make(map[string]*daemon.Swarm)
  447. for _, d := range []*daemon.Swarm{d1, d2, d3} {
  448. for _, id := range d.ActiveContainers() {
  449. m[id] = d
  450. }
  451. }
  452. return m
  453. }
  454. containers := getContainers()
  455. c.Assert(containers, checker.HasLen, instances)
  456. var toRemove string
  457. for i := range containers {
  458. toRemove = i
  459. }
  460. _, err := containers[toRemove].Cmd("stop", toRemove)
  461. c.Assert(err, checker.IsNil)
  462. waitAndAssert(c, defaultReconciliationTimeout, reducedCheck(sumAsIntegers, d1.CheckActiveContainerCount, d2.CheckActiveContainerCount, d3.CheckActiveContainerCount), checker.Equals, instances)
  463. containers2 := getContainers()
  464. c.Assert(containers2, checker.HasLen, instances)
  465. for i := range containers {
  466. if i == toRemove {
  467. c.Assert(containers2[i], checker.IsNil)
  468. } else {
  469. c.Assert(containers2[i], checker.NotNil)
  470. }
  471. }
  472. containers = containers2
  473. for i := range containers {
  474. toRemove = i
  475. }
  476. // try with killing process outside of docker
  477. pidStr, err := containers[toRemove].Cmd("inspect", "-f", "{{.State.Pid}}", toRemove)
  478. c.Assert(err, checker.IsNil)
  479. pid, err := strconv.Atoi(strings.TrimSpace(pidStr))
  480. c.Assert(err, checker.IsNil)
  481. c.Assert(syscall.Kill(pid, syscall.SIGKILL), checker.IsNil)
  482. time.Sleep(time.Second) // give some time to handle the signal
  483. waitAndAssert(c, defaultReconciliationTimeout, reducedCheck(sumAsIntegers, d1.CheckActiveContainerCount, d2.CheckActiveContainerCount, d3.CheckActiveContainerCount), checker.Equals, instances)
  484. containers2 = getContainers()
  485. c.Assert(containers2, checker.HasLen, instances)
  486. for i := range containers {
  487. if i == toRemove {
  488. c.Assert(containers2[i], checker.IsNil)
  489. } else {
  490. c.Assert(containers2[i], checker.NotNil)
  491. }
  492. }
  493. }