mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Add integration test for START_FIRST update order
Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
This commit is contained in:
parent
9b54994a8a
commit
6763641d69
2 changed files with 127 additions and 0 deletions
|
@ -175,6 +175,115 @@ func (s *DockerSwarmSuite) TestAPISwarmServicesUpdate(c *check.C) {
|
|||
map[string]int{image1: instances})
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestAPISwarmServicesUpdateStartFirst(c *check.C) {
|
||||
d := s.AddDaemon(c, true, true)
|
||||
|
||||
// service image at start
|
||||
image1 := "busybox:latest"
|
||||
// target image in update
|
||||
image2 := "testhealth"
|
||||
|
||||
// service started from this image won't pass health check
|
||||
_, _, err := d.BuildImageWithOut(image2,
|
||||
`FROM busybox
|
||||
HEALTHCHECK --interval=1s --timeout=1s --retries=1024\
|
||||
CMD cat /status`,
|
||||
true)
|
||||
c.Check(err, check.IsNil)
|
||||
|
||||
// create service
|
||||
instances := 5
|
||||
parallelism := 2
|
||||
rollbackParallelism := 3
|
||||
id := d.CreateService(c, serviceForUpdate, setInstances(instances), setUpdateOrder(swarm.UpdateOrderStartFirst), setRollbackOrder(swarm.UpdateOrderStartFirst))
|
||||
|
||||
checkStartingTasks := func(expected int) []swarm.Task {
|
||||
var startingTasks []swarm.Task
|
||||
waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
|
||||
tasks := d.GetServiceTasks(c, id)
|
||||
startingTasks = nil
|
||||
for _, t := range tasks {
|
||||
if t.Status.State == swarm.TaskStateStarting {
|
||||
startingTasks = append(startingTasks, t)
|
||||
}
|
||||
}
|
||||
return startingTasks, nil
|
||||
}, checker.HasLen, expected)
|
||||
|
||||
return startingTasks
|
||||
}
|
||||
|
||||
makeTasksHealthy := func(tasks []swarm.Task) {
|
||||
for _, t := range tasks {
|
||||
containerID := t.Status.ContainerStatus.ContainerID
|
||||
d.Cmd("exec", containerID, "touch", "/status")
|
||||
}
|
||||
}
|
||||
|
||||
// wait for tasks ready
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d.CheckRunningTaskImages, checker.DeepEquals,
|
||||
map[string]int{image1: instances})
|
||||
|
||||
// issue service update
|
||||
service := d.GetService(c, id)
|
||||
d.UpdateService(c, service, setImage(image2))
|
||||
|
||||
// first batch
|
||||
|
||||
// The old tasks should be running, and the new ones should be starting.
|
||||
startingTasks := checkStartingTasks(parallelism)
|
||||
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d.CheckRunningTaskImages, checker.DeepEquals,
|
||||
map[string]int{image1: instances})
|
||||
|
||||
// make it healthy
|
||||
makeTasksHealthy(startingTasks)
|
||||
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d.CheckRunningTaskImages, checker.DeepEquals,
|
||||
map[string]int{image1: instances - parallelism, image2: parallelism})
|
||||
|
||||
// 2nd batch
|
||||
|
||||
// The old tasks should be running, and the new ones should be starting.
|
||||
startingTasks = checkStartingTasks(parallelism)
|
||||
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d.CheckRunningTaskImages, checker.DeepEquals,
|
||||
map[string]int{image1: instances - parallelism, image2: parallelism})
|
||||
|
||||
// make it healthy
|
||||
makeTasksHealthy(startingTasks)
|
||||
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d.CheckRunningTaskImages, checker.DeepEquals,
|
||||
map[string]int{image1: instances - 2*parallelism, image2: 2 * parallelism})
|
||||
|
||||
// 3nd batch
|
||||
|
||||
// The old tasks should be running, and the new ones should be starting.
|
||||
startingTasks = checkStartingTasks(1)
|
||||
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d.CheckRunningTaskImages, checker.DeepEquals,
|
||||
map[string]int{image1: instances - 2*parallelism, image2: 2 * parallelism})
|
||||
|
||||
// make it healthy
|
||||
makeTasksHealthy(startingTasks)
|
||||
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d.CheckRunningTaskImages, checker.DeepEquals,
|
||||
map[string]int{image2: instances})
|
||||
|
||||
// Roll back to the previous version. This uses the CLI because
|
||||
// rollback is a client-side operation.
|
||||
out, err := d.Cmd("service", "update", "--rollback", id)
|
||||
c.Assert(err, checker.IsNil, check.Commentf(out))
|
||||
|
||||
// first batch
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d.CheckRunningTaskImages, checker.DeepEquals,
|
||||
map[string]int{image2: instances - rollbackParallelism, image1: rollbackParallelism})
|
||||
|
||||
// 2nd batch
|
||||
waitAndAssert(c, defaultReconciliationTimeout, d.CheckRunningTaskImages, checker.DeepEquals,
|
||||
map[string]int{image1: instances})
|
||||
}
|
||||
|
||||
func (s *DockerSwarmSuite) TestAPISwarmServicesFailedUpdate(c *check.C) {
|
||||
const nodeCount = 3
|
||||
var daemons [nodeCount]*daemon.Swarm
|
||||
|
|
|
@ -596,6 +596,24 @@ func setInstances(replicas int) daemon.ServiceConstructor {
|
|||
}
|
||||
}
|
||||
|
||||
func setUpdateOrder(order string) daemon.ServiceConstructor {
|
||||
return func(s *swarm.Service) {
|
||||
if s.Spec.UpdateConfig == nil {
|
||||
s.Spec.UpdateConfig = &swarm.UpdateConfig{}
|
||||
}
|
||||
s.Spec.UpdateConfig.Order = order
|
||||
}
|
||||
}
|
||||
|
||||
func setRollbackOrder(order string) daemon.ServiceConstructor {
|
||||
return func(s *swarm.Service) {
|
||||
if s.Spec.RollbackConfig == nil {
|
||||
s.Spec.RollbackConfig = &swarm.UpdateConfig{}
|
||||
}
|
||||
s.Spec.RollbackConfig.Order = order
|
||||
}
|
||||
}
|
||||
|
||||
func setImage(image string) daemon.ServiceConstructor {
|
||||
return func(s *swarm.Service) {
|
||||
s.Spec.TaskTemplate.ContainerSpec.Image = image
|
||||
|
|
Loading…
Add table
Reference in a new issue