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