Browse code

Merge pull request #24878 from dongluochen/swarmConstraintTest

Add integration test for constraints

Aaron Lehmann authored on 2016/08/02 08:45:23
Showing 2 changed files
... ...
@@ -139,6 +139,26 @@ func (d *SwarmDaemon) getServiceTasks(c *check.C, service string) []swarm.Task {
139 139
 	return tasks
140 140
 }
141 141
 
142
+func (d *SwarmDaemon) checkServiceRunningTasks(c *check.C, service string) func(*check.C) (interface{}, check.CommentInterface) {
143
+	return func(*check.C) (interface{}, check.CommentInterface) {
144
+		tasks := d.getServiceTasks(c, service)
145
+		var runningCount int
146
+		for _, task := range tasks {
147
+			if task.Status.State == swarm.TaskStateRunning {
148
+				runningCount++
149
+			}
150
+		}
151
+		return runningCount, nil
152
+	}
153
+}
154
+
155
+func (d *SwarmDaemon) checkServiceTasks(c *check.C, service string) func(*check.C) (interface{}, check.CommentInterface) {
156
+	return func(*check.C) (interface{}, check.CommentInterface) {
157
+		tasks := d.getServiceTasks(c, service)
158
+		return len(tasks), nil
159
+	}
160
+}
161
+
142 162
 func (d *SwarmDaemon) checkRunningTaskImages(c *check.C) (interface{}, check.CommentInterface) {
143 163
 	var tasks []swarm.Task
144 164
 
... ...
@@ -312,6 +312,153 @@ func (s *DockerSwarmSuite) TestApiSwarmServicesUpdate(c *check.C) {
312 312
 		map[string]int{image2: instances})
313 313
 }
314 314
 
