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  }