docker_api_swarm_service_test.go 26 KB

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