github.com/endophage/docker@v1.4.2-0.20161027011718-242853499895/integration-cli/docker_cli_swarm_test.go (about)

     1  // +build !windows
     2  
     3  package main
     4  
     5  import (
     6  	"encoding/json"
     7  	"fmt"
     8  	"io/ioutil"
     9  	"net/http"
    10  	"net/http/httptest"
    11  	"os"
    12  	"strings"
    13  	"time"
    14  
    15  	"github.com/docker/docker/api/types/swarm"
    16  	"github.com/docker/docker/pkg/integration/checker"
    17  	"github.com/docker/libnetwork/driverapi"
    18  	"github.com/docker/libnetwork/ipamapi"
    19  	remoteipam "github.com/docker/libnetwork/ipams/remote/api"
    20  	"github.com/go-check/check"
    21  	"github.com/vishvananda/netlink"
    22  )
    23  
    24  func (s *DockerSwarmSuite) TestSwarmUpdate(c *check.C) {
    25  	d := s.AddDaemon(c, true, true)
    26  
    27  	getSpec := func() swarm.Spec {
    28  		sw := d.getSwarm(c)
    29  		return sw.Spec
    30  	}
    31  
    32  	out, err := d.Cmd("swarm", "update", "--cert-expiry", "30h", "--dispatcher-heartbeat", "11s")
    33  	c.Assert(err, checker.IsNil, check.Commentf("out: %v", out))
    34  
    35  	spec := getSpec()
    36  	c.Assert(spec.CAConfig.NodeCertExpiry, checker.Equals, 30*time.Hour)
    37  	c.Assert(spec.Dispatcher.HeartbeatPeriod, checker.Equals, 11*time.Second)
    38  
    39  	// setting anything under 30m for cert-expiry is not allowed
    40  	out, err = d.Cmd("swarm", "update", "--cert-expiry", "15m")
    41  	c.Assert(err, checker.NotNil)
    42  	c.Assert(out, checker.Contains, "minimum certificate expiry time")
    43  	spec = getSpec()
    44  	c.Assert(spec.CAConfig.NodeCertExpiry, checker.Equals, 30*time.Hour)
    45  }
    46  
    47  func (s *DockerSwarmSuite) TestSwarmInit(c *check.C) {
    48  	d := s.AddDaemon(c, false, false)
    49  
    50  	getSpec := func() swarm.Spec {
    51  		sw := d.getSwarm(c)
    52  		return sw.Spec
    53  	}
    54  
    55  	out, err := d.Cmd("swarm", "init", "--cert-expiry", "30h", "--dispatcher-heartbeat", "11s")
    56  	c.Assert(err, checker.IsNil, check.Commentf("out: %v", out))
    57  
    58  	spec := getSpec()
    59  	c.Assert(spec.CAConfig.NodeCertExpiry, checker.Equals, 30*time.Hour)
    60  	c.Assert(spec.Dispatcher.HeartbeatPeriod, checker.Equals, 11*time.Second)
    61  
    62  	c.Assert(d.Leave(true), checker.IsNil)
    63  	time.Sleep(500 * time.Millisecond) // https://github.com/docker/swarmkit/issues/1421
    64  	out, err = d.Cmd("swarm", "init")
    65  	c.Assert(err, checker.IsNil, check.Commentf("out: %v", out))
    66  
    67  	spec = getSpec()
    68  	c.Assert(spec.CAConfig.NodeCertExpiry, checker.Equals, 90*24*time.Hour)
    69  	c.Assert(spec.Dispatcher.HeartbeatPeriod, checker.Equals, 5*time.Second)
    70  }
    71  
    72  func (s *DockerSwarmSuite) TestSwarmInitIPv6(c *check.C) {
    73  	testRequires(c, IPv6)
    74  	d1 := s.AddDaemon(c, false, false)
    75  	out, err := d1.Cmd("swarm", "init", "--listen-addr", "::1")
    76  	c.Assert(err, checker.IsNil, check.Commentf("out: %v", out))
    77  
    78  	d2 := s.AddDaemon(c, false, false)
    79  	out, err = d2.Cmd("swarm", "join", "::1")
    80  	c.Assert(err, checker.IsNil, check.Commentf("out: %v", out))
    81  
    82  	out, err = d2.Cmd("info")
    83  	c.Assert(err, checker.IsNil, check.Commentf("out: %v", out))
    84  	c.Assert(out, checker.Contains, "Swarm: active")
    85  }
    86  
    87  func (s *DockerSwarmSuite) TestSwarmIncompatibleDaemon(c *check.C) {
    88  	// init swarm mode and stop a daemon
    89  	d := s.AddDaemon(c, true, true)
    90  	info, err := d.info()
    91  	c.Assert(err, checker.IsNil)
    92  	c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStateActive)
    93  	c.Assert(d.Stop(), checker.IsNil)
    94  
    95  	// start a daemon with --cluster-store and --cluster-advertise
    96  	err = d.Start("--cluster-store=consul://consuladdr:consulport/some/path", "--cluster-advertise=1.1.1.1:2375")
    97  	c.Assert(err, checker.NotNil)
    98  	content, _ := ioutil.ReadFile(d.logFile.Name())
    99  	c.Assert(string(content), checker.Contains, "--cluster-store and --cluster-advertise daemon configurations are incompatible with swarm mode")
   100  
   101  	// start a daemon with --live-restore
   102  	err = d.Start("--live-restore")
   103  	c.Assert(err, checker.NotNil)
   104  	content, _ = ioutil.ReadFile(d.logFile.Name())
   105  	c.Assert(string(content), checker.Contains, "--live-restore daemon configuration is incompatible with swarm mode")
   106  	// restart for teardown
   107  	c.Assert(d.Start(), checker.IsNil)
   108  }
   109  
   110  // Test case for #24090
   111  func (s *DockerSwarmSuite) TestSwarmNodeListHostname(c *check.C) {
   112  	d := s.AddDaemon(c, true, true)
   113  
   114  	// The first line should contain "HOSTNAME"
   115  	out, err := d.Cmd("node", "ls")
   116  	c.Assert(err, checker.IsNil)
   117  	c.Assert(strings.Split(out, "\n")[0], checker.Contains, "HOSTNAME")
   118  }
   119  
   120  // Test case for #24270
   121  func (s *DockerSwarmSuite) TestSwarmServiceListFilter(c *check.C) {
   122  	d := s.AddDaemon(c, true, true)
   123  
   124  	name1 := "redis-cluster-md5"
   125  	name2 := "redis-cluster"
   126  	name3 := "other-cluster"
   127  	out, err := d.Cmd("service", "create", "--name", name1, "busybox", "top")
   128  	c.Assert(err, checker.IsNil)
   129  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   130  
   131  	out, err = d.Cmd("service", "create", "--name", name2, "busybox", "top")
   132  	c.Assert(err, checker.IsNil)
   133  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   134  
   135  	out, err = d.Cmd("service", "create", "--name", name3, "busybox", "top")
   136  	c.Assert(err, checker.IsNil)
   137  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   138  
   139  	filter1 := "name=redis-cluster-md5"
   140  	filter2 := "name=redis-cluster"
   141  
   142  	// We search checker.Contains with `name+" "` to prevent prefix only.
   143  	out, err = d.Cmd("service", "ls", "--filter", filter1)
   144  	c.Assert(err, checker.IsNil)
   145  	c.Assert(out, checker.Contains, name1+" ")
   146  	c.Assert(out, checker.Not(checker.Contains), name2+" ")
   147  	c.Assert(out, checker.Not(checker.Contains), name3+" ")
   148  
   149  	out, err = d.Cmd("service", "ls", "--filter", filter2)
   150  	c.Assert(err, checker.IsNil)
   151  	c.Assert(out, checker.Contains, name1+" ")
   152  	c.Assert(out, checker.Contains, name2+" ")
   153  	c.Assert(out, checker.Not(checker.Contains), name3+" ")
   154  
   155  	out, err = d.Cmd("service", "ls")
   156  	c.Assert(err, checker.IsNil)
   157  	c.Assert(out, checker.Contains, name1+" ")
   158  	c.Assert(out, checker.Contains, name2+" ")
   159  	c.Assert(out, checker.Contains, name3+" ")
   160  }
   161  
   162  func (s *DockerSwarmSuite) TestSwarmNodeListFilter(c *check.C) {
   163  	d := s.AddDaemon(c, true, true)
   164  
   165  	out, err := d.Cmd("node", "inspect", "--format", "{{ .Description.Hostname }}", "self")
   166  	c.Assert(err, checker.IsNil)
   167  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   168  	name := strings.TrimSpace(out)
   169  
   170  	filter := "name=" + name[:4]
   171  
   172  	out, err = d.Cmd("node", "ls", "--filter", filter)
   173  	c.Assert(err, checker.IsNil)
   174  	c.Assert(out, checker.Contains, name)
   175  
   176  	out, err = d.Cmd("node", "ls", "--filter", "name=none")
   177  	c.Assert(err, checker.IsNil)
   178  	c.Assert(out, checker.Not(checker.Contains), name)
   179  }
   180  
   181  func (s *DockerSwarmSuite) TestSwarmNodeTaskListFilter(c *check.C) {
   182  	d := s.AddDaemon(c, true, true)
   183  
   184  	name := "redis-cluster-md5"
   185  	out, err := d.Cmd("service", "create", "--name", name, "--replicas=3", "busybox", "top")
   186  	c.Assert(err, checker.IsNil)
   187  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   188  
   189  	// make sure task has been deployed.
   190  	waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 3)
   191  
   192  	filter := "name=redis-cluster"
   193  
   194  	out, err = d.Cmd("node", "ps", "--filter", filter, "self")
   195  	c.Assert(err, checker.IsNil)
   196  	c.Assert(out, checker.Contains, name+".1")
   197  	c.Assert(out, checker.Contains, name+".2")
   198  	c.Assert(out, checker.Contains, name+".3")
   199  
   200  	out, err = d.Cmd("node", "ps", "--filter", "name=none", "self")
   201  	c.Assert(err, checker.IsNil)
   202  	c.Assert(out, checker.Not(checker.Contains), name+".1")
   203  	c.Assert(out, checker.Not(checker.Contains), name+".2")
   204  	c.Assert(out, checker.Not(checker.Contains), name+".3")
   205  }
   206  
   207  // Test case for #25375
   208  func (s *DockerSwarmSuite) TestSwarmPublishAdd(c *check.C) {
   209  	d := s.AddDaemon(c, true, true)
   210  
   211  	name := "top"
   212  	out, err := d.Cmd("service", "create", "--name", name, "--label", "x=y", "busybox", "top")
   213  	c.Assert(err, checker.IsNil)
   214  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   215  
   216  	out, err = d.Cmd("service", "update", "--publish-add", "80:80", name)
   217  	c.Assert(err, checker.IsNil)
   218  
   219  	out, err = d.cmdRetryOutOfSequence("service", "update", "--publish-add", "80:80", name)
   220  	c.Assert(err, checker.IsNil)
   221  
   222  	out, err = d.cmdRetryOutOfSequence("service", "update", "--publish-add", "80:80", "--publish-add", "80:20", name)
   223  	c.Assert(err, checker.NotNil)
   224  
   225  	out, err = d.cmdRetryOutOfSequence("service", "update", "--publish-add", "80:20", name)
   226  	c.Assert(err, checker.IsNil)
   227  
   228  	out, err = d.Cmd("service", "inspect", "--format", "{{ .Spec.EndpointSpec.Ports }}", name)
   229  	c.Assert(err, checker.IsNil)
   230  	c.Assert(strings.TrimSpace(out), checker.Equals, "[{ tcp 20 80}]")
   231  }
   232  
   233  func (s *DockerSwarmSuite) TestSwarmServiceWithGroup(c *check.C) {
   234  	d := s.AddDaemon(c, true, true)
   235  
   236  	name := "top"
   237  	out, err := d.Cmd("service", "create", "--name", name, "--user", "root:root", "--group-add", "wheel", "--group-add", "audio", "--group-add", "staff", "--group-add", "777", "busybox", "top")
   238  	c.Assert(err, checker.IsNil)
   239  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   240  
   241  	// make sure task has been deployed.
   242  	waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 1)
   243  
   244  	out, err = d.Cmd("ps", "-q")
   245  	c.Assert(err, checker.IsNil)
   246  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   247  
   248  	container := strings.TrimSpace(out)
   249  
   250  	out, err = d.Cmd("exec", container, "id")
   251  	c.Assert(err, checker.IsNil)
   252  	c.Assert(strings.TrimSpace(out), checker.Equals, "uid=0(root) gid=0(root) groups=10(wheel),29(audio),50(staff),777")
   253  }
   254  
   255  func (s *DockerSwarmSuite) TestSwarmContainerAutoStart(c *check.C) {
   256  	d := s.AddDaemon(c, true, true)
   257  
   258  	out, err := d.Cmd("network", "create", "--attachable", "-d", "overlay", "foo")
   259  	c.Assert(err, checker.IsNil)
   260  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   261  
   262  	out, err = d.Cmd("run", "-id", "--restart=always", "--net=foo", "--name=test", "busybox", "top")
   263  	c.Assert(err, checker.IsNil)
   264  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   265  
   266  	out, err = d.Cmd("ps", "-q")
   267  	c.Assert(err, checker.IsNil)
   268  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   269  
   270  	d.Restart()
   271  
   272  	out, err = d.Cmd("ps", "-q")
   273  	c.Assert(err, checker.IsNil)
   274  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   275  }
   276  
   277  func (s *DockerSwarmSuite) TestSwarmRemoveInternalNetwork(c *check.C) {
   278  	d := s.AddDaemon(c, true, true)
   279  
   280  	name := "ingress"
   281  	out, err := d.Cmd("network", "rm", name)
   282  	c.Assert(err, checker.NotNil)
   283  	c.Assert(strings.TrimSpace(out), checker.Contains, name)
   284  	c.Assert(strings.TrimSpace(out), checker.Contains, "is a pre-defined network and cannot be removed")
   285  }
   286  
   287  // Test case for #24108, also the case from:
   288  // https://github.com/docker/docker/pull/24620#issuecomment-233715656
   289  func (s *DockerSwarmSuite) TestSwarmTaskListFilter(c *check.C) {
   290  	d := s.AddDaemon(c, true, true)
   291  
   292  	name := "redis-cluster-md5"
   293  	out, err := d.Cmd("service", "create", "--name", name, "--replicas=3", "busybox", "top")
   294  	c.Assert(err, checker.IsNil)
   295  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   296  
   297  	filter := "name=redis-cluster"
   298  
   299  	checkNumTasks := func(*check.C) (interface{}, check.CommentInterface) {
   300  		out, err := d.Cmd("service", "ps", "--filter", filter, name)
   301  		c.Assert(err, checker.IsNil)
   302  		return len(strings.Split(out, "\n")) - 2, nil // includes header and nl in last line
   303  	}
   304  
   305  	// wait until all tasks have been created
   306  	waitAndAssert(c, defaultReconciliationTimeout, checkNumTasks, checker.Equals, 3)
   307  
   308  	out, err = d.Cmd("service", "ps", "--filter", filter, name)
   309  	c.Assert(err, checker.IsNil)
   310  	c.Assert(out, checker.Contains, name+".1")
   311  	c.Assert(out, checker.Contains, name+".2")
   312  	c.Assert(out, checker.Contains, name+".3")
   313  
   314  	out, err = d.Cmd("service", "ps", "--filter", "name="+name+".1", name)
   315  	c.Assert(err, checker.IsNil)
   316  	c.Assert(out, checker.Contains, name+".1")
   317  	c.Assert(out, checker.Not(checker.Contains), name+".2")
   318  	c.Assert(out, checker.Not(checker.Contains), name+".3")
   319  
   320  	out, err = d.Cmd("service", "ps", "--filter", "name=none", name)
   321  	c.Assert(err, checker.IsNil)
   322  	c.Assert(out, checker.Not(checker.Contains), name+".1")
   323  	c.Assert(out, checker.Not(checker.Contains), name+".2")
   324  	c.Assert(out, checker.Not(checker.Contains), name+".3")
   325  
   326  	name = "redis-cluster-sha1"
   327  	out, err = d.Cmd("service", "create", "--name", name, "--mode=global", "busybox", "top")
   328  	c.Assert(err, checker.IsNil)
   329  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   330  
   331  	waitAndAssert(c, defaultReconciliationTimeout, checkNumTasks, checker.Equals, 1)
   332  
   333  	filter = "name=redis-cluster"
   334  	out, err = d.Cmd("service", "ps", "--filter", filter, name)
   335  	c.Assert(err, checker.IsNil)
   336  	c.Assert(out, checker.Contains, name)
   337  
   338  	out, err = d.Cmd("service", "ps", "--filter", "name="+name, name)
   339  	c.Assert(err, checker.IsNil)
   340  	c.Assert(out, checker.Contains, name)
   341  
   342  	out, err = d.Cmd("service", "ps", "--filter", "name=none", name)
   343  	c.Assert(err, checker.IsNil)
   344  	c.Assert(out, checker.Not(checker.Contains), name)
   345  }
   346  
   347  func (s *DockerSwarmSuite) TestPsListContainersFilterIsTask(c *check.C) {
   348  	d := s.AddDaemon(c, true, true)
   349  
   350  	// Create a bare container
   351  	out, err := d.Cmd("run", "-d", "--name=bare-container", "busybox", "top")
   352  	c.Assert(err, checker.IsNil)
   353  	bareID := strings.TrimSpace(out)[:12]
   354  	// Create a service
   355  	name := "busybox-top"
   356  	out, err = d.Cmd("service", "create", "--name", name, "busybox", "top")
   357  	c.Assert(err, checker.IsNil)
   358  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   359  
   360  	// make sure task has been deployed.
   361  	waitAndAssert(c, defaultReconciliationTimeout, d.checkServiceRunningTasks(name), checker.Equals, 1)
   362  
   363  	// Filter non-tasks
   364  	out, err = d.Cmd("ps", "-a", "-q", "--filter=is-task=false")
   365  	c.Assert(err, checker.IsNil)
   366  	psOut := strings.TrimSpace(out)
   367  	c.Assert(psOut, checker.Equals, bareID, check.Commentf("Expected id %s, got %s for is-task label, output %q", bareID, psOut, out))
   368  
   369  	// Filter tasks
   370  	out, err = d.Cmd("ps", "-a", "-q", "--filter=is-task=true")
   371  	c.Assert(err, checker.IsNil)
   372  	lines := strings.Split(strings.Trim(out, "\n "), "\n")
   373  	c.Assert(lines, checker.HasLen, 1)
   374  	c.Assert(lines[0], checker.Not(checker.Equals), bareID, check.Commentf("Expected not %s, but got it for is-task label, output %q", bareID, out))
   375  }
   376  
   377  const globalNetworkPlugin = "global-network-plugin"
   378  const globalIPAMPlugin = "global-ipam-plugin"
   379  
   380  func (s *DockerSwarmSuite) SetUpSuite(c *check.C) {
   381  	mux := http.NewServeMux()
   382  	s.server = httptest.NewServer(mux)
   383  	c.Assert(s.server, check.NotNil, check.Commentf("Failed to start an HTTP Server"))
   384  	setupRemoteGlobalNetworkPlugin(c, mux, s.server.URL, globalNetworkPlugin, globalIPAMPlugin)
   385  }
   386  
   387  func setupRemoteGlobalNetworkPlugin(c *check.C, mux *http.ServeMux, url, netDrv, ipamDrv string) {
   388  
   389  	mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) {
   390  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   391  		fmt.Fprintf(w, `{"Implements": ["%s", "%s"]}`, driverapi.NetworkPluginEndpointType, ipamapi.PluginEndpointType)
   392  	})
   393  
   394  	// Network driver implementation
   395  	mux.HandleFunc(fmt.Sprintf("/%s.GetCapabilities", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   396  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   397  		fmt.Fprintf(w, `{"Scope":"global"}`)
   398  	})
   399  
   400  	mux.HandleFunc(fmt.Sprintf("/%s.AllocateNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   401  		err := json.NewDecoder(r.Body).Decode(&remoteDriverNetworkRequest)
   402  		if err != nil {
   403  			http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
   404  			return
   405  		}
   406  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   407  		fmt.Fprintf(w, "null")
   408  	})
   409  
   410  	mux.HandleFunc(fmt.Sprintf("/%s.FreeNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   411  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   412  		fmt.Fprintf(w, "null")
   413  	})
   414  
   415  	mux.HandleFunc(fmt.Sprintf("/%s.CreateNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   416  		err := json.NewDecoder(r.Body).Decode(&remoteDriverNetworkRequest)
   417  		if err != nil {
   418  			http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
   419  			return
   420  		}
   421  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   422  		fmt.Fprintf(w, "null")
   423  	})
   424  
   425  	mux.HandleFunc(fmt.Sprintf("/%s.DeleteNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   426  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   427  		fmt.Fprintf(w, "null")
   428  	})
   429  
   430  	mux.HandleFunc(fmt.Sprintf("/%s.CreateEndpoint", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   431  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   432  		fmt.Fprintf(w, `{"Interface":{"MacAddress":"a0:b1:c2:d3:e4:f5"}}`)
   433  	})
   434  
   435  	mux.HandleFunc(fmt.Sprintf("/%s.Join", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   436  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   437  
   438  		veth := &netlink.Veth{
   439  			LinkAttrs: netlink.LinkAttrs{Name: "randomIfName", TxQLen: 0}, PeerName: "cnt0"}
   440  		if err := netlink.LinkAdd(veth); err != nil {
   441  			fmt.Fprintf(w, `{"Error":"failed to add veth pair: `+err.Error()+`"}`)
   442  		} else {
   443  			fmt.Fprintf(w, `{"InterfaceName":{ "SrcName":"cnt0", "DstPrefix":"veth"}}`)
   444  		}
   445  	})
   446  
   447  	mux.HandleFunc(fmt.Sprintf("/%s.Leave", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   448  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   449  		fmt.Fprintf(w, "null")
   450  	})
   451  
   452  	mux.HandleFunc(fmt.Sprintf("/%s.DeleteEndpoint", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   453  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   454  		if link, err := netlink.LinkByName("cnt0"); err == nil {
   455  			netlink.LinkDel(link)
   456  		}
   457  		fmt.Fprintf(w, "null")
   458  	})
   459  
   460  	// IPAM Driver implementation
   461  	var (
   462  		poolRequest       remoteipam.RequestPoolRequest
   463  		poolReleaseReq    remoteipam.ReleasePoolRequest
   464  		addressRequest    remoteipam.RequestAddressRequest
   465  		addressReleaseReq remoteipam.ReleaseAddressRequest
   466  		lAS               = "localAS"
   467  		gAS               = "globalAS"
   468  		pool              = "172.28.0.0/16"
   469  		poolID            = lAS + "/" + pool
   470  		gw                = "172.28.255.254/16"
   471  	)
   472  
   473  	mux.HandleFunc(fmt.Sprintf("/%s.GetDefaultAddressSpaces", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   474  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   475  		fmt.Fprintf(w, `{"LocalDefaultAddressSpace":"`+lAS+`", "GlobalDefaultAddressSpace": "`+gAS+`"}`)
   476  	})
   477  
   478  	mux.HandleFunc(fmt.Sprintf("/%s.RequestPool", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   479  		err := json.NewDecoder(r.Body).Decode(&poolRequest)
   480  		if err != nil {
   481  			http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
   482  			return
   483  		}
   484  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   485  		if poolRequest.AddressSpace != lAS && poolRequest.AddressSpace != gAS {
   486  			fmt.Fprintf(w, `{"Error":"Unknown address space in pool request: `+poolRequest.AddressSpace+`"}`)
   487  		} else if poolRequest.Pool != "" && poolRequest.Pool != pool {
   488  			fmt.Fprintf(w, `{"Error":"Cannot handle explicit pool requests yet"}`)
   489  		} else {
   490  			fmt.Fprintf(w, `{"PoolID":"`+poolID+`", "Pool":"`+pool+`"}`)
   491  		}
   492  	})
   493  
   494  	mux.HandleFunc(fmt.Sprintf("/%s.RequestAddress", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   495  		err := json.NewDecoder(r.Body).Decode(&addressRequest)
   496  		if err != nil {
   497  			http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
   498  			return
   499  		}
   500  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   501  		// make sure libnetwork is now querying on the expected pool id
   502  		if addressRequest.PoolID != poolID {
   503  			fmt.Fprintf(w, `{"Error":"unknown pool id"}`)
   504  		} else if addressRequest.Address != "" {
   505  			fmt.Fprintf(w, `{"Error":"Cannot handle explicit address requests yet"}`)
   506  		} else {
   507  			fmt.Fprintf(w, `{"Address":"`+gw+`"}`)
   508  		}
   509  	})
   510  
   511  	mux.HandleFunc(fmt.Sprintf("/%s.ReleaseAddress", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   512  		err := json.NewDecoder(r.Body).Decode(&addressReleaseReq)
   513  		if err != nil {
   514  			http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
   515  			return
   516  		}
   517  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   518  		// make sure libnetwork is now asking to release the expected address from the expected poolid
   519  		if addressRequest.PoolID != poolID {
   520  			fmt.Fprintf(w, `{"Error":"unknown pool id"}`)
   521  		} else if addressReleaseReq.Address != gw {
   522  			fmt.Fprintf(w, `{"Error":"unknown address"}`)
   523  		} else {
   524  			fmt.Fprintf(w, "null")
   525  		}
   526  	})
   527  
   528  	mux.HandleFunc(fmt.Sprintf("/%s.ReleasePool", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   529  		err := json.NewDecoder(r.Body).Decode(&poolReleaseReq)
   530  		if err != nil {
   531  			http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
   532  			return
   533  		}
   534  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   535  		// make sure libnetwork is now asking to release the expected poolid
   536  		if addressRequest.PoolID != poolID {
   537  			fmt.Fprintf(w, `{"Error":"unknown pool id"}`)
   538  		} else {
   539  			fmt.Fprintf(w, "null")
   540  		}
   541  	})
   542  
   543  	err := os.MkdirAll("/etc/docker/plugins", 0755)
   544  	c.Assert(err, checker.IsNil)
   545  
   546  	fileName := fmt.Sprintf("/etc/docker/plugins/%s.spec", netDrv)
   547  	err = ioutil.WriteFile(fileName, []byte(url), 0644)
   548  	c.Assert(err, checker.IsNil)
   549  
   550  	ipamFileName := fmt.Sprintf("/etc/docker/plugins/%s.spec", ipamDrv)
   551  	err = ioutil.WriteFile(ipamFileName, []byte(url), 0644)
   552  	c.Assert(err, checker.IsNil)
   553  }
   554  
   555  func (s *DockerSwarmSuite) TestSwarmNetworkPlugin(c *check.C) {
   556  	d := s.AddDaemon(c, true, true)
   557  
   558  	out, err := d.Cmd("network", "create", "-d", globalNetworkPlugin, "foo")
   559  	c.Assert(err, checker.IsNil)
   560  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   561  
   562  	name := "top"
   563  	out, err = d.Cmd("service", "create", "--name", name, "--network", "foo", "busybox", "top")
   564  	c.Assert(err, checker.IsNil)
   565  	c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
   566  
   567  	out, err = d.Cmd("service", "inspect", "--format", "{{range .Spec.Networks}}{{.Target}}{{end}}", name)
   568  	c.Assert(err, checker.IsNil)
   569  	c.Assert(strings.TrimSpace(out), checker.Equals, "foo")
   570  }