github.com/flavio/docker@v0.1.3-0.20170117145210-f63d1a6eec47/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/integration-cli/checker"
    19  	"github.com/docker/docker/integration-cli/daemon"
    20  	"github.com/docker/libnetwork/driverapi"
    21  	"github.com/docker/libnetwork/ipamapi"
    22  	remoteipam "github.com/docker/libnetwork/ipams/remote/api"
    23  	"github.com/go-check/check"
    24  	"github.com/vishvananda/netlink"
    25  )
    26  
    27  func (s *DockerSwarmSuite) TestSwarmUpdate(c *check.C) {
    28  	d := s.AddDaemon(c, true, true)
    29  
    30  	getSpec := func() swarm.Spec {
    31  		sw := d.GetSwarm(c)
    32  		return sw.Spec
    33  	}
    34  
    35  	out, err := d.Cmd("swarm", "update", "--cert-expiry", "30h", "--dispatcher-heartbeat", "11s")
    36  	c.Assert(err, checker.IsNil, check.Commentf("out: %v", out))
    37  
    38  	spec := getSpec()
    39  	c.Assert(spec.CAConfig.NodeCertExpiry, checker.Equals, 30*time.Hour)
    40  	c.Assert(spec.Dispatcher.HeartbeatPeriod, checker.Equals, 11*time.Second)
    41  
    42  	// setting anything under 30m for cert-expiry is not allowed
    43  	out, err = d.Cmd("swarm", "update", "--cert-expiry", "15m")
    44  	c.Assert(err, checker.NotNil)
    45  	c.Assert(out, checker.Contains, "minimum certificate expiry time")
    46  	spec = getSpec()
    47  	c.Assert(spec.CAConfig.NodeCertExpiry, checker.Equals, 30*time.Hour)
    48  }
    49  
    50  func (s *DockerSwarmSuite) TestSwarmInit(c *check.C) {
    51  	d := s.AddDaemon(c, false, false)
    52  
    53  	getSpec := func() swarm.Spec {
    54  		sw := d.GetSwarm(c)
    55  		return sw.Spec
    56  	}
    57  
    58  	out, err := d.Cmd("swarm", "init", "--cert-expiry", "30h", "--dispatcher-heartbeat", "11s")
    59  	c.Assert(err, checker.IsNil, check.Commentf("out: %v", out))
    60  
    61  	spec := getSpec()
    62  	c.Assert(spec.CAConfig.NodeCertExpiry, checker.Equals, 30*time.Hour)
    63  	c.Assert(spec.Dispatcher.HeartbeatPeriod, checker.Equals, 11*time.Second)
    64  
    65  	c.Assert(d.Leave(true), checker.IsNil)
    66  	time.Sleep(500 * time.Millisecond) // https://github.com/docker/swarmkit/issues/1421
    67  	out, err = d.Cmd("swarm", "init")
    68  	c.Assert(err, checker.IsNil, check.Commentf("out: %v", out))
    69  
    70  	spec = getSpec()
    71  	c.Assert(spec.CAConfig.NodeCertExpiry, checker.Equals, 90*24*time.Hour)
    72  	c.Assert(spec.Dispatcher.HeartbeatPeriod, checker.Equals, 5*time.Second)
    73  }
    74  
    75  func (s *DockerSwarmSuite) TestSwarmInitIPv6(c *check.C) {
    76  	testRequires(c, IPv6)
    77  	d1 := s.AddDaemon(c, false, false)
    78  	out, err := d1.Cmd("swarm", "init", "--listen-addr", "::1")
    79  	c.Assert(err, checker.IsNil, check.Commentf("out: %v", out))
    80  
    81  	d2 := s.AddDaemon(c, false, false)
    82  	out, err = d2.Cmd("swarm", "join", "::1")
    83  	c.Assert(err, checker.IsNil, check.Commentf("out: %v", out))
    84  
    85  	out, err = d2.Cmd("info")
    86  	c.Assert(err, checker.IsNil, check.Commentf("out: %v", out))
    87  	c.Assert(out, checker.Contains, "Swarm: active")
    88  }
    89  
    90  func (s *DockerSwarmSuite) TestSwarmInitUnspecifiedAdvertiseAddr(c *check.C) {
    91  	d := s.AddDaemon(c, false, false)
    92  	out, err := d.Cmd("swarm", "init", "--advertise-addr", "0.0.0.0")
    93  	c.Assert(err, checker.NotNil)
    94  	c.Assert(out, checker.Contains, "advertise address must be a non-zero IP address")
    95  }
    96  
    97  func (s *DockerSwarmSuite) TestSwarmIncompatibleDaemon(c *check.C) {
    98  	// init swarm mode and stop a daemon
    99  	d := s.AddDaemon(c, true, true)
   100  	info, err := d.SwarmInfo()
   101  	c.Assert(err, checker.IsNil)
   102  	c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
   103  	d.Stop(c)
   104  
   105  	// start a daemon with --cluster-store and --cluster-advertise
   106  	err = d.StartWithError("--cluster-store=consul://consuladdr:consulport/some/path", "--cluster-advertise=1.1.1.1:2375")
   107  	c.Assert(err, checker.NotNil)
   108  	content, err := d.ReadLogFile()
   109  	c.Assert(err, checker.IsNil)
   110  	c.Assert(string(content), checker.Contains, "--cluster-store and --cluster-advertise daemon configurations are incompatible with swarm mode")
   111  
   112  	// start a daemon with --live-restore
   113  	err = d.StartWithError("--live-restore")
   114  	c.Assert(err, checker.NotNil)
   115  	content, err = d.ReadLogFile()
   116  	c.Assert(err, checker.IsNil)
   117  	c.Assert(string(content), checker.Contains, "--live-restore daemon configuration is incompatible with swarm mode")
   118  	// restart for teardown
   119  	d.Start(c)
   120  }
   121  
   122  func (s *DockerSwarmSuite) TestSwarmServiceTemplatingHostname(c *check.C) {
   123  	d := s.AddDaemon(c, true, true)
   124  
   125  	out, err := d.Cmd("service", "create", "--name", "test", "--hostname", "{{.Service.Name}}-{{.Task.Slot}}", "busybox", "top")
   126  	c.Assert(err, checker.IsNil, check.Commentf(out))
   127  
   128  	// make sure task has been deployed.
   129  	waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1)
   130  
   131  	containers := d.ActiveContainers()
   132  	out, err = d.Cmd("inspect", "--type", "container", "--format", "{{.Config.Hostname}}", containers[0])
   133  	c.Assert(err, checker.IsNil, check.Commentf(out))
   134  	c.Assert(strings.Split(out, "\n")[0], checker.Equals, "test-1", check.Commentf("hostname with templating invalid"))
   135  }
   136  
   137  // Test case for #24270
   138  func (s *DockerSwarmSuite) TestSwarmServiceListFilter(c *check.C) {
   139  	d := s.AddDaemon(c, true, true)
   140  
   141  	name1 := "redis-cluster-md5"
   142  	name2 := "redis-cluster"
   143  	name3 := "other-cluster"
   144  	out, err := d.Cmd("service", "create", "--name", name1, "busybox", "top")
   145  	c.Assert(err, checker.IsNil)
   146  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   147  
   148  	out, err = d.Cmd("service", "create", "--name", name2, "busybox", "top")
   149  	c.Assert(err, checker.IsNil)
   150  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   151  
   152  	out, err = d.Cmd("service", "create", "--name", name3, "busybox", "top")
   153  	c.Assert(err, checker.IsNil)
   154  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   155  
   156  	filter1 := "name=redis-cluster-md5"
   157  	filter2 := "name=redis-cluster"
   158  
   159  	// We search checker.Contains with `name+" "` to prevent prefix only.
   160  	out, err = d.Cmd("service", "ls", "--filter", filter1)
   161  	c.Assert(err, checker.IsNil)
   162  	c.Assert(out, checker.Contains, name1+" ")
   163  	c.Assert(out, checker.Not(checker.Contains), name2+" ")
   164  	c.Assert(out, checker.Not(checker.Contains), name3+" ")
   165  
   166  	out, err = d.Cmd("service", "ls", "--filter", filter2)
   167  	c.Assert(err, checker.IsNil)
   168  	c.Assert(out, checker.Contains, name1+" ")
   169  	c.Assert(out, checker.Contains, name2+" ")
   170  	c.Assert(out, checker.Not(checker.Contains), name3+" ")
   171  
   172  	out, err = d.Cmd("service", "ls")
   173  	c.Assert(err, checker.IsNil)
   174  	c.Assert(out, checker.Contains, name1+" ")
   175  	c.Assert(out, checker.Contains, name2+" ")
   176  	c.Assert(out, checker.Contains, name3+" ")
   177  }
   178  
   179  func (s *DockerSwarmSuite) TestSwarmNodeListFilter(c *check.C) {
   180  	d := s.AddDaemon(c, true, true)
   181  
   182  	out, err := d.Cmd("node", "inspect", "--format", "{{ .Description.Hostname }}", "self")
   183  	c.Assert(err, checker.IsNil)
   184  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   185  	name := strings.TrimSpace(out)
   186  
   187  	filter := "name=" + name[:4]
   188  
   189  	out, err = d.Cmd("node", "ls", "--filter", filter)
   190  	c.Assert(err, checker.IsNil)
   191  	c.Assert(out, checker.Contains, name)
   192  
   193  	out, err = d.Cmd("node", "ls", "--filter", "name=none")
   194  	c.Assert(err, checker.IsNil)
   195  	c.Assert(out, checker.Not(checker.Contains), name)
   196  }
   197  
   198  func (s *DockerSwarmSuite) TestSwarmNodeTaskListFilter(c *check.C) {
   199  	d := s.AddDaemon(c, true, true)
   200  
   201  	name := "redis-cluster-md5"
   202  	out, err := d.Cmd("service", "create", "--name", name, "--replicas=3", "busybox", "top")
   203  	c.Assert(err, checker.IsNil)
   204  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   205  
   206  	// make sure task has been deployed.
   207  	waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 3)
   208  
   209  	filter := "name=redis-cluster"
   210  
   211  	out, err = d.Cmd("node", "ps", "--filter", filter, "self")
   212  	c.Assert(err, checker.IsNil)
   213  	c.Assert(out, checker.Contains, name+".1")
   214  	c.Assert(out, checker.Contains, name+".2")
   215  	c.Assert(out, checker.Contains, name+".3")
   216  
   217  	out, err = d.Cmd("node", "ps", "--filter", "name=none", "self")
   218  	c.Assert(err, checker.IsNil)
   219  	c.Assert(out, checker.Not(checker.Contains), name+".1")
   220  	c.Assert(out, checker.Not(checker.Contains), name+".2")
   221  	c.Assert(out, checker.Not(checker.Contains), name+".3")
   222  }
   223  
   224  // Test case for #25375
   225  func (s *DockerSwarmSuite) TestSwarmPublishAdd(c *check.C) {
   226  	d := s.AddDaemon(c, true, true)
   227  
   228  	name := "top"
   229  	out, err := d.Cmd("service", "create", "--name", name, "--label", "x=y", "busybox", "top")
   230  	c.Assert(err, checker.IsNil)
   231  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   232  
   233  	out, err = d.Cmd("service", "update", "--publish-add", "80:80", name)
   234  	c.Assert(err, checker.IsNil)
   235  
   236  	out, err = d.CmdRetryOutOfSequence("service", "update", "--publish-add", "80:80", name)
   237  	c.Assert(err, checker.IsNil)
   238  
   239  	out, err = d.CmdRetryOutOfSequence("service", "update", "--publish-add", "80:80", "--publish-add", "80:20", name)
   240  	c.Assert(err, checker.NotNil)
   241  
   242  	out, err = d.Cmd("service", "inspect", "--format", "{{ .Spec.EndpointSpec.Ports }}", name)
   243  	c.Assert(err, checker.IsNil)
   244  	c.Assert(strings.TrimSpace(out), checker.Equals, "[{ tcp 80 80 ingress}]")
   245  }
   246  
   247  func (s *DockerSwarmSuite) TestSwarmServiceWithGroup(c *check.C) {
   248  	d := s.AddDaemon(c, true, true)
   249  
   250  	name := "top"
   251  	out, err := d.Cmd("service", "create", "--name", name, "--user", "root:root", "--group", "wheel", "--group", "audio", "--group", "staff", "--group", "777", "busybox", "top")
   252  	c.Assert(err, checker.IsNil)
   253  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   254  
   255  	// make sure task has been deployed.
   256  	waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1)
   257  
   258  	out, err = d.Cmd("ps", "-q")
   259  	c.Assert(err, checker.IsNil)
   260  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   261  
   262  	container := strings.TrimSpace(out)
   263  
   264  	out, err = d.Cmd("exec", container, "id")
   265  	c.Assert(err, checker.IsNil)
   266  	c.Assert(strings.TrimSpace(out), checker.Equals, "uid=0(root) gid=0(root) groups=10(wheel),29(audio),50(staff),777")
   267  }
   268  
   269  func (s *DockerSwarmSuite) TestSwarmContainerAutoStart(c *check.C) {
   270  	d := s.AddDaemon(c, true, true)
   271  
   272  	out, err := d.Cmd("network", "create", "--attachable", "-d", "overlay", "foo")
   273  	c.Assert(err, checker.IsNil)
   274  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   275  
   276  	out, err = d.Cmd("run", "-id", "--restart=always", "--net=foo", "--name=test", "busybox", "top")
   277  	c.Assert(err, checker.IsNil, check.Commentf(out))
   278  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   279  
   280  	out, err = d.Cmd("ps", "-q")
   281  	c.Assert(err, checker.IsNil, check.Commentf(out))
   282  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   283  
   284  	d.Restart(c)
   285  
   286  	out, err = d.Cmd("ps", "-q")
   287  	c.Assert(err, checker.IsNil, check.Commentf(out))
   288  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   289  }
   290  
   291  func (s *DockerSwarmSuite) TestSwarmContainerEndpointOptions(c *check.C) {
   292  	d := s.AddDaemon(c, true, true)
   293  
   294  	out, err := d.Cmd("network", "create", "--attachable", "-d", "overlay", "foo")
   295  	c.Assert(err, checker.IsNil, check.Commentf(out))
   296  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   297  
   298  	_, err = d.Cmd("run", "-d", "--net=foo", "--name=first", "--net-alias=first-alias", "busybox", "top")
   299  	c.Assert(err, checker.IsNil, check.Commentf(out))
   300  
   301  	_, err = d.Cmd("run", "-d", "--net=foo", "--name=second", "busybox", "top")
   302  	c.Assert(err, checker.IsNil, check.Commentf(out))
   303  
   304  	// ping first container and its alias
   305  	_, err = d.Cmd("exec", "second", "ping", "-c", "1", "first")
   306  	c.Assert(err, check.IsNil, check.Commentf(out))
   307  	_, err = d.Cmd("exec", "second", "ping", "-c", "1", "first-alias")
   308  	c.Assert(err, check.IsNil, check.Commentf(out))
   309  }
   310  
   311  func (s *DockerSwarmSuite) TestSwarmContainerAttachByNetworkId(c *check.C) {
   312  	d := s.AddDaemon(c, true, true)
   313  
   314  	out, err := d.Cmd("network", "create", "--attachable", "-d", "overlay", "testnet")
   315  	c.Assert(err, checker.IsNil)
   316  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   317  	networkID := strings.TrimSpace(out)
   318  
   319  	out, err = d.Cmd("run", "-d", "--net", networkID, "busybox", "top")
   320  	c.Assert(err, checker.IsNil)
   321  	cID := strings.TrimSpace(out)
   322  	d.WaitRun(cID)
   323  
   324  	_, err = d.Cmd("rm", "-f", cID)
   325  	c.Assert(err, checker.IsNil)
   326  
   327  	out, err = d.Cmd("network", "rm", "testnet")
   328  	c.Assert(err, checker.IsNil)
   329  
   330  	checkNetwork := func(*check.C) (interface{}, check.CommentInterface) {
   331  		out, err := d.Cmd("network", "ls")
   332  		c.Assert(err, checker.IsNil)
   333  		return out, nil
   334  	}
   335  
   336  	waitAndAssert(c, 3*time.Second, checkNetwork, checker.Not(checker.Contains), "testnet")
   337  }
   338  
   339  func (s *DockerSwarmSuite) TestOverlayAttachable(c *check.C) {
   340  	d := s.AddDaemon(c, true, true)
   341  
   342  	out, err := d.Cmd("network", "create", "-d", "overlay", "--attachable", "ovnet")
   343  	c.Assert(err, checker.IsNil, check.Commentf(out))
   344  
   345  	// validate attachable
   346  	out, err = d.Cmd("network", "inspect", "--format", "{{json .Attachable}}", "ovnet")
   347  	c.Assert(err, checker.IsNil, check.Commentf(out))
   348  	c.Assert(strings.TrimSpace(out), checker.Equals, "true")
   349  
   350  	// validate containers can attache to this overlay network
   351  	out, err = d.Cmd("run", "-d", "--network", "ovnet", "--name", "c1", "busybox", "top")
   352  	c.Assert(err, checker.IsNil, check.Commentf(out))
   353  
   354  	// redo validation, there was a bug that the value of attachable changes after
   355  	// containers attach to the network
   356  	out, err = d.Cmd("network", "inspect", "--format", "{{json .Attachable}}", "ovnet")
   357  	c.Assert(err, checker.IsNil, check.Commentf(out))
   358  	c.Assert(strings.TrimSpace(out), checker.Equals, "true")
   359  }
   360  
   361  func (s *DockerSwarmSuite) TestSwarmRemoveInternalNetwork(c *check.C) {
   362  	d := s.AddDaemon(c, true, true)
   363  
   364  	name := "ingress"
   365  	out, err := d.Cmd("network", "rm", name)
   366  	c.Assert(err, checker.NotNil)
   367  	c.Assert(strings.TrimSpace(out), checker.Contains, name)
   368  	c.Assert(strings.TrimSpace(out), checker.Contains, "is a pre-defined network and cannot be removed")
   369  }
   370  
   371  // Test case for #24108, also the case from:
   372  // https://github.com/docker/docker/pull/24620#issuecomment-233715656
   373  func (s *DockerSwarmSuite) TestSwarmTaskListFilter(c *check.C) {
   374  	d := s.AddDaemon(c, true, true)
   375  
   376  	name := "redis-cluster-md5"
   377  	out, err := d.Cmd("service", "create", "--name", name, "--replicas=3", "busybox", "top")
   378  	c.Assert(err, checker.IsNil)
   379  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   380  
   381  	filter := "name=redis-cluster"
   382  
   383  	checkNumTasks := func(*check.C) (interface{}, check.CommentInterface) {
   384  		out, err := d.Cmd("service", "ps", "--filter", filter, name)
   385  		c.Assert(err, checker.IsNil)
   386  		return len(strings.Split(out, "\n")) - 2, nil // includes header and nl in last line
   387  	}
   388  
   389  	// wait until all tasks have been created
   390  	waitAndAssert(c, defaultReconciliationTimeout, checkNumTasks, checker.Equals, 3)
   391  
   392  	out, err = d.Cmd("service", "ps", "--filter", filter, name)
   393  	c.Assert(err, checker.IsNil)
   394  	c.Assert(out, checker.Contains, name+".1")
   395  	c.Assert(out, checker.Contains, name+".2")
   396  	c.Assert(out, checker.Contains, name+".3")
   397  
   398  	out, err = d.Cmd("service", "ps", "--filter", "name="+name+".1", name)
   399  	c.Assert(err, checker.IsNil)
   400  	c.Assert(out, checker.Contains, name+".1")
   401  	c.Assert(out, checker.Not(checker.Contains), name+".2")
   402  	c.Assert(out, checker.Not(checker.Contains), name+".3")
   403  
   404  	out, err = d.Cmd("service", "ps", "--filter", "name=none", name)
   405  	c.Assert(err, checker.IsNil)
   406  	c.Assert(out, checker.Not(checker.Contains), name+".1")
   407  	c.Assert(out, checker.Not(checker.Contains), name+".2")
   408  	c.Assert(out, checker.Not(checker.Contains), name+".3")
   409  
   410  	name = "redis-cluster-sha1"
   411  	out, err = d.Cmd("service", "create", "--name", name, "--mode=global", "busybox", "top")
   412  	c.Assert(err, checker.IsNil)
   413  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   414  
   415  	waitAndAssert(c, defaultReconciliationTimeout, checkNumTasks, checker.Equals, 1)
   416  
   417  	filter = "name=redis-cluster"
   418  	out, err = d.Cmd("service", "ps", "--filter", filter, name)
   419  	c.Assert(err, checker.IsNil)
   420  	c.Assert(out, checker.Contains, name)
   421  
   422  	out, err = d.Cmd("service", "ps", "--filter", "name="+name, name)
   423  	c.Assert(err, checker.IsNil)
   424  	c.Assert(out, checker.Contains, name)
   425  
   426  	out, err = d.Cmd("service", "ps", "--filter", "name=none", name)
   427  	c.Assert(err, checker.IsNil)
   428  	c.Assert(out, checker.Not(checker.Contains), name)
   429  }
   430  
   431  func (s *DockerSwarmSuite) TestPsListContainersFilterIsTask(c *check.C) {
   432  	d := s.AddDaemon(c, true, true)
   433  
   434  	// Create a bare container
   435  	out, err := d.Cmd("run", "-d", "--name=bare-container", "busybox", "top")
   436  	c.Assert(err, checker.IsNil)
   437  	bareID := strings.TrimSpace(out)[:12]
   438  	// Create a service
   439  	name := "busybox-top"
   440  	out, err = d.Cmd("service", "create", "--name", name, "busybox", "top")
   441  	c.Assert(err, checker.IsNil)
   442  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   443  
   444  	// make sure task has been deployed.
   445  	waitAndAssert(c, defaultReconciliationTimeout, d.CheckServiceRunningTasks(name), checker.Equals, 1)
   446  
   447  	// Filter non-tasks
   448  	out, err = d.Cmd("ps", "-a", "-q", "--filter=is-task=false")
   449  	c.Assert(err, checker.IsNil)
   450  	psOut := strings.TrimSpace(out)
   451  	c.Assert(psOut, checker.Equals, bareID, check.Commentf("Expected id %s, got %s for is-task label, output %q", bareID, psOut, out))
   452  
   453  	// Filter tasks
   454  	out, err = d.Cmd("ps", "-a", "-q", "--filter=is-task=true")
   455  	c.Assert(err, checker.IsNil)
   456  	lines := strings.Split(strings.Trim(out, "\n "), "\n")
   457  	c.Assert(lines, checker.HasLen, 1)
   458  	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))
   459  }
   460  
   461  const globalNetworkPlugin = "global-network-plugin"
   462  const globalIPAMPlugin = "global-ipam-plugin"
   463  
   464  func setupRemoteGlobalNetworkPlugin(c *check.C, mux *http.ServeMux, url, netDrv, ipamDrv string) {
   465  
   466  	mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) {
   467  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   468  		fmt.Fprintf(w, `{"Implements": ["%s", "%s"]}`, driverapi.NetworkPluginEndpointType, ipamapi.PluginEndpointType)
   469  	})
   470  
   471  	// Network driver implementation
   472  	mux.HandleFunc(fmt.Sprintf("/%s.GetCapabilities", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   473  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   474  		fmt.Fprintf(w, `{"Scope":"global"}`)
   475  	})
   476  
   477  	mux.HandleFunc(fmt.Sprintf("/%s.AllocateNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   478  		err := json.NewDecoder(r.Body).Decode(&remoteDriverNetworkRequest)
   479  		if err != nil {
   480  			http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
   481  			return
   482  		}
   483  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   484  		fmt.Fprintf(w, "null")
   485  	})
   486  
   487  	mux.HandleFunc(fmt.Sprintf("/%s.FreeNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   488  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   489  		fmt.Fprintf(w, "null")
   490  	})
   491  
   492  	mux.HandleFunc(fmt.Sprintf("/%s.CreateNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   493  		err := json.NewDecoder(r.Body).Decode(&remoteDriverNetworkRequest)
   494  		if err != nil {
   495  			http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
   496  			return
   497  		}
   498  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   499  		fmt.Fprintf(w, "null")
   500  	})
   501  
   502  	mux.HandleFunc(fmt.Sprintf("/%s.DeleteNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   503  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   504  		fmt.Fprintf(w, "null")
   505  	})
   506  
   507  	mux.HandleFunc(fmt.Sprintf("/%s.CreateEndpoint", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   508  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   509  		fmt.Fprintf(w, `{"Interface":{"MacAddress":"a0:b1:c2:d3:e4:f5"}}`)
   510  	})
   511  
   512  	mux.HandleFunc(fmt.Sprintf("/%s.Join", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   513  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   514  
   515  		veth := &netlink.Veth{
   516  			LinkAttrs: netlink.LinkAttrs{Name: "randomIfName", TxQLen: 0}, PeerName: "cnt0"}
   517  		if err := netlink.LinkAdd(veth); err != nil {
   518  			fmt.Fprintf(w, `{"Error":"failed to add veth pair: `+err.Error()+`"}`)
   519  		} else {
   520  			fmt.Fprintf(w, `{"InterfaceName":{ "SrcName":"cnt0", "DstPrefix":"veth"}}`)
   521  		}
   522  	})
   523  
   524  	mux.HandleFunc(fmt.Sprintf("/%s.Leave", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   525  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   526  		fmt.Fprintf(w, "null")
   527  	})
   528  
   529  	mux.HandleFunc(fmt.Sprintf("/%s.DeleteEndpoint", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   530  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   531  		if link, err := netlink.LinkByName("cnt0"); err == nil {
   532  			netlink.LinkDel(link)
   533  		}
   534  		fmt.Fprintf(w, "null")
   535  	})
   536  
   537  	// IPAM Driver implementation
   538  	var (
   539  		poolRequest       remoteipam.RequestPoolRequest
   540  		poolReleaseReq    remoteipam.ReleasePoolRequest
   541  		addressRequest    remoteipam.RequestAddressRequest
   542  		addressReleaseReq remoteipam.ReleaseAddressRequest
   543  		lAS               = "localAS"
   544  		gAS               = "globalAS"
   545  		pool              = "172.28.0.0/16"
   546  		poolID            = lAS + "/" + pool
   547  		gw                = "172.28.255.254/16"
   548  	)
   549  
   550  	mux.HandleFunc(fmt.Sprintf("/%s.GetDefaultAddressSpaces", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   551  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   552  		fmt.Fprintf(w, `{"LocalDefaultAddressSpace":"`+lAS+`", "GlobalDefaultAddressSpace": "`+gAS+`"}`)
   553  	})
   554  
   555  	mux.HandleFunc(fmt.Sprintf("/%s.RequestPool", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   556  		err := json.NewDecoder(r.Body).Decode(&poolRequest)
   557  		if err != nil {
   558  			http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
   559  			return
   560  		}
   561  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   562  		if poolRequest.AddressSpace != lAS && poolRequest.AddressSpace != gAS {
   563  			fmt.Fprintf(w, `{"Error":"Unknown address space in pool request: `+poolRequest.AddressSpace+`"}`)
   564  		} else if poolRequest.Pool != "" && poolRequest.Pool != pool {
   565  			fmt.Fprintf(w, `{"Error":"Cannot handle explicit pool requests yet"}`)
   566  		} else {
   567  			fmt.Fprintf(w, `{"PoolID":"`+poolID+`", "Pool":"`+pool+`"}`)
   568  		}
   569  	})
   570  
   571  	mux.HandleFunc(fmt.Sprintf("/%s.RequestAddress", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   572  		err := json.NewDecoder(r.Body).Decode(&addressRequest)
   573  		if err != nil {
   574  			http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
   575  			return
   576  		}
   577  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   578  		// make sure libnetwork is now querying on the expected pool id
   579  		if addressRequest.PoolID != poolID {
   580  			fmt.Fprintf(w, `{"Error":"unknown pool id"}`)
   581  		} else if addressRequest.Address != "" {
   582  			fmt.Fprintf(w, `{"Error":"Cannot handle explicit address requests yet"}`)
   583  		} else {
   584  			fmt.Fprintf(w, `{"Address":"`+gw+`"}`)
   585  		}
   586  	})
   587  
   588  	mux.HandleFunc(fmt.Sprintf("/%s.ReleaseAddress", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   589  		err := json.NewDecoder(r.Body).Decode(&addressReleaseReq)
   590  		if err != nil {
   591  			http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
   592  			return
   593  		}
   594  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   595  		// make sure libnetwork is now asking to release the expected address from the expected poolid
   596  		if addressRequest.PoolID != poolID {
   597  			fmt.Fprintf(w, `{"Error":"unknown pool id"}`)
   598  		} else if addressReleaseReq.Address != gw {
   599  			fmt.Fprintf(w, `{"Error":"unknown address"}`)
   600  		} else {
   601  			fmt.Fprintf(w, "null")
   602  		}
   603  	})
   604  
   605  	mux.HandleFunc(fmt.Sprintf("/%s.ReleasePool", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   606  		err := json.NewDecoder(r.Body).Decode(&poolReleaseReq)
   607  		if err != nil {
   608  			http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
   609  			return
   610  		}
   611  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   612  		// make sure libnetwork is now asking to release the expected poolid
   613  		if addressRequest.PoolID != poolID {
   614  			fmt.Fprintf(w, `{"Error":"unknown pool id"}`)
   615  		} else {
   616  			fmt.Fprintf(w, "null")
   617  		}
   618  	})
   619  
   620  	err := os.MkdirAll("/etc/docker/plugins", 0755)
   621  	c.Assert(err, checker.IsNil)
   622  
   623  	fileName := fmt.Sprintf("/etc/docker/plugins/%s.spec", netDrv)
   624  	err = ioutil.WriteFile(fileName, []byte(url), 0644)
   625  	c.Assert(err, checker.IsNil)
   626  
   627  	ipamFileName := fmt.Sprintf("/etc/docker/plugins/%s.spec", ipamDrv)
   628  	err = ioutil.WriteFile(ipamFileName, []byte(url), 0644)
   629  	c.Assert(err, checker.IsNil)
   630  }
   631  
   632  func (s *DockerSwarmSuite) TestSwarmNetworkPlugin(c *check.C) {
   633  	mux := http.NewServeMux()
   634  	s.server = httptest.NewServer(mux)
   635  	c.Assert(s.server, check.NotNil, check.Commentf("Failed to start an HTTP Server"))
   636  	setupRemoteGlobalNetworkPlugin(c, mux, s.server.URL, globalNetworkPlugin, globalIPAMPlugin)
   637  	defer func() {
   638  		s.server.Close()
   639  		err := os.RemoveAll("/etc/docker/plugins")
   640  		c.Assert(err, checker.IsNil)
   641  	}()
   642  
   643  	d := s.AddDaemon(c, true, true)
   644  
   645  	out, err := d.Cmd("network", "create", "-d", globalNetworkPlugin, "foo")
   646  	c.Assert(err, checker.IsNil)
   647  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   648  
   649  	name := "top"
   650  	out, err = d.Cmd("service", "create", "--name", name, "--network", "foo", "busybox", "top")
   651  	c.Assert(err, checker.IsNil)
   652  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   653  
   654  	out, err = d.Cmd("service", "inspect", "--format", "{{range .Spec.Networks}}{{.Target}}{{end}}", name)
   655  	c.Assert(err, checker.IsNil)
   656  	c.Assert(strings.TrimSpace(out), checker.Equals, "foo")
   657  }
   658  
   659  // Test case for #24712
   660  func (s *DockerSwarmSuite) TestSwarmServiceEnvFile(c *check.C) {
   661  	d := s.AddDaemon(c, true, true)
   662  
   663  	path := filepath.Join(d.Folder, "env.txt")
   664  	err := ioutil.WriteFile(path, []byte("VAR1=A\nVAR2=A\n"), 0644)
   665  	c.Assert(err, checker.IsNil)
   666  
   667  	name := "worker"
   668  	out, err := d.Cmd("service", "create", "--env-file", path, "--env", "VAR1=B", "--env", "VAR1=C", "--env", "VAR2=", "--env", "VAR2", "--name", name, "busybox", "top")
   669  	c.Assert(err, checker.IsNil)
   670  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   671  
   672  	// The complete env is [VAR1=A VAR2=A VAR1=B VAR1=C VAR2= VAR2] and duplicates will be removed => [VAR1=C VAR2]
   673  	out, err = d.Cmd("inspect", "--format", "{{ .Spec.TaskTemplate.ContainerSpec.Env }}", name)
   674  	c.Assert(err, checker.IsNil)
   675  	c.Assert(out, checker.Contains, "[VAR1=C VAR2]")
   676  }
   677  
   678  func (s *DockerSwarmSuite) TestSwarmServiceTTY(c *check.C) {
   679  	d := s.AddDaemon(c, true, true)
   680  
   681  	name := "top"
   682  
   683  	ttyCheck := "if [ -t 0 ]; then echo TTY > /status && top; else echo none > /status && top; fi"
   684  
   685  	// Without --tty
   686  	expectedOutput := "none"
   687  	out, err := d.Cmd("service", "create", "--name", name, "busybox", "sh", "-c", ttyCheck)
   688  	c.Assert(err, checker.IsNil)
   689  
   690  	// Make sure task has been deployed.
   691  	waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1)
   692  
   693  	// We need to get the container id.
   694  	out, err = d.Cmd("ps", "-a", "-q", "--no-trunc")
   695  	c.Assert(err, checker.IsNil)
   696  	id := strings.TrimSpace(out)
   697  
   698  	out, err = d.Cmd("exec", id, "cat", "/status")
   699  	c.Assert(err, checker.IsNil)
   700  	c.Assert(out, checker.Contains, expectedOutput, check.Commentf("Expected '%s', but got %q", expectedOutput, out))
   701  
   702  	// Remove service
   703  	out, err = d.Cmd("service", "rm", name)
   704  	c.Assert(err, checker.IsNil)
   705  	// Make sure container has been destroyed.
   706  	waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 0)
   707  
   708  	// With --tty
   709  	expectedOutput = "TTY"
   710  	out, err = d.Cmd("service", "create", "--name", name, "--tty", "busybox", "sh", "-c", ttyCheck)
   711  	c.Assert(err, checker.IsNil)
   712  
   713  	// Make sure task has been deployed.
   714  	waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1)
   715  
   716  	// We need to get the container id.
   717  	out, err = d.Cmd("ps", "-a", "-q", "--no-trunc")
   718  	c.Assert(err, checker.IsNil)
   719  	id = strings.TrimSpace(out)
   720  
   721  	out, err = d.Cmd("exec", id, "cat", "/status")
   722  	c.Assert(err, checker.IsNil)
   723  	c.Assert(out, checker.Contains, expectedOutput, check.Commentf("Expected '%s', but got %q", expectedOutput, out))
   724  }
   725  
   726  func (s *DockerSwarmSuite) TestSwarmServiceTTYUpdate(c *check.C) {
   727  	d := s.AddDaemon(c, true, true)
   728  
   729  	// Create a service
   730  	name := "top"
   731  	_, err := d.Cmd("service", "create", "--name", name, "busybox", "top")
   732  	c.Assert(err, checker.IsNil)
   733  
   734  	// Make sure task has been deployed.
   735  	waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1)
   736  
   737  	out, err := d.Cmd("service", "inspect", "--format", "{{ .Spec.TaskTemplate.ContainerSpec.TTY }}", name)
   738  	c.Assert(err, checker.IsNil)
   739  	c.Assert(strings.TrimSpace(out), checker.Equals, "false")
   740  
   741  	_, err = d.Cmd("service", "update", "--tty", name)
   742  	c.Assert(err, checker.IsNil)
   743  
   744  	out, err = d.Cmd("service", "inspect", "--format", "{{ .Spec.TaskTemplate.ContainerSpec.TTY }}", name)
   745  	c.Assert(err, checker.IsNil)
   746  	c.Assert(strings.TrimSpace(out), checker.Equals, "true")
   747  }
   748  
   749  func (s *DockerSwarmSuite) TestDNSConfig(c *check.C) {
   750  	d := s.AddDaemon(c, true, true)
   751  
   752  	// Create a service
   753  	name := "top"
   754  	_, err := d.Cmd("service", "create", "--name", name, "--dns=1.2.3.4", "--dns-search=example.com", "--dns-option=timeout:3", "busybox", "top")
   755  	c.Assert(err, checker.IsNil)
   756  
   757  	// Make sure task has been deployed.
   758  	waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1)
   759  
   760  	// We need to get the container id.
   761  	out, err := d.Cmd("ps", "-a", "-q", "--no-trunc")
   762  	c.Assert(err, checker.IsNil)
   763  	id := strings.TrimSpace(out)
   764  
   765  	// Compare against expected output.
   766  	expectedOutput1 := "nameserver 1.2.3.4"
   767  	expectedOutput2 := "search example.com"
   768  	expectedOutput3 := "options timeout:3"
   769  	out, err = d.Cmd("exec", id, "cat", "/etc/resolv.conf")
   770  	c.Assert(err, checker.IsNil)
   771  	c.Assert(out, checker.Contains, expectedOutput1, check.Commentf("Expected '%s', but got %q", expectedOutput1, out))
   772  	c.Assert(out, checker.Contains, expectedOutput2, check.Commentf("Expected '%s', but got %q", expectedOutput2, out))
   773  	c.Assert(out, checker.Contains, expectedOutput3, check.Commentf("Expected '%s', but got %q", expectedOutput3, out))
   774  }
   775  
   776  func (s *DockerSwarmSuite) TestDNSConfigUpdate(c *check.C) {
   777  	d := s.AddDaemon(c, true, true)
   778  
   779  	// Create a service
   780  	name := "top"
   781  	_, err := d.Cmd("service", "create", "--name", name, "busybox", "top")
   782  	c.Assert(err, checker.IsNil)
   783  
   784  	// Make sure task has been deployed.
   785  	waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1)
   786  
   787  	_, err = d.Cmd("service", "update", "--dns-add=1.2.3.4", "--dns-search-add=example.com", "--dns-option-add=timeout:3", name)
   788  	c.Assert(err, checker.IsNil)
   789  
   790  	out, err := d.Cmd("service", "inspect", "--format", "{{ .Spec.TaskTemplate.ContainerSpec.DNSConfig }}", name)
   791  	c.Assert(err, checker.IsNil)
   792  	c.Assert(strings.TrimSpace(out), checker.Equals, "{[1.2.3.4] [example.com] [timeout:3]}")
   793  }
   794  
   795  func getNodeStatus(c *check.C, d *daemon.Swarm) swarm.LocalNodeState {
   796  	info, err := d.SwarmInfo()
   797  	c.Assert(err, checker.IsNil)
   798  	return info.LocalNodeState
   799  }
   800  
   801  func checkSwarmLockedToUnlocked(c *check.C, d *daemon.Swarm, unlockKey string) {
   802  	d.Restart(c)
   803  	status := getNodeStatus(c, d)
   804  	if status == swarm.LocalNodeStateLocked {
   805  		// it must not have updated to be unlocked in time - unlock, wait 3 seconds, and try again
   806  		cmd := d.Command("swarm", "unlock")
   807  		cmd.Stdin = bytes.NewBufferString(unlockKey)
   808  		out, err := cmd.CombinedOutput()
   809  		c.Assert(err, checker.IsNil, check.Commentf("out: %v", string(out)))
   810  
   811  		c.Assert(getNodeStatus(c, d), checker.Equals, swarm.LocalNodeStateActive)
   812  
   813  		time.Sleep(3 * time.Second)
   814  		d.Restart(c)
   815  	}
   816  
   817  	c.Assert(getNodeStatus(c, d), checker.Equals, swarm.LocalNodeStateActive)
   818  }
   819  
   820  func checkSwarmUnlockedToLocked(c *check.C, d *daemon.Swarm) {
   821  	d.Restart(c)
   822  	status := getNodeStatus(c, d)
   823  	if status == swarm.LocalNodeStateActive {
   824  		// it must not have updated to be unlocked in time - wait 3 seconds, and try again
   825  		time.Sleep(3 * time.Second)
   826  		d.Restart(c)
   827  	}
   828  	c.Assert(getNodeStatus(c, d), checker.Equals, swarm.LocalNodeStateLocked)
   829  }
   830  
   831  func (s *DockerSwarmSuite) TestUnlockEngineAndUnlockedSwarm(c *check.C) {
   832  	d := s.AddDaemon(c, false, false)
   833  
   834  	// unlocking a normal engine should return an error - it does not even ask for the key
   835  	cmd := d.Command("swarm", "unlock")
   836  	outs, err := cmd.CombinedOutput()
   837  
   838  	c.Assert(err, checker.NotNil, check.Commentf("out: %v", string(outs)))
   839  	c.Assert(string(outs), checker.Contains, "Error: This node is not part of a swarm")
   840  	c.Assert(string(outs), checker.Not(checker.Contains), "Please enter unlock key")
   841  
   842  	_, err = d.Cmd("swarm", "init")
   843  	c.Assert(err, checker.IsNil)
   844  
   845  	// unlocking an unlocked swarm should return an error - it does not even ask for the key
   846  	cmd = d.Command("swarm", "unlock")
   847  	outs, err = cmd.CombinedOutput()
   848  
   849  	c.Assert(err, checker.NotNil, check.Commentf("out: %v", string(outs)))
   850  	c.Assert(string(outs), checker.Contains, "Error: swarm is not locked")
   851  	c.Assert(string(outs), checker.Not(checker.Contains), "Please enter unlock key")
   852  }
   853  
   854  func (s *DockerSwarmSuite) TestSwarmInitLocked(c *check.C) {
   855  	d := s.AddDaemon(c, false, false)
   856  
   857  	outs, err := d.Cmd("swarm", "init", "--autolock")
   858  	c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs))
   859  
   860  	c.Assert(outs, checker.Contains, "docker swarm unlock")
   861  
   862  	var unlockKey string
   863  	for _, line := range strings.Split(outs, "\n") {
   864  		if strings.Contains(line, "SWMKEY") {
   865  			unlockKey = strings.TrimSpace(line)
   866  			break
   867  		}
   868  	}
   869  
   870  	c.Assert(unlockKey, checker.Not(checker.Equals), "")
   871  
   872  	outs, err = d.Cmd("swarm", "unlock-key", "-q")
   873  	c.Assert(outs, checker.Equals, unlockKey+"\n")
   874  
   875  	c.Assert(getNodeStatus(c, d), checker.Equals, swarm.LocalNodeStateActive)
   876  
   877  	// It starts off locked
   878  	d.Restart(c)
   879  	c.Assert(getNodeStatus(c, d), checker.Equals, swarm.LocalNodeStateLocked)
   880  
   881  	cmd := d.Command("swarm", "unlock")
   882  	cmd.Stdin = bytes.NewBufferString("wrong-secret-key")
   883  	out, err := cmd.CombinedOutput()
   884  	c.Assert(err, checker.NotNil, check.Commentf("out: %v", string(out)))
   885  	c.Assert(string(out), checker.Contains, "invalid key")
   886  
   887  	c.Assert(getNodeStatus(c, d), checker.Equals, swarm.LocalNodeStateLocked)
   888  
   889  	cmd = d.Command("swarm", "unlock")
   890  	cmd.Stdin = bytes.NewBufferString(unlockKey)
   891  	out, err = cmd.CombinedOutput()
   892  	c.Assert(err, checker.IsNil, check.Commentf("out: %v", string(out)))
   893  
   894  	c.Assert(getNodeStatus(c, d), checker.Equals, swarm.LocalNodeStateActive)
   895  
   896  	outs, err = d.Cmd("node", "ls")
   897  	c.Assert(err, checker.IsNil)
   898  	c.Assert(outs, checker.Not(checker.Contains), "Swarm is encrypted and needs to be unlocked")
   899  
   900  	outs, err = d.Cmd("swarm", "update", "--autolock=false")
   901  	c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs))
   902  
   903  	checkSwarmLockedToUnlocked(c, d, unlockKey)
   904  
   905  	outs, err = d.Cmd("node", "ls")
   906  	c.Assert(err, checker.IsNil)
   907  	c.Assert(outs, checker.Not(checker.Contains), "Swarm is encrypted and needs to be unlocked")
   908  }
   909  
   910  func (s *DockerSwarmSuite) TestSwarmLeaveLocked(c *check.C) {
   911  	d := s.AddDaemon(c, false, false)
   912  
   913  	outs, err := d.Cmd("swarm", "init", "--autolock")
   914  	c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs))
   915  
   916  	// It starts off locked
   917  	d.Restart(c, "--swarm-default-advertise-addr=lo")
   918  
   919  	info, err := d.SwarmInfo()
   920  	c.Assert(err, checker.IsNil)
   921  	c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateLocked)
   922  
   923  	outs, _ = d.Cmd("node", "ls")
   924  	c.Assert(outs, checker.Contains, "Swarm is encrypted and needs to be unlocked")
   925  
   926  	// `docker swarm leave` a locked swarm without --force will return an error
   927  	outs, _ = d.Cmd("swarm", "leave")
   928  	c.Assert(outs, checker.Contains, "Swarm is encrypted and locked.")
   929  
   930  	// It is OK for user to leave a locked swarm with --force
   931  	outs, err = d.Cmd("swarm", "leave", "--force")
   932  	c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs))
   933  
   934  	info, err = d.SwarmInfo()
   935  	c.Assert(err, checker.IsNil)
   936  	c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateInactive)
   937  
   938  	outs, err = d.Cmd("swarm", "init")
   939  	c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs))
   940  
   941  	info, err = d.SwarmInfo()
   942  	c.Assert(err, checker.IsNil)
   943  	c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
   944  }
   945  
   946  func (s *DockerSwarmSuite) TestSwarmLockUnlockCluster(c *check.C) {
   947  	d1 := s.AddDaemon(c, true, true)
   948  	d2 := s.AddDaemon(c, true, true)
   949  	d3 := s.AddDaemon(c, true, true)
   950  
   951  	// they start off unlocked
   952  	d2.Restart(c)
   953  	c.Assert(getNodeStatus(c, d2), checker.Equals, swarm.LocalNodeStateActive)
   954  
   955  	// stop this one so it does not get autolock info
   956  	d2.Stop(c)
   957  
   958  	// enable autolock
   959  	outs, err := d1.Cmd("swarm", "update", "--autolock")
   960  	c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs))
   961  
   962  	c.Assert(outs, checker.Contains, "docker swarm unlock")
   963  
   964  	var unlockKey string
   965  	for _, line := range strings.Split(outs, "\n") {
   966  		if strings.Contains(line, "SWMKEY") {
   967  			unlockKey = strings.TrimSpace(line)
   968  			break
   969  		}
   970  	}
   971  
   972  	c.Assert(unlockKey, checker.Not(checker.Equals), "")
   973  
   974  	outs, err = d1.Cmd("swarm", "unlock-key", "-q")
   975  	c.Assert(outs, checker.Equals, unlockKey+"\n")
   976  
   977  	// The ones that got the cluster update should be set to locked
   978  	for _, d := range []*daemon.Swarm{d1, d3} {
   979  		checkSwarmUnlockedToLocked(c, d)
   980  
   981  		cmd := d.Command("swarm", "unlock")
   982  		cmd.Stdin = bytes.NewBufferString(unlockKey)
   983  		out, err := cmd.CombinedOutput()
   984  		c.Assert(err, checker.IsNil, check.Commentf("out: %v", string(out)))
   985  		c.Assert(getNodeStatus(c, d), checker.Equals, swarm.LocalNodeStateActive)
   986  	}
   987  
   988  	// d2 never got the cluster update, so it is still set to unlocked
   989  	d2.Start(c)
   990  	c.Assert(getNodeStatus(c, d2), checker.Equals, swarm.LocalNodeStateActive)
   991  
   992  	// d2 is now set to lock
   993  	checkSwarmUnlockedToLocked(c, d2)
   994  
   995  	// leave it locked, and set the cluster to no longer autolock
   996  	outs, err = d1.Cmd("swarm", "update", "--autolock=false")
   997  	c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs))
   998  
   999  	// the ones that got the update are now set to unlocked
  1000  	for _, d := range []*daemon.Swarm{d1, d3} {
  1001  		checkSwarmLockedToUnlocked(c, d, unlockKey)
  1002  	}
  1003  
  1004  	// d2 still locked
  1005  	c.Assert(getNodeStatus(c, d2), checker.Equals, swarm.LocalNodeStateLocked)
  1006  
  1007  	// unlock it
  1008  	cmd := d2.Command("swarm", "unlock")
  1009  	cmd.Stdin = bytes.NewBufferString(unlockKey)
  1010  	out, err := cmd.CombinedOutput()
  1011  	c.Assert(err, checker.IsNil, check.Commentf("out: %v", string(out)))
  1012  	c.Assert(getNodeStatus(c, d2), checker.Equals, swarm.LocalNodeStateActive)
  1013  
  1014  	// once it's caught up, d2 is set to not be locked
  1015  	checkSwarmLockedToUnlocked(c, d2, unlockKey)
  1016  
  1017  	// managers who join now are never set to locked in the first place
  1018  	d4 := s.AddDaemon(c, true, true)
  1019  	d4.Restart(c)
  1020  	c.Assert(getNodeStatus(c, d4), checker.Equals, swarm.LocalNodeStateActive)
  1021  }
  1022  
  1023  func (s *DockerSwarmSuite) TestSwarmJoinPromoteLocked(c *check.C) {
  1024  	d1 := s.AddDaemon(c, true, true)
  1025  
  1026  	// enable autolock
  1027  	outs, err := d1.Cmd("swarm", "update", "--autolock")
  1028  	c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs))
  1029  
  1030  	c.Assert(outs, checker.Contains, "docker swarm unlock")
  1031  
  1032  	var unlockKey string
  1033  	for _, line := range strings.Split(outs, "\n") {
  1034  		if strings.Contains(line, "SWMKEY") {
  1035  			unlockKey = strings.TrimSpace(line)
  1036  			break
  1037  		}
  1038  	}
  1039  
  1040  	c.Assert(unlockKey, checker.Not(checker.Equals), "")
  1041  
  1042  	outs, err = d1.Cmd("swarm", "unlock-key", "-q")
  1043  	c.Assert(outs, checker.Equals, unlockKey+"\n")
  1044  
  1045  	// joined workers start off unlocked
  1046  	d2 := s.AddDaemon(c, true, false)
  1047  	d2.Restart(c)
  1048  	c.Assert(getNodeStatus(c, d2), checker.Equals, swarm.LocalNodeStateActive)
  1049  
  1050  	// promote worker
  1051  	outs, err = d1.Cmd("node", "promote", d2.Info.NodeID)
  1052  	c.Assert(err, checker.IsNil)
  1053  	c.Assert(outs, checker.Contains, "promoted to a manager in the swarm")
  1054  
  1055  	// join new manager node
  1056  	d3 := s.AddDaemon(c, true, true)
  1057  
  1058  	// both new nodes are locked
  1059  	for _, d := range []*daemon.Swarm{d2, d3} {
  1060  		checkSwarmUnlockedToLocked(c, d)
  1061  
  1062  		cmd := d.Command("swarm", "unlock")
  1063  		cmd.Stdin = bytes.NewBufferString(unlockKey)
  1064  		out, err := cmd.CombinedOutput()
  1065  		c.Assert(err, checker.IsNil, check.Commentf("out: %v", string(out)))
  1066  		c.Assert(getNodeStatus(c, d), checker.Equals, swarm.LocalNodeStateActive)
  1067  	}
  1068  
  1069  	// get d3's cert
  1070  	d3cert, err := ioutil.ReadFile(filepath.Join(d3.Folder, "root", "swarm", "certificates", "swarm-node.crt"))
  1071  	c.Assert(err, checker.IsNil)
  1072  
  1073  	// demote manager back to worker - workers are not locked
  1074  	outs, err = d1.Cmd("node", "demote", d3.Info.NodeID)
  1075  	c.Assert(err, checker.IsNil)
  1076  	c.Assert(outs, checker.Contains, "demoted in the swarm")
  1077  
  1078  	// Wait for it to actually be demoted, for the key and cert to be replaced.
  1079  	// Then restart and assert that the node is not locked.  If we don't wait for the cert
  1080  	// to be replaced, then the node still has the manager TLS key which is still locked
  1081  	// (because we never want a manager TLS key to be on disk unencrypted if the cluster
  1082  	// is set to autolock)
  1083  	waitAndAssert(c, defaultReconciliationTimeout, d3.CheckControlAvailable, checker.False)
  1084  	waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
  1085  		cert, err := ioutil.ReadFile(filepath.Join(d3.Folder, "root", "swarm", "certificates", "swarm-node.crt"))
  1086  		if err != nil {
  1087  			return "", check.Commentf("error: %v", err)
  1088  		}
  1089  		return string(cert), check.Commentf("cert: %v", string(cert))
  1090  	}, checker.Not(checker.Equals), string(d3cert))
  1091  
  1092  	// by now, it should *never* be locked on restart
  1093  	d3.Restart(c)
  1094  	c.Assert(getNodeStatus(c, d3), checker.Equals, swarm.LocalNodeStateActive)
  1095  }
  1096  
  1097  func (s *DockerSwarmSuite) TestSwarmRotateUnlockKey(c *check.C) {
  1098  	d := s.AddDaemon(c, true, true)
  1099  
  1100  	outs, err := d.Cmd("swarm", "update", "--autolock")
  1101  	c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs))
  1102  
  1103  	c.Assert(outs, checker.Contains, "docker swarm unlock")
  1104  
  1105  	var unlockKey string
  1106  	for _, line := range strings.Split(outs, "\n") {
  1107  		if strings.Contains(line, "SWMKEY") {
  1108  			unlockKey = strings.TrimSpace(line)
  1109  			break
  1110  		}
  1111  	}
  1112  
  1113  	c.Assert(unlockKey, checker.Not(checker.Equals), "")
  1114  
  1115  	outs, err = d.Cmd("swarm", "unlock-key", "-q")
  1116  	c.Assert(outs, checker.Equals, unlockKey+"\n")
  1117  
  1118  	// Rotate multiple times
  1119  	for i := 0; i != 3; i++ {
  1120  		outs, err = d.Cmd("swarm", "unlock-key", "-q", "--rotate")
  1121  		c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs))
  1122  		// Strip \n
  1123  		newUnlockKey := outs[:len(outs)-1]
  1124  		c.Assert(newUnlockKey, checker.Not(checker.Equals), "")
  1125  		c.Assert(newUnlockKey, checker.Not(checker.Equals), unlockKey)
  1126  
  1127  		d.Restart(c)
  1128  		c.Assert(getNodeStatus(c, d), checker.Equals, swarm.LocalNodeStateLocked)
  1129  
  1130  		outs, _ = d.Cmd("node", "ls")
  1131  		c.Assert(outs, checker.Contains, "Swarm is encrypted and needs to be unlocked")
  1132  
  1133  		cmd := d.Command("swarm", "unlock")
  1134  		cmd.Stdin = bytes.NewBufferString(unlockKey)
  1135  		out, err := cmd.CombinedOutput()
  1136  
  1137  		if err == nil {
  1138  			// On occasion, the daemon may not have finished
  1139  			// rotating the KEK before restarting. The test is
  1140  			// intentionally written to explore this behavior.
  1141  			// When this happens, unlocking with the old key will
  1142  			// succeed. If we wait for the rotation to happen and
  1143  			// restart again, the new key should be required this
  1144  			// time.
  1145  
  1146  			time.Sleep(3 * time.Second)
  1147  
  1148  			d.Restart(c)
  1149  
  1150  			cmd = d.Command("swarm", "unlock")
  1151  			cmd.Stdin = bytes.NewBufferString(unlockKey)
  1152  			out, err = cmd.CombinedOutput()
  1153  		}
  1154  		c.Assert(err, checker.NotNil, check.Commentf("out: %v", string(out)))
  1155  		c.Assert(string(out), checker.Contains, "invalid key")
  1156  
  1157  		outs, _ = d.Cmd("node", "ls")
  1158  		c.Assert(outs, checker.Contains, "Swarm is encrypted and needs to be unlocked")
  1159  
  1160  		cmd = d.Command("swarm", "unlock")
  1161  		cmd.Stdin = bytes.NewBufferString(newUnlockKey)
  1162  		out, err = cmd.CombinedOutput()
  1163  		c.Assert(err, checker.IsNil, check.Commentf("out: %v", string(out)))
  1164  
  1165  		c.Assert(getNodeStatus(c, d), checker.Equals, swarm.LocalNodeStateActive)
  1166  
  1167  		outs, err = d.Cmd("node", "ls")
  1168  		c.Assert(err, checker.IsNil)
  1169  		c.Assert(outs, checker.Not(checker.Contains), "Swarm is encrypted and needs to be unlocked")
  1170  
  1171  		unlockKey = newUnlockKey
  1172  	}
  1173  }
  1174  
  1175  // This differs from `TestSwarmRotateUnlockKey` because that one rotates a single node, which is the leader.
  1176  // This one keeps the leader up, and asserts that other manager nodes in the cluster also have their unlock
  1177  // key rotated.
  1178  func (s *DockerSwarmSuite) TestSwarmClusterRotateUnlockKey(c *check.C) {
  1179  	d1 := s.AddDaemon(c, true, true) // leader - don't restart this one, we don't want leader election delays
  1180  	d2 := s.AddDaemon(c, true, true)
  1181  	d3 := s.AddDaemon(c, true, true)
  1182  
  1183  	outs, err := d1.Cmd("swarm", "update", "--autolock")
  1184  	c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs))
  1185  
  1186  	c.Assert(outs, checker.Contains, "docker swarm unlock")
  1187  
  1188  	var unlockKey string
  1189  	for _, line := range strings.Split(outs, "\n") {
  1190  		if strings.Contains(line, "SWMKEY") {
  1191  			unlockKey = strings.TrimSpace(line)
  1192  			break
  1193  		}
  1194  	}
  1195  
  1196  	c.Assert(unlockKey, checker.Not(checker.Equals), "")
  1197  
  1198  	outs, err = d1.Cmd("swarm", "unlock-key", "-q")
  1199  	c.Assert(outs, checker.Equals, unlockKey+"\n")
  1200  
  1201  	// Rotate multiple times
  1202  	for i := 0; i != 3; i++ {
  1203  		outs, err = d1.Cmd("swarm", "unlock-key", "-q", "--rotate")
  1204  		c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs))
  1205  		// Strip \n
  1206  		newUnlockKey := outs[:len(outs)-1]
  1207  		c.Assert(newUnlockKey, checker.Not(checker.Equals), "")
  1208  		c.Assert(newUnlockKey, checker.Not(checker.Equals), unlockKey)
  1209  
  1210  		d2.Restart(c)
  1211  		d3.Restart(c)
  1212  
  1213  		for _, d := range []*daemon.Swarm{d2, d3} {
  1214  			c.Assert(getNodeStatus(c, d), checker.Equals, swarm.LocalNodeStateLocked)
  1215  
  1216  			outs, _ := d.Cmd("node", "ls")
  1217  			c.Assert(outs, checker.Contains, "Swarm is encrypted and needs to be unlocked")
  1218  
  1219  			cmd := d.Command("swarm", "unlock")
  1220  			cmd.Stdin = bytes.NewBufferString(unlockKey)
  1221  			out, err := cmd.CombinedOutput()
  1222  
  1223  			if err == nil {
  1224  				// On occasion, the daemon may not have finished
  1225  				// rotating the KEK before restarting. The test is
  1226  				// intentionally written to explore this behavior.
  1227  				// When this happens, unlocking with the old key will
  1228  				// succeed. If we wait for the rotation to happen and
  1229  				// restart again, the new key should be required this
  1230  				// time.
  1231  
  1232  				time.Sleep(3 * time.Second)
  1233  
  1234  				d.Restart(c)
  1235  
  1236  				cmd = d.Command("swarm", "unlock")
  1237  				cmd.Stdin = bytes.NewBufferString(unlockKey)
  1238  				out, err = cmd.CombinedOutput()
  1239  			}
  1240  			c.Assert(err, checker.NotNil, check.Commentf("out: %v", string(out)))
  1241  			c.Assert(string(out), checker.Contains, "invalid key")
  1242  
  1243  			outs, _ = d.Cmd("node", "ls")
  1244  			c.Assert(outs, checker.Contains, "Swarm is encrypted and needs to be unlocked")
  1245  
  1246  			cmd = d.Command("swarm", "unlock")
  1247  			cmd.Stdin = bytes.NewBufferString(newUnlockKey)
  1248  			out, err = cmd.CombinedOutput()
  1249  			c.Assert(err, checker.IsNil, check.Commentf("out: %v", string(out)))
  1250  
  1251  			c.Assert(getNodeStatus(c, d), checker.Equals, swarm.LocalNodeStateActive)
  1252  
  1253  			outs, err = d.Cmd("node", "ls")
  1254  			c.Assert(err, checker.IsNil)
  1255  			c.Assert(outs, checker.Not(checker.Contains), "Swarm is encrypted and needs to be unlocked")
  1256  		}
  1257  
  1258  		unlockKey = newUnlockKey
  1259  	}
  1260  }
  1261  
  1262  func (s *DockerSwarmSuite) TestSwarmAlternateLockUnlock(c *check.C) {
  1263  	d := s.AddDaemon(c, true, true)
  1264  
  1265  	var unlockKey string
  1266  	for i := 0; i < 2; i++ {
  1267  		// set to lock
  1268  		outs, err := d.Cmd("swarm", "update", "--autolock")
  1269  		c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs))
  1270  		c.Assert(outs, checker.Contains, "docker swarm unlock")
  1271  
  1272  		for _, line := range strings.Split(outs, "\n") {
  1273  			if strings.Contains(line, "SWMKEY") {
  1274  				unlockKey = strings.TrimSpace(line)
  1275  				break
  1276  			}
  1277  		}
  1278  
  1279  		c.Assert(unlockKey, checker.Not(checker.Equals), "")
  1280  		checkSwarmUnlockedToLocked(c, d)
  1281  
  1282  		cmd := d.Command("swarm", "unlock")
  1283  		cmd.Stdin = bytes.NewBufferString(unlockKey)
  1284  		out, err := cmd.CombinedOutput()
  1285  		c.Assert(err, checker.IsNil, check.Commentf("out: %v", string(out)))
  1286  
  1287  		c.Assert(getNodeStatus(c, d), checker.Equals, swarm.LocalNodeStateActive)
  1288  
  1289  		outs, err = d.Cmd("swarm", "update", "--autolock=false")
  1290  		c.Assert(err, checker.IsNil, check.Commentf("out: %v", outs))
  1291  
  1292  		checkSwarmLockedToUnlocked(c, d, unlockKey)
  1293  	}
  1294  }
  1295  
  1296  func (s *DockerSwarmSuite) TestExtraHosts(c *check.C) {
  1297  	d := s.AddDaemon(c, true, true)
  1298  
  1299  	// Create a service
  1300  	name := "top"
  1301  	_, err := d.Cmd("service", "create", "--name", name, "--host=example.com:1.2.3.4", "busybox", "top")
  1302  	c.Assert(err, checker.IsNil)
  1303  
  1304  	// Make sure task has been deployed.
  1305  	waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1)
  1306  
  1307  	// We need to get the container id.
  1308  	out, err := d.Cmd("ps", "-a", "-q", "--no-trunc")
  1309  	c.Assert(err, checker.IsNil)
  1310  	id := strings.TrimSpace(out)
  1311  
  1312  	// Compare against expected output.
  1313  	expectedOutput := "1.2.3.4\texample.com"
  1314  	out, err = d.Cmd("exec", id, "cat", "/etc/hosts")
  1315  	c.Assert(err, checker.IsNil)
  1316  	c.Assert(out, checker.Contains, expectedOutput, check.Commentf("Expected '%s', but got %q", expectedOutput, out))
  1317  }
  1318  
  1319  func (s *DockerSwarmSuite) TestSwarmManagerAddress(c *check.C) {
  1320  	d1 := s.AddDaemon(c, true, true)
  1321  	d2 := s.AddDaemon(c, true, false)
  1322  	d3 := s.AddDaemon(c, true, false)
  1323  
  1324  	// Manager Addresses will always show Node 1's address
  1325  	expectedOutput := fmt.Sprintf("Manager Addresses:\n  127.0.0.1:%d\n", d1.Port)
  1326  
  1327  	out, err := d1.Cmd("info")
  1328  	c.Assert(err, checker.IsNil)
  1329  	c.Assert(out, checker.Contains, expectedOutput)
  1330  
  1331  	out, err = d2.Cmd("info")
  1332  	c.Assert(err, checker.IsNil)
  1333  	c.Assert(out, checker.Contains, expectedOutput)
  1334  
  1335  	out, err = d3.Cmd("info")
  1336  	c.Assert(err, checker.IsNil)
  1337  	c.Assert(out, checker.Contains, expectedOutput)
  1338  }
  1339  
  1340  func (s *DockerSwarmSuite) TestSwarmServiceInspectPretty(c *check.C) {
  1341  	d := s.AddDaemon(c, true, true)
  1342  
  1343  	name := "top"
  1344  	out, err := d.Cmd("service", "create", "--name", name, "--limit-cpu=0.5", "busybox", "top")
  1345  	c.Assert(err, checker.IsNil, check.Commentf(out))
  1346  
  1347  	expectedOutput := `
  1348  Resources:
  1349   Limits:
  1350    CPU:		0.5`
  1351  	out, err = d.Cmd("service", "inspect", "--pretty", name)
  1352  	c.Assert(err, checker.IsNil, check.Commentf(out))
  1353  	c.Assert(out, checker.Contains, expectedOutput, check.Commentf(out))
  1354  }
  1355  
  1356  func (s *DockerSwarmSuite) TestSwarmNetworkIPAMOptions(c *check.C) {
  1357  	d := s.AddDaemon(c, true, true)
  1358  
  1359  	out, err := d.Cmd("network", "create", "-d", "overlay", "--ipam-opt", "foo=bar", "foo")
  1360  	c.Assert(err, checker.IsNil, check.Commentf(out))
  1361  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
  1362  
  1363  	out, err = d.Cmd("network", "inspect", "--format", "{{.IPAM.Options}}", "foo")
  1364  	c.Assert(err, checker.IsNil, check.Commentf(out))
  1365  	c.Assert(strings.TrimSpace(out), checker.Equals, "map[foo:bar]")
  1366  
  1367  	out, err = d.Cmd("service", "create", "--network=foo", "--name", "top", "busybox", "top")
  1368  	c.Assert(err, checker.IsNil, check.Commentf(out))
  1369  
  1370  	// make sure task has been deployed.
  1371  	waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1)
  1372  
  1373  	out, err = d.Cmd("network", "inspect", "--format", "{{.IPAM.Options}}", "foo")
  1374  	c.Assert(err, checker.IsNil, check.Commentf(out))
  1375  	c.Assert(strings.TrimSpace(out), checker.Equals, "map[foo:bar]")
  1376  }
  1377  
  1378  func (s *DockerTrustedSwarmSuite) TestTrustedServiceCreate(c *check.C) {
  1379  	d := s.swarmSuite.AddDaemon(c, true, true)
  1380  
  1381  	// Attempt creating a service from an image that is known to notary.
  1382  	repoName := s.trustSuite.setupTrustedImage(c, "trusted-pull")
  1383  
  1384  	name := "trusted"
  1385  	serviceCmd := d.Command("-D", "service", "create", "--name", name, repoName, "top")
  1386  	trustedExecCmd(serviceCmd)
  1387  	out, _, err := runCommandWithOutput(serviceCmd)
  1388  	c.Assert(err, checker.IsNil, check.Commentf(out))
  1389  	c.Assert(out, checker.Contains, "resolved image tag to", check.Commentf(out))
  1390  
  1391  	out, err = d.Cmd("service", "inspect", "--pretty", name)
  1392  	c.Assert(err, checker.IsNil, check.Commentf(out))
  1393  	c.Assert(out, checker.Contains, repoName+"@", check.Commentf(out))
  1394  
  1395  	// Try trusted service create on an untrusted tag.
  1396  
  1397  	repoName = fmt.Sprintf("%v/untrustedservicecreate/createtest:latest", privateRegistryURL)
  1398  	// tag the image and upload it to the private registry
  1399  	dockerCmd(c, "tag", "busybox", repoName)
  1400  	dockerCmd(c, "push", repoName)
  1401  	dockerCmd(c, "rmi", repoName)
  1402  
  1403  	name = "untrusted"
  1404  	serviceCmd = d.Command("service", "create", "--name", name, repoName, "top")
  1405  	trustedExecCmd(serviceCmd)
  1406  	out, _, err = runCommandWithOutput(serviceCmd)
  1407  
  1408  	c.Assert(err, check.NotNil, check.Commentf(out))
  1409  	c.Assert(string(out), checker.Contains, "Error: remote trust data does not exist", check.Commentf(out))
  1410  
  1411  	out, err = d.Cmd("service", "inspect", "--pretty", name)
  1412  	c.Assert(err, checker.NotNil, check.Commentf(out))
  1413  }
  1414  
  1415  func (s *DockerTrustedSwarmSuite) TestTrustedServiceUpdate(c *check.C) {
  1416  	d := s.swarmSuite.AddDaemon(c, true, true)
  1417  
  1418  	// Attempt creating a service from an image that is known to notary.
  1419  	repoName := s.trustSuite.setupTrustedImage(c, "trusted-pull")
  1420  
  1421  	name := "myservice"
  1422  
  1423  	// Create a service without content trust
  1424  	_, err := d.Cmd("service", "create", "--name", name, repoName, "top")
  1425  	c.Assert(err, checker.IsNil)
  1426  
  1427  	out, err := d.Cmd("service", "inspect", "--pretty", name)
  1428  	c.Assert(err, checker.IsNil, check.Commentf(out))
  1429  	// Daemon won't insert the digest because this is disabled by
  1430  	// DOCKER_SERVICE_PREFER_OFFLINE_IMAGE.
  1431  	c.Assert(out, check.Not(checker.Contains), repoName+"@", check.Commentf(out))
  1432  
  1433  	serviceCmd := d.Command("-D", "service", "update", "--image", repoName, name)
  1434  	trustedExecCmd(serviceCmd)
  1435  	out, _, err = runCommandWithOutput(serviceCmd)
  1436  	c.Assert(err, checker.IsNil, check.Commentf(out))
  1437  	c.Assert(out, checker.Contains, "resolved image tag to", check.Commentf(out))
  1438  
  1439  	out, err = d.Cmd("service", "inspect", "--pretty", name)
  1440  	c.Assert(err, checker.IsNil, check.Commentf(out))
  1441  	c.Assert(out, checker.Contains, repoName+"@", check.Commentf(out))
  1442  
  1443  	// Try trusted service update on an untrusted tag.
  1444  
  1445  	repoName = fmt.Sprintf("%v/untrustedservicecreate/createtest:latest", privateRegistryURL)
  1446  	// tag the image and upload it to the private registry
  1447  	dockerCmd(c, "tag", "busybox", repoName)
  1448  	dockerCmd(c, "push", repoName)
  1449  	dockerCmd(c, "rmi", repoName)
  1450  
  1451  	serviceCmd = d.Command("service", "update", "--image", repoName, name)
  1452  	trustedExecCmd(serviceCmd)
  1453  	out, _, err = runCommandWithOutput(serviceCmd)
  1454  
  1455  	c.Assert(err, check.NotNil, check.Commentf(out))
  1456  	c.Assert(string(out), checker.Contains, "Error: remote trust data does not exist", check.Commentf(out))
  1457  }
  1458  
  1459  // Test case for issue #27866, which did not allow NW name that is the prefix of a swarm NW ID.
  1460  // e.g. if the ingress ID starts with "n1", it was impossible to create a NW named "n1".
  1461  func (s *DockerSwarmSuite) TestSwarmNetworkCreateIssue27866(c *check.C) {
  1462  	d := s.AddDaemon(c, true, true)
  1463  	out, err := d.Cmd("network", "inspect", "-f", "{{.Id}}", "ingress")
  1464  	c.Assert(err, checker.IsNil, check.Commentf("out: %v", out))
  1465  	ingressID := strings.TrimSpace(out)
  1466  	c.Assert(ingressID, checker.Not(checker.Equals), "")
  1467  
  1468  	// create a network of which name is the prefix of the ID of an overlay network
  1469  	// (ingressID in this case)
  1470  	newNetName := ingressID[0:2]
  1471  	out, err = d.Cmd("network", "create", "--driver", "overlay", newNetName)
  1472  	// In #27866, it was failing because of "network with name %s already exists"
  1473  	c.Assert(err, checker.IsNil, check.Commentf("out: %v", out))
  1474  	out, err = d.Cmd("network", "rm", newNetName)
  1475  	c.Assert(err, checker.IsNil, check.Commentf("out: %v", out))
  1476  }
  1477  
  1478  // Test case for https://github.com/docker/docker/pull/27938#issuecomment-265768303
  1479  // This test creates two networks with the same name sequentially, with various drivers.
  1480  // Since the operations in this test are done sequentially, the 2nd call should fail with
  1481  // "network with name FOO already exists".
  1482  // Note that it is to ok have multiple networks with the same name if the operations are done
  1483  // in parallel. (#18864)
  1484  func (s *DockerSwarmSuite) TestSwarmNetworkCreateDup(c *check.C) {
  1485  	d := s.AddDaemon(c, true, true)
  1486  	drivers := []string{"bridge", "overlay"}
  1487  	for i, driver1 := range drivers {
  1488  		nwName := fmt.Sprintf("network-test-%d", i)
  1489  		for _, driver2 := range drivers {
  1490  			c.Logf("Creating a network named %q with %q, then %q",
  1491  				nwName, driver1, driver2)
  1492  			out, err := d.Cmd("network", "create", "--driver", driver1, nwName)
  1493  			c.Assert(err, checker.IsNil, check.Commentf("out: %v", out))
  1494  			out, err = d.Cmd("network", "create", "--driver", driver2, nwName)
  1495  			c.Assert(out, checker.Contains,
  1496  				fmt.Sprintf("network with name %s already exists", nwName))
  1497  			c.Assert(err, checker.NotNil)
  1498  			c.Logf("As expected, the attempt to network %q with %q failed: %s",
  1499  				nwName, driver2, out)
  1500  			out, err = d.Cmd("network", "rm", nwName)
  1501  			c.Assert(err, checker.IsNil, check.Commentf("out: %v", out))
  1502  		}
  1503  	}
  1504  }
  1505  
  1506  func (s *DockerSwarmSuite) TestSwarmServicePsMultipleServiceIDs(c *check.C) {
  1507  	d := s.AddDaemon(c, true, true)
  1508  
  1509  	name1 := "top1"
  1510  	out, err := d.Cmd("service", "create", "--name", name1, "--replicas=3", "busybox", "top")
  1511  	c.Assert(err, checker.IsNil)
  1512  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
  1513  	id1 := strings.TrimSpace(out)
  1514  
  1515  	name2 := "top2"
  1516  	out, err = d.Cmd("service", "create", "--name", name2, "--replicas=3", "busybox", "top")
  1517  	c.Assert(err, checker.IsNil)
  1518  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
  1519  	id2 := strings.TrimSpace(out)
  1520  
  1521  	// make sure task has been deployed.
  1522  	waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 6)
  1523  
  1524  	out, err = d.Cmd("service", "ps", name1)
  1525  	c.Assert(err, checker.IsNil)
  1526  	c.Assert(out, checker.Contains, name1+".1")
  1527  	c.Assert(out, checker.Contains, name1+".2")
  1528  	c.Assert(out, checker.Contains, name1+".3")
  1529  	c.Assert(out, checker.Not(checker.Contains), name2+".1")
  1530  	c.Assert(out, checker.Not(checker.Contains), name2+".2")
  1531  	c.Assert(out, checker.Not(checker.Contains), name2+".3")
  1532  
  1533  	out, err = d.Cmd("service", "ps", name1, name2)
  1534  	c.Assert(err, checker.IsNil)
  1535  	c.Assert(out, checker.Contains, name1+".1")
  1536  	c.Assert(out, checker.Contains, name1+".2")
  1537  	c.Assert(out, checker.Contains, name1+".3")
  1538  	c.Assert(out, checker.Contains, name2+".1")
  1539  	c.Assert(out, checker.Contains, name2+".2")
  1540  	c.Assert(out, checker.Contains, name2+".3")
  1541  
  1542  	// Name Prefix
  1543  	out, err = d.Cmd("service", "ps", "to")
  1544  	c.Assert(err, checker.IsNil)
  1545  	c.Assert(out, checker.Contains, name1+".1")
  1546  	c.Assert(out, checker.Contains, name1+".2")
  1547  	c.Assert(out, checker.Contains, name1+".3")
  1548  	c.Assert(out, checker.Contains, name2+".1")
  1549  	c.Assert(out, checker.Contains, name2+".2")
  1550  	c.Assert(out, checker.Contains, name2+".3")
  1551  
  1552  	// Name Prefix (no hit)
  1553  	out, err = d.Cmd("service", "ps", "noname")
  1554  	c.Assert(err, checker.NotNil)
  1555  	c.Assert(out, checker.Contains, "no such services: noname")
  1556  
  1557  	out, err = d.Cmd("service", "ps", id1)
  1558  	c.Assert(err, checker.IsNil)
  1559  	c.Assert(out, checker.Contains, name1+".1")
  1560  	c.Assert(out, checker.Contains, name1+".2")
  1561  	c.Assert(out, checker.Contains, name1+".3")
  1562  	c.Assert(out, checker.Not(checker.Contains), name2+".1")
  1563  	c.Assert(out, checker.Not(checker.Contains), name2+".2")
  1564  	c.Assert(out, checker.Not(checker.Contains), name2+".3")
  1565  
  1566  	out, err = d.Cmd("service", "ps", id1, id2)
  1567  	c.Assert(err, checker.IsNil)
  1568  	c.Assert(out, checker.Contains, name1+".1")
  1569  	c.Assert(out, checker.Contains, name1+".2")
  1570  	c.Assert(out, checker.Contains, name1+".3")
  1571  	c.Assert(out, checker.Contains, name2+".1")
  1572  	c.Assert(out, checker.Contains, name2+".2")
  1573  	c.Assert(out, checker.Contains, name2+".3")
  1574  }
  1575  
  1576  func (s *DockerSwarmSuite) TestSwarmPublishDuplicatePorts(c *check.C) {
  1577  	d := s.AddDaemon(c, true, true)
  1578  
  1579  	out, err := d.Cmd("service", "create", "--publish", "5000:80", "--publish", "5001:80", "--publish", "80", "--publish", "80", "busybox", "top")
  1580  	c.Assert(err, check.IsNil, check.Commentf(out))
  1581  	id := strings.TrimSpace(out)
  1582  
  1583  	// make sure task has been deployed.
  1584  	waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1)
  1585  
  1586  	// Total len = 4, with 2 dynamic ports and 2 non-dynamic ports
  1587  	// Dynamic ports are likely to be 30000 and 30001 but doesn't matter
  1588  	out, err = d.Cmd("service", "inspect", "--format", "{{.Endpoint.Ports}} len={{len .Endpoint.Ports}}", id)
  1589  	c.Assert(err, check.IsNil, check.Commentf(out))
  1590  	c.Assert(out, checker.Contains, "len=4")
  1591  	c.Assert(out, checker.Contains, "{ tcp 80 5000 ingress}")
  1592  	c.Assert(out, checker.Contains, "{ tcp 80 5001 ingress}")
  1593  }
  1594  
  1595  func (s *DockerSwarmSuite) TestSwarmJoinWithDrain(c *check.C) {
  1596  	d := s.AddDaemon(c, true, true)
  1597  
  1598  	out, err := d.Cmd("node", "ls")
  1599  	c.Assert(err, checker.IsNil)
  1600  	c.Assert(out, checker.Not(checker.Contains), "Drain")
  1601  
  1602  	out, err = d.Cmd("swarm", "join-token", "-q", "manager")
  1603  	c.Assert(err, checker.IsNil)
  1604  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
  1605  
  1606  	token := strings.TrimSpace(out)
  1607  
  1608  	d1 := s.AddDaemon(c, false, false)
  1609  
  1610  	out, err = d1.Cmd("swarm", "join", "--availability=drain", "--token", token, d.ListenAddr)
  1611  	c.Assert(err, checker.IsNil)
  1612  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
  1613  
  1614  	out, err = d.Cmd("node", "ls")
  1615  	c.Assert(err, checker.IsNil)
  1616  	c.Assert(out, checker.Contains, "Drain")
  1617  
  1618  	out, err = d1.Cmd("node", "ls")
  1619  	c.Assert(err, checker.IsNil)
  1620  	c.Assert(out, checker.Contains, "Drain")
  1621  }
  1622  
  1623  func (s *DockerSwarmSuite) TestSwarmInitWithDrain(c *check.C) {
  1624  	d := s.AddDaemon(c, false, false)
  1625  
  1626  	out, err := d.Cmd("swarm", "init", "--availability", "drain")
  1627  	c.Assert(err, checker.IsNil, check.Commentf("out: %v", out))
  1628  
  1629  	out, err = d.Cmd("node", "ls")
  1630  	c.Assert(err, checker.IsNil)
  1631  	c.Assert(out, checker.Contains, "Drain")
  1632  }