github.com/yogeshlonkar/moby@v1.13.2-0.20201203103638-c0b64beaea94/integration-cli/docker_cli_swarm_test.go (about)

     1  // +build !windows
     2  
     3  package main
     4  
     5  import (
     6  	"bytes"
     7  	"encoding/json"
     8  	"fmt"
     9  	"io/ioutil"
    10  	"net/http"
    11  	"net/http/httptest"
    12  	"os"
    13  	"path/filepath"
    14  	"strings"
    15  	"time"
    16  
    17  	"github.com/docker/docker/api/types/swarm"
    18  	"github.com/docker/docker/pkg/integration/checker"
    19  	"github.com/docker/libnetwork/driverapi"
    20  	"github.com/docker/libnetwork/ipamapi"
    21  	remoteipam "github.com/docker/libnetwork/ipams/remote/api"
    22  	"github.com/go-check/check"
    23  	"github.com/vishvananda/netlink"
    24  )
    25  
    26  func (s *DockerSwarmSuite) TestSwarmUpdate(c *check.C) {
    27  	d := s.AddDaemon(c, true, true)
    28  
    29  	getSpec := func() swarm.Spec {
    30  		sw := d.getSwarm(c)
    31  		return sw.Spec
    32  	}
    33  
    34  	out, err := d.Cmd("swarm", "update", "--cert-expiry", "30h", "--dispatcher-heartbeat", "11s")
    35  	c.Assert(err, checker.IsNil, check.Commentf("out: %v", out))
    36  
    37  	spec := getSpec()
    38  	c.Assert(spec.CAConfig.NodeCertExpiry, checker.Equals, 30*time.Hour)
    39  	c.Assert(spec.Dispatcher.HeartbeatPeriod, checker.Equals, 11*time.Second)
    40  
    41  	// setting anything under 30m for cert-expiry is not allowed
    42  	out, err = d.Cmd("swarm", "update", "--cert-expiry", "15m")
    43  	c.Assert(err, checker.NotNil)
    44  	c.Assert(out, checker.Contains, "minimum certificate expiry time")
    45  	spec = getSpec()
    46  	c.Assert(spec.CAConfig.NodeCertExpiry, checker.Equals, 30*time.Hour)
    47  }
    48  
    49  func (s *DockerSwarmSuite) TestSwarmInit(c *check.C) {
    50  	d := s.AddDaemon(c, false, false)
    51  
    52  	getSpec := func() swarm.Spec {
    53  		sw := d.getSwarm(c)
    54  		return sw.Spec
    55  	}
    56  
    57  	out, err := d.Cmd("swarm", "init", "--cert-expiry", "30h", "--dispatcher-heartbeat", "11s")
    58  	c.Assert(err, checker.IsNil, check.Commentf("out: %v", out))
    59  
    60  	spec := getSpec()
    61  	c.Assert(spec.CAConfig.NodeCertExpiry, checker.Equals, 30*time.Hour)
    62  	c.Assert(spec.Dispatcher.HeartbeatPeriod, checker.Equals, 11*time.Second)
    63  
    64  	c.Assert(d.Leave(true), checker.IsNil)
    65  	time.Sleep(500 * time.Millisecond) // https://github.com/docker/swarmkit/issues/1421
    66  	out, err = d.Cmd("swarm", "init")
    67  	c.Assert(err, checker.IsNil, check.Commentf("out: %v", out))
    68  
    69  	spec = getSpec()
    70  	c.Assert(spec.CAConfig.NodeCertExpiry, checker.Equals, 90*24*time.Hour)
    71  	c.Assert(spec.Dispatcher.HeartbeatPeriod, checker.Equals, 5*time.Second)
    72  }
    73  
    74  func (s *DockerSwarmSuite) TestSwarmInitIPv6(c *check.C) {
    75  	testRequires(c, IPv6)
    76  	d1 := s.AddDaemon(c, false, false)
    77  	out, err := d1.Cmd("swarm", "init", "--listen-addr", "::1")
    78  	c.Assert(err, checker.IsNil, check.Commentf("out: %v", out))
    79  
    80  	d2 := s.AddDaemon(c, false, false)
    81  	out, err = d2.Cmd("swarm", "join", "::1")
    82  	c.Assert(err, checker.IsNil, check.Commentf("out: %v", out))
    83  
    84  	out, err = d2.Cmd("info")
    85  	c.Assert(err, checker.IsNil, check.Commentf("out: %v", out))
    86  	c.Assert(out, checker.Contains, "Swarm: active")
    87  }
    88  
    89  func (s *DockerSwarmSuite) TestSwarmInitUnspecifiedAdvertiseAddr(c *check.C) {
    90  	d := s.AddDaemon(c, false, false)
    91  	out, err := d.Cmd("swarm", "init", "--advertise-addr", "0.0.0.0")
    92  	c.Assert(err, checker.NotNil)
    93  	c.Assert(out, checker.Contains, "advertise address must be a non-zero IP address")
    94  }
    95  
    96  func (s *DockerSwarmSuite) TestSwarmIncompatibleDaemon(c *check.C) {
    97  	// init swarm mode and stop a daemon
    98  	d := s.AddDaemon(c, true, true)
    99  	info, err := d.info()
   100  	c.Assert(err, checker.IsNil)
   101  	c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
   102  	c.Assert(d.Stop(), checker.IsNil)
   103  
   104  	// start a daemon with --cluster-store and --cluster-advertise
   105  	err = d.Start("--cluster-store=consul://consuladdr:consulport/some/path", "--cluster-advertise=1.1.1.1:2375")
   106  	c.Assert(err, checker.NotNil)
   107  	content, _ := ioutil.ReadFile(d.logFile.Name())
   108  	c.Assert(string(content), checker.Contains, "--cluster-store and --cluster-advertise daemon configurations are incompatible with swarm mode")
   109  
   110  	// start a daemon with --live-restore
   111  	err = d.Start("--live-restore")
   112  	c.Assert(err, checker.NotNil)
   113  	content, _ = ioutil.ReadFile(d.logFile.Name())
   114  	c.Assert(string(content), checker.Contains, "--live-restore daemon configuration is incompatible with swarm mode")
   115  	// restart for teardown
   116  	c.Assert(d.Start(), checker.IsNil)
   117  }
   118  
   119  // Test case for #24090
   120  func (s *DockerSwarmSuite) TestSwarmNodeListHostname(c *check.C) {
   121  	d := s.AddDaemon(c, true, true)
   122  
   123  	// The first line should contain "HOSTNAME"
   124  	out, err := d.Cmd("node", "ls")
   125  	c.Assert(err, checker.IsNil)
   126  	c.Assert(strings.Split(out, "\n")[0], checker.Contains, "HOSTNAME")
   127  }
   128  
   129  func (s *DockerSwarmSuite) TestSwarmServiceTemplatingHostname(c *check.C) {
   130  	d := s.AddDaemon(c, true, true)
   131  
   132  	out, err := d.Cmd("service", "create", "--name", "test", "--hostname", "{{.Service.Name}}-{{.Task.Slot}}", "busybox", "top")
   133  	c.Assert(err, checker.IsNil, check.Commentf(out))
   134  
   135  	// make sure task has been deployed.
   136  	waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 1)
   137  
   138  	containers := d.activeContainers()
   139  	out, err = d.Cmd("inspect", "--type", "container", "--format", "{{.Config.Hostname}}", containers[0])
   140  	c.Assert(err, checker.IsNil, check.Commentf(out))
   141  	c.Assert(strings.Split(out, "\n")[0], checker.Equals, "test-1", check.Commentf("hostname with templating invalid"))
   142  }
   143  
   144  // Test case for #24270
   145  func (s *DockerSwarmSuite) TestSwarmServiceListFilter(c *check.C) {
   146  	d := s.AddDaemon(c, true, true)
   147  
   148  	name1 := "redis-cluster-md5"
   149  	name2 := "redis-cluster"
   150  	name3 := "other-cluster"
   151  	out, err := d.Cmd("service", "create", "--name", name1, "busybox", "top")
   152  	c.Assert(err, checker.IsNil)
   153  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   154  
   155  	out, err = d.Cmd("service", "create", "--name", name2, "busybox", "top")
   156  	c.Assert(err, checker.IsNil)
   157  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   158  
   159  	out, err = d.Cmd("service", "create", "--name", name3, "busybox", "top")
   160  	c.Assert(err, checker.IsNil)
   161  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   162  
   163  	filter1 := "name=redis-cluster-md5"
   164  	filter2 := "name=redis-cluster"
   165  
   166  	// We search checker.Contains with `name+" "` to prevent prefix only.
   167  	out, err = d.Cmd("service", "ls", "--filter", filter1)
   168  	c.Assert(err, checker.IsNil)
   169  	c.Assert(out, checker.Contains, name1+" ")
   170  	c.Assert(out, checker.Not(checker.Contains), name2+" ")
   171  	c.Assert(out, checker.Not(checker.Contains), name3+" ")
   172  
   173  	out, err = d.Cmd("service", "ls", "--filter", filter2)
   174  	c.Assert(err, checker.IsNil)
   175  	c.Assert(out, checker.Contains, name1+" ")
   176  	c.Assert(out, checker.Contains, name2+" ")
   177  	c.Assert(out, checker.Not(checker.Contains), name3+" ")
   178  
   179  	out, err = d.Cmd("service", "ls")
   180  	c.Assert(err, checker.IsNil)
   181  	c.Assert(out, checker.Contains, name1+" ")
   182  	c.Assert(out, checker.Contains, name2+" ")
   183  	c.Assert(out, checker.Contains, name3+" ")
   184  }
   185  
   186  func (s *DockerSwarmSuite) TestSwarmNodeListFilter(c *check.C) {
   187  	d := s.AddDaemon(c, true, true)
   188  
   189  	out, err := d.Cmd("node", "inspect", "--format", "{{ .Description.Hostname }}", "self")
   190  	c.Assert(err, checker.IsNil)
   191  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   192  	name := strings.TrimSpace(out)
   193  
   194  	filter := "name=" + name[:4]
   195  
   196  	out, err = d.Cmd("node", "ls", "--filter", filter)
   197  	c.Assert(err, checker.IsNil)
   198  	c.Assert(out, checker.Contains, name)
   199  
   200  	out, err = d.Cmd("node", "ls", "--filter", "name=none")
   201  	c.Assert(err, checker.IsNil)
   202  	c.Assert(out, checker.Not(checker.Contains), name)
   203  }
   204  
   205  func (s *DockerSwarmSuite) TestSwarmNodeTaskListFilter(c *check.C) {
   206  	d := s.AddDaemon(c, true, true)
   207  
   208  	name := "redis-cluster-md5"
   209  	out, err := d.Cmd("service", "create", "--name", name, "--replicas=3", "busybox", "top")
   210  	c.Assert(err, checker.IsNil)
   211  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   212  
   213  	// make sure task has been deployed.
   214  	waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 3)
   215  
   216  	filter := "name=redis-cluster"
   217  
   218  	out, err = d.Cmd("node", "ps", "--filter", filter, "self")
   219  	c.Assert(err, checker.IsNil)
   220  	c.Assert(out, checker.Contains, name+".1")
   221  	c.Assert(out, checker.Contains, name+".2")
   222  	c.Assert(out, checker.Contains, name+".3")
   223  
   224  	out, err = d.Cmd("node", "ps", "--filter", "name=none", "self")
   225  	c.Assert(err, checker.IsNil)
   226  	c.Assert(out, checker.Not(checker.Contains), name+".1")
   227  	c.Assert(out, checker.Not(checker.Contains), name+".2")
   228  	c.Assert(out, checker.Not(checker.Contains), name+".3")
   229  }
   230  
   231  // Test case for #25375
   232  func (s *DockerSwarmSuite) TestSwarmPublishAdd(c *check.C) {
   233  	d := s.AddDaemon(c, true, true)
   234  
   235  	testCases := []struct {
   236  		name       string
   237  		publishAdd []string
   238  		ports      string
   239  	}{
   240  		{
   241  			name: "simple-syntax",
   242  			publishAdd: []string{
   243  				"80:80",
   244  				"80:80",
   245  				"80:80",
   246  				"80:20",
   247  			},
   248  			ports: "[{ tcp 80 80 ingress}]",
   249  		},
   250  		{
   251  			name: "complex-syntax",
   252  			publishAdd: []string{
   253  				"target=90,published=90,protocol=tcp,mode=ingress",
   254  				"target=90,published=90,protocol=tcp,mode=ingress",
   255  				"target=90,published=90,protocol=tcp,mode=ingress",
   256  				"target=30,published=90,protocol=tcp,mode=ingress",
   257  			},
   258  			ports: "[{ tcp 90 90 ingress}]",
   259  		},
   260  	}
   261  
   262  	for _, tc := range testCases {
   263  		out, err := d.Cmd("service", "create", "--name", tc.name, "--label", "x=y", "busybox", "top")
   264  		c.Assert(err, checker.IsNil, check.Commentf(out))
   265  		c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   266  
   267  		out, err = d.cmdRetryOutOfSequence("service", "update", "--publish-add", tc.publishAdd[0], tc.name)
   268  		c.Assert(err, checker.IsNil, check.Commentf(out))
   269  
   270  		out, err = d.cmdRetryOutOfSequence("service", "update", "--publish-add", tc.publishAdd[1], tc.name)
   271  		c.Assert(err, checker.IsNil, check.Commentf(out))
   272  
   273  		out, err = d.cmdRetryOutOfSequence("service", "update", "--publish-add", tc.publishAdd[2], "--publish-add", tc.publishAdd[3], tc.name)
   274  		c.Assert(err, checker.NotNil, check.Commentf(out))
   275  
   276  		out, err = d.Cmd("service", "inspect", "--format", "{{ .Spec.EndpointSpec.Ports }}", tc.name)
   277  		c.Assert(err, checker.IsNil)
   278  		c.Assert(strings.TrimSpace(out), checker.Equals, tc.ports)
   279  	}
   280  }
   281  
   282  func (s *DockerSwarmSuite) TestSwarmServiceWithGroup(c *check.C) {
   283  	d := s.AddDaemon(c, true, true)
   284  
   285  	name := "top"
   286  	out, err := d.Cmd("service", "create", "--name", name, "--user", "root:root", "--group", "wheel", "--group", "audio", "--group", "staff", "--group", "777", "busybox", "top")
   287  	c.Assert(err, checker.IsNil)
   288  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   289  
   290  	// make sure task has been deployed.
   291  	waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 1)
   292  
   293  	out, err = d.Cmd("ps", "-q")
   294  	c.Assert(err, checker.IsNil)
   295  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   296  
   297  	container := strings.TrimSpace(out)
   298  
   299  	out, err = d.Cmd("exec", container, "id")
   300  	c.Assert(err, checker.IsNil)
   301  	c.Assert(strings.TrimSpace(out), checker.Equals, "uid=0(root) gid=0(root) groups=10(wheel),29(audio),50(staff),777")
   302  }
   303  
   304  func (s *DockerSwarmSuite) TestSwarmContainerAutoStart(c *check.C) {
   305  	d := s.AddDaemon(c, true, true)
   306  
   307  	out, err := d.Cmd("network", "create", "--attachable", "-d", "overlay", "foo")
   308  	c.Assert(err, checker.IsNil)
   309  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   310  
   311  	out, err = d.Cmd("run", "-id", "--restart=always", "--net=foo", "--name=test", "busybox", "top")
   312  	c.Assert(err, checker.IsNil, check.Commentf(out))
   313  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   314  
   315  	out, err = d.Cmd("ps", "-q")
   316  	c.Assert(err, checker.IsNil, check.Commentf(out))
   317  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   318  
   319  	d.Restart()
   320  
   321  	out, err = d.Cmd("ps", "-q")
   322  	c.Assert(err, checker.IsNil, check.Commentf(out))
   323  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   324  }
   325  
   326  func (s *DockerSwarmSuite) TestSwarmContainerEndpointOptions(c *check.C) {
   327  	d := s.AddDaemon(c, true, true)
   328  
   329  	out, err := d.Cmd("network", "create", "--attachable", "-d", "overlay", "foo")
   330  	c.Assert(err, checker.IsNil, check.Commentf(out))
   331  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   332  
   333  	_, err = d.Cmd("run", "-d", "--net=foo", "--name=first", "--net-alias=first-alias", "busybox", "top")
   334  	c.Assert(err, checker.IsNil, check.Commentf(out))
   335  
   336  	_, err = d.Cmd("run", "-d", "--net=foo", "--name=second", "busybox", "top")
   337  	c.Assert(err, checker.IsNil, check.Commentf(out))
   338  
   339  	// ping first container and its alias
   340  	_, err = d.Cmd("exec", "second", "ping", "-c", "1", "first")
   341  	c.Assert(err, check.IsNil, check.Commentf(out))
   342  	_, err = d.Cmd("exec", "second", "ping", "-c", "1", "first-alias")
   343  	c.Assert(err, check.IsNil, check.Commentf(out))
   344  }
   345  
   346  func (s *DockerSwarmSuite) TestSwarmContainerAttachByNetworkId(c *check.C) {
   347  	d := s.AddDaemon(c, true, true)
   348  
   349  	out, err := d.Cmd("network", "create", "--attachable", "-d", "overlay", "testnet")
   350  	c.Assert(err, checker.IsNil)
   351  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   352  	networkID := strings.TrimSpace(out)
   353  
   354  	out, err = d.Cmd("run", "-d", "--net", networkID, "busybox", "top")
   355  	c.Assert(err, checker.IsNil)
   356  	cID := strings.TrimSpace(out)
   357  	d.waitRun(cID)
   358  
   359  	_, err = d.Cmd("rm", "-f", cID)
   360  	c.Assert(err, checker.IsNil)
   361  
   362  	out, err = d.Cmd("network", "rm", "testnet")
   363  	c.Assert(err, checker.IsNil)
   364  
   365  	checkNetwork := func(*check.C) (interface{}, check.CommentInterface) {
   366  		out, err := d.Cmd("network", "ls")
   367  		c.Assert(err, checker.IsNil)
   368  		return out, nil
   369  	}
   370  
   371  	waitAndAssert(c, 3*time.Second, checkNetwork, checker.Not(checker.Contains), "testnet")
   372  }
   373  
   374  func (s *DockerSwarmSuite) TestOverlayAttachable(c *check.C) {
   375  	d := s.AddDaemon(c, true, true)
   376  
   377  	out, err := d.Cmd("network", "create", "-d", "overlay", "--attachable", "ovnet")
   378  	c.Assert(err, checker.IsNil, check.Commentf(out))
   379  
   380  	// validate attachable
   381  	out, err = d.Cmd("network", "inspect", "--format", "{{json .Attachable}}", "ovnet")
   382  	c.Assert(err, checker.IsNil, check.Commentf(out))
   383  	c.Assert(strings.TrimSpace(out), checker.Equals, "true")
   384  
   385  	// validate containers can attache to this overlay network
   386  	out, err = d.Cmd("run", "-d", "--network", "ovnet", "--name", "c1", "busybox", "top")
   387  	c.Assert(err, checker.IsNil, check.Commentf(out))
   388  
   389  	// redo validation, there was a bug that the value of attachable changes after
   390  	// containers attach to the network
   391  	out, err = d.Cmd("network", "inspect", "--format", "{{json .Attachable}}", "ovnet")
   392  	c.Assert(err, checker.IsNil, check.Commentf(out))
   393  	c.Assert(strings.TrimSpace(out), checker.Equals, "true")
   394  }
   395  
   396  func (s *DockerSwarmSuite) TestOverlayAttachableOnSwarmLeave(c *check.C) {
   397  	d := s.AddDaemon(c, true, true)
   398  
   399  	// Create an attachable swarm network
   400  	nwName := "attovl"
   401  	out, err := d.Cmd("network", "create", "-d", "overlay", "--attachable", nwName)
   402  	c.Assert(err, checker.IsNil, check.Commentf(out))
   403  
   404  	// Connect a container to the network
   405  	out, err = d.Cmd("run", "-d", "--network", nwName, "--name", "c1", "busybox", "top")
   406  	c.Assert(err, checker.IsNil, check.Commentf(out))
   407  
   408  	// Leave the swarm
   409  	err = d.Leave(true)
   410  	c.Assert(err, checker.IsNil)
   411  
   412  	// Check the container is disconnected
   413  	out, err = d.Cmd("inspect", "c1", "--format", "{{.NetworkSettings.Networks."+nwName+"}}")
   414  	c.Assert(err, checker.IsNil)
   415  	c.Assert(strings.TrimSpace(out), checker.Equals, "<no value>")
   416  
   417  	// Check the network is gone
   418  	out, err = d.Cmd("network", "ls", "--format", "{{.Name}}")
   419  	c.Assert(err, checker.IsNil)
   420  	c.Assert(out, checker.Not(checker.Contains), nwName)
   421  }
   422  
   423  func (s *DockerSwarmSuite) TestOverlayAttachableReleaseResourcesOnFailure(c *check.C) {
   424  	d := s.AddDaemon(c, true, true)
   425  
   426  	// Create attachable network
   427  	out, err := d.Cmd("network", "create", "-d", "overlay", "--attachable", "--subnet", "10.10.9.0/24", "ovnet")
   428  	c.Assert(err, checker.IsNil, check.Commentf(out))
   429  
   430  	// Attach a container with specific IP
   431  	out, err = d.Cmd("run", "-d", "--network", "ovnet", "--name", "c1", "--ip", "10.10.9.33", "busybox", "top")
   432  	c.Assert(err, checker.IsNil, check.Commentf(out))
   433  
   434  	// Attempt to attach another contianer with same IP, must fail
   435  	_, err = d.Cmd("run", "-d", "--network", "ovnet", "--name", "c2", "--ip", "10.10.9.33", "busybox", "top")
   436  	c.Assert(err, checker.NotNil)
   437  
   438  	// Remove first container
   439  	out, err = d.Cmd("rm", "-f", "c1")
   440  	c.Assert(err, checker.IsNil, check.Commentf(out))
   441  
   442  	// Verify the network can be removed, no phantom network attachment task left over
   443  	out, err = d.Cmd("network", "rm", "ovnet")
   444  	c.Assert(err, checker.IsNil, check.Commentf(out))
   445  }
   446  
   447  func (s *DockerSwarmSuite) TestSwarmRemoveInternalNetwork(c *check.C) {
   448  	d := s.AddDaemon(c, true, true)
   449  
   450  	name := "ingress"
   451  	out, err := d.Cmd("network", "rm", name)
   452  	c.Assert(err, checker.NotNil)
   453  	c.Assert(strings.TrimSpace(out), checker.Contains, name)
   454  	c.Assert(strings.TrimSpace(out), checker.Contains, "is a pre-defined network and cannot be removed")
   455  }
   456  
   457  // Test case for #24108, also the case from:
   458  // https://github.com/docker/docker/pull/24620#issuecomment-233715656
   459  func (s *DockerSwarmSuite) TestSwarmTaskListFilter(c *check.C) {
   460  	d := s.AddDaemon(c, true, true)
   461  
   462  	name := "redis-cluster-md5"
   463  	out, err := d.Cmd("service", "create", "--name", name, "--replicas=3", "busybox", "top")
   464  	c.Assert(err, checker.IsNil)
   465  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   466  
   467  	filter := "name=redis-cluster"
   468  
   469  	checkNumTasks := func(*check.C) (interface{}, check.CommentInterface) {
   470  		out, err := d.Cmd("service", "ps", "--filter", filter, name)
   471  		c.Assert(err, checker.IsNil)
   472  		return len(strings.Split(out, "\n")) - 2, nil // includes header and nl in last line
   473  	}
   474  
   475  	// wait until all tasks have been created
   476  	waitAndAssert(c, defaultReconciliationTimeout, checkNumTasks, checker.Equals, 3)
   477  
   478  	out, err = d.Cmd("service", "ps", "--filter", filter, name)
   479  	c.Assert(err, checker.IsNil)
   480  	c.Assert(out, checker.Contains, name+".1")
   481  	c.Assert(out, checker.Contains, name+".2")
   482  	c.Assert(out, checker.Contains, name+".3")
   483  
   484  	out, err = d.Cmd("service", "ps", "--filter", "name="+name+".1", name)
   485  	c.Assert(err, checker.IsNil)
   486  	c.Assert(out, checker.Contains, name+".1")
   487  	c.Assert(out, checker.Not(checker.Contains), name+".2")
   488  	c.Assert(out, checker.Not(checker.Contains), name+".3")
   489  
   490  	out, err = d.Cmd("service", "ps", "--filter", "name=none", name)
   491  	c.Assert(err, checker.IsNil)
   492  	c.Assert(out, checker.Not(checker.Contains), name+".1")
   493  	c.Assert(out, checker.Not(checker.Contains), name+".2")
   494  	c.Assert(out, checker.Not(checker.Contains), name+".3")
   495  
   496  	name = "redis-cluster-sha1"
   497  	out, err = d.Cmd("service", "create", "--name", name, "--mode=global", "busybox", "top")
   498  	c.Assert(err, checker.IsNil)
   499  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   500  
   501  	waitAndAssert(c, defaultReconciliationTimeout, checkNumTasks, checker.Equals, 1)
   502  
   503  	filter = "name=redis-cluster"
   504  	out, err = d.Cmd("service", "ps", "--filter", filter, name)
   505  	c.Assert(err, checker.IsNil)
   506  	c.Assert(out, checker.Contains, name)
   507  
   508  	out, err = d.Cmd("service", "ps", "--filter", "name="+name, name)
   509  	c.Assert(err, checker.IsNil)
   510  	c.Assert(out, checker.Contains, name)
   511  
   512  	out, err = d.Cmd("service", "ps", "--filter", "name=none", name)
   513  	c.Assert(err, checker.IsNil)
   514  	c.Assert(out, checker.Not(checker.Contains), name)
   515  }
   516  
   517  func (s *DockerSwarmSuite) TestPsListContainersFilterIsTask(c *check.C) {
   518  	d := s.AddDaemon(c, true, true)
   519  
   520  	// Create a bare container
   521  	out, err := d.Cmd("run", "-d", "--name=bare-container", "busybox", "top")
   522  	c.Assert(err, checker.IsNil)
   523  	bareID := strings.TrimSpace(out)[:12]
   524  	// Create a service
   525  	name := "busybox-top"
   526  	out, err = d.Cmd("service", "create", "--name", name, "busybox", "top")
   527  	c.Assert(err, checker.IsNil)
   528  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   529  
   530  	// make sure task has been deployed.
   531  	waitAndAssert(c, defaultReconciliationTimeout, d.checkServiceRunningTasks(name), checker.Equals, 1)
   532  
   533  	// Filter non-tasks
   534  	out, err = d.Cmd("ps", "-a", "-q", "--filter=is-task=false")
   535  	c.Assert(err, checker.IsNil)
   536  	psOut := strings.TrimSpace(out)
   537  	c.Assert(psOut, checker.Equals, bareID, check.Commentf("Expected id %s, got %s for is-task label, output %q", bareID, psOut, out))
   538  
   539  	// Filter tasks
   540  	out, err = d.Cmd("ps", "-a", "-q", "--filter=is-task=true")
   541  	c.Assert(err, checker.IsNil)
   542  	lines := strings.Split(strings.Trim(out, "\n "), "\n")
   543  	c.Assert(lines, checker.HasLen, 1)
   544  	c.Assert(lines[0], checker.Not(checker.Equals), bareID, check.Commentf("Expected not %s, but got it for is-task label, output %q", bareID, out))
   545  }
   546  
   547  const globalNetworkPlugin = "global-network-plugin"
   548  const globalIPAMPlugin = "global-ipam-plugin"
   549  
   550  func setupRemoteGlobalNetworkPlugin(c *check.C, mux *http.ServeMux, url, netDrv, ipamDrv string) {
   551  
   552  	mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) {
   553  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   554  		fmt.Fprintf(w, `{"Implements": ["%s", "%s"]}`, driverapi.NetworkPluginEndpointType, ipamapi.PluginEndpointType)
   555  	})
   556  
   557  	// Network driver implementation
   558  	mux.HandleFunc(fmt.Sprintf("/%s.GetCapabilities", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   559  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   560  		fmt.Fprintf(w, `{"Scope":"global"}`)
   561  	})
   562  
   563  	mux.HandleFunc(fmt.Sprintf("/%s.AllocateNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   564  		err := json.NewDecoder(r.Body).Decode(&remoteDriverNetworkRequest)
   565  		if err != nil {
   566  			http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
   567  			return
   568  		}
   569  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   570  		fmt.Fprintf(w, "null")
   571  	})
   572  
   573  	mux.HandleFunc(fmt.Sprintf("/%s.FreeNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   574  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   575  		fmt.Fprintf(w, "null")
   576  	})
   577  
   578  	mux.HandleFunc(fmt.Sprintf("/%s.CreateNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   579  		err := json.NewDecoder(r.Body).Decode(&remoteDriverNetworkRequest)
   580  		if err != nil {
   581  			http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
   582  			return
   583  		}
   584  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   585  		fmt.Fprintf(w, "null")
   586  	})
   587  
   588  	mux.HandleFunc(fmt.Sprintf("/%s.DeleteNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   589  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   590  		fmt.Fprintf(w, "null")
   591  	})
   592  
   593  	mux.HandleFunc(fmt.Sprintf("/%s.CreateEndpoint", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   594  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   595  		fmt.Fprintf(w, `{"Interface":{"MacAddress":"a0:b1:c2:d3:e4:f5"}}`)
   596  	})
   597  
   598  	mux.HandleFunc(fmt.Sprintf("/%s.Join", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   599  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   600  
   601  		veth := &netlink.Veth{
   602  			LinkAttrs: netlink.LinkAttrs{Name: "randomIfName", TxQLen: 0}, PeerName: "cnt0"}
   603  		if err := netlink.LinkAdd(veth); err != nil {
   604  			fmt.Fprintf(w, `{"Error":"failed to add veth pair: `+err.Error()+`"}`)
   605  		} else {
   606  			fmt.Fprintf(w, `{"InterfaceName":{ "SrcName":"cnt0", "DstPrefix":"veth"}}`)
   607  		}
   608  	})
   609  
   610  	mux.HandleFunc(fmt.Sprintf("/%s.Leave", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   611  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   612  		fmt.Fprintf(w, "null")
   613  	})
   614  
   615  	mux.HandleFunc(fmt.Sprintf("/%s.DeleteEndpoint", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   616  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   617  		if link, err := netlink.LinkByName("cnt0"); err == nil {
   618  			netlink.LinkDel(link)
   619  		}
   620  		fmt.Fprintf(w, "null")
   621  	})
   622  
   623  	// IPAM Driver implementation
   624  	var (
   625  		poolRequest       remoteipam.RequestPoolRequest
   626  		poolReleaseReq    remoteipam.ReleasePoolRequest
   627  		addressRequest    remoteipam.RequestAddressRequest
   628  		addressReleaseReq remoteipam.ReleaseAddressRequest
   629  		lAS               = "localAS"
   630  		gAS               = "globalAS"
   631  		pool              = "172.28.0.0/16"
   632  		poolID            = lAS + "/" + pool
   633  		gw                = "172.28.255.254/16"
   634  	)
   635  
   636  	mux.HandleFunc(fmt.Sprintf("/%s.GetDefaultAddressSpaces", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   637  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   638  		fmt.Fprintf(w, `{"LocalDefaultAddressSpace":"`+lAS+`", "GlobalDefaultAddressSpace": "`+gAS+`"}`)
   639  	})
   640  
   641  	mux.HandleFunc(fmt.Sprintf("/%s.RequestPool", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   642  		err := json.NewDecoder(r.Body).Decode(&poolRequest)
   643  		if err != nil {
   644  			http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
   645  			return
   646  		}
   647  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   648  		if poolRequest.AddressSpace != lAS && poolRequest.AddressSpace != gAS {
   649  			fmt.Fprintf(w, `{"Error":"Unknown address space in pool request: `+poolRequest.AddressSpace+`"}`)
   650  		} else if poolRequest.Pool != "" && poolRequest.Pool != pool {
   651  			fmt.Fprintf(w, `{"Error":"Cannot handle explicit pool requests yet"}`)
   652  		} else {
   653  			fmt.Fprintf(w, `{"PoolID":"`+poolID+`", "Pool":"`+pool+`"}`)
   654  		}
   655  	})
   656  
   657  	mux.HandleFunc(fmt.Sprintf("/%s.RequestAddress", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   658  		err := json.NewDecoder(r.Body).Decode(&addressRequest)
   659  		if err != nil {
   660  			http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
   661  			return
   662  		}
   663  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   664  		// make sure libnetwork is now querying on the expected pool id
   665  		if addressRequest.PoolID != poolID {
   666  			fmt.Fprintf(w, `{"Error":"unknown pool id"}`)
   667  		} else if addressRequest.Address != "" {
   668  			fmt.Fprintf(w, `{"Error":"Cannot handle explicit address requests yet"}`)
   669  		} else {
   670  			fmt.Fprintf(w, `{"Address":"`+gw+`"}`)
   671  		}
   672  	})
   673  
   674  	mux.HandleFunc(fmt.Sprintf("/%s.ReleaseAddress", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   675  		err := json.NewDecoder(r.Body).Decode(&addressReleaseReq)
   676  		if err != nil {
   677  			http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
   678  			return
   679  		}
   680  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   681  		// make sure libnetwork is now asking to release the expected address from the expected poolid
   682  		if addressRequest.PoolID != poolID {
   683  			fmt.Fprintf(w, `{"Error":"unknown pool id"}`)
   684  		} else if addressReleaseReq.Address != gw {
   685  			fmt.Fprintf(w, `{"Error":"unknown address"}`)
   686  		} else {
   687  			fmt.Fprintf(w, "null")
   688  		}
   689  	})
   690  
   691  	mux.HandleFunc(fmt.Sprintf("/%s.ReleasePool", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   692  		err := json.NewDecoder(r.Body).Decode(&poolReleaseReq)
   693  		if err != nil {
   694  			http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
   695  			return
   696  		}
   697  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   698  		// make sure libnetwork is now asking to release the expected poolid
   699  		if addressRequest.PoolID != poolID {
   700  			fmt.Fprintf(w, `{"Error":"unknown pool id"}`)
   701  		} else {
   702  			fmt.Fprintf(w, "null")
   703  		}
   704  	})
   705  
   706  	err := os.MkdirAll("/etc/docker/plugins", 0755)
   707  	c.Assert(err, checker.IsNil)
   708  
   709  	fileName := fmt.Sprintf("/etc/docker/plugins/%s.spec", netDrv)
   710  	err = ioutil.WriteFile(fileName, []byte(url), 0644)
   711  	c.Assert(err, checker.IsNil)
   712  
   713  	ipamFileName := fmt.Sprintf("/etc/docker/plugins/%s.spec", ipamDrv)
   714  	err = ioutil.WriteFile(ipamFileName, []byte(url), 0644)
   715  	c.Assert(err, checker.IsNil)
   716  }
   717  
   718  func (s *DockerSwarmSuite) TestSwarmNetworkPlugin(c *check.C) {
   719  	mux := http.NewServeMux()
   720  	s.server = httptest.NewServer(mux)
   721  	c.Assert(s.server, check.NotNil, check.Commentf("Failed to start an HTTP Server"))
   722  	setupRemoteGlobalNetworkPlugin(c, mux, s.server.URL, globalNetworkPlugin, globalIPAMPlugin)
   723  	defer func() {
   724  		s.server.Close()
   725  		err := os.RemoveAll("/etc/docker/plugins")
   726  		c.Assert(err, checker.IsNil)
   727  	}()
   728  
   729  	d := s.AddDaemon(c, true, true)
   730  
   731  	out, err := d.Cmd("network", "create", "-d", globalNetworkPlugin, "foo")
   732  	c.Assert(err, checker.NotNil)
   733  	c.Assert(out, checker.Contains, "not supported in swarm mode")
   734  }
   735  
   736  // Test case for #24712
   737  func (s *DockerSwarmSuite) TestSwarmServiceEnvFile(c *check.C) {
   738  	d := s.AddDaemon(c, true, true)
   739  
   740  	path := filepath.Join(d.folder, "env.txt")
   741  	err := ioutil.WriteFile(path, []byte("VAR1=A\nVAR2=A\n"), 0644)
   742  	c.Assert(err, checker.IsNil)
   743  
   744  	name := "worker"
   745  	out, err := d.Cmd("service", "create", "--env-file", path, "--env", "VAR1=B", "--env", "VAR1=C", "--env", "VAR2=", "--env", "VAR2", "--name", name, "busybox", "top")
   746  	c.Assert(err, checker.IsNil)
   747  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   748  
   749  	// The complete env is [VAR1=A VAR2=A VAR1=B VAR1=C VAR2= VAR2] and duplicates will be removed => [VAR1=C VAR2]
   750  	out, err = d.Cmd("inspect", "--format", "{{ .Spec.TaskTemplate.ContainerSpec.Env }}", name)
   751  	c.Assert(err, checker.IsNil)
   752  	c.Assert(out, checker.Contains, "[VAR1=C VAR2]")
   753  }
   754  
   755  func (s *DockerSwarmSuite) TestSwarmServiceTTY(c *check.C) {
   756  	d := s.AddDaemon(c, true, true)
   757  
   758  	name := "top"
   759  
   760  	ttyCheck := "if [ -t 0 ]; then echo TTY > /status && top; else echo none > /status && top; fi"
   761  
   762  	// Without --tty
   763  	expectedOutput := "none"
   764  	out, err := d.Cmd("service", "create", "--name", name, "busybox", "sh", "-c", ttyCheck)
   765  	c.Assert(err, checker.IsNil)
   766  
   767  	// Make sure task has been deployed.
   768  	waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 1)
   769  
   770  	// We need to get the container id.
   771  	out, err = d.Cmd("ps", "-a", "-q", "--no-trunc")
   772  	c.Assert(err, checker.IsNil)
   773  	id := strings.TrimSpace(out)
   774  
   775  	out, err = d.Cmd("exec", id, "cat", "/status")
   776  	c.Assert(err, checker.IsNil)
   777  	c.Assert(out, checker.Contains, expectedOutput, check.Commentf("Expected '%s', but got %q", expectedOutput, out))
   778  
   779  	// Remove service
   780  	out, err = d.Cmd("service", "rm", name)
   781  	c.Assert(err, checker.IsNil)
   782  	// Make sure container has been destroyed.
   783  	waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 0)
   784  
   785  	// With --tty
   786  	expectedOutput = "TTY"
   787  	out, err = d.Cmd("service", "create", "--name", name, "--tty", "busybox", "sh", "-c", ttyCheck)
   788  	c.Assert(err, checker.IsNil)
   789  
   790  	// Make sure task has been deployed.
   791  	waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 1)
   792  
   793  	// We need to get the container id.
   794  	out, err = d.Cmd("ps", "-a", "-q", "--no-trunc")
   795  	c.Assert(err, checker.IsNil)
   796  	id = strings.TrimSpace(out)
   797  
   798  	out, err = d.Cmd("exec", id, "cat", "/status")
   799  	c.Assert(err, checker.IsNil)
   800  	c.Assert(out, checker.Contains, expectedOutput, check.Commentf("Expected '%s', but got %q", expectedOutput, out))
   801  }
   802  
   803  func (s *DockerSwarmSuite) TestSwarmServiceTTYUpdate(c *check.C) {
   804  	d := s.AddDaemon(c, true, true)
   805  
   806  	// Create a service
   807  	name := "top"
   808  	_, err := d.Cmd("service", "create", "--name", name, "busybox", "top")
   809  	c.Assert(err, checker.IsNil)
   810  
   811  	// Make sure task has been deployed.
   812  	waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 1)
   813  
   814  	out, err := d.Cmd("service", "inspect", "--format", "{{ .Spec.TaskTemplate.ContainerSpec.TTY }}", name)
   815  	c.Assert(err, checker.IsNil)
   816  	c.Assert(strings.TrimSpace(out), checker.Equals, "false")
   817  
   818  	_, err = d.Cmd("service", "update", "--tty", name)
   819  	c.Assert(err, checker.IsNil)
   820  
   821  	out, err = d.Cmd("service", "inspect", "--format", "{{ .Spec.TaskTemplate.ContainerSpec.TTY }}", name)
   822  	c.Assert(err, checker.IsNil)
   823  	c.Assert(strings.TrimSpace(out), checker.Equals, "true")
   824  }
   825  
   826  func (s *DockerSwarmSuite) TestDNSConfig(c *check.C) {
   827  	d := s.AddDaemon(c, true, true)
   828  
   829  	// Create a service
   830  	name := "top"
   831  	_, err := d.Cmd("service", "create", "--name", name, "--dns=1.2.3.4", "--dns-search=example.com", "--dns-option=timeout:3", "busybox", "top")
   832  	c.Assert(err, checker.IsNil)
   833  
   834  	// Make sure task has been deployed.
   835  	waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 1)
   836  
   837  	// We need to get the container id.
   838  	out, err := d.Cmd("ps", "-a", "-q", "--no-trunc")
   839  	c.Assert(err, checker.IsNil)
   840  	id := strings.TrimSpace(out)
   841  
   842  	// Compare against expected output.
   843  	expectedOutput1 := "nameserver 1.2.3.4"
   844  	expectedOutput2 := "search example.com"
   845  	expectedOutput3 := "options timeout:3"
   846  	out, err = d.Cmd("exec", id, "cat", "/etc/resolv.conf")
   847  	c.Assert(err, checker.IsNil)
   848  	c.Assert(out, checker.Contains, expectedOutput1, check.Commentf("Expected '%s', but got %q", expectedOutput1, out))
   849  	c.Assert(out, checker.Contains, expectedOutput2, check.Commentf("Expected '%s', but got %q", expectedOutput2, out))
   850  	c.Assert(out, checker.Contains, expectedOutput3, check.Commentf("Expected '%s', but got %q", expectedOutput3, out))
   851  }
   852  
   853  func (s *DockerSwarmSuite) TestDNSConfigUpdate(c *check.C) {
   854  	d := s.AddDaemon(c, true, true)
   855  
   856  	// Create a service
   857  	name := "top"
   858  	_, err := d.Cmd("service", "create", "--name", name, "busybox", "top")
   859  	c.Assert(err, checker.IsNil)
   860  
   861  	// Make sure task has been deployed.
   862  	waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 1)
   863  
   864  	_, err = d.Cmd("service", "update", "--dns-add=1.2.3.4", "--dns-search-add=example.com", "--dns-option-add=timeout:3", name)
   865  	c.Assert(err, checker.IsNil)
   866  
   867  	out, err := d.Cmd("service", "inspect", "--format", "{{ .Spec.TaskTemplate.ContainerSpec.DNSConfig }}", name)
   868  	c.Assert(err, checker.IsNil)
   869  	c.Assert(strings.TrimSpace(out), checker.Equals, "{[1.2.3.4] [example.com] [timeout:3]}")
   870  }
   871  
   872  func (s *DockerSwarmSuite) TestSwarmInitLocked(c *check.C) {
   873  	d := s.AddDaemon(c, false, false)
   874  
   875  	outs, err := d.Cmd("swarm", "init", "--autolock")
   876  	c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs))
   877  
   878  	c.Assert(outs, checker.Contains, "docker swarm unlock")
   879  
   880  	var unlockKey string
   881  	for _, line := range strings.Split(outs, "\n") {
   882  		if strings.Contains(line, "SWMKEY") {
   883  			unlockKey = strings.TrimSpace(line)
   884  			break
   885  		}
   886  	}
   887  
   888  	c.Assert(unlockKey, checker.Not(checker.Equals), "")
   889  
   890  	outs, err = d.Cmd("swarm", "unlock-key", "-q")
   891  	c.Assert(outs, checker.Equals, unlockKey+"\n")
   892  
   893  	info, err := d.info()
   894  	c.Assert(err, checker.IsNil)
   895  	c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
   896  
   897  	c.Assert(d.Restart(), checker.IsNil)
   898  
   899  	info, err = d.info()
   900  	c.Assert(err, checker.IsNil)
   901  	c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateLocked)
   902  
   903  	cmd := d.command("swarm", "unlock")
   904  	cmd.Stdin = bytes.NewBufferString("wrong-secret-key")
   905  	out, err := cmd.CombinedOutput()
   906  	c.Assert(err, checker.NotNil, check.Commentf("out: %v", string(out)))
   907  	c.Assert(string(out), checker.Contains, "invalid key")
   908  
   909  	cmd = d.command("swarm", "unlock")
   910  	cmd.Stdin = bytes.NewBufferString(unlockKey)
   911  	out, err = cmd.CombinedOutput()
   912  	c.Assert(err, checker.IsNil, check.Commentf("out: %v", string(out)))
   913  
   914  	info, err = d.info()
   915  	c.Assert(err, checker.IsNil)
   916  	c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
   917  
   918  	outs, err = d.Cmd("node", "ls")
   919  	c.Assert(err, checker.IsNil)
   920  	c.Assert(outs, checker.Not(checker.Contains), "Swarm is encrypted and needs to be unlocked")
   921  
   922  	outs, err = d.Cmd("swarm", "update", "--autolock=false")
   923  	c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs))
   924  
   925  	// Wait for autolock to be turned off
   926  	time.Sleep(time.Second)
   927  
   928  	c.Assert(d.Restart(), checker.IsNil)
   929  
   930  	info, err = d.info()
   931  	c.Assert(err, checker.IsNil)
   932  	c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
   933  
   934  	outs, err = d.Cmd("node", "ls")
   935  	c.Assert(err, checker.IsNil)
   936  	c.Assert(outs, checker.Not(checker.Contains), "Swarm is encrypted and needs to be unlocked")
   937  }
   938  
   939  func (s *DockerSwarmSuite) TestSwarmLeaveLocked(c *check.C) {
   940  	d := s.AddDaemon(c, false, false)
   941  
   942  	outs, err := d.Cmd("swarm", "init", "--autolock")
   943  	c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs))
   944  
   945  	c.Assert(d.Restart("--swarm-default-advertise-addr=lo"), checker.IsNil)
   946  
   947  	info, err := d.info()
   948  	c.Assert(err, checker.IsNil)
   949  	c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateLocked)
   950  
   951  	outs, _ = d.Cmd("node", "ls")
   952  	c.Assert(outs, checker.Contains, "Swarm is encrypted and needs to be unlocked")
   953  
   954  	outs, err = d.Cmd("swarm", "leave", "--force")
   955  	c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs))
   956  
   957  	info, err = d.info()
   958  	c.Assert(err, checker.IsNil)
   959  	c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateInactive)
   960  
   961  	outs, err = d.Cmd("swarm", "init")
   962  	c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs))
   963  
   964  	info, err = d.info()
   965  	c.Assert(err, checker.IsNil)
   966  	c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
   967  }
   968  
   969  func (s *DockerSwarmSuite) TestSwarmRotateUnlockKey(c *check.C) {
   970  	d := s.AddDaemon(c, true, true)
   971  
   972  	outs, err := d.Cmd("swarm", "update", "--autolock")
   973  	c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs))
   974  
   975  	c.Assert(outs, checker.Contains, "docker swarm unlock")
   976  
   977  	var unlockKey string
   978  	for _, line := range strings.Split(outs, "\n") {
   979  		if strings.Contains(line, "SWMKEY") {
   980  			unlockKey = strings.TrimSpace(line)
   981  			break
   982  		}
   983  	}
   984  
   985  	c.Assert(unlockKey, checker.Not(checker.Equals), "")
   986  
   987  	outs, err = d.Cmd("swarm", "unlock-key", "-q")
   988  	c.Assert(outs, checker.Equals, unlockKey+"\n")
   989  
   990  	// Rotate multiple times
   991  	for i := 0; i != 3; i++ {
   992  		outs, err = d.Cmd("swarm", "unlock-key", "-q", "--rotate")
   993  		c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs))
   994  		// Strip \n
   995  		newUnlockKey := outs[:len(outs)-1]
   996  		c.Assert(newUnlockKey, checker.Not(checker.Equals), "")
   997  		c.Assert(newUnlockKey, checker.Not(checker.Equals), unlockKey)
   998  
   999  		c.Assert(d.Restart(), checker.IsNil)
  1000  
  1001  		info, err := d.info()
  1002  		c.Assert(err, checker.IsNil)
  1003  		c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateLocked)
  1004  
  1005  		outs, _ = d.Cmd("node", "ls")
  1006  		c.Assert(outs, checker.Contains, "Swarm is encrypted and needs to be unlocked")
  1007  
  1008  		cmd := d.command("swarm", "unlock")
  1009  		cmd.Stdin = bytes.NewBufferString(unlockKey)
  1010  		out, err := cmd.CombinedOutput()
  1011  
  1012  		if err == nil {
  1013  			// On occasion, the daemon may not have finished
  1014  			// rotating the KEK before restarting. The test is
  1015  			// intentionally written to explore this behavior.
  1016  			// When this happens, unlocking with the old key will
  1017  			// succeed. If we wait for the rotation to happen and
  1018  			// restart again, the new key should be required this
  1019  			// time.
  1020  
  1021  			time.Sleep(3 * time.Second)
  1022  
  1023  			c.Assert(d.Restart(), checker.IsNil)
  1024  
  1025  			cmd = d.command("swarm", "unlock")
  1026  			cmd.Stdin = bytes.NewBufferString(unlockKey)
  1027  			out, err = cmd.CombinedOutput()
  1028  		}
  1029  		c.Assert(err, checker.NotNil, check.Commentf("out: %v", string(out)))
  1030  		c.Assert(string(out), checker.Contains, "invalid key")
  1031  
  1032  		outs, _ = d.Cmd("node", "ls")
  1033  		c.Assert(outs, checker.Contains, "Swarm is encrypted and needs to be unlocked")
  1034  
  1035  		cmd = d.command("swarm", "unlock")
  1036  		cmd.Stdin = bytes.NewBufferString(newUnlockKey)
  1037  		out, err = cmd.CombinedOutput()
  1038  		c.Assert(err, checker.IsNil, check.Commentf("out: %v", string(out)))
  1039  
  1040  		info, err = d.info()
  1041  		c.Assert(err, checker.IsNil)
  1042  		c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
  1043  
  1044  		outs, err = d.Cmd("node", "ls")
  1045  		c.Assert(err, checker.IsNil)
  1046  		c.Assert(outs, checker.Not(checker.Contains), "Swarm is encrypted and needs to be unlocked")
  1047  
  1048  		unlockKey = newUnlockKey
  1049  	}
  1050  }
  1051  
  1052  func (s *DockerSwarmSuite) TestExtraHosts(c *check.C) {
  1053  	d := s.AddDaemon(c, true, true)
  1054  
  1055  	// Create a service
  1056  	name := "top"
  1057  	_, err := d.Cmd("service", "create", "--name", name, "--host=example.com:1.2.3.4", "busybox", "top")
  1058  	c.Assert(err, checker.IsNil)
  1059  
  1060  	// Make sure task has been deployed.
  1061  	waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 1)
  1062  
  1063  	// We need to get the container id.
  1064  	out, err := d.Cmd("ps", "-a", "-q", "--no-trunc")
  1065  	c.Assert(err, checker.IsNil)
  1066  	id := strings.TrimSpace(out)
  1067  
  1068  	// Compare against expected output.
  1069  	expectedOutput := "1.2.3.4\texample.com"
  1070  	out, err = d.Cmd("exec", id, "cat", "/etc/hosts")
  1071  	c.Assert(err, checker.IsNil)
  1072  	c.Assert(out, checker.Contains, expectedOutput, check.Commentf("Expected '%s', but got %q", expectedOutput, out))
  1073  }
  1074  
  1075  func (s *DockerSwarmSuite) TestSwarmManagerAddress(c *check.C) {
  1076  	d1 := s.AddDaemon(c, true, true)
  1077  	d2 := s.AddDaemon(c, true, false)
  1078  	d3 := s.AddDaemon(c, true, false)
  1079  
  1080  	// Manager Addresses will always show Node 1's address
  1081  	expectedOutput := fmt.Sprintf("Manager Addresses:\n  127.0.0.1:%d\n", d1.port)
  1082  
  1083  	out, err := d1.Cmd("info")
  1084  	c.Assert(err, checker.IsNil)
  1085  	c.Assert(out, checker.Contains, expectedOutput)
  1086  
  1087  	out, err = d2.Cmd("info")
  1088  	c.Assert(err, checker.IsNil)
  1089  	c.Assert(out, checker.Contains, expectedOutput)
  1090  
  1091  	out, err = d3.Cmd("info")
  1092  	c.Assert(err, checker.IsNil)
  1093  	c.Assert(out, checker.Contains, expectedOutput)
  1094  }
  1095  
  1096  func (s *DockerSwarmSuite) TestSwarmServiceInspectPretty(c *check.C) {
  1097  	d := s.AddDaemon(c, true, true)
  1098  
  1099  	name := "top"
  1100  	out, err := d.Cmd("service", "create", "--name", name, "--limit-cpu=0.5", "busybox", "top")
  1101  	c.Assert(err, checker.IsNil, check.Commentf(out))
  1102  
  1103  	expectedOutput := `
  1104  Resources:
  1105   Limits:
  1106    CPU:		0.5`
  1107  	out, err = d.Cmd("service", "inspect", "--pretty", name)
  1108  	c.Assert(err, checker.IsNil, check.Commentf(out))
  1109  	c.Assert(out, checker.Contains, expectedOutput, check.Commentf(out))
  1110  }
  1111  
  1112  func (s *DockerSwarmSuite) TestSwarmNetworkIPAMOptions(c *check.C) {
  1113  	d := s.AddDaemon(c, true, true)
  1114  
  1115  	out, err := d.Cmd("network", "create", "-d", "overlay", "--ipam-opt", "foo=bar", "foo")
  1116  	c.Assert(err, checker.IsNil, check.Commentf(out))
  1117  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
  1118  
  1119  	out, err = d.Cmd("network", "inspect", "--format", "{{.IPAM.Options}}", "foo")
  1120  	c.Assert(err, checker.IsNil, check.Commentf(out))
  1121  	c.Assert(strings.TrimSpace(out), checker.Equals, "map[foo:bar]")
  1122  
  1123  	out, err = d.Cmd("service", "create", "--network=foo", "--name", "top", "busybox", "top")
  1124  	c.Assert(err, checker.IsNil, check.Commentf(out))
  1125  
  1126  	// make sure task has been deployed.
  1127  	waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 1)
  1128  
  1129  	out, err = d.Cmd("network", "inspect", "--format", "{{.IPAM.Options}}", "foo")
  1130  	c.Assert(err, checker.IsNil, check.Commentf(out))
  1131  	c.Assert(strings.TrimSpace(out), checker.Equals, "map[foo:bar]")
  1132  }
  1133  
  1134  // TODO: migrate to a unit test
  1135  // This test could be migrated to unit test and save costly integration test,
  1136  // once PR #29143 is merged.
  1137  func (s *DockerSwarmSuite) TestSwarmUpdateWithoutArgs(c *check.C) {
  1138  	d := s.AddDaemon(c, true, true)
  1139  
  1140  	expectedOutput := `
  1141  Usage:	docker swarm update [OPTIONS]
  1142  
  1143  Update the swarm
  1144  
  1145  Options:`
  1146  
  1147  	out, err := d.Cmd("swarm", "update")
  1148  	c.Assert(err, checker.IsNil, check.Commentf("out: %v", out))
  1149  	c.Assert(out, checker.Contains, expectedOutput, check.Commentf(out))
  1150  }
  1151  
  1152  func (s *DockerTrustedSwarmSuite) TestTrustedServiceCreate(c *check.C) {
  1153  	d := s.swarmSuite.AddDaemon(c, true, true)
  1154  
  1155  	// Attempt creating a service from an image that is known to notary.
  1156  	repoName := s.trustSuite.setupTrustedImage(c, "trusted-pull")
  1157  
  1158  	name := "trusted"
  1159  	serviceCmd := d.command("-D", "service", "create", "--name", name, repoName, "top")
  1160  	s.trustSuite.trustedCmd(serviceCmd)
  1161  	out, _, err := runCommandWithOutput(serviceCmd)
  1162  	c.Assert(err, checker.IsNil, check.Commentf(out))
  1163  	c.Assert(out, checker.Contains, "resolved image tag to", check.Commentf(out))
  1164  
  1165  	out, err = d.Cmd("service", "inspect", "--pretty", name)
  1166  	c.Assert(err, checker.IsNil, check.Commentf(out))
  1167  	c.Assert(out, checker.Contains, repoName+"@", check.Commentf(out))
  1168  
  1169  	// Try trusted service create on an untrusted tag.
  1170  
  1171  	repoName = fmt.Sprintf("%v/untrustedservicecreate/createtest:latest", privateRegistryURL)
  1172  	// tag the image and upload it to the private registry
  1173  	dockerCmd(c, "tag", "busybox", repoName)
  1174  	dockerCmd(c, "push", repoName)
  1175  	dockerCmd(c, "rmi", repoName)
  1176  
  1177  	name = "untrusted"
  1178  	serviceCmd = d.command("service", "create", "--name", name, repoName, "top")
  1179  	s.trustSuite.trustedCmd(serviceCmd)
  1180  	out, _, err = runCommandWithOutput(serviceCmd)
  1181  
  1182  	c.Assert(err, check.NotNil, check.Commentf(out))
  1183  	c.Assert(string(out), checker.Contains, "Error: remote trust data does not exist", check.Commentf(out))
  1184  
  1185  	out, err = d.Cmd("service", "inspect", "--pretty", name)
  1186  	c.Assert(err, checker.NotNil, check.Commentf(out))
  1187  }
  1188  
  1189  func (s *DockerTrustedSwarmSuite) TestTrustedServiceUpdate(c *check.C) {
  1190  	d := s.swarmSuite.AddDaemon(c, true, true)
  1191  
  1192  	// Attempt creating a service from an image that is known to notary.
  1193  	repoName := s.trustSuite.setupTrustedImage(c, "trusted-pull")
  1194  
  1195  	name := "myservice"
  1196  
  1197  	// Create a service without content trust
  1198  	_, err := d.Cmd("service", "create", "--name", name, repoName, "top")
  1199  	c.Assert(err, checker.IsNil)
  1200  
  1201  	out, err := d.Cmd("service", "inspect", "--pretty", name)
  1202  	c.Assert(err, checker.IsNil, check.Commentf(out))
  1203  	// Daemon won't insert the digest because this is disabled by
  1204  	// DOCKER_SERVICE_PREFER_OFFLINE_IMAGE.
  1205  	c.Assert(out, check.Not(checker.Contains), repoName+"@", check.Commentf(out))
  1206  
  1207  	serviceCmd := d.command("-D", "service", "update", "--image", repoName, name)
  1208  	s.trustSuite.trustedCmd(serviceCmd)
  1209  	out, _, err = runCommandWithOutput(serviceCmd)
  1210  	c.Assert(err, checker.IsNil, check.Commentf(out))
  1211  	c.Assert(out, checker.Contains, "resolved image tag to", check.Commentf(out))
  1212  
  1213  	out, err = d.Cmd("service", "inspect", "--pretty", name)
  1214  	c.Assert(err, checker.IsNil, check.Commentf(out))
  1215  	c.Assert(out, checker.Contains, repoName+"@", check.Commentf(out))
  1216  
  1217  	// Try trusted service update on an untrusted tag.
  1218  
  1219  	repoName = fmt.Sprintf("%v/untrustedservicecreate/createtest:latest", privateRegistryURL)
  1220  	// tag the image and upload it to the private registry
  1221  	dockerCmd(c, "tag", "busybox", repoName)
  1222  	dockerCmd(c, "push", repoName)
  1223  	dockerCmd(c, "rmi", repoName)
  1224  
  1225  	serviceCmd = d.command("service", "update", "--image", repoName, name)
  1226  	s.trustSuite.trustedCmd(serviceCmd)
  1227  	out, _, err = runCommandWithOutput(serviceCmd)
  1228  
  1229  	c.Assert(err, check.NotNil, check.Commentf(out))
  1230  	c.Assert(string(out), checker.Contains, "Error: remote trust data does not exist", check.Commentf(out))
  1231  }
  1232  
  1233  // Test case for issue #27866, which did not allow NW name that is the prefix of a swarm NW ID.
  1234  // e.g. if the ingress ID starts with "n1", it was impossible to create a NW named "n1".
  1235  func (s *DockerSwarmSuite) TestSwarmNetworkCreateIssue27866(c *check.C) {
  1236  	d := s.AddDaemon(c, true, true)
  1237  	out, err := d.Cmd("network", "inspect", "-f", "{{.Id}}", "ingress")
  1238  	c.Assert(err, checker.IsNil, check.Commentf("out: %v", out))
  1239  	ingressID := strings.TrimSpace(out)
  1240  	c.Assert(ingressID, checker.Not(checker.Equals), "")
  1241  
  1242  	// create a network of which name is the prefix of the ID of an overlay network
  1243  	// (ingressID in this case)
  1244  	newNetName := ingressID[0:2]
  1245  	out, err = d.Cmd("network", "create", "--driver", "overlay", newNetName)
  1246  	// In #27866, it was failing because of "network with name %s already exists"
  1247  	c.Assert(err, checker.IsNil, check.Commentf("out: %v", out))
  1248  	out, err = d.Cmd("network", "rm", newNetName)
  1249  	c.Assert(err, checker.IsNil, check.Commentf("out: %v", out))
  1250  }
  1251  
  1252  // Test case for https://github.com/docker/docker/pull/27938#issuecomment-265768303
  1253  // This test creates two networks with the same name sequentially, with various drivers.
  1254  // Since the operations in this test are done sequentially, the 2nd call should fail with
  1255  // "network with name FOO already exists".
  1256  // Note that it is to ok have multiple networks with the same name if the operations are done
  1257  // in parallel. (#18864)
  1258  func (s *DockerSwarmSuite) TestSwarmNetworkCreateDup(c *check.C) {
  1259  	d := s.AddDaemon(c, true, true)
  1260  	drivers := []string{"bridge", "overlay"}
  1261  	for i, driver1 := range drivers {
  1262  		nwName := fmt.Sprintf("network-test-%d", i)
  1263  		for _, driver2 := range drivers {
  1264  			c.Logf("Creating a network named %q with %q, then %q",
  1265  				nwName, driver1, driver2)
  1266  			out, err := d.Cmd("network", "create", "--driver", driver1, nwName)
  1267  			c.Assert(err, checker.IsNil, check.Commentf("out: %v", out))
  1268  			out, err = d.Cmd("network", "create", "--driver", driver2, nwName)
  1269  			c.Assert(out, checker.Contains,
  1270  				fmt.Sprintf("network with name %s already exists", nwName))
  1271  			c.Assert(err, checker.NotNil)
  1272  			c.Logf("As expected, the attempt to network %q with %q failed: %s",
  1273  				nwName, driver2, out)
  1274  			out, err = d.Cmd("network", "rm", nwName)
  1275  			c.Assert(err, checker.IsNil, check.Commentf("out: %v", out))
  1276  		}
  1277  	}
  1278  }