315
+func (s *DockerSwarmSuite) TestApiSwarmServiceConstraintRole(c *check.C) {
316
+	const nodeCount = 3
317
+	var daemons [nodeCount]*SwarmDaemon
318
+	for i := 0; i < nodeCount; i++ {
319
+		daemons[i] = s.AddDaemon(c, true, i == 0)
320
+	}
321
+	// wait for nodes ready
322
+	waitAndAssert(c, 5*time.Second, daemons[0].checkNodeReadyCount, checker.Equals, nodeCount)
323
+
324
+	// create service
325
+	constraints := []string{"node.role==worker"}
326
+	instances := 3
327
+	id := daemons[0].createService(c, simpleTestService, setConstraints(constraints), setInstances(instances))
328
+	// wait for tasks ready
329
+	waitAndAssert(c, defaultReconciliationTimeout, daemons[0].checkServiceRunningTasks(c, id), checker.Equals, instances)
330
+	// validate tasks are running on worker nodes
331
+	tasks := daemons[0].getServiceTasks(c, id)
332
+	for _, task := range tasks {
333
+		node := daemons[0].getNode(c, task.NodeID)
334
+		c.Assert(node.Spec.Role, checker.Equals, swarm.NodeRoleWorker)
335
+	}
336
+	//remove service
337
+	daemons[0].removeService(c, id)
338
+
339
+	// create service
340
+	constraints = []string{"node.role!=worker"}
341
+	id = daemons[0].createService(c, simpleTestService, setConstraints(constraints), setInstances(instances))
342
+	// wait for tasks ready
343
+	waitAndAssert(c, defaultReconciliationTimeout, daemons[0].checkServiceRunningTasks(c, id), checker.Equals, instances)
344
+	tasks = daemons[0].getServiceTasks(c, id)
345
+	// validate tasks are running on manager nodes
346
+	for _, task := range tasks {
347
+		node := daemons[0].getNode(c, task.NodeID)
348
+		c.Assert(node.Spec.Role, checker.Equals, swarm.NodeRoleManager)
349
+	}
350
+	//remove service
351
+	daemons[0].removeService(c, id)
352
+
353
+	// create service
354
+	constraints = []string{"node.role==nosuchrole"}
355
+	id = daemons[0].createService(c, simpleTestService, setConstraints(constraints), setInstances(instances))
356
+	// wait for tasks created
357
+	waitAndAssert(c, defaultReconciliationTimeout, daemons[0].checkServiceTasks(c, id), checker.Equals, instances)
358
+	// let scheduler try
359
+	time.Sleep(250 * time.Millisecond)
360
+	// validate tasks are not assigned to any node
361
+	tasks = daemons[0].getServiceTasks(c, id)
362
+	for _, task := range tasks {
363
+		c.Assert(task.NodeID, checker.Equals, "")
364
+	}
365
+}
366
+
367
+func (s *DockerSwarmSuite) TestApiSwarmServiceConstraintLabel(c *check.C) {
368
+	const nodeCount = 3
369
+	var daemons [nodeCount]*SwarmDaemon
370
+	for i := 0; i < nodeCount; i++ {
371
+		daemons[i] = s.AddDaemon(c, true, i == 0)
372
+	}
373
+	// wait for nodes ready
374
+	waitAndAssert(c, 5*time.Second, daemons[0].checkNodeReadyCount, checker.Equals, nodeCount)
375
+	nodes := daemons[0].listNodes(c)
376
+	c.Assert(len(nodes), checker.Equals, nodeCount)
377
+
378
+	// add labels to nodes
379
+	daemons[0].updateNode(c, nodes[0].ID, func(n *swarm.Node) {
380
+		n.Spec.Annotations.Labels = map[string]string{
381
+			"security": "high",
382
+		}
383
+	})
384
+	for i := 1; i < nodeCount; i++ {
385
+		daemons[0].updateNode(c, nodes[i].ID, func(n *swarm.Node) {
386
+			n.Spec.Annotations.Labels = map[string]string{
387
+				"security": "low",
388
+			}
389
+		})
390
+	}
391
+
392
+	// create service
393
+	instances := 3
394
+	constraints := []string{"node.labels.security==high"}
395
+	id := daemons[0].createService(c, simpleTestService, setConstraints(constraints), setInstances(instances))
396
+	// wait for tasks ready
397
+	waitAndAssert(c, defaultReconciliationTimeout, daemons[0].checkServiceRunningTasks(c, id), checker.Equals, instances)
398
+	tasks := daemons[0].getServiceTasks(c, id)
399
+	// validate all tasks are running on nodes[0]
400
+	for _, task := range tasks {
401
+		c.Assert(task.NodeID, checker.Equals, nodes[0].ID)
402
+	}
403
+	//remove service
404
+	daemons[0].removeService(c, id)
405
+
406
+	// create service
407
+	constraints = []string{"node.labels.security!=high"}
408
+	id = daemons[0].createService(c, simpleTestService, setConstraints(constraints), setInstances(instances))
409
+	// wait for tasks ready
410
+	waitAndAssert(c, defaultReconciliationTimeout, daemons[0].checkServiceRunningTasks(c, id), checker.Equals, instances)
411
+	tasks = daemons[0].getServiceTasks(c, id)
412
+	// validate all tasks are NOT running on nodes[0]
413
+	for _, task := range tasks {
414
+		c.Assert(task.NodeID, checker.Not(checker.Equals), nodes[0].ID)
415
+	}
416
+	//remove service
417
+	daemons[0].removeService(c, id)
418
+
419
+	constraints = []string{"node.labels.security==medium"}
420
+	id = daemons[0].createService(c, simpleTestService, setConstraints(constraints), setInstances(instances))
421
+	// wait for tasks created
422
+	waitAndAssert(c, defaultReconciliationTimeout, daemons[0].checkServiceTasks(c, id), checker.Equals, instances)
423
+	// let scheduler try
424
+	time.Sleep(250 * time.Millisecond)
425
+	tasks = daemons[0].getServiceTasks(c, id)
426
+	// validate tasks are not assigned
427
+	for _, task := range tasks {
428
+		c.Assert(task.NodeID, checker.Equals, "")
429
+	}
430
+	//remove service
431
+	daemons[0].removeService(c, id)
432
+
433
+	// multiple constraints
434
+	constraints = []string{
435
+		"node.labels.security==high",
436
+		fmt.Sprintf("node.id==%s", nodes[1].ID),
437
+	}
438
+	id = daemons[0].createService(c, simpleTestService, setConstraints(constraints), setInstances(instances))
439
+	// wait for tasks created
440
+	waitAndAssert(c, defaultReconciliationTimeout, daemons[0].checkServiceTasks(c, id), checker.Equals, instances)
441
+	// let scheduler try
442
+	time.Sleep(250 * time.Millisecond)
443
+	tasks = daemons[0].getServiceTasks(c, id)
444
+	// validate tasks are not assigned
445
+	for _, task := range tasks {
446
+		c.Assert(task.NodeID, checker.Equals, "")
447
+	}
448
+	// make nodes[1] fulfills the constraints
449
+	daemons[0].updateNode(c, nodes[1].ID, func(n *swarm.Node) {
450
+		n.Spec.Annotations.Labels = map[string]string{
451
+			"security": "high",
452
+		}
453
+	})
454
+	// wait for tasks ready
455
+	waitAndAssert(c, defaultReconciliationTimeout, daemons[0].checkServiceRunningTasks(c, id), checker.Equals, instances)
456
+	tasks = daemons[0].getServiceTasks(c, id)
457
+	for _, task := range tasks {
458
+		c.Assert(task.NodeID, checker.Equals, nodes[1].ID)
459
+	}
460
+}
461
+
315 462
 func (s *DockerSwarmSuite) TestApiSwarmServicesStateReporting(c *check.C) {
316 463
 	testRequires(c, SameHostDaemon)
317 464
 	testRequires(c, DaemonIsLinux)
... ...
@@ -834,6 +981,15 @@ func setImage(image string) serviceConstructor {
834 834
 	}
835 835
 }
836 836
 
837
+func setConstraints(constraints []string) serviceConstructor {
838
+	return func(s *swarm.Service) {
839
+		if s.Spec.TaskTemplate.Placement == nil {
840
+			s.Spec.TaskTemplate.Placement = &swarm.Placement{}
841
+		}
842
+		s.Spec.TaskTemplate.Placement.Constraints = constraints
843
+	}
844
+}
845
+
837 846
 func setGlobalMode(s *swarm.Service) {
838 847
 	s.Spec.Mode = swarm.ServiceMode{
839 848
 		Global: &swarm.GlobalService{},