Переглянути джерело

Test rolling update.

Signed-off-by: Dong Chen <dongluo.chen@docker.com>
Dong Chen 9 роки тому
батько
коміт
d327765a62

+ 33 - 0
integration-cli/daemon_swarm.go

@@ -148,6 +148,39 @@ func (d *SwarmDaemon) getServiceTasks(c *check.C, service string) []swarm.Task {
 	return tasks
 }
 
+func (d *SwarmDaemon) checkRunningTaskImages(c *check.C) (interface{}, check.CommentInterface) {
+	var tasks []swarm.Task
+
+	filterArgs := filters.NewArgs()
+	filterArgs.Add("desired-state", "running")
+	filters, err := filters.ToParam(filterArgs)
+	c.Assert(err, checker.IsNil)
+
+	status, out, err := d.SockRequest("GET", "/tasks?filters="+filters, nil)
+	c.Assert(status, checker.Equals, http.StatusOK, check.Commentf("output: %q", string(out)))
+	c.Assert(err, checker.IsNil, check.Commentf(string(out)))
+	c.Assert(json.Unmarshal(out, &tasks), checker.IsNil)
+
+	result := make(map[string]int)
+	for _, task := range tasks {
+		if task.Status.State == swarm.TaskStateRunning {
+			result[task.Spec.ContainerSpec.Image]++
+		}
+	}
+	return result, nil
+}
+
+func (d *SwarmDaemon) checkNodeReadyCount(c *check.C) (interface{}, check.CommentInterface) {
+	nodes := d.listNodes(c)
+	var readyCount int
+	for _, node := range nodes {
+		if node.Status.State == swarm.NodeStateReady {
+			readyCount++
+		}
+	}
+	return readyCount, nil
+}
+
 func (d *SwarmDaemon) getTask(c *check.C, id string) swarm.Task {
 	var task swarm.Task
 

+ 75 - 0
integration-cli/docker_api_swarm_test.go

@@ -371,6 +371,52 @@ func (s *DockerSwarmSuite) TestApiSwarmServicesCreateGlobal(c *check.C) {
 	waitAndAssert(c, defaultReconciliationTimeout, d5.checkActiveContainerCount, checker.Equals, 1)
 }
 
+func (s *DockerSwarmSuite) TestApiSwarmServicesUpdate(c *check.C) {
+	const nodeCount = 3
+	var daemons [nodeCount]*SwarmDaemon
+	for i := 0; i < nodeCount; i++ {
+		daemons[i] = s.AddDaemon(c, true, i == 0)
+	}
+	// wait for nodes ready
+	waitAndAssert(c, 5*time.Second, daemons[0].checkNodeReadyCount, checker.Equals, nodeCount)
+
+	// service image at start
+	image1 := "busybox:latest"
+	// target image in update
+	image2 := "busybox:test"
+
+	// create a different tag
+	for _, d := range daemons {
+		out, err := d.Cmd("tag", image1, image2)
+		c.Assert(err, checker.IsNil, check.Commentf(out))
+	}
+
+	// create service
+	instances := 5
+	parallelism := 2
+	id := daemons[0].createService(c, serviceForUpdate, setInstances(instances))
+
+	// wait for tasks ready
+	waitAndAssert(c, defaultReconciliationTimeout, daemons[0].checkRunningTaskImages, checker.DeepEquals,
+		map[string]int{image1: instances})
+
+	// issue service update
+	service := daemons[0].getService(c, id)
+	daemons[0].updateService(c, service, setImage(image2))
+
+	// first batch
+	waitAndAssert(c, defaultReconciliationTimeout, daemons[0].checkRunningTaskImages, checker.DeepEquals,
+		map[string]int{image1: instances - parallelism, image2: parallelism})
+
+	// 2nd batch
+	waitAndAssert(c, defaultReconciliationTimeout, daemons[0].checkRunningTaskImages, checker.DeepEquals,
+		map[string]int{image1: instances - 2*parallelism, image2: 2 * parallelism})
+
+	// 3nd batch
+	waitAndAssert(c, defaultReconciliationTimeout, daemons[0].checkRunningTaskImages, checker.DeepEquals,
+		map[string]int{image2: instances})
+}
+
 func (s *DockerSwarmSuite) TestApiSwarmServicesStateReporting(c *check.C) {
 	testRequires(c, Network)
 	testRequires(c, SameHostDaemon)
@@ -779,6 +825,29 @@ func simpleTestService(s *swarm.Service) {
 	s.Spec.Name = "top"
 }
 
+func serviceForUpdate(s *swarm.Service) {
+	var ureplicas uint64
+	ureplicas = 1
+	s.Spec = swarm.ServiceSpec{
+		TaskTemplate: swarm.TaskSpec{
+			ContainerSpec: swarm.ContainerSpec{
+				Image:   "busybox:latest",
+				Command: []string{"/bin/top"},
+			},
+		},
+		Mode: swarm.ServiceMode{
+			Replicated: &swarm.ReplicatedService{
+				Replicas: &ureplicas,
+			},
+		},
+		UpdateConfig: &swarm.UpdateConfig{
+			Parallelism: 2,
+			Delay:       8 * time.Second,
+		},
+	}
+	s.Spec.Name = "updatetest"
+}
+
 func setInstances(replicas int) serviceConstructor {
 	ureplicas := uint64(replicas)
 	return func(s *swarm.Service) {
@@ -790,6 +859,12 @@ func setInstances(replicas int) serviceConstructor {
 	}
 }
 
+func setImage(image string) serviceConstructor {
+	return func(s *swarm.Service) {
+		s.Spec.TaskTemplate.ContainerSpec.Image = image
+	}
+}
+
 func setGlobalMode(s *swarm.Service) {
 	s.Spec.Mode = swarm.ServiceMode{
 		Global: &swarm.GlobalService{},