Browse code

Test rolling update.

Signed-off-by: Dong Chen <dongluo.chen@docker.com>
(cherry picked from commit d327765a62a99dc63e9a8c16ac291861cee066f3)
Signed-off-by: Tibor Vass <tibor@docker.com>

Dong Chen authored on 2016/07/12 09:15:30
Showing 2 changed files
... ...
@@ -148,6 +148,39 @@ func (d *SwarmDaemon) getServiceTasks(c *check.C, service string) []swarm.Task {
148 148
 	return tasks
149 149
 }
150 150
 
151
+func (d *SwarmDaemon) checkRunningTaskImages(c *check.C) (interface{}, check.CommentInterface) {
152
+	var tasks []swarm.Task
153
+
154
+	filterArgs := filters.NewArgs()
155
+	filterArgs.Add("desired-state", "running")
156
+	filters, err := filters.ToParam(filterArgs)
157
+	c.Assert(err, checker.IsNil)
158
+
159
+	status, out, err := d.SockRequest("GET", "/tasks?filters="+filters, nil)
160
+	c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out)))
161
+	c.Assert(err, checker.IsNil, check.Commentf(string(out)))
162
+	c.Assert(json.Unmarshal(out, &tasks), checker.IsNil)
163
+
164
+	result := make(map[string]int)
165
+	for _, task := range tasks {
166
+		if task.Status.State == swarm.TaskStateRunning {
167
+			result[task.Spec.ContainerSpec.Image]++
168
+		}
169
+	}
170
+	return result, nil
171
+}
172
+
173
+func (d *SwarmDaemon) checkNodeReadyCount(c *check.C) (interface{}, check.CommentInterface) {
174
+	nodes := d.listNodes(c)
175
+	var readyCount int
176
+	for _, node := range nodes {
177
+		if node.Status.State == swarm.NodeStateReady {
178
+			readyCount++
179
+		}
180
+	}
181
+	return readyCount, nil
182
+}
183
+
151 184
 func (d *SwarmDaemon) getTask(c *check.C, id string) swarm.Task {
152 185
 	var task swarm.Task
153 186
 
... ...
@@ -371,6 +371,52 @@ func (s *DockerSwarmSuite) TestApiSwarmServicesCreateGlobal(c *check.C) {
371 371
 	waitAndAssert(c, defaultReconciliationTimeout, d5.checkActiveContainerCount, checker.Equals, 1)
372 372
 }
373 373
 
374
+func (s *DockerSwarmSuite) TestApiSwarmServicesUpdate(c *check.C) {
375
+	const nodeCount = 3
376
+	var daemons [nodeCount]*SwarmDaemon
377
+	for i := 0; i < nodeCount; i++ {
378
+		daemons[i] = s.AddDaemon(c, true, i == 0)
379
+	}
380
+	// wait for nodes ready
381
+	waitAndAssert(c, 5*time.Second, daemons[0].checkNodeReadyCount, checker.Equals, nodeCount)
382
+
383
+	// service image at start
384
+	image1 := "busybox:latest"
385
+	// target image in update
386
+	image2 := "busybox:test"
387
+
388
+	// create a different tag
389
+	for _, d := range daemons {
390
+		out, err := d.Cmd("tag", image1, image2)
391
+		c.Assert(err, checker.IsNil, check.Commentf(out))
392
+	}
393
+
394
+	// create service
395
+	instances := 5
396
+	parallelism := 2
397
+	id := daemons[0].createService(c, serviceForUpdate, setInstances(instances))
398
+
399
+	// wait for tasks ready
400
+	waitAndAssert(c, defaultReconciliationTimeout, daemons[0].checkRunningTaskImages, checker.DeepEquals,
401
+		map[string]int{image1: instances})
402
+
403
+	// issue service update
404
+	service := daemons[0].getService(c, id)
405
+	daemons[0].updateService(c, service, setImage(image2))
406
+
407
+	// first batch
408
+	waitAndAssert(c, defaultReconciliationTimeout, daemons[0].checkRunningTaskImages, checker.DeepEquals,
409
+		map[string]int{image1: instances - parallelism, image2: parallelism})
410
+
411
+	// 2nd batch
412
+	waitAndAssert(c, defaultReconciliationTimeout, daemons[0].checkRunningTaskImages, checker.DeepEquals,
413
+		map[string]int{image1: instances - 2*parallelism, image2: 2 * parallelism})
414
+
415
+	// 3nd batch
416
+	waitAndAssert(c, defaultReconciliationTimeout, daemons[0].checkRunningTaskImages, checker.DeepEquals,
417
+		map[string]int{image2: instances})
418
+}
419
+
374 420
 func (s *DockerSwarmSuite) TestApiSwarmServicesStateReporting(c *check.C) {
375 421
 	testRequires(c, Network)
376 422
 	testRequires(c, SameHostDaemon)
... ...
@@ -754,6 +800,29 @@ func simpleTestService(s *swarm.Service) {
754 754
 	s.Spec.Name = "top"
755 755
 }
756 756
 
757
+func serviceForUpdate(s *swarm.Service) {
758
+	var ureplicas uint64
759
+	ureplicas = 1
760
+	s.Spec = swarm.ServiceSpec{
761
+		TaskTemplate: swarm.TaskSpec{
762
+			ContainerSpec: swarm.ContainerSpec{
763
+				Image:   "busybox:latest",
764
+				Command: []string{"/bin/top"},
765
+			},
766
+		},
767
+		Mode: swarm.ServiceMode{
768
+			Replicated: &swarm.ReplicatedService{
769
+				Replicas: &ureplicas,
770
+			},
771
+		},
772
+		UpdateConfig: &swarm.UpdateConfig{
773
+			Parallelism: 2,
774
+			Delay:       8 * time.Second,
775
+		},
776
+	}
777
+	s.Spec.Name = "updatetest"
778
+}
779
+
757 780
 func setInstances(replicas int) serviceConstructor {
758 781
 	ureplicas := uint64(replicas)
759 782
 	return func(s *swarm.Service) {
... ...
@@ -765,6 +834,12 @@ func setInstances(replicas int) serviceConstructor {
765 765
 	}
766 766
 }
767 767
 
768
+func setImage(image string) serviceConstructor {
769
+	return func(s *swarm.Service) {
770
+		s.Spec.TaskTemplate.ContainerSpec.Image = image
771
+	}
772
+}
773
+
768 774
 func setGlobalMode(s *swarm.Service) {
769 775
 	s.Spec.Mode = swarm.ServiceMode{
770 776
 		Global: &swarm.GlobalService{},