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