github.com/devdivbcp/moby@v17.12.0-ce-rc1.0.20200726071732-2d4bfdc789ad+incompatible/integration-cli/docker_cli_swarm_test.go (about)

     1  // +build !windows
     2  
     3  package main
     4  
     5  import (
     6  	"bytes"
     7  	"context"
     8  	"encoding/json"
     9  	"encoding/pem"
    10  	"fmt"
    11  	"io/ioutil"
    12  	"net/http"
    13  	"net/http/httptest"
    14  	"os"
    15  	"path/filepath"
    16  	"runtime"
    17  	"strings"
    18  	"testing"
    19  	"time"
    20  
    21  	"github.com/cloudflare/cfssl/helpers"
    22  	"github.com/docker/docker/api/types"
    23  	"github.com/docker/docker/api/types/swarm"
    24  	"github.com/docker/docker/integration-cli/checker"
    25  	"github.com/docker/docker/integration-cli/cli"
    26  	"github.com/docker/docker/integration-cli/daemon"
    27  	"github.com/docker/libnetwork/driverapi"
    28  	"github.com/docker/libnetwork/ipamapi"
    29  	remoteipam "github.com/docker/libnetwork/ipams/remote/api"
    30  	"github.com/docker/swarmkit/ca/keyutils"
    31  	"github.com/vishvananda/netlink"
    32  	"gotest.tools/assert"
    33  	"gotest.tools/fs"
    34  	"gotest.tools/icmd"
    35  	"gotest.tools/poll"
    36  )
    37  
    38  func (s *DockerSwarmSuite) TestSwarmUpdate(c *testing.T) {
    39  	d := s.AddDaemon(c, true, true)
    40  
    41  	getSpec := func() swarm.Spec {
    42  		sw := d.GetSwarm(c)
    43  		return sw.Spec
    44  	}
    45  
    46  	out, err := d.Cmd("swarm", "update", "--cert-expiry", "30h", "--dispatcher-heartbeat", "11s")
    47  	assert.NilError(c, err, out)
    48  
    49  	spec := getSpec()
    50  	assert.Equal(c, spec.CAConfig.NodeCertExpiry, 30*time.Hour)
    51  	assert.Equal(c, spec.Dispatcher.HeartbeatPeriod, 11*time.Second)
    52  
    53  	// setting anything under 30m for cert-expiry is not allowed
    54  	out, err = d.Cmd("swarm", "update", "--cert-expiry", "15m")
    55  	assert.ErrorContains(c, err, "")
    56  	assert.Assert(c, strings.Contains(out, "minimum certificate expiry time"))
    57  	spec = getSpec()
    58  	assert.Equal(c, spec.CAConfig.NodeCertExpiry, 30*time.Hour)
    59  
    60  	// passing an external CA (this is without starting a root rotation) does not fail
    61  	cli.Docker(cli.Args("swarm", "update", "--external-ca", "protocol=cfssl,url=https://something.org",
    62  		"--external-ca", "protocol=cfssl,url=https://somethingelse.org,cacert=fixtures/https/ca.pem"),
    63  		cli.Daemon(d)).Assert(c, icmd.Success)
    64  
    65  	expected, err := ioutil.ReadFile("fixtures/https/ca.pem")
    66  	assert.NilError(c, err)
    67  
    68  	spec = getSpec()
    69  	assert.Equal(c, len(spec.CAConfig.ExternalCAs), 2)
    70  	assert.Equal(c, spec.CAConfig.ExternalCAs[0].CACert, "")
    71  	assert.Equal(c, spec.CAConfig.ExternalCAs[1].CACert, string(expected))
    72  
    73  	// passing an invalid external CA fails
    74  	tempFile := fs.NewFile(c, "testfile", fs.WithContent("fakecert"))
    75  	defer tempFile.Remove()
    76  
    77  	result := cli.Docker(cli.Args("swarm", "update",
    78  		"--external-ca", fmt.Sprintf("protocol=cfssl,url=https://something.org,cacert=%s", tempFile.Path())),
    79  		cli.Daemon(d))
    80  	result.Assert(c, icmd.Expected{
    81  		ExitCode: 125,
    82  		Err:      "must be in PEM format",
    83  	})
    84  }
    85  
    86  func (s *DockerSwarmSuite) TestSwarmInit(c *testing.T) {
    87  	d := s.AddDaemon(c, false, false)
    88  
    89  	getSpec := func() swarm.Spec {
    90  		sw := d.GetSwarm(c)
    91  		return sw.Spec
    92  	}
    93  
    94  	// passing an invalid external CA fails
    95  	tempFile := fs.NewFile(c, "testfile", fs.WithContent("fakecert"))
    96  	defer tempFile.Remove()
    97  
    98  	result := cli.Docker(cli.Args("swarm", "init", "--cert-expiry", "30h", "--dispatcher-heartbeat", "11s",
    99  		"--external-ca", fmt.Sprintf("protocol=cfssl,url=https://somethingelse.org,cacert=%s", tempFile.Path())),
   100  		cli.Daemon(d))
   101  	result.Assert(c, icmd.Expected{
   102  		ExitCode: 125,
   103  		Err:      "must be in PEM format",
   104  	})
   105  
   106  	cli.Docker(cli.Args("swarm", "init", "--cert-expiry", "30h", "--dispatcher-heartbeat", "11s",
   107  		"--external-ca", "protocol=cfssl,url=https://something.org",
   108  		"--external-ca", "protocol=cfssl,url=https://somethingelse.org,cacert=fixtures/https/ca.pem"),
   109  		cli.Daemon(d)).Assert(c, icmd.Success)
   110  
   111  	expected, err := ioutil.ReadFile("fixtures/https/ca.pem")
   112  	assert.NilError(c, err)
   113  
   114  	spec := getSpec()
   115  	assert.Equal(c, spec.CAConfig.NodeCertExpiry, 30*time.Hour)
   116  	assert.Equal(c, spec.Dispatcher.HeartbeatPeriod, 11*time.Second)
   117  	assert.Equal(c, len(spec.CAConfig.ExternalCAs), 2)
   118  	assert.Equal(c, spec.CAConfig.ExternalCAs[0].CACert, "")
   119  	assert.Equal(c, spec.CAConfig.ExternalCAs[1].CACert, string(expected))
   120  
   121  	assert.Assert(c, d.SwarmLeave(c, true) == nil)
   122  	cli.Docker(cli.Args("swarm", "init"), cli.Daemon(d)).Assert(c, icmd.Success)
   123  
   124  	spec = getSpec()
   125  	assert.Equal(c, spec.CAConfig.NodeCertExpiry, 90*24*time.Hour)
   126  	assert.Equal(c, spec.Dispatcher.HeartbeatPeriod, 5*time.Second)
   127  }
   128  
   129  func (s *DockerSwarmSuite) TestSwarmInitIPv6(c *testing.T) {
   130  	testRequires(c, IPv6)
   131  	d1 := s.AddDaemon(c, false, false)
   132  	cli.Docker(cli.Args("swarm", "init", "--listen-add", "::1"), cli.Daemon(d1)).Assert(c, icmd.Success)
   133  
   134  	d2 := s.AddDaemon(c, false, false)
   135  	cli.Docker(cli.Args("swarm", "join", "::1"), cli.Daemon(d2)).Assert(c, icmd.Success)
   136  
   137  	out := cli.Docker(cli.Args("info"), cli.Daemon(d2)).Assert(c, icmd.Success).Combined()
   138  	assert.Assert(c, strings.Contains(out, "Swarm: active"))
   139  }
   140  
   141  func (s *DockerSwarmSuite) TestSwarmInitUnspecifiedAdvertiseAddr(c *testing.T) {
   142  	d := s.AddDaemon(c, false, false)
   143  	out, err := d.Cmd("swarm", "init", "--advertise-addr", "0.0.0.0")
   144  	assert.ErrorContains(c, err, "")
   145  	assert.Assert(c, strings.Contains(out, "advertise address must be a non-zero IP address"))
   146  }
   147  
   148  func (s *DockerSwarmSuite) TestSwarmIncompatibleDaemon(c *testing.T) {
   149  	// init swarm mode and stop a daemon
   150  	d := s.AddDaemon(c, true, true)
   151  	info := d.SwarmInfo(c)
   152  	assert.Equal(c, info.LocalNodeState, swarm.LocalNodeStateActive)
   153  	d.Stop(c)
   154  
   155  	// start a daemon with --cluster-store and --cluster-advertise
   156  	err := d.StartWithError("--cluster-store=consul://consuladdr:consulport/some/path", "--cluster-advertise=1.1.1.1:2375")
   157  	assert.ErrorContains(c, err, "")
   158  	content, err := d.ReadLogFile()
   159  	assert.NilError(c, err)
   160  	assert.Assert(c, strings.Contains(string(content), "--cluster-store and --cluster-advertise daemon configurations are incompatible with swarm mode"))
   161  	// start a daemon with --live-restore
   162  	err = d.StartWithError("--live-restore")
   163  	assert.ErrorContains(c, err, "")
   164  	content, err = d.ReadLogFile()
   165  	assert.NilError(c, err)
   166  	assert.Assert(c, strings.Contains(string(content), "--live-restore daemon configuration is incompatible with swarm mode"))
   167  	// restart for teardown
   168  	d.StartNode(c)
   169  }
   170  
   171  func (s *DockerSwarmSuite) TestSwarmServiceTemplatingHostname(c *testing.T) {
   172  	d := s.AddDaemon(c, true, true)
   173  	hostname, err := d.Cmd("node", "inspect", "--format", "{{.Description.Hostname}}", "self")
   174  	assert.Assert(c, err == nil, "%s", hostname)
   175  
   176  	out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", "test", "--hostname", "{{.Service.Name}}-{{.Task.Slot}}-{{.Node.Hostname}}", "busybox", "top")
   177  	assert.NilError(c, err, out)
   178  
   179  	// make sure task has been deployed.
   180  	poll.WaitOn(c, pollCheck(c, d.CheckActiveContainerCount, checker.Equals(1)), poll.WithTimeout(defaultReconciliationTimeout))
   181  
   182  	containers := d.ActiveContainers(c)
   183  	out, err = d.Cmd("inspect", "--type", "container", "--format", "{{.Config.Hostname}}", containers[0])
   184  	assert.NilError(c, err, out)
   185  	assert.Equal(c, strings.Split(out, "\n")[0], "test-1-"+strings.Split(hostname, "\n")[0], "hostname with templating invalid")
   186  }
   187  
   188  // Test case for #24270
   189  func (s *DockerSwarmSuite) TestSwarmServiceListFilter(c *testing.T) {
   190  	d := s.AddDaemon(c, true, true)
   191  
   192  	name1 := "redis-cluster-md5"
   193  	name2 := "redis-cluster"
   194  	name3 := "other-cluster"
   195  	out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", name1, "busybox", "top")
   196  	assert.NilError(c, err, out)
   197  	assert.Assert(c, strings.TrimSpace(out) != "")
   198  
   199  	out, err = d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", name2, "busybox", "top")
   200  	assert.NilError(c, err, out)
   201  	assert.Assert(c, strings.TrimSpace(out) != "")
   202  
   203  	out, err = d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", name3, "busybox", "top")
   204  	assert.NilError(c, err, out)
   205  	assert.Assert(c, strings.TrimSpace(out) != "")
   206  
   207  	filter1 := "name=redis-cluster-md5"
   208  	filter2 := "name=redis-cluster"
   209  
   210  	// We search checker.Contains with `name+" "` to prevent prefix only.
   211  	out, err = d.Cmd("service", "ls", "--filter", filter1)
   212  	assert.NilError(c, err, out)
   213  	assert.Assert(c, strings.Contains(out, name1+" "))
   214  	assert.Assert(c, !strings.Contains(out, name2+" "))
   215  	assert.Assert(c, !strings.Contains(out, name3+" "))
   216  	out, err = d.Cmd("service", "ls", "--filter", filter2)
   217  	assert.NilError(c, err, out)
   218  	assert.Assert(c, strings.Contains(out, name1+" "))
   219  	assert.Assert(c, strings.Contains(out, name2+" "))
   220  	assert.Assert(c, !strings.Contains(out, name3+" "))
   221  	out, err = d.Cmd("service", "ls")
   222  	assert.NilError(c, err, out)
   223  	assert.Assert(c, strings.Contains(out, name1+" "))
   224  	assert.Assert(c, strings.Contains(out, name2+" "))
   225  	assert.Assert(c, strings.Contains(out, name3+" "))
   226  }
   227  
   228  func (s *DockerSwarmSuite) TestSwarmNodeListFilter(c *testing.T) {
   229  	d := s.AddDaemon(c, true, true)
   230  
   231  	out, err := d.Cmd("node", "inspect", "--format", "{{ .Description.Hostname }}", "self")
   232  	assert.NilError(c, err, out)
   233  	assert.Assert(c, strings.TrimSpace(out) != "")
   234  	name := strings.TrimSpace(out)
   235  
   236  	filter := "name=" + name[:4]
   237  
   238  	out, err = d.Cmd("node", "ls", "--filter", filter)
   239  	assert.NilError(c, err, out)
   240  	assert.Assert(c, strings.Contains(out, name))
   241  	out, err = d.Cmd("node", "ls", "--filter", "name=none")
   242  	assert.NilError(c, err, out)
   243  	assert.Assert(c, !strings.Contains(out, name))
   244  }
   245  
   246  func (s *DockerSwarmSuite) TestSwarmNodeTaskListFilter(c *testing.T) {
   247  	d := s.AddDaemon(c, true, true)
   248  
   249  	name := "redis-cluster-md5"
   250  	out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", name, "--replicas=3", "busybox", "top")
   251  	assert.NilError(c, err, out)
   252  	assert.Assert(c, strings.TrimSpace(out) != "")
   253  
   254  	// make sure task has been deployed.
   255  	poll.WaitOn(c, pollCheck(c, d.CheckActiveContainerCount, checker.Equals(3)), poll.WithTimeout(defaultReconciliationTimeout))
   256  
   257  	filter := "name=redis-cluster"
   258  
   259  	out, err = d.Cmd("node", "ps", "--filter", filter, "self")
   260  	assert.NilError(c, err, out)
   261  	assert.Assert(c, strings.Contains(out, name+".1"))
   262  	assert.Assert(c, strings.Contains(out, name+".2"))
   263  	assert.Assert(c, strings.Contains(out, name+".3"))
   264  	out, err = d.Cmd("node", "ps", "--filter", "name=none", "self")
   265  	assert.NilError(c, err, out)
   266  	assert.Assert(c, !strings.Contains(out, name+".1"))
   267  	assert.Assert(c, !strings.Contains(out, name+".2"))
   268  	assert.Assert(c, !strings.Contains(out, name+".3"))
   269  }
   270  
   271  // Test case for #25375
   272  func (s *DockerSwarmSuite) TestSwarmPublishAdd(c *testing.T) {
   273  	d := s.AddDaemon(c, true, true)
   274  
   275  	name := "top"
   276  	// this first command does not have to be retried because service creates
   277  	// don't return out of sequence errors.
   278  	out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", name, "--label", "x=y", "busybox", "top")
   279  	assert.NilError(c, err, out)
   280  	assert.Assert(c, strings.TrimSpace(out) != "")
   281  
   282  	out, err = d.CmdRetryOutOfSequence("service", "update", "--detach", "--publish-add", "80:80", name)
   283  	assert.NilError(c, err, out)
   284  
   285  	out, err = d.CmdRetryOutOfSequence("service", "update", "--detach", "--publish-add", "80:80", name)
   286  	assert.NilError(c, err, out)
   287  
   288  	_, err = d.CmdRetryOutOfSequence("service", "update", "--detach", "--publish-add", "80:80", "--publish-add", "80:20", name)
   289  	assert.ErrorContains(c, err, "")
   290  
   291  	// this last command does not have to be retried because service inspect
   292  	// does not return out of sequence errors.
   293  	out, err = d.Cmd("service", "inspect", "--format", "{{ .Spec.EndpointSpec.Ports }}", name)
   294  	assert.NilError(c, err, out)
   295  	assert.Equal(c, strings.TrimSpace(out), "[{ tcp 80 80 ingress}]")
   296  }
   297  
   298  func (s *DockerSwarmSuite) TestSwarmServiceWithGroup(c *testing.T) {
   299  	d := s.AddDaemon(c, true, true)
   300  
   301  	name := "top"
   302  	out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", name, "--user", "root:root", "--group", "wheel", "--group", "audio", "--group", "staff", "--group", "777", "busybox", "top")
   303  	assert.NilError(c, err, out)
   304  	assert.Assert(c, strings.TrimSpace(out) != "")
   305  
   306  	// make sure task has been deployed.
   307  	poll.WaitOn(c, pollCheck(c, d.CheckActiveContainerCount, checker.Equals(1)), poll.WithTimeout(defaultReconciliationTimeout))
   308  
   309  	out, err = d.Cmd("ps", "-q")
   310  	assert.NilError(c, err, out)
   311  	assert.Assert(c, strings.TrimSpace(out) != "")
   312  
   313  	container := strings.TrimSpace(out)
   314  
   315  	out, err = d.Cmd("exec", container, "id")
   316  	assert.NilError(c, err, out)
   317  	assert.Equal(c, strings.TrimSpace(out), "uid=0(root) gid=0(root) groups=10(wheel),29(audio),50(staff),777")
   318  }
   319  
   320  func (s *DockerSwarmSuite) TestSwarmContainerAutoStart(c *testing.T) {
   321  	d := s.AddDaemon(c, true, true)
   322  
   323  	out, err := d.Cmd("network", "create", "--attachable", "-d", "overlay", "foo")
   324  	assert.NilError(c, err, out)
   325  	assert.Assert(c, strings.TrimSpace(out) != "")
   326  
   327  	out, err = d.Cmd("run", "-id", "--restart=always", "--net=foo", "--name=test", "busybox", "top")
   328  	assert.NilError(c, err, out)
   329  	assert.Assert(c, strings.TrimSpace(out) != "")
   330  
   331  	out, err = d.Cmd("ps", "-q")
   332  	assert.NilError(c, err, out)
   333  	assert.Assert(c, strings.TrimSpace(out) != "")
   334  
   335  	d.RestartNode(c)
   336  
   337  	out, err = d.Cmd("ps", "-q")
   338  	assert.NilError(c, err, out)
   339  	assert.Assert(c, strings.TrimSpace(out) != "")
   340  }
   341  
   342  func (s *DockerSwarmSuite) TestSwarmContainerEndpointOptions(c *testing.T) {
   343  	d := s.AddDaemon(c, true, true)
   344  
   345  	out, err := d.Cmd("network", "create", "--attachable", "-d", "overlay", "foo")
   346  	assert.NilError(c, err, out)
   347  	assert.Assert(c, strings.TrimSpace(out) != "")
   348  
   349  	out, err = d.Cmd("run", "-d", "--net=foo", "--name=first", "--net-alias=first-alias", "busybox:glibc", "top")
   350  	assert.NilError(c, err, out)
   351  
   352  	out, err = d.Cmd("run", "-d", "--net=foo", "--name=second", "busybox:glibc", "top")
   353  	assert.NilError(c, err, out)
   354  
   355  	out, err = d.Cmd("run", "-d", "--net=foo", "--net-alias=third-alias", "busybox:glibc", "top")
   356  	assert.NilError(c, err, out)
   357  
   358  	// ping first container and its alias, also ping third and anonymous container by its alias
   359  	out, err = d.Cmd("exec", "second", "ping", "-c", "1", "first")
   360  	assert.NilError(c, err, out)
   361  	out, err = d.Cmd("exec", "second", "ping", "-c", "1", "first-alias")
   362  	assert.NilError(c, err, out)
   363  	out, err = d.Cmd("exec", "second", "ping", "-c", "1", "third-alias")
   364  	assert.NilError(c, err, out)
   365  }
   366  
   367  func (s *DockerSwarmSuite) TestSwarmContainerAttachByNetworkId(c *testing.T) {
   368  	d := s.AddDaemon(c, true, true)
   369  
   370  	out, err := d.Cmd("network", "create", "--attachable", "-d", "overlay", "testnet")
   371  	assert.NilError(c, err, out)
   372  	assert.Assert(c, strings.TrimSpace(out) != "")
   373  	networkID := strings.TrimSpace(out)
   374  
   375  	out, err = d.Cmd("run", "-d", "--net", networkID, "busybox", "top")
   376  	assert.NilError(c, err, out)
   377  	cID := strings.TrimSpace(out)
   378  	d.WaitRun(cID)
   379  
   380  	out, err = d.Cmd("rm", "-f", cID)
   381  	assert.NilError(c, err, out)
   382  
   383  	out, err = d.Cmd("network", "rm", "testnet")
   384  	assert.NilError(c, err, out)
   385  
   386  	checkNetwork := func(*testing.T) (interface{}, string) {
   387  		out, err := d.Cmd("network", "ls")
   388  		assert.NilError(c, err)
   389  		return out, ""
   390  	}
   391  
   392  	poll.WaitOn(c, pollCheck(c, checkNetwork, checker.Not(checker.Contains("testnet"))), poll.WithTimeout(3*time.Second))
   393  }
   394  
   395  func (s *DockerSwarmSuite) TestOverlayAttachable(c *testing.T) {
   396  	d := s.AddDaemon(c, true, true)
   397  
   398  	out, err := d.Cmd("network", "create", "-d", "overlay", "--attachable", "ovnet")
   399  	assert.NilError(c, err, out)
   400  
   401  	// validate attachable
   402  	out, err = d.Cmd("network", "inspect", "--format", "{{json .Attachable}}", "ovnet")
   403  	assert.NilError(c, err, out)
   404  	assert.Equal(c, strings.TrimSpace(out), "true")
   405  
   406  	// validate containers can attach to this overlay network
   407  	out, err = d.Cmd("run", "-d", "--network", "ovnet", "--name", "c1", "busybox", "top")
   408  	assert.NilError(c, err, out)
   409  
   410  	// redo validation, there was a bug that the value of attachable changes after
   411  	// containers attach to the network
   412  	out, err = d.Cmd("network", "inspect", "--format", "{{json .Attachable}}", "ovnet")
   413  	assert.NilError(c, err, out)
   414  	assert.Equal(c, strings.TrimSpace(out), "true")
   415  }
   416  
   417  func (s *DockerSwarmSuite) TestOverlayAttachableOnSwarmLeave(c *testing.T) {
   418  	d := s.AddDaemon(c, true, true)
   419  
   420  	// Create an attachable swarm network
   421  	nwName := "attovl"
   422  	out, err := d.Cmd("network", "create", "-d", "overlay", "--attachable", nwName)
   423  	assert.NilError(c, err, out)
   424  
   425  	// Connect a container to the network
   426  	out, err = d.Cmd("run", "-d", "--network", nwName, "--name", "c1", "busybox", "top")
   427  	assert.NilError(c, err, out)
   428  
   429  	// Leave the swarm
   430  	assert.Assert(c, d.SwarmLeave(c, true) == nil)
   431  
   432  	// Check the container is disconnected
   433  	out, err = d.Cmd("inspect", "c1", "--format", "{{.NetworkSettings.Networks."+nwName+"}}")
   434  	assert.NilError(c, err, out)
   435  	assert.Equal(c, strings.TrimSpace(out), "<no value>")
   436  
   437  	// Check the network is gone
   438  	out, err = d.Cmd("network", "ls", "--format", "{{.Name}}")
   439  	assert.NilError(c, err, out)
   440  	assert.Assert(c, !strings.Contains(out, nwName))
   441  }
   442  
   443  func (s *DockerSwarmSuite) TestOverlayAttachableReleaseResourcesOnFailure(c *testing.T) {
   444  	d := s.AddDaemon(c, true, true)
   445  
   446  	// Create attachable network
   447  	out, err := d.Cmd("network", "create", "-d", "overlay", "--attachable", "--subnet", "10.10.9.0/24", "ovnet")
   448  	assert.NilError(c, err, out)
   449  
   450  	// Attach a container with specific IP
   451  	out, err = d.Cmd("run", "-d", "--network", "ovnet", "--name", "c1", "--ip", "10.10.9.33", "busybox", "top")
   452  	assert.NilError(c, err, out)
   453  
   454  	// Attempt to attach another container with same IP, must fail
   455  	out, err = d.Cmd("run", "-d", "--network", "ovnet", "--name", "c2", "--ip", "10.10.9.33", "busybox", "top")
   456  	assert.ErrorContains(c, err, "", out)
   457  
   458  	// Remove first container
   459  	out, err = d.Cmd("rm", "-f", "c1")
   460  	assert.NilError(c, err, out)
   461  
   462  	// Verify the network can be removed, no phantom network attachment task left over
   463  	out, err = d.Cmd("network", "rm", "ovnet")
   464  	assert.NilError(c, err, out)
   465  }
   466  
   467  func (s *DockerSwarmSuite) TestSwarmIngressNetwork(c *testing.T) {
   468  	d := s.AddDaemon(c, true, true)
   469  
   470  	// Ingress network can be removed
   471  	removeNetwork := func(name string) *icmd.Result {
   472  		return cli.Docker(
   473  			cli.Args("-H", d.Sock(), "network", "rm", name),
   474  			cli.WithStdin(strings.NewReader("Y")))
   475  	}
   476  
   477  	result := removeNetwork("ingress")
   478  	result.Assert(c, icmd.Success)
   479  
   480  	// And recreated
   481  	out, err := d.Cmd("network", "create", "-d", "overlay", "--ingress", "new-ingress")
   482  	assert.NilError(c, err, out)
   483  
   484  	// But only one is allowed
   485  	out, err = d.Cmd("network", "create", "-d", "overlay", "--ingress", "another-ingress")
   486  	assert.ErrorContains(c, err, "")
   487  	assert.Assert(c, strings.Contains(strings.TrimSpace(out), "is already present"))
   488  	// It cannot be removed if it is being used
   489  	out, err = d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", "srv1", "-p", "9000:8000", "busybox", "top")
   490  	assert.NilError(c, err, out)
   491  
   492  	result = removeNetwork("new-ingress")
   493  	result.Assert(c, icmd.Expected{
   494  		ExitCode: 1,
   495  		Err:      "ingress network cannot be removed because service",
   496  	})
   497  
   498  	// But it can be removed once no more services depend on it
   499  	out, err = d.Cmd("service", "update", "--detach", "--publish-rm", "9000:8000", "srv1")
   500  	assert.NilError(c, err, out)
   501  
   502  	result = removeNetwork("new-ingress")
   503  	result.Assert(c, icmd.Success)
   504  
   505  	// A service which needs the ingress network cannot be created if no ingress is present
   506  	out, err = d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", "srv2", "-p", "500:500", "busybox", "top")
   507  	assert.ErrorContains(c, err, "")
   508  	assert.Assert(c, strings.Contains(strings.TrimSpace(out), "no ingress network is present"))
   509  	// An existing service cannot be updated to use the ingress nw if the nw is not present
   510  	out, err = d.Cmd("service", "update", "--detach", "--publish-add", "9000:8000", "srv1")
   511  	assert.ErrorContains(c, err, "")
   512  	assert.Assert(c, strings.Contains(strings.TrimSpace(out), "no ingress network is present"))
   513  	// But services which do not need routing mesh can be created regardless
   514  	out, err = d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", "srv3", "--endpoint-mode", "dnsrr", "busybox", "top")
   515  	assert.NilError(c, err, out)
   516  }
   517  
   518  func (s *DockerSwarmSuite) TestSwarmCreateServiceWithNoIngressNetwork(c *testing.T) {
   519  	d := s.AddDaemon(c, true, true)
   520  
   521  	// Remove ingress network
   522  	result := cli.Docker(
   523  		cli.Args("-H", d.Sock(), "network", "rm", "ingress"),
   524  		cli.WithStdin(strings.NewReader("Y")))
   525  	result.Assert(c, icmd.Success)
   526  
   527  	// Create a overlay network and launch a service on it
   528  	// Make sure nothing panics because ingress network is missing
   529  	out, err := d.Cmd("network", "create", "-d", "overlay", "another-network")
   530  	assert.NilError(c, err, out)
   531  	out, err = d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", "srv4", "--network", "another-network", "busybox", "top")
   532  	assert.NilError(c, err, out)
   533  }
   534  
   535  // Test case for #24108, also the case from:
   536  // https://github.com/docker/docker/pull/24620#issuecomment-233715656
   537  func (s *DockerSwarmSuite) TestSwarmTaskListFilter(c *testing.T) {
   538  	d := s.AddDaemon(c, true, true)
   539  
   540  	name := "redis-cluster-md5"
   541  	out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", name, "--replicas=3", "busybox", "top")
   542  	assert.NilError(c, err, out)
   543  	assert.Assert(c, strings.TrimSpace(out) != "")
   544  
   545  	filter := "name=redis-cluster"
   546  
   547  	checkNumTasks := func(*testing.T) (interface{}, string) {
   548  		out, err := d.Cmd("service", "ps", "--filter", filter, name)
   549  		assert.NilError(c, err, out)
   550  		return len(strings.Split(out, "\n")) - 2, "" // includes header and nl in last line
   551  	}
   552  
   553  	// wait until all tasks have been created
   554  	poll.WaitOn(c, pollCheck(c, checkNumTasks, checker.Equals(3)), poll.WithTimeout(defaultReconciliationTimeout))
   555  
   556  	out, err = d.Cmd("service", "ps", "--filter", filter, name)
   557  	assert.NilError(c, err, out)
   558  	assert.Assert(c, strings.Contains(out, name+".1"))
   559  	assert.Assert(c, strings.Contains(out, name+".2"))
   560  	assert.Assert(c, strings.Contains(out, name+".3"))
   561  	out, err = d.Cmd("service", "ps", "--filter", "name="+name+".1", name)
   562  	assert.NilError(c, err, out)
   563  	assert.Assert(c, strings.Contains(out, name+".1"))
   564  	assert.Assert(c, !strings.Contains(out, name+".2"))
   565  	assert.Assert(c, !strings.Contains(out, name+".3"))
   566  	out, err = d.Cmd("service", "ps", "--filter", "name=none", name)
   567  	assert.NilError(c, err, out)
   568  	assert.Assert(c, !strings.Contains(out, name+".1"))
   569  	assert.Assert(c, !strings.Contains(out, name+".2"))
   570  	assert.Assert(c, !strings.Contains(out, name+".3"))
   571  	name = "redis-cluster-sha1"
   572  	out, err = d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", name, "--mode=global", "busybox", "top")
   573  	assert.NilError(c, err, out)
   574  	assert.Assert(c, strings.TrimSpace(out) != "")
   575  
   576  	poll.WaitOn(c, pollCheck(c, checkNumTasks, checker.Equals(1)), poll.WithTimeout(defaultReconciliationTimeout))
   577  
   578  	filter = "name=redis-cluster"
   579  	out, err = d.Cmd("service", "ps", "--filter", filter, name)
   580  	assert.NilError(c, err, out)
   581  	assert.Assert(c, strings.Contains(out, name))
   582  	out, err = d.Cmd("service", "ps", "--filter", "name="+name, name)
   583  	assert.NilError(c, err, out)
   584  	assert.Assert(c, strings.Contains(out, name))
   585  	out, err = d.Cmd("service", "ps", "--filter", "name=none", name)
   586  	assert.NilError(c, err, out)
   587  	assert.Assert(c, !strings.Contains(out, name))
   588  }
   589  
   590  func (s *DockerSwarmSuite) TestPsListContainersFilterIsTask(c *testing.T) {
   591  	d := s.AddDaemon(c, true, true)
   592  
   593  	// Create a bare container
   594  	out, err := d.Cmd("run", "-d", "--name=bare-container", "busybox", "top")
   595  	assert.NilError(c, err, out)
   596  	bareID := strings.TrimSpace(out)[:12]
   597  	// Create a service
   598  	name := "busybox-top"
   599  	out, err = d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", name, "busybox", "top")
   600  	assert.NilError(c, err, out)
   601  	assert.Assert(c, strings.TrimSpace(out) != "")
   602  
   603  	// make sure task has been deployed.
   604  	poll.WaitOn(c, pollCheck(c, d.CheckServiceRunningTasks(name), checker.Equals(1)), poll.WithTimeout(defaultReconciliationTimeout))
   605  
   606  	// Filter non-tasks
   607  	out, err = d.Cmd("ps", "-a", "-q", "--filter=is-task=false")
   608  	assert.NilError(c, err, out)
   609  	psOut := strings.TrimSpace(out)
   610  	assert.Equal(c, psOut, bareID, fmt.Sprintf("Expected id %s, got %s for is-task label, output %q", bareID, psOut, out))
   611  
   612  	// Filter tasks
   613  	out, err = d.Cmd("ps", "-a", "-q", "--filter=is-task=true")
   614  	assert.NilError(c, err, out)
   615  	lines := strings.Split(strings.Trim(out, "\n "), "\n")
   616  	assert.Equal(c, len(lines), 1)
   617  	assert.Assert(c, lines[0] != bareID, "Expected not %s, but got it for is-task label, output %q", bareID, out)
   618  }
   619  
   620  const globalNetworkPlugin = "global-network-plugin"
   621  const globalIPAMPlugin = "global-ipam-plugin"
   622  
   623  func setupRemoteGlobalNetworkPlugin(c *testing.T, mux *http.ServeMux, url, netDrv, ipamDrv string) {
   624  
   625  	mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) {
   626  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   627  		fmt.Fprintf(w, `{"Implements": ["%s", "%s"]}`, driverapi.NetworkPluginEndpointType, ipamapi.PluginEndpointType)
   628  	})
   629  
   630  	// Network driver implementation
   631  	mux.HandleFunc(fmt.Sprintf("/%s.GetCapabilities", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   632  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   633  		fmt.Fprintf(w, `{"Scope":"global"}`)
   634  	})
   635  
   636  	mux.HandleFunc(fmt.Sprintf("/%s.AllocateNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   637  		err := json.NewDecoder(r.Body).Decode(&remoteDriverNetworkRequest)
   638  		if err != nil {
   639  			http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
   640  			return
   641  		}
   642  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   643  		fmt.Fprintf(w, "null")
   644  	})
   645  
   646  	mux.HandleFunc(fmt.Sprintf("/%s.FreeNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   647  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   648  		fmt.Fprintf(w, "null")
   649  	})
   650  
   651  	mux.HandleFunc(fmt.Sprintf("/%s.CreateNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   652  		err := json.NewDecoder(r.Body).Decode(&remoteDriverNetworkRequest)
   653  		if err != nil {
   654  			http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
   655  			return
   656  		}
   657  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   658  		fmt.Fprintf(w, "null")
   659  	})
   660  
   661  	mux.HandleFunc(fmt.Sprintf("/%s.DeleteNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   662  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   663  		fmt.Fprintf(w, "null")
   664  	})
   665  
   666  	mux.HandleFunc(fmt.Sprintf("/%s.CreateEndpoint", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   667  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   668  		fmt.Fprintf(w, `{"Interface":{"MacAddress":"a0:b1:c2:d3:e4:f5"}}`)
   669  	})
   670  
   671  	mux.HandleFunc(fmt.Sprintf("/%s.Join", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   672  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   673  
   674  		veth := &netlink.Veth{
   675  			LinkAttrs: netlink.LinkAttrs{Name: "randomIfName", TxQLen: 0}, PeerName: "cnt0"}
   676  		if err := netlink.LinkAdd(veth); err != nil {
   677  			fmt.Fprintf(w, `{"Error":"failed to add veth pair: `+err.Error()+`"}`)
   678  		} else {
   679  			fmt.Fprintf(w, `{"InterfaceName":{ "SrcName":"cnt0", "DstPrefix":"veth"}}`)
   680  		}
   681  	})
   682  
   683  	mux.HandleFunc(fmt.Sprintf("/%s.Leave", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   684  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   685  		fmt.Fprintf(w, "null")
   686  	})
   687  
   688  	mux.HandleFunc(fmt.Sprintf("/%s.DeleteEndpoint", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   689  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   690  		if link, err := netlink.LinkByName("cnt0"); err == nil {
   691  			netlink.LinkDel(link)
   692  		}
   693  		fmt.Fprintf(w, "null")
   694  	})
   695  
   696  	// IPAM Driver implementation
   697  	var (
   698  		poolRequest       remoteipam.RequestPoolRequest
   699  		poolReleaseReq    remoteipam.ReleasePoolRequest
   700  		addressRequest    remoteipam.RequestAddressRequest
   701  		addressReleaseReq remoteipam.ReleaseAddressRequest
   702  		lAS               = "localAS"
   703  		gAS               = "globalAS"
   704  		pool              = "172.28.0.0/16"
   705  		poolID            = lAS + "/" + pool
   706  		gw                = "172.28.255.254/16"
   707  	)
   708  
   709  	mux.HandleFunc(fmt.Sprintf("/%s.GetDefaultAddressSpaces", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   710  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   711  		fmt.Fprintf(w, `{"LocalDefaultAddressSpace":"`+lAS+`", "GlobalDefaultAddressSpace": "`+gAS+`"}`)
   712  	})
   713  
   714  	mux.HandleFunc(fmt.Sprintf("/%s.RequestPool", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   715  		err := json.NewDecoder(r.Body).Decode(&poolRequest)
   716  		if err != nil {
   717  			http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
   718  			return
   719  		}
   720  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   721  		if poolRequest.AddressSpace != lAS && poolRequest.AddressSpace != gAS {
   722  			fmt.Fprintf(w, `{"Error":"Unknown address space in pool request: `+poolRequest.AddressSpace+`"}`)
   723  		} else if poolRequest.Pool != "" && poolRequest.Pool != pool {
   724  			fmt.Fprintf(w, `{"Error":"Cannot handle explicit pool requests yet"}`)
   725  		} else {
   726  			fmt.Fprintf(w, `{"PoolID":"`+poolID+`", "Pool":"`+pool+`"}`)
   727  		}
   728  	})
   729  
   730  	mux.HandleFunc(fmt.Sprintf("/%s.RequestAddress", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   731  		err := json.NewDecoder(r.Body).Decode(&addressRequest)
   732  		if err != nil {
   733  			http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
   734  			return
   735  		}
   736  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   737  		// make sure libnetwork is now querying on the expected pool id
   738  		if addressRequest.PoolID != poolID {
   739  			fmt.Fprintf(w, `{"Error":"unknown pool id"}`)
   740  		} else if addressRequest.Address != "" {
   741  			fmt.Fprintf(w, `{"Error":"Cannot handle explicit address requests yet"}`)
   742  		} else {
   743  			fmt.Fprintf(w, `{"Address":"`+gw+`"}`)
   744  		}
   745  	})
   746  
   747  	mux.HandleFunc(fmt.Sprintf("/%s.ReleaseAddress", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   748  		err := json.NewDecoder(r.Body).Decode(&addressReleaseReq)
   749  		if err != nil {
   750  			http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
   751  			return
   752  		}
   753  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   754  		// make sure libnetwork is now asking to release the expected address from the expected poolid
   755  		if addressRequest.PoolID != poolID {
   756  			fmt.Fprintf(w, `{"Error":"unknown pool id"}`)
   757  		} else if addressReleaseReq.Address != gw {
   758  			fmt.Fprintf(w, `{"Error":"unknown address"}`)
   759  		} else {
   760  			fmt.Fprintf(w, "null")
   761  		}
   762  	})
   763  
   764  	mux.HandleFunc(fmt.Sprintf("/%s.ReleasePool", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   765  		err := json.NewDecoder(r.Body).Decode(&poolReleaseReq)
   766  		if err != nil {
   767  			http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
   768  			return
   769  		}
   770  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   771  		// make sure libnetwork is now asking to release the expected poolid
   772  		if addressRequest.PoolID != poolID {
   773  			fmt.Fprintf(w, `{"Error":"unknown pool id"}`)
   774  		} else {
   775  			fmt.Fprintf(w, "null")
   776  		}
   777  	})
   778  
   779  	err := os.MkdirAll("/etc/docker/plugins", 0755)
   780  	assert.NilError(c, err)
   781  
   782  	fileName := fmt.Sprintf("/etc/docker/plugins/%s.spec", netDrv)
   783  	err = ioutil.WriteFile(fileName, []byte(url), 0644)
   784  	assert.NilError(c, err)
   785  
   786  	ipamFileName := fmt.Sprintf("/etc/docker/plugins/%s.spec", ipamDrv)
   787  	err = ioutil.WriteFile(ipamFileName, []byte(url), 0644)
   788  	assert.NilError(c, err)
   789  }
   790  
   791  func (s *DockerSwarmSuite) TestSwarmNetworkPlugin(c *testing.T) {
   792  	mux := http.NewServeMux()
   793  	s.server = httptest.NewServer(mux)
   794  	assert.Assert(c, s.server != nil) // check that HTTP server has started
   795  	setupRemoteGlobalNetworkPlugin(c, mux, s.server.URL, globalNetworkPlugin, globalIPAMPlugin)
   796  	defer func() {
   797  		s.server.Close()
   798  		err := os.RemoveAll("/etc/docker/plugins")
   799  		assert.NilError(c, err)
   800  	}()
   801  
   802  	d := s.AddDaemon(c, true, true)
   803  
   804  	out, err := d.Cmd("network", "create", "-d", globalNetworkPlugin, "foo")
   805  	assert.ErrorContains(c, err, "", out)
   806  	assert.Assert(c, strings.Contains(out, "not supported in swarm mode"))
   807  }
   808  
   809  // Test case for #24712
   810  func (s *DockerSwarmSuite) TestSwarmServiceEnvFile(c *testing.T) {
   811  	d := s.AddDaemon(c, true, true)
   812  
   813  	path := filepath.Join(d.Folder, "env.txt")
   814  	err := ioutil.WriteFile(path, []byte("VAR1=A\nVAR2=A\n"), 0644)
   815  	assert.NilError(c, err)
   816  
   817  	name := "worker"
   818  	out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--env-file", path, "--env", "VAR1=B", "--env", "VAR1=C", "--env", "VAR2=", "--env", "VAR2", "--name", name, "busybox", "top")
   819  	assert.NilError(c, err, out)
   820  	assert.Assert(c, strings.TrimSpace(out) != "")
   821  
   822  	// The complete env is [VAR1=A VAR2=A VAR1=B VAR1=C VAR2= VAR2] and duplicates will be removed => [VAR1=C VAR2]
   823  	out, err = d.Cmd("inspect", "--format", "{{ .Spec.TaskTemplate.ContainerSpec.Env }}", name)
   824  	assert.NilError(c, err, out)
   825  	assert.Assert(c, strings.Contains(out, "[VAR1=C VAR2]"))
   826  }
   827  
   828  func (s *DockerSwarmSuite) TestSwarmServiceTTY(c *testing.T) {
   829  	d := s.AddDaemon(c, true, true)
   830  
   831  	name := "top"
   832  
   833  	ttyCheck := "if [ -t 0 ]; then echo TTY > /status; else echo none > /status; fi; exec top"
   834  
   835  	// Without --tty
   836  	expectedOutput := "none"
   837  	out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", name, "busybox", "sh", "-c", ttyCheck)
   838  	assert.NilError(c, err, out)
   839  
   840  	// Make sure task has been deployed.
   841  	poll.WaitOn(c, pollCheck(c, d.CheckActiveContainerCount, checker.Equals(1)), poll.WithTimeout(defaultReconciliationTimeout))
   842  
   843  	// We need to get the container id.
   844  	out, err = d.Cmd("ps", "-q", "--no-trunc")
   845  	assert.NilError(c, err, out)
   846  	id := strings.TrimSpace(out)
   847  
   848  	out, err = d.Cmd("exec", id, "cat", "/status")
   849  	assert.NilError(c, err, out)
   850  	assert.Assert(c, strings.Contains(out, expectedOutput), "Expected '%s', but got %q", expectedOutput, out)
   851  	// Remove service
   852  	out, err = d.Cmd("service", "rm", name)
   853  	assert.NilError(c, err, out)
   854  	// Make sure container has been destroyed.
   855  	poll.WaitOn(c, pollCheck(c, d.CheckActiveContainerCount, checker.Equals(0)), poll.WithTimeout(defaultReconciliationTimeout))
   856  
   857  	// With --tty
   858  	expectedOutput = "TTY"
   859  	out, err = d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", name, "--tty", "busybox", "sh", "-c", ttyCheck)
   860  	assert.NilError(c, err, out)
   861  
   862  	// Make sure task has been deployed.
   863  	poll.WaitOn(c, pollCheck(c, d.CheckActiveContainerCount, checker.Equals(1)), poll.WithTimeout(defaultReconciliationTimeout))
   864  
   865  	// We need to get the container id.
   866  	out, err = d.Cmd("ps", "-q", "--no-trunc")
   867  	assert.NilError(c, err, out)
   868  	id = strings.TrimSpace(out)
   869  
   870  	out, err = d.Cmd("exec", id, "cat", "/status")
   871  	assert.NilError(c, err, out)
   872  	assert.Assert(c, strings.Contains(out, expectedOutput), "Expected '%s', but got %q", expectedOutput, out)
   873  }
   874  
   875  func (s *DockerSwarmSuite) TestSwarmServiceTTYUpdate(c *testing.T) {
   876  	d := s.AddDaemon(c, true, true)
   877  
   878  	// Create a service
   879  	name := "top"
   880  	out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", name, "busybox", "top")
   881  	assert.NilError(c, err, out)
   882  
   883  	// Make sure task has been deployed.
   884  	poll.WaitOn(c, pollCheck(c, d.CheckActiveContainerCount, checker.Equals(1)), poll.WithTimeout(defaultReconciliationTimeout))
   885  
   886  	out, err = d.Cmd("service", "inspect", "--format", "{{ .Spec.TaskTemplate.ContainerSpec.TTY }}", name)
   887  	assert.NilError(c, err, out)
   888  	assert.Equal(c, strings.TrimSpace(out), "false")
   889  
   890  	out, err = d.Cmd("service", "update", "--detach", "--tty", name)
   891  	assert.NilError(c, err, out)
   892  
   893  	out, err = d.Cmd("service", "inspect", "--format", "{{ .Spec.TaskTemplate.ContainerSpec.TTY }}", name)
   894  	assert.NilError(c, err, out)
   895  	assert.Equal(c, strings.TrimSpace(out), "true")
   896  }
   897  
   898  func (s *DockerSwarmSuite) TestSwarmServiceNetworkUpdate(c *testing.T) {
   899  	d := s.AddDaemon(c, true, true)
   900  
   901  	result := icmd.RunCmd(d.Command("network", "create", "-d", "overlay", "foo"))
   902  	result.Assert(c, icmd.Success)
   903  	fooNetwork := strings.TrimSpace(result.Combined())
   904  
   905  	result = icmd.RunCmd(d.Command("network", "create", "-d", "overlay", "bar"))
   906  	result.Assert(c, icmd.Success)
   907  	barNetwork := strings.TrimSpace(result.Combined())
   908  
   909  	result = icmd.RunCmd(d.Command("network", "create", "-d", "overlay", "baz"))
   910  	result.Assert(c, icmd.Success)
   911  	bazNetwork := strings.TrimSpace(result.Combined())
   912  
   913  	// Create a service
   914  	name := "top"
   915  	result = icmd.RunCmd(d.Command("service", "create", "--detach", "--no-resolve-image", "--network", "foo", "--network", "bar", "--name", name, "busybox", "top"))
   916  	result.Assert(c, icmd.Success)
   917  
   918  	// Make sure task has been deployed.
   919  	poll.WaitOn(c, pollCheck(c, d.CheckRunningTaskNetworks, checker.DeepEquals(map[string]int{fooNetwork: 1, barNetwork: 1})), poll.WithTimeout(defaultReconciliationTimeout))
   920  
   921  	// Remove a network
   922  	result = icmd.RunCmd(d.Command("service", "update", "--detach", "--network-rm", "foo", name))
   923  	result.Assert(c, icmd.Success)
   924  
   925  	poll.WaitOn(c, pollCheck(c, d.CheckRunningTaskNetworks, checker.DeepEquals(map[string]int{barNetwork: 1})), poll.WithTimeout(defaultReconciliationTimeout))
   926  
   927  	// Add a network
   928  	result = icmd.RunCmd(d.Command("service", "update", "--detach", "--network-add", "baz", name))
   929  	result.Assert(c, icmd.Success)
   930  
   931  	poll.WaitOn(c, pollCheck(c, d.CheckRunningTaskNetworks, checker.DeepEquals(map[string]int{barNetwork: 1, bazNetwork: 1})), poll.WithTimeout(defaultReconciliationTimeout))
   932  
   933  }
   934  
   935  func (s *DockerSwarmSuite) TestDNSConfig(c *testing.T) {
   936  	d := s.AddDaemon(c, true, true)
   937  
   938  	// Create a service
   939  	name := "top"
   940  	out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", name, "--dns=1.2.3.4", "--dns-search=example.com", "--dns-option=timeout:3", "busybox", "top")
   941  	assert.NilError(c, err, out)
   942  
   943  	// Make sure task has been deployed.
   944  	poll.WaitOn(c, pollCheck(c, d.CheckActiveContainerCount, checker.Equals(1)), poll.WithTimeout(defaultReconciliationTimeout))
   945  
   946  	// We need to get the container id.
   947  	out, err = d.Cmd("ps", "-a", "-q", "--no-trunc")
   948  	assert.NilError(c, err, out)
   949  	id := strings.TrimSpace(out)
   950  
   951  	// Compare against expected output.
   952  	expectedOutput1 := "nameserver 1.2.3.4"
   953  	expectedOutput2 := "search example.com"
   954  	expectedOutput3 := "options timeout:3"
   955  	out, err = d.Cmd("exec", id, "cat", "/etc/resolv.conf")
   956  	assert.NilError(c, err, out)
   957  	assert.Assert(c, strings.Contains(out, expectedOutput1), "Expected '%s', but got %q", expectedOutput1, out)
   958  	assert.Assert(c, strings.Contains(out, expectedOutput2), "Expected '%s', but got %q", expectedOutput2, out)
   959  	assert.Assert(c, strings.Contains(out, expectedOutput3), "Expected '%s', but got %q", expectedOutput3, out)
   960  }
   961  
   962  func (s *DockerSwarmSuite) TestDNSConfigUpdate(c *testing.T) {
   963  	d := s.AddDaemon(c, true, true)
   964  
   965  	// Create a service
   966  	name := "top"
   967  	out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", name, "busybox", "top")
   968  	assert.NilError(c, err, out)
   969  
   970  	// Make sure task has been deployed.
   971  	poll.WaitOn(c, pollCheck(c, d.CheckActiveContainerCount, checker.Equals(1)), poll.WithTimeout(defaultReconciliationTimeout))
   972  
   973  	out, err = d.Cmd("service", "update", "--detach", "--dns-add=1.2.3.4", "--dns-search-add=example.com", "--dns-option-add=timeout:3", name)
   974  	assert.NilError(c, err, out)
   975  
   976  	out, err = d.Cmd("service", "inspect", "--format", "{{ .Spec.TaskTemplate.ContainerSpec.DNSConfig }}", name)
   977  	assert.NilError(c, err, out)
   978  	assert.Equal(c, strings.TrimSpace(out), "{[1.2.3.4] [example.com] [timeout:3]}")
   979  }
   980  
   981  func getNodeStatus(c *testing.T, d *daemon.Daemon) swarm.LocalNodeState {
   982  	info := d.SwarmInfo(c)
   983  	return info.LocalNodeState
   984  }
   985  
   986  func checkKeyIsEncrypted(d *daemon.Daemon) func(*testing.T) (interface{}, string) {
   987  	return func(c *testing.T) (interface{}, string) {
   988  		keyBytes, err := ioutil.ReadFile(filepath.Join(d.Folder, "root", "swarm", "certificates", "swarm-node.key"))
   989  		if err != nil {
   990  			return fmt.Errorf("error reading key: %v", err), ""
   991  		}
   992  
   993  		keyBlock, _ := pem.Decode(keyBytes)
   994  		if keyBlock == nil {
   995  			return fmt.Errorf("invalid PEM-encoded private key"), ""
   996  		}
   997  
   998  		return keyutils.IsEncryptedPEMBlock(keyBlock), ""
   999  	}
  1000  }
  1001  
  1002  func checkSwarmLockedToUnlocked(c *testing.T, d *daemon.Daemon) {
  1003  	// Wait for the PEM file to become unencrypted
  1004  	poll.WaitOn(c, pollCheck(c, checkKeyIsEncrypted(d), checker.Equals(false)), poll.WithTimeout(defaultReconciliationTimeout))
  1005  
  1006  	d.RestartNode(c)
  1007  	poll.WaitOn(c, pollCheck(c, d.CheckLocalNodeState, checker.Equals(swarm.LocalNodeStateActive)), poll.WithTimeout(time.Second))
  1008  }
  1009  
  1010  func checkSwarmUnlockedToLocked(c *testing.T, d *daemon.Daemon) {
  1011  	// Wait for the PEM file to become encrypted
  1012  	poll.WaitOn(c, pollCheck(c, checkKeyIsEncrypted(d), checker.Equals(true)), poll.WithTimeout(defaultReconciliationTimeout))
  1013  
  1014  	d.RestartNode(c)
  1015  	poll.WaitOn(c, pollCheck(c, d.CheckLocalNodeState, checker.Equals(swarm.LocalNodeStateLocked)), poll.WithTimeout(time.Second))
  1016  }
  1017  
  1018  func (s *DockerSwarmSuite) TestUnlockEngineAndUnlockedSwarm(c *testing.T) {
  1019  	d := s.AddDaemon(c, false, false)
  1020  
  1021  	// unlocking a normal engine should return an error - it does not even ask for the key
  1022  	cmd := d.Command("swarm", "unlock")
  1023  	result := icmd.RunCmd(cmd)
  1024  	result.Assert(c, icmd.Expected{
  1025  		ExitCode: 1,
  1026  	})
  1027  	assert.Assert(c, strings.Contains(result.Combined(), "Error: This node is not part of a swarm"))
  1028  	assert.Assert(c, !strings.Contains(result.Combined(), "Please enter unlock key"))
  1029  	out, err := d.Cmd("swarm", "init")
  1030  	assert.NilError(c, err, out)
  1031  
  1032  	// unlocking an unlocked swarm should return an error - it does not even ask for the key
  1033  	cmd = d.Command("swarm", "unlock")
  1034  	result = icmd.RunCmd(cmd)
  1035  	result.Assert(c, icmd.Expected{
  1036  		ExitCode: 1,
  1037  	})
  1038  	assert.Assert(c, strings.Contains(result.Combined(), "Error: swarm is not locked"))
  1039  	assert.Assert(c, !strings.Contains(result.Combined(), "Please enter unlock key"))
  1040  }
  1041  
  1042  func (s *DockerSwarmSuite) TestSwarmInitLocked(c *testing.T) {
  1043  	d := s.AddDaemon(c, false, false)
  1044  
  1045  	outs, err := d.Cmd("swarm", "init", "--autolock")
  1046  	assert.Assert(c, err == nil, "%s", outs)
  1047  	unlockKey := getUnlockKey(d, c, outs)
  1048  
  1049  	assert.Equal(c, getNodeStatus(c, d), swarm.LocalNodeStateActive)
  1050  
  1051  	// It starts off locked
  1052  	d.RestartNode(c)
  1053  	assert.Equal(c, getNodeStatus(c, d), swarm.LocalNodeStateLocked)
  1054  
  1055  	cmd := d.Command("swarm", "unlock")
  1056  	cmd.Stdin = bytes.NewBufferString("wrong-secret-key")
  1057  	icmd.RunCmd(cmd).Assert(c, icmd.Expected{
  1058  		ExitCode: 1,
  1059  		Err:      "invalid key",
  1060  	})
  1061  
  1062  	assert.Equal(c, getNodeStatus(c, d), swarm.LocalNodeStateLocked)
  1063  
  1064  	cmd = d.Command("swarm", "unlock")
  1065  	cmd.Stdin = bytes.NewBufferString(unlockKey)
  1066  	icmd.RunCmd(cmd).Assert(c, icmd.Success)
  1067  
  1068  	assert.Equal(c, getNodeStatus(c, d), swarm.LocalNodeStateActive)
  1069  
  1070  	outs, err = d.Cmd("node", "ls")
  1071  	assert.Assert(c, err == nil, "%s", outs)
  1072  	assert.Assert(c, !strings.Contains(outs, "Swarm is encrypted and needs to be unlocked"))
  1073  	outs, err = d.Cmd("swarm", "update", "--autolock=false")
  1074  	assert.Assert(c, err == nil, "%s", outs)
  1075  
  1076  	checkSwarmLockedToUnlocked(c, d)
  1077  
  1078  	outs, err = d.Cmd("node", "ls")
  1079  	assert.Assert(c, err == nil, "%s", outs)
  1080  	assert.Assert(c, !strings.Contains(outs, "Swarm is encrypted and needs to be unlocked"))
  1081  }
  1082  
  1083  func (s *DockerSwarmSuite) TestSwarmLeaveLocked(c *testing.T) {
  1084  	d := s.AddDaemon(c, false, false)
  1085  
  1086  	outs, err := d.Cmd("swarm", "init", "--autolock")
  1087  	assert.Assert(c, err == nil, "%s", outs)
  1088  
  1089  	// It starts off locked
  1090  	d.RestartNode(c)
  1091  
  1092  	info := d.SwarmInfo(c)
  1093  	assert.Equal(c, info.LocalNodeState, swarm.LocalNodeStateLocked)
  1094  
  1095  	outs, _ = d.Cmd("node", "ls")
  1096  	assert.Assert(c, strings.Contains(outs, "Swarm is encrypted and needs to be unlocked"))
  1097  	// `docker swarm leave` a locked swarm without --force will return an error
  1098  	outs, _ = d.Cmd("swarm", "leave")
  1099  	assert.Assert(c, strings.Contains(outs, "Swarm is encrypted and locked."))
  1100  	// It is OK for user to leave a locked swarm with --force
  1101  	outs, err = d.Cmd("swarm", "leave", "--force")
  1102  	assert.Assert(c, err == nil, "%s", outs)
  1103  
  1104  	info = d.SwarmInfo(c)
  1105  	assert.Equal(c, info.LocalNodeState, swarm.LocalNodeStateInactive)
  1106  
  1107  	outs, err = d.Cmd("swarm", "init")
  1108  	assert.Assert(c, err == nil, "%s", outs)
  1109  
  1110  	info = d.SwarmInfo(c)
  1111  	assert.Equal(c, info.LocalNodeState, swarm.LocalNodeStateActive)
  1112  }
  1113  
  1114  func (s *DockerSwarmSuite) TestSwarmLockUnlockCluster(c *testing.T) {
  1115  	d1 := s.AddDaemon(c, true, true)
  1116  	d2 := s.AddDaemon(c, true, true)
  1117  	d3 := s.AddDaemon(c, true, true)
  1118  
  1119  	// they start off unlocked
  1120  	d2.RestartNode(c)
  1121  	assert.Equal(c, getNodeStatus(c, d2), swarm.LocalNodeStateActive)
  1122  
  1123  	// stop this one so it does not get autolock info
  1124  	d2.Stop(c)
  1125  
  1126  	// enable autolock
  1127  	outs, err := d1.Cmd("swarm", "update", "--autolock")
  1128  	assert.Assert(c, err == nil, "%s", outs)
  1129  	unlockKey := getUnlockKey(d1, c, outs)
  1130  
  1131  	// The ones that got the cluster update should be set to locked
  1132  	for _, d := range []*daemon.Daemon{d1, d3} {
  1133  		checkSwarmUnlockedToLocked(c, d)
  1134  
  1135  		cmd := d.Command("swarm", "unlock")
  1136  		cmd.Stdin = bytes.NewBufferString(unlockKey)
  1137  		icmd.RunCmd(cmd).Assert(c, icmd.Success)
  1138  		assert.Equal(c, getNodeStatus(c, d), swarm.LocalNodeStateActive)
  1139  	}
  1140  
  1141  	// d2 never got the cluster update, so it is still set to unlocked
  1142  	d2.StartNode(c)
  1143  	assert.Equal(c, getNodeStatus(c, d2), swarm.LocalNodeStateActive)
  1144  
  1145  	// d2 is now set to lock
  1146  	checkSwarmUnlockedToLocked(c, d2)
  1147  
  1148  	// leave it locked, and set the cluster to no longer autolock
  1149  	outs, err = d1.Cmd("swarm", "update", "--autolock=false")
  1150  	assert.Assert(c, err == nil, "out: %v", outs)
  1151  
  1152  	// the ones that got the update are now set to unlocked
  1153  	for _, d := range []*daemon.Daemon{d1, d3} {
  1154  		checkSwarmLockedToUnlocked(c, d)
  1155  	}
  1156  
  1157  	// d2 still locked
  1158  	assert.Equal(c, getNodeStatus(c, d2), swarm.LocalNodeStateLocked)
  1159  
  1160  	// unlock it
  1161  	cmd := d2.Command("swarm", "unlock")
  1162  	cmd.Stdin = bytes.NewBufferString(unlockKey)
  1163  	icmd.RunCmd(cmd).Assert(c, icmd.Success)
  1164  	assert.Equal(c, getNodeStatus(c, d2), swarm.LocalNodeStateActive)
  1165  
  1166  	// once it's caught up, d2 is set to not be locked
  1167  	checkSwarmLockedToUnlocked(c, d2)
  1168  
  1169  	// managers who join now are never set to locked in the first place
  1170  	d4 := s.AddDaemon(c, true, true)
  1171  	d4.RestartNode(c)
  1172  	assert.Equal(c, getNodeStatus(c, d4), swarm.LocalNodeStateActive)
  1173  }
  1174  
  1175  func (s *DockerSwarmSuite) TestSwarmJoinPromoteLocked(c *testing.T) {
  1176  	d1 := s.AddDaemon(c, true, true)
  1177  
  1178  	// enable autolock
  1179  	outs, err := d1.Cmd("swarm", "update", "--autolock")
  1180  	assert.Assert(c, err == nil, "out: %v", outs)
  1181  	unlockKey := getUnlockKey(d1, c, outs)
  1182  
  1183  	// joined workers start off unlocked
  1184  	d2 := s.AddDaemon(c, true, false)
  1185  	d2.RestartNode(c)
  1186  	poll.WaitOn(c, pollCheck(c, d2.CheckLocalNodeState, checker.Equals(swarm.LocalNodeStateActive)), poll.WithTimeout(time.Second))
  1187  
  1188  	// promote worker
  1189  	outs, err = d1.Cmd("node", "promote", d2.NodeID())
  1190  	assert.NilError(c, err)
  1191  	assert.Assert(c, strings.Contains(outs, "promoted to a manager in the swarm"))
  1192  	// join new manager node
  1193  	d3 := s.AddDaemon(c, true, true)
  1194  
  1195  	// both new nodes are locked
  1196  	for _, d := range []*daemon.Daemon{d2, d3} {
  1197  		checkSwarmUnlockedToLocked(c, d)
  1198  
  1199  		cmd := d.Command("swarm", "unlock")
  1200  		cmd.Stdin = bytes.NewBufferString(unlockKey)
  1201  		icmd.RunCmd(cmd).Assert(c, icmd.Success)
  1202  		assert.Equal(c, getNodeStatus(c, d), swarm.LocalNodeStateActive)
  1203  	}
  1204  
  1205  	// demote manager back to worker - workers are not locked
  1206  	outs, err = d1.Cmd("node", "demote", d3.NodeID())
  1207  	assert.NilError(c, err)
  1208  	assert.Assert(c, strings.Contains(outs, "demoted in the swarm"))
  1209  	// Wait for it to actually be demoted, for the key and cert to be replaced.
  1210  	// Then restart and assert that the node is not locked.  If we don't wait for the cert
  1211  	// to be replaced, then the node still has the manager TLS key which is still locked
  1212  	// (because we never want a manager TLS key to be on disk unencrypted if the cluster
  1213  	// is set to autolock)
  1214  	poll.WaitOn(c, pollCheck(c, d3.CheckControlAvailable, checker.False()), poll.WithTimeout(defaultReconciliationTimeout))
  1215  	poll.WaitOn(c, pollCheck(c, func(c *testing.T) (interface{}, string) {
  1216  		certBytes, err := ioutil.ReadFile(filepath.Join(d3.Folder, "root", "swarm", "certificates", "swarm-node.crt"))
  1217  		if err != nil {
  1218  			return "", fmt.Sprintf("error: %v", err)
  1219  		}
  1220  		certs, err := helpers.ParseCertificatesPEM(certBytes)
  1221  		if err == nil && len(certs) > 0 && len(certs[0].Subject.OrganizationalUnit) > 0 {
  1222  			return certs[0].Subject.OrganizationalUnit[0], ""
  1223  		}
  1224  		return "", "could not get organizational unit from certificate"
  1225  	}, checker.Equals("swarm-worker")), poll.WithTimeout(defaultReconciliationTimeout))
  1226  
  1227  	// by now, it should *never* be locked on restart
  1228  	d3.RestartNode(c)
  1229  	poll.WaitOn(c, pollCheck(c, d3.CheckLocalNodeState, checker.Equals(swarm.LocalNodeStateActive)), poll.WithTimeout(time.Second))
  1230  }
  1231  
  1232  func (s *DockerSwarmSuite) TestSwarmRotateUnlockKey(c *testing.T) {
  1233  	d := s.AddDaemon(c, true, true)
  1234  
  1235  	outs, err := d.Cmd("swarm", "update", "--autolock")
  1236  	assert.Assert(c, err == nil, "out: %v", outs)
  1237  	unlockKey := getUnlockKey(d, c, outs)
  1238  
  1239  	// Rotate multiple times
  1240  	for i := 0; i != 3; i++ {
  1241  		outs, err = d.Cmd("swarm", "unlock-key", "-q", "--rotate")
  1242  		assert.Assert(c, err == nil, "out: %v", outs)
  1243  		// Strip \n
  1244  		newUnlockKey := outs[:len(outs)-1]
  1245  		assert.Assert(c, newUnlockKey != "")
  1246  		assert.Assert(c, newUnlockKey != unlockKey)
  1247  
  1248  		d.RestartNode(c)
  1249  		assert.Equal(c, getNodeStatus(c, d), swarm.LocalNodeStateLocked)
  1250  
  1251  		outs, _ = d.Cmd("node", "ls")
  1252  		assert.Assert(c, strings.Contains(outs, "Swarm is encrypted and needs to be unlocked"))
  1253  		cmd := d.Command("swarm", "unlock")
  1254  		cmd.Stdin = bytes.NewBufferString(unlockKey)
  1255  		result := icmd.RunCmd(cmd)
  1256  
  1257  		if result.Error == nil {
  1258  			// On occasion, the daemon may not have finished
  1259  			// rotating the KEK before restarting. The test is
  1260  			// intentionally written to explore this behavior.
  1261  			// When this happens, unlocking with the old key will
  1262  			// succeed. If we wait for the rotation to happen and
  1263  			// restart again, the new key should be required this
  1264  			// time.
  1265  
  1266  			time.Sleep(3 * time.Second)
  1267  
  1268  			d.RestartNode(c)
  1269  
  1270  			cmd = d.Command("swarm", "unlock")
  1271  			cmd.Stdin = bytes.NewBufferString(unlockKey)
  1272  			result = icmd.RunCmd(cmd)
  1273  		}
  1274  		result.Assert(c, icmd.Expected{
  1275  			ExitCode: 1,
  1276  			Err:      "invalid key",
  1277  		})
  1278  
  1279  		outs, _ = d.Cmd("node", "ls")
  1280  		assert.Assert(c, strings.Contains(outs, "Swarm is encrypted and needs to be unlocked"))
  1281  		cmd = d.Command("swarm", "unlock")
  1282  		cmd.Stdin = bytes.NewBufferString(newUnlockKey)
  1283  		icmd.RunCmd(cmd).Assert(c, icmd.Success)
  1284  
  1285  		assert.Equal(c, getNodeStatus(c, d), swarm.LocalNodeStateActive)
  1286  
  1287  		retry := 0
  1288  		for {
  1289  			// an issue sometimes prevents leader to be available right away
  1290  			outs, err = d.Cmd("node", "ls")
  1291  			if err != nil && retry < 5 {
  1292  				if strings.Contains(outs, "swarm does not have a leader") {
  1293  					retry++
  1294  					time.Sleep(3 * time.Second)
  1295  					continue
  1296  				}
  1297  			}
  1298  			assert.NilError(c, err)
  1299  			assert.Assert(c, !strings.Contains(outs, "Swarm is encrypted and needs to be unlocked"))
  1300  			break
  1301  		}
  1302  
  1303  		unlockKey = newUnlockKey
  1304  	}
  1305  }
  1306  
  1307  // This differs from `TestSwarmRotateUnlockKey` because that one rotates a single node, which is the leader.
  1308  // This one keeps the leader up, and asserts that other manager nodes in the cluster also have their unlock
  1309  // key rotated.
  1310  func (s *DockerSwarmSuite) TestSwarmClusterRotateUnlockKey(c *testing.T) {
  1311  	if runtime.GOARCH == "s390x" {
  1312  		c.Skip("Disabled on s390x")
  1313  	}
  1314  	if runtime.GOARCH == "ppc64le" {
  1315  		c.Skip("Disabled on  ppc64le")
  1316  	}
  1317  
  1318  	d1 := s.AddDaemon(c, true, true) // leader - don't restart this one, we don't want leader election delays
  1319  	d2 := s.AddDaemon(c, true, true)
  1320  	d3 := s.AddDaemon(c, true, true)
  1321  
  1322  	outs, err := d1.Cmd("swarm", "update", "--autolock")
  1323  	assert.Assert(c, err == nil, "%s", outs)
  1324  	unlockKey := getUnlockKey(d1, c, outs)
  1325  
  1326  	// Rotate multiple times
  1327  	for i := 0; i != 3; i++ {
  1328  		outs, err = d1.Cmd("swarm", "unlock-key", "-q", "--rotate")
  1329  		assert.Assert(c, err == nil, "%s", outs)
  1330  		// Strip \n
  1331  		newUnlockKey := outs[:len(outs)-1]
  1332  		assert.Assert(c, newUnlockKey != "")
  1333  		assert.Assert(c, newUnlockKey != unlockKey)
  1334  
  1335  		d2.RestartNode(c)
  1336  		d3.RestartNode(c)
  1337  
  1338  		for _, d := range []*daemon.Daemon{d2, d3} {
  1339  			assert.Equal(c, getNodeStatus(c, d), swarm.LocalNodeStateLocked)
  1340  
  1341  			outs, _ := d.Cmd("node", "ls")
  1342  			assert.Assert(c, strings.Contains(outs, "Swarm is encrypted and needs to be unlocked"))
  1343  			cmd := d.Command("swarm", "unlock")
  1344  			cmd.Stdin = bytes.NewBufferString(unlockKey)
  1345  			result := icmd.RunCmd(cmd)
  1346  
  1347  			if result.Error == nil {
  1348  				// On occasion, the daemon may not have finished
  1349  				// rotating the KEK before restarting. The test is
  1350  				// intentionally written to explore this behavior.
  1351  				// When this happens, unlocking with the old key will
  1352  				// succeed. If we wait for the rotation to happen and
  1353  				// restart again, the new key should be required this
  1354  				// time.
  1355  
  1356  				time.Sleep(3 * time.Second)
  1357  
  1358  				d.RestartNode(c)
  1359  
  1360  				cmd = d.Command("swarm", "unlock")
  1361  				cmd.Stdin = bytes.NewBufferString(unlockKey)
  1362  				result = icmd.RunCmd(cmd)
  1363  			}
  1364  			result.Assert(c, icmd.Expected{
  1365  				ExitCode: 1,
  1366  				Err:      "invalid key",
  1367  			})
  1368  
  1369  			outs, _ = d.Cmd("node", "ls")
  1370  			assert.Assert(c, strings.Contains(outs, "Swarm is encrypted and needs to be unlocked"))
  1371  			cmd = d.Command("swarm", "unlock")
  1372  			cmd.Stdin = bytes.NewBufferString(newUnlockKey)
  1373  			icmd.RunCmd(cmd).Assert(c, icmd.Success)
  1374  
  1375  			assert.Equal(c, getNodeStatus(c, d), swarm.LocalNodeStateActive)
  1376  
  1377  			retry := 0
  1378  			for {
  1379  				// an issue sometimes prevents leader to be available right away
  1380  				outs, err = d.Cmd("node", "ls")
  1381  				if err != nil && retry < 5 {
  1382  					if strings.Contains(outs, "swarm does not have a leader") {
  1383  						retry++
  1384  						time.Sleep(3 * time.Second)
  1385  						continue
  1386  					}
  1387  				}
  1388  				assert.Assert(c, err == nil, "%s", outs)
  1389  				assert.Assert(c, !strings.Contains(outs, "Swarm is encrypted and needs to be unlocked"))
  1390  				break
  1391  			}
  1392  		}
  1393  
  1394  		unlockKey = newUnlockKey
  1395  	}
  1396  }
  1397  
  1398  func (s *DockerSwarmSuite) TestSwarmAlternateLockUnlock(c *testing.T) {
  1399  	d := s.AddDaemon(c, true, true)
  1400  
  1401  	for i := 0; i < 2; i++ {
  1402  		// set to lock
  1403  		outs, err := d.Cmd("swarm", "update", "--autolock")
  1404  		assert.Assert(c, err == nil, "out: %v", outs)
  1405  		assert.Assert(c, strings.Contains(outs, "docker swarm unlock"))
  1406  		unlockKey := getUnlockKey(d, c, outs)
  1407  
  1408  		checkSwarmUnlockedToLocked(c, d)
  1409  
  1410  		cmd := d.Command("swarm", "unlock")
  1411  		cmd.Stdin = bytes.NewBufferString(unlockKey)
  1412  		icmd.RunCmd(cmd).Assert(c, icmd.Success)
  1413  
  1414  		assert.Equal(c, getNodeStatus(c, d), swarm.LocalNodeStateActive)
  1415  
  1416  		outs, err = d.Cmd("swarm", "update", "--autolock=false")
  1417  		assert.Assert(c, err == nil, "out: %v", outs)
  1418  
  1419  		checkSwarmLockedToUnlocked(c, d)
  1420  	}
  1421  }
  1422  
  1423  func (s *DockerSwarmSuite) TestExtraHosts(c *testing.T) {
  1424  	d := s.AddDaemon(c, true, true)
  1425  
  1426  	// Create a service
  1427  	name := "top"
  1428  	out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", name, "--host=example.com:1.2.3.4", "busybox", "top")
  1429  	assert.NilError(c, err, out)
  1430  
  1431  	// Make sure task has been deployed.
  1432  	poll.WaitOn(c, pollCheck(c, d.CheckActiveContainerCount, checker.Equals(1)), poll.WithTimeout(defaultReconciliationTimeout))
  1433  
  1434  	// We need to get the container id.
  1435  	out, err = d.Cmd("ps", "-a", "-q", "--no-trunc")
  1436  	assert.NilError(c, err, out)
  1437  	id := strings.TrimSpace(out)
  1438  
  1439  	// Compare against expected output.
  1440  	expectedOutput := "1.2.3.4\texample.com"
  1441  	out, err = d.Cmd("exec", id, "cat", "/etc/hosts")
  1442  	assert.NilError(c, err, out)
  1443  	assert.Assert(c, strings.Contains(out, expectedOutput), "Expected '%s', but got %q", expectedOutput, out)
  1444  }
  1445  
  1446  func (s *DockerSwarmSuite) TestSwarmManagerAddress(c *testing.T) {
  1447  	d1 := s.AddDaemon(c, true, true)
  1448  	d2 := s.AddDaemon(c, true, false)
  1449  	d3 := s.AddDaemon(c, true, false)
  1450  
  1451  	// Manager Addresses will always show Node 1's address
  1452  	expectedOutput := fmt.Sprintf("Manager Addresses:\n  127.0.0.1:%d\n", d1.SwarmPort)
  1453  
  1454  	out, err := d1.Cmd("info")
  1455  	assert.NilError(c, err, out)
  1456  	assert.Assert(c, strings.Contains(out, expectedOutput))
  1457  
  1458  	out, err = d2.Cmd("info")
  1459  	assert.NilError(c, err, out)
  1460  	assert.Assert(c, strings.Contains(out, expectedOutput))
  1461  
  1462  	out, err = d3.Cmd("info")
  1463  	assert.NilError(c, err, out)
  1464  	assert.Assert(c, strings.Contains(out, expectedOutput))
  1465  }
  1466  
  1467  func (s *DockerSwarmSuite) TestSwarmNetworkIPAMOptions(c *testing.T) {
  1468  	d := s.AddDaemon(c, true, true)
  1469  
  1470  	out, err := d.Cmd("network", "create", "-d", "overlay", "--ipam-opt", "foo=bar", "foo")
  1471  	assert.NilError(c, err, out)
  1472  	assert.Assert(c, strings.TrimSpace(out) != "")
  1473  
  1474  	out, err = d.Cmd("network", "inspect", "--format", "{{.IPAM.Options}}", "foo")
  1475  	assert.NilError(c, err, out)
  1476  	assert.Assert(c, strings.Contains(strings.TrimSpace(out), "foo:bar"))
  1477  	assert.Assert(c, strings.Contains(strings.TrimSpace(out), "com.docker.network.ipam.serial:true"))
  1478  	out, err = d.Cmd("service", "create", "--detach", "--no-resolve-image", "--network=foo", "--name", "top", "busybox", "top")
  1479  	assert.NilError(c, err, out)
  1480  
  1481  	// make sure task has been deployed.
  1482  	poll.WaitOn(c, pollCheck(c, d.CheckActiveContainerCount, checker.Equals(1)), poll.WithTimeout(defaultReconciliationTimeout))
  1483  
  1484  	out, err = d.Cmd("network", "inspect", "--format", "{{.IPAM.Options}}", "foo")
  1485  	assert.NilError(c, err, out)
  1486  	assert.Assert(c, strings.Contains(strings.TrimSpace(out), "foo:bar"))
  1487  	assert.Assert(c, strings.Contains(strings.TrimSpace(out), "com.docker.network.ipam.serial:true"))
  1488  }
  1489  
  1490  // Test case for issue #27866, which did not allow NW name that is the prefix of a swarm NW ID.
  1491  // e.g. if the ingress ID starts with "n1", it was impossible to create a NW named "n1".
  1492  func (s *DockerSwarmSuite) TestSwarmNetworkCreateIssue27866(c *testing.T) {
  1493  	d := s.AddDaemon(c, true, true)
  1494  	out, err := d.Cmd("network", "inspect", "-f", "{{.Id}}", "ingress")
  1495  	assert.NilError(c, err, "out: %v", out)
  1496  	ingressID := strings.TrimSpace(out)
  1497  	assert.Assert(c, ingressID != "")
  1498  
  1499  	// create a network of which name is the prefix of the ID of an overlay network
  1500  	// (ingressID in this case)
  1501  	newNetName := ingressID[0:2]
  1502  	out, err = d.Cmd("network", "create", "--driver", "overlay", newNetName)
  1503  	// In #27866, it was failing because of "network with name %s already exists"
  1504  	assert.NilError(c, err, "out: %v", out)
  1505  	out, err = d.Cmd("network", "rm", newNetName)
  1506  	assert.NilError(c, err, "out: %v", out)
  1507  }
  1508  
  1509  // Test case for https://github.com/docker/docker/pull/27938#issuecomment-265768303
  1510  // This test creates two networks with the same name sequentially, with various drivers.
  1511  // Since the operations in this test are done sequentially, the 2nd call should fail with
  1512  // "network with name FOO already exists".
  1513  // Note that it is to ok have multiple networks with the same name if the operations are done
  1514  // in parallel. (#18864)
  1515  func (s *DockerSwarmSuite) TestSwarmNetworkCreateDup(c *testing.T) {
  1516  	d := s.AddDaemon(c, true, true)
  1517  	drivers := []string{"bridge", "overlay"}
  1518  	for i, driver1 := range drivers {
  1519  		nwName := fmt.Sprintf("network-test-%d", i)
  1520  		for _, driver2 := range drivers {
  1521  			c.Logf("Creating a network named %q with %q, then %q",
  1522  				nwName, driver1, driver2)
  1523  			out, err := d.Cmd("network", "create", "--driver", driver1, nwName)
  1524  			assert.NilError(c, err, "out: %v", out)
  1525  			out, err = d.Cmd("network", "create", "--driver", driver2, nwName)
  1526  			assert.Assert(c, strings.Contains(out, fmt.Sprintf("network with name %s already exists", nwName)))
  1527  			assert.ErrorContains(c, err, "")
  1528  			c.Logf("As expected, the attempt to network %q with %q failed: %s",
  1529  				nwName, driver2, out)
  1530  			out, err = d.Cmd("network", "rm", nwName)
  1531  			assert.NilError(c, err, "out: %v", out)
  1532  		}
  1533  	}
  1534  }
  1535  
  1536  func (s *DockerSwarmSuite) TestSwarmPublishDuplicatePorts(c *testing.T) {
  1537  	d := s.AddDaemon(c, true, true)
  1538  
  1539  	out, err := d.Cmd("service", "create", "--no-resolve-image", "--detach=true", "--publish", "5005:80", "--publish", "5006:80", "--publish", "80", "--publish", "80", "busybox", "top")
  1540  	assert.NilError(c, err, out)
  1541  	id := strings.TrimSpace(out)
  1542  
  1543  	// make sure task has been deployed.
  1544  	poll.WaitOn(c, pollCheck(c, d.CheckActiveContainerCount, checker.Equals(1)), poll.WithTimeout(defaultReconciliationTimeout))
  1545  
  1546  	// Total len = 4, with 2 dynamic ports and 2 non-dynamic ports
  1547  	// Dynamic ports are likely to be 30000 and 30001 but doesn't matter
  1548  	out, err = d.Cmd("service", "inspect", "--format", "{{.Endpoint.Ports}} len={{len .Endpoint.Ports}}", id)
  1549  	assert.NilError(c, err, out)
  1550  	assert.Assert(c, strings.Contains(out, "len=4"))
  1551  	assert.Assert(c, strings.Contains(out, "{ tcp 80 5005 ingress}"))
  1552  	assert.Assert(c, strings.Contains(out, "{ tcp 80 5006 ingress}"))
  1553  }
  1554  
  1555  func (s *DockerSwarmSuite) TestSwarmJoinWithDrain(c *testing.T) {
  1556  	d := s.AddDaemon(c, true, true)
  1557  
  1558  	out, err := d.Cmd("node", "ls")
  1559  	assert.NilError(c, err)
  1560  	assert.Assert(c, !strings.Contains(out, "Drain"))
  1561  	out, err = d.Cmd("swarm", "join-token", "-q", "manager")
  1562  	assert.NilError(c, err)
  1563  	assert.Assert(c, strings.TrimSpace(out) != "")
  1564  
  1565  	token := strings.TrimSpace(out)
  1566  
  1567  	d1 := s.AddDaemon(c, false, false)
  1568  
  1569  	out, err = d1.Cmd("swarm", "join", "--availability=drain", "--token", token, d.SwarmListenAddr())
  1570  	assert.NilError(c, err)
  1571  	assert.Assert(c, strings.TrimSpace(out) != "")
  1572  
  1573  	out, err = d.Cmd("node", "ls")
  1574  	assert.NilError(c, err)
  1575  	assert.Assert(c, strings.Contains(out, "Drain"))
  1576  	out, err = d1.Cmd("node", "ls")
  1577  	assert.NilError(c, err)
  1578  	assert.Assert(c, strings.Contains(out, "Drain"))
  1579  }
  1580  
  1581  func (s *DockerSwarmSuite) TestSwarmInitWithDrain(c *testing.T) {
  1582  	d := s.AddDaemon(c, false, false)
  1583  
  1584  	out, err := d.Cmd("swarm", "init", "--availability", "drain")
  1585  	assert.NilError(c, err, "out: %v", out)
  1586  
  1587  	out, err = d.Cmd("node", "ls")
  1588  	assert.NilError(c, err)
  1589  	assert.Assert(c, strings.Contains(out, "Drain"))
  1590  }
  1591  
  1592  func (s *DockerSwarmSuite) TestSwarmReadonlyRootfs(c *testing.T) {
  1593  	testRequires(c, DaemonIsLinux, UserNamespaceROMount)
  1594  
  1595  	d := s.AddDaemon(c, true, true)
  1596  
  1597  	out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", "top", "--read-only", "busybox", "top")
  1598  	assert.NilError(c, err, out)
  1599  
  1600  	// make sure task has been deployed.
  1601  	poll.WaitOn(c, pollCheck(c, d.CheckActiveContainerCount, checker.Equals(1)), poll.WithTimeout(defaultReconciliationTimeout))
  1602  
  1603  	out, err = d.Cmd("service", "inspect", "--format", "{{ .Spec.TaskTemplate.ContainerSpec.ReadOnly }}", "top")
  1604  	assert.NilError(c, err, out)
  1605  	assert.Equal(c, strings.TrimSpace(out), "true")
  1606  
  1607  	containers := d.ActiveContainers(c)
  1608  	out, err = d.Cmd("inspect", "--type", "container", "--format", "{{.HostConfig.ReadonlyRootfs}}", containers[0])
  1609  	assert.NilError(c, err, out)
  1610  	assert.Equal(c, strings.TrimSpace(out), "true")
  1611  }
  1612  
  1613  func (s *DockerSwarmSuite) TestNetworkInspectWithDuplicateNames(c *testing.T) {
  1614  	d := s.AddDaemon(c, true, true)
  1615  
  1616  	name := "foo"
  1617  	options := types.NetworkCreate{
  1618  		CheckDuplicate: false,
  1619  		Driver:         "bridge",
  1620  	}
  1621  
  1622  	cli := d.NewClientT(c)
  1623  	defer cli.Close()
  1624  
  1625  	n1, err := cli.NetworkCreate(context.Background(), name, options)
  1626  	assert.NilError(c, err)
  1627  
  1628  	// Full ID always works
  1629  	out, err := d.Cmd("network", "inspect", "--format", "{{.ID}}", n1.ID)
  1630  	assert.NilError(c, err, out)
  1631  	assert.Equal(c, strings.TrimSpace(out), n1.ID)
  1632  
  1633  	// Name works if it is unique
  1634  	out, err = d.Cmd("network", "inspect", "--format", "{{.ID}}", name)
  1635  	assert.NilError(c, err, out)
  1636  	assert.Equal(c, strings.TrimSpace(out), n1.ID)
  1637  
  1638  	n2, err := cli.NetworkCreate(context.Background(), name, options)
  1639  	assert.NilError(c, err)
  1640  	// Full ID always works
  1641  	out, err = d.Cmd("network", "inspect", "--format", "{{.ID}}", n1.ID)
  1642  	assert.NilError(c, err, out)
  1643  	assert.Equal(c, strings.TrimSpace(out), n1.ID)
  1644  
  1645  	out, err = d.Cmd("network", "inspect", "--format", "{{.ID}}", n2.ID)
  1646  	assert.NilError(c, err, out)
  1647  	assert.Equal(c, strings.TrimSpace(out), n2.ID)
  1648  
  1649  	// Name with duplicates
  1650  	out, err = d.Cmd("network", "inspect", "--format", "{{.ID}}", name)
  1651  	assert.ErrorContains(c, err, "", out)
  1652  	assert.Assert(c, strings.Contains(out, "2 matches found based on name"))
  1653  	out, err = d.Cmd("network", "rm", n2.ID)
  1654  	assert.NilError(c, err, out)
  1655  
  1656  	// Duplicates with name but with different driver
  1657  	options.Driver = "overlay"
  1658  
  1659  	n2, err = cli.NetworkCreate(context.Background(), name, options)
  1660  	assert.NilError(c, err)
  1661  
  1662  	// Full ID always works
  1663  	out, err = d.Cmd("network", "inspect", "--format", "{{.ID}}", n1.ID)
  1664  	assert.NilError(c, err, out)
  1665  	assert.Equal(c, strings.TrimSpace(out), n1.ID)
  1666  
  1667  	out, err = d.Cmd("network", "inspect", "--format", "{{.ID}}", n2.ID)
  1668  	assert.NilError(c, err, out)
  1669  	assert.Equal(c, strings.TrimSpace(out), n2.ID)
  1670  
  1671  	// Name with duplicates
  1672  	out, err = d.Cmd("network", "inspect", "--format", "{{.ID}}", name)
  1673  	assert.ErrorContains(c, err, "", out)
  1674  	assert.Assert(c, strings.Contains(out, "2 matches found based on name"))
  1675  }
  1676  
  1677  func (s *DockerSwarmSuite) TestSwarmStopSignal(c *testing.T) {
  1678  	testRequires(c, DaemonIsLinux, UserNamespaceROMount)
  1679  
  1680  	d := s.AddDaemon(c, true, true)
  1681  
  1682  	out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", "top", "--stop-signal=SIGHUP", "busybox", "top")
  1683  	assert.NilError(c, err, out)
  1684  
  1685  	// make sure task has been deployed.
  1686  	poll.WaitOn(c, pollCheck(c, d.CheckActiveContainerCount, checker.Equals(1)), poll.WithTimeout(defaultReconciliationTimeout))
  1687  
  1688  	out, err = d.Cmd("service", "inspect", "--format", "{{ .Spec.TaskTemplate.ContainerSpec.StopSignal }}", "top")
  1689  	assert.NilError(c, err, out)
  1690  	assert.Equal(c, strings.TrimSpace(out), "SIGHUP")
  1691  
  1692  	containers := d.ActiveContainers(c)
  1693  	out, err = d.Cmd("inspect", "--type", "container", "--format", "{{.Config.StopSignal}}", containers[0])
  1694  	assert.NilError(c, err, out)
  1695  	assert.Equal(c, strings.TrimSpace(out), "SIGHUP")
  1696  
  1697  	out, err = d.Cmd("service", "update", "--detach", "--stop-signal=SIGUSR1", "top")
  1698  	assert.NilError(c, err, out)
  1699  
  1700  	out, err = d.Cmd("service", "inspect", "--format", "{{ .Spec.TaskTemplate.ContainerSpec.StopSignal }}", "top")
  1701  	assert.NilError(c, err, out)
  1702  	assert.Equal(c, strings.TrimSpace(out), "SIGUSR1")
  1703  }
  1704  
  1705  func (s *DockerSwarmSuite) TestSwarmServiceLsFilterMode(c *testing.T) {
  1706  	d := s.AddDaemon(c, true, true)
  1707  
  1708  	out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", "top1", "busybox", "top")
  1709  	assert.NilError(c, err, out)
  1710  	assert.Assert(c, strings.TrimSpace(out) != "")
  1711  
  1712  	out, err = d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", "top2", "--mode=global", "busybox", "top")
  1713  	assert.NilError(c, err, out)
  1714  	assert.Assert(c, strings.TrimSpace(out) != "")
  1715  
  1716  	// make sure task has been deployed.
  1717  	poll.WaitOn(c, pollCheck(c, d.CheckActiveContainerCount, checker.Equals(2)), poll.WithTimeout(defaultReconciliationTimeout))
  1718  
  1719  	out, err = d.Cmd("service", "ls")
  1720  	assert.NilError(c, err, out)
  1721  	assert.Assert(c, strings.Contains(out, "top1"))
  1722  	assert.Assert(c, strings.Contains(out, "top2"))
  1723  	assert.Assert(c, !strings.Contains(out, "localnet"))
  1724  	out, err = d.Cmd("service", "ls", "--filter", "mode=global")
  1725  	assert.Assert(c, !strings.Contains(out, "top1"))
  1726  	assert.Assert(c, strings.Contains(out, "top2"))
  1727  	assert.NilError(c, err, out)
  1728  
  1729  	out, err = d.Cmd("service", "ls", "--filter", "mode=replicated")
  1730  	assert.NilError(c, err, out)
  1731  	assert.Assert(c, strings.Contains(out, "top1"))
  1732  	assert.Assert(c, !strings.Contains(out, "top2"))
  1733  }
  1734  
  1735  func (s *DockerSwarmSuite) TestSwarmInitUnspecifiedDataPathAddr(c *testing.T) {
  1736  	d := s.AddDaemon(c, false, false)
  1737  
  1738  	out, err := d.Cmd("swarm", "init", "--data-path-addr", "0.0.0.0")
  1739  	assert.ErrorContains(c, err, "")
  1740  	assert.Assert(c, strings.Contains(out, "data path address must be a non-zero IP"))
  1741  	out, err = d.Cmd("swarm", "init", "--data-path-addr", "0.0.0.0:2000")
  1742  	assert.ErrorContains(c, err, "")
  1743  	assert.Assert(c, strings.Contains(out, "data path address must be a non-zero IP"))
  1744  }
  1745  
  1746  func (s *DockerSwarmSuite) TestSwarmJoinLeave(c *testing.T) {
  1747  	d := s.AddDaemon(c, true, true)
  1748  
  1749  	out, err := d.Cmd("swarm", "join-token", "-q", "worker")
  1750  	assert.NilError(c, err)
  1751  	assert.Assert(c, strings.TrimSpace(out) != "")
  1752  
  1753  	token := strings.TrimSpace(out)
  1754  
  1755  	// Verify that back to back join/leave does not cause panics
  1756  	d1 := s.AddDaemon(c, false, false)
  1757  	for i := 0; i < 10; i++ {
  1758  		out, err = d1.Cmd("swarm", "join", "--token", token, d.SwarmListenAddr())
  1759  		assert.NilError(c, err)
  1760  		assert.Assert(c, strings.TrimSpace(out) != "")
  1761  
  1762  		_, err = d1.Cmd("swarm", "leave")
  1763  		assert.NilError(c, err)
  1764  	}
  1765  }
  1766  
  1767  const defaultRetryCount = 10
  1768  
  1769  func waitForEvent(c *testing.T, d *daemon.Daemon, since string, filter string, event string, retry int) string {
  1770  	if retry < 1 {
  1771  		c.Fatalf("retry count %d is invalid. It should be no less than 1", retry)
  1772  		return ""
  1773  	}
  1774  	var out string
  1775  	for i := 0; i < retry; i++ {
  1776  		until := daemonUnixTime(c)
  1777  		var err error
  1778  		if len(filter) > 0 {
  1779  			out, err = d.Cmd("events", "--since", since, "--until", until, filter)
  1780  		} else {
  1781  			out, err = d.Cmd("events", "--since", since, "--until", until)
  1782  		}
  1783  		assert.NilError(c, err, out)
  1784  		if strings.Contains(out, event) {
  1785  			return strings.TrimSpace(out)
  1786  		}
  1787  		// no need to sleep after last retry
  1788  		if i < retry-1 {
  1789  			time.Sleep(200 * time.Millisecond)
  1790  		}
  1791  	}
  1792  	c.Fatalf("docker events output '%s' doesn't contain event '%s'", out, event)
  1793  	return ""
  1794  }
  1795  
  1796  func (s *DockerSwarmSuite) TestSwarmClusterEventsSource(c *testing.T) {
  1797  	d1 := s.AddDaemon(c, true, true)
  1798  	d2 := s.AddDaemon(c, true, true)
  1799  	d3 := s.AddDaemon(c, true, false)
  1800  
  1801  	// create a network
  1802  	out, err := d1.Cmd("network", "create", "--attachable", "-d", "overlay", "foo")
  1803  	assert.NilError(c, err, out)
  1804  	networkID := strings.TrimSpace(out)
  1805  	assert.Assert(c, networkID != "")
  1806  
  1807  	// d1, d2 are managers that can get swarm events
  1808  	waitForEvent(c, d1, "0", "-f scope=swarm", "network create "+networkID, defaultRetryCount)
  1809  	waitForEvent(c, d2, "0", "-f scope=swarm", "network create "+networkID, defaultRetryCount)
  1810  
  1811  	// d3 is a worker, not able to get cluster events
  1812  	out = waitForEvent(c, d3, "0", "-f scope=swarm", "", 1)
  1813  	assert.Assert(c, !strings.Contains(out, "network create "))
  1814  }
  1815  
  1816  func (s *DockerSwarmSuite) TestSwarmClusterEventsScope(c *testing.T) {
  1817  	d := s.AddDaemon(c, true, true)
  1818  
  1819  	// create a service
  1820  	out, err := d.Cmd("service", "create", "--no-resolve-image", "--name", "test", "--detach=false", "busybox", "top")
  1821  	assert.NilError(c, err, out)
  1822  	serviceID := strings.Split(out, "\n")[0]
  1823  
  1824  	// scope swarm filters cluster events
  1825  	out = waitForEvent(c, d, "0", "-f scope=swarm", "service create "+serviceID, defaultRetryCount)
  1826  	assert.Assert(c, !strings.Contains(out, "container create "))
  1827  	// all events are returned if scope is not specified
  1828  	waitForEvent(c, d, "0", "", "service create "+serviceID, 1)
  1829  	waitForEvent(c, d, "0", "", "container create ", defaultRetryCount)
  1830  
  1831  	// scope local only shows non-cluster events
  1832  	out = waitForEvent(c, d, "0", "-f scope=local", "container create ", 1)
  1833  	assert.Assert(c, !strings.Contains(out, "service create "))
  1834  }
  1835  
  1836  func (s *DockerSwarmSuite) TestSwarmClusterEventsType(c *testing.T) {
  1837  	d := s.AddDaemon(c, true, true)
  1838  
  1839  	// create a service
  1840  	out, err := d.Cmd("service", "create", "--no-resolve-image", "--name", "test", "--detach=false", "busybox", "top")
  1841  	assert.NilError(c, err, out)
  1842  	serviceID := strings.Split(out, "\n")[0]
  1843  
  1844  	// create a network
  1845  	out, err = d.Cmd("network", "create", "--attachable", "-d", "overlay", "foo")
  1846  	assert.NilError(c, err, out)
  1847  	networkID := strings.TrimSpace(out)
  1848  	assert.Assert(c, networkID != "")
  1849  
  1850  	// filter by service
  1851  	out = waitForEvent(c, d, "0", "-f type=service", "service create "+serviceID, defaultRetryCount)
  1852  	assert.Assert(c, !strings.Contains(out, "network create"))
  1853  	// filter by network
  1854  	out = waitForEvent(c, d, "0", "-f type=network", "network create "+networkID, defaultRetryCount)
  1855  	assert.Assert(c, !strings.Contains(out, "service create"))
  1856  }
  1857  
  1858  func (s *DockerSwarmSuite) TestSwarmClusterEventsService(c *testing.T) {
  1859  	d := s.AddDaemon(c, true, true)
  1860  
  1861  	// create a service
  1862  	out, err := d.Cmd("service", "create", "--no-resolve-image", "--name", "test", "--detach=false", "busybox", "top")
  1863  	assert.NilError(c, err, out)
  1864  	serviceID := strings.Split(out, "\n")[0]
  1865  
  1866  	// validate service create event
  1867  	waitForEvent(c, d, "0", "-f scope=swarm", "service create "+serviceID, defaultRetryCount)
  1868  
  1869  	t1 := daemonUnixTime(c)
  1870  	out, err = d.Cmd("service", "update", "--force", "--detach=false", "test")
  1871  	assert.NilError(c, err, out)
  1872  
  1873  	// wait for service update start
  1874  	out = waitForEvent(c, d, t1, "-f scope=swarm", "service update "+serviceID, defaultRetryCount)
  1875  	assert.Assert(c, strings.Contains(out, "updatestate.new=updating"))
  1876  	// allow service update complete. This is a service with 1 instance
  1877  	time.Sleep(400 * time.Millisecond)
  1878  	out = waitForEvent(c, d, t1, "-f scope=swarm", "service update "+serviceID, defaultRetryCount)
  1879  	assert.Assert(c, strings.Contains(out, "updatestate.new=completed, updatestate.old=updating"))
  1880  	// scale service
  1881  	t2 := daemonUnixTime(c)
  1882  	out, err = d.Cmd("service", "scale", "test=3")
  1883  	assert.NilError(c, err, out)
  1884  
  1885  	out = waitForEvent(c, d, t2, "-f scope=swarm", "service update "+serviceID, defaultRetryCount)
  1886  	assert.Assert(c, strings.Contains(out, "replicas.new=3, replicas.old=1"))
  1887  	// remove service
  1888  	t3 := daemonUnixTime(c)
  1889  	out, err = d.Cmd("service", "rm", "test")
  1890  	assert.NilError(c, err, out)
  1891  
  1892  	waitForEvent(c, d, t3, "-f scope=swarm", "service remove "+serviceID, defaultRetryCount)
  1893  }
  1894  
  1895  func (s *DockerSwarmSuite) TestSwarmClusterEventsNode(c *testing.T) {
  1896  	d1 := s.AddDaemon(c, true, true)
  1897  	s.AddDaemon(c, true, true)
  1898  	d3 := s.AddDaemon(c, true, true)
  1899  
  1900  	d3ID := d3.NodeID()
  1901  	waitForEvent(c, d1, "0", "-f scope=swarm", "node create "+d3ID, defaultRetryCount)
  1902  
  1903  	t1 := daemonUnixTime(c)
  1904  	out, err := d1.Cmd("node", "update", "--availability=pause", d3ID)
  1905  	assert.NilError(c, err, out)
  1906  
  1907  	// filter by type
  1908  	out = waitForEvent(c, d1, t1, "-f type=node", "node update "+d3ID, defaultRetryCount)
  1909  	assert.Assert(c, strings.Contains(out, "availability.new=pause, availability.old=active"))
  1910  	t2 := daemonUnixTime(c)
  1911  	out, err = d1.Cmd("node", "demote", d3ID)
  1912  	assert.NilError(c, err, out)
  1913  
  1914  	waitForEvent(c, d1, t2, "-f type=node", "node update "+d3ID, defaultRetryCount)
  1915  
  1916  	t3 := daemonUnixTime(c)
  1917  	out, err = d1.Cmd("node", "rm", "-f", d3ID)
  1918  	assert.NilError(c, err, out)
  1919  
  1920  	// filter by scope
  1921  	waitForEvent(c, d1, t3, "-f scope=swarm", "node remove "+d3ID, defaultRetryCount)
  1922  }
  1923  
  1924  func (s *DockerSwarmSuite) TestSwarmClusterEventsNetwork(c *testing.T) {
  1925  	d := s.AddDaemon(c, true, true)
  1926  
  1927  	// create a network
  1928  	out, err := d.Cmd("network", "create", "--attachable", "-d", "overlay", "foo")
  1929  	assert.NilError(c, err, out)
  1930  	networkID := strings.TrimSpace(out)
  1931  
  1932  	waitForEvent(c, d, "0", "-f scope=swarm", "network create "+networkID, defaultRetryCount)
  1933  
  1934  	// remove network
  1935  	t1 := daemonUnixTime(c)
  1936  	out, err = d.Cmd("network", "rm", "foo")
  1937  	assert.NilError(c, err, out)
  1938  
  1939  	// filtered by network
  1940  	waitForEvent(c, d, t1, "-f type=network", "network remove "+networkID, defaultRetryCount)
  1941  }
  1942  
  1943  func (s *DockerSwarmSuite) TestSwarmClusterEventsSecret(c *testing.T) {
  1944  	d := s.AddDaemon(c, true, true)
  1945  
  1946  	testName := "test_secret"
  1947  	id := d.CreateSecret(c, swarm.SecretSpec{
  1948  		Annotations: swarm.Annotations{
  1949  			Name: testName,
  1950  		},
  1951  		Data: []byte("TESTINGDATA"),
  1952  	})
  1953  	assert.Assert(c, id != "", "secrets: %s", id)
  1954  
  1955  	waitForEvent(c, d, "0", "-f scope=swarm", "secret create "+id, defaultRetryCount)
  1956  
  1957  	t1 := daemonUnixTime(c)
  1958  	d.DeleteSecret(c, id)
  1959  	// filtered by secret
  1960  	waitForEvent(c, d, t1, "-f type=secret", "secret remove "+id, defaultRetryCount)
  1961  }
  1962  
  1963  func (s *DockerSwarmSuite) TestSwarmClusterEventsConfig(c *testing.T) {
  1964  	d := s.AddDaemon(c, true, true)
  1965  
  1966  	testName := "test_config"
  1967  	id := d.CreateConfig(c, swarm.ConfigSpec{
  1968  		Annotations: swarm.Annotations{
  1969  			Name: testName,
  1970  		},
  1971  		Data: []byte("TESTINGDATA"),
  1972  	})
  1973  	assert.Assert(c, id != "", "configs: %s", id)
  1974  
  1975  	waitForEvent(c, d, "0", "-f scope=swarm", "config create "+id, defaultRetryCount)
  1976  
  1977  	t1 := daemonUnixTime(c)
  1978  	d.DeleteConfig(c, id)
  1979  	// filtered by config
  1980  	waitForEvent(c, d, t1, "-f type=config", "config remove "+id, defaultRetryCount)
  1981  }
  1982  
  1983  func getUnlockKey(d *daemon.Daemon, c *testing.T, autolockOutput string) string {
  1984  	unlockKey, err := d.Cmd("swarm", "unlock-key", "-q")
  1985  	assert.Assert(c, err == nil, "%s", unlockKey)
  1986  	unlockKey = strings.TrimSuffix(unlockKey, "\n")
  1987  
  1988  	// Check that "docker swarm init --autolock" or "docker swarm update --autolock"
  1989  	// contains all the expected strings, including the unlock key
  1990  	assert.Assert(c, strings.Contains(autolockOutput, "docker swarm unlock"))
  1991  	assert.Assert(c, strings.Contains(autolockOutput, unlockKey))
  1992  	return unlockKey
  1993  }