IT for e2e network-plugin support for swarmkit & services

As of https://github.com/docker/swarmkit/pull/1607, swarmkit honors
global network plugins while allocating network resources.

This IT covers the e2e integration between libnetwork, swarmkit and
docker engine to support global network-plugins for swarm-mode

Signed-off-by: Madhu Venugopal <madhu@docker.com>
This commit is contained in:
Madhu Venugopal 2016-10-15 10:20:34 -07:00
parent 5e9c78aeaf
commit af185a3806
2 changed files with 206 additions and 0 deletions

View File

@ -2,6 +2,7 @@ package main
import (
"fmt"
"net/http/httptest"
"os"
"path/filepath"
"sync"
@ -240,6 +241,7 @@ func init() {
}
type DockerSwarmSuite struct {
server *httptest.Server
ds *DockerSuite
daemons []*SwarmDaemon
daemonsLock sync.Mutex // protect access to daemons

View File

@ -3,13 +3,22 @@
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"os"
"strings"
"time"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/pkg/integration/checker"
"github.com/docker/libnetwork/driverapi"
"github.com/docker/libnetwork/ipamapi"
remoteipam "github.com/docker/libnetwork/ipams/remote/api"
"github.com/go-check/check"
"github.com/vishvananda/netlink"
)
func (s *DockerSwarmSuite) TestSwarmUpdate(c *check.C) {
@ -364,3 +373,198 @@ func (s *DockerSwarmSuite) TestPsListContainersFilterIsTask(c *check.C) {
c.Assert(lines, checker.HasLen, 1)
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))
}
const globalNetworkPlugin = "global-network-plugin"
const globalIPAMPlugin = "global-ipam-plugin"
func (s *DockerSwarmSuite) SetUpSuite(c *check.C) {
mux := http.NewServeMux()
s.server = httptest.NewServer(mux)
c.Assert(s.server, check.NotNil, check.Commentf("Failed to start an HTTP Server"))
setupRemoteGlobalNetworkPlugin(c, mux, s.server.URL, globalNetworkPlugin, globalIPAMPlugin)
}
func setupRemoteGlobalNetworkPlugin(c *check.C, mux *http.ServeMux, url, netDrv, ipamDrv string) {
mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
fmt.Fprintf(w, `{"Implements": ["%s", "%s"]}`, driverapi.NetworkPluginEndpointType, ipamapi.PluginEndpointType)
})
// Network driver implementation
mux.HandleFunc(fmt.Sprintf("/%s.GetCapabilities", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
fmt.Fprintf(w, `{"Scope":"global"}`)
})
mux.HandleFunc(fmt.Sprintf("/%s.AllocateNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
err := json.NewDecoder(r.Body).Decode(&remoteDriverNetworkRequest)
if err != nil {
http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
return
}
w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
fmt.Fprintf(w, "null")
})
mux.HandleFunc(fmt.Sprintf("/%s.FreeNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
fmt.Fprintf(w, "null")
})
mux.HandleFunc(fmt.Sprintf("/%s.CreateNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
err := json.NewDecoder(r.Body).Decode(&remoteDriverNetworkRequest)
if err != nil {
http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
return
}
w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
fmt.Fprintf(w, "null")
})
mux.HandleFunc(fmt.Sprintf("/%s.DeleteNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
fmt.Fprintf(w, "null")
})
mux.HandleFunc(fmt.Sprintf("/%s.CreateEndpoint", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
fmt.Fprintf(w, `{"Interface":{"MacAddress":"a0:b1:c2:d3:e4:f5"}}`)
})
mux.HandleFunc(fmt.Sprintf("/%s.Join", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
veth := &netlink.Veth{
LinkAttrs: netlink.LinkAttrs{Name: "randomIfName", TxQLen: 0}, PeerName: "cnt0"}
if err := netlink.LinkAdd(veth); err != nil {
fmt.Fprintf(w, `{"Error":"failed to add veth pair: `+err.Error()+`"}`)
} else {
fmt.Fprintf(w, `{"InterfaceName":{ "SrcName":"cnt0", "DstPrefix":"veth"}}`)
}
})
mux.HandleFunc(fmt.Sprintf("/%s.Leave", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
fmt.Fprintf(w, "null")
})
mux.HandleFunc(fmt.Sprintf("/%s.DeleteEndpoint", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
if link, err := netlink.LinkByName("cnt0"); err == nil {
netlink.LinkDel(link)
}
fmt.Fprintf(w, "null")
})
// IPAM Driver implementation
var (
poolRequest remoteipam.RequestPoolRequest
poolReleaseReq remoteipam.ReleasePoolRequest
addressRequest remoteipam.RequestAddressRequest
addressReleaseReq remoteipam.ReleaseAddressRequest
lAS = "localAS"
gAS = "globalAS"
pool = "172.28.0.0/16"
poolID = lAS + "/" + pool
gw = "172.28.255.254/16"
)
mux.HandleFunc(fmt.Sprintf("/%s.GetDefaultAddressSpaces", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
fmt.Fprintf(w, `{"LocalDefaultAddressSpace":"`+lAS+`", "GlobalDefaultAddressSpace": "`+gAS+`"}`)
})
mux.HandleFunc(fmt.Sprintf("/%s.RequestPool", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
err := json.NewDecoder(r.Body).Decode(&poolRequest)
if err != nil {
http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
return
}
w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
if poolRequest.AddressSpace != lAS && poolRequest.AddressSpace != gAS {
fmt.Fprintf(w, `{"Error":"Unknown address space in pool request: `+poolRequest.AddressSpace+`"}`)
} else if poolRequest.Pool != "" && poolRequest.Pool != pool {
fmt.Fprintf(w, `{"Error":"Cannot handle explicit pool requests yet"}`)
} else {
fmt.Fprintf(w, `{"PoolID":"`+poolID+`", "Pool":"`+pool+`"}`)
}
})
mux.HandleFunc(fmt.Sprintf("/%s.RequestAddress", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
err := json.NewDecoder(r.Body).Decode(&addressRequest)
if err != nil {
http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
return
}
w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
// make sure libnetwork is now querying on the expected pool id
if addressRequest.PoolID != poolID {
fmt.Fprintf(w, `{"Error":"unknown pool id"}`)
} else if addressRequest.Address != "" {
fmt.Fprintf(w, `{"Error":"Cannot handle explicit address requests yet"}`)
} else {
fmt.Fprintf(w, `{"Address":"`+gw+`"}`)
}
})
mux.HandleFunc(fmt.Sprintf("/%s.ReleaseAddress", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
err := json.NewDecoder(r.Body).Decode(&addressReleaseReq)
if err != nil {
http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
return
}
w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
// make sure libnetwork is now asking to release the expected address from the expected poolid
if addressRequest.PoolID != poolID {
fmt.Fprintf(w, `{"Error":"unknown pool id"}`)
} else if addressReleaseReq.Address != gw {
fmt.Fprintf(w, `{"Error":"unknown address"}`)
} else {
fmt.Fprintf(w, "null")
}
})
mux.HandleFunc(fmt.Sprintf("/%s.ReleasePool", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
err := json.NewDecoder(r.Body).Decode(&poolReleaseReq)
if err != nil {
http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
return
}
w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
// make sure libnetwork is now asking to release the expected poolid
if addressRequest.PoolID != poolID {
fmt.Fprintf(w, `{"Error":"unknown pool id"}`)
} else {
fmt.Fprintf(w, "null")
}
})
err := os.MkdirAll("/etc/docker/plugins", 0755)
c.Assert(err, checker.IsNil)
fileName := fmt.Sprintf("/etc/docker/plugins/%s.spec", netDrv)
err = ioutil.WriteFile(fileName, []byte(url), 0644)
c.Assert(err, checker.IsNil)
ipamFileName := fmt.Sprintf("/etc/docker/plugins/%s.spec", ipamDrv)
err = ioutil.WriteFile(ipamFileName, []byte(url), 0644)
c.Assert(err, checker.IsNil)
}
func (s *DockerSwarmSuite) TestSwarmNetworkPlugin(c *check.C) {
d := s.AddDaemon(c, true, true)
out, err := d.Cmd("network", "create", "-d", globalNetworkPlugin, "foo")
c.Assert(err, checker.IsNil)
c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
name := "top"
out, err = d.Cmd("service", "create", "--name", name, "--network", "foo", "busybox", "top")
c.Assert(err, checker.IsNil)
c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
out, err = d.Cmd("service", "inspect", "--format", "{{range .Spec.Networks}}{{.Target}}{{end}}", name)
c.Assert(err, checker.IsNil)
c.Assert(strings.TrimSpace(out), checker.Equals, "foo")
}