瀏覽代碼

Merge pull request #13424 from mavenugo/vendorin

Vendoring in libnetwork 67438080724b17b641b411322822c00d0d3c3201
Arnaud Porterie 10 年之前
父節點
當前提交
f83073d3eb
共有 57 個文件被更改,包括 3361 次插入1085 次删除
  1. 7 7
      daemon/container_linux.go
  2. 1 1
      hack/vendor.sh
  3. 1 1
      vendor/src/github.com/docker/libnetwork/Makefile
  4. 122 62
      vendor/src/github.com/docker/libnetwork/api/api.go
  5. 406 146
      vendor/src/github.com/docker/libnetwork/api/api_test.go
  6. 3 4
      vendor/src/github.com/docker/libnetwork/api/types.go
  7. 6 0
      vendor/src/github.com/docker/libnetwork/client/client.go
  8. 124 0
      vendor/src/github.com/docker/libnetwork/client/client_experimental_test.go
  9. 102 44
      vendor/src/github.com/docker/libnetwork/client/client_test.go
  10. 125 16
      vendor/src/github.com/docker/libnetwork/client/network.go
  11. 7 0
      vendor/src/github.com/docker/libnetwork/client/service.go
  12. 317 0
      vendor/src/github.com/docker/libnetwork/client/service_experimental.go
  13. 36 2
      vendor/src/github.com/docker/libnetwork/client/types.go
  14. 5 7
      vendor/src/github.com/docker/libnetwork/cmd/dnet/dnet.go
  15. 1 1
      vendor/src/github.com/docker/libnetwork/cmd/dnet/flags.go
  16. 2 2
      vendor/src/github.com/docker/libnetwork/cmd/readme_test/readme.go
  17. 9 6
      vendor/src/github.com/docker/libnetwork/controller.go
  18. 1 1
      vendor/src/github.com/docker/libnetwork/docs/design.md
  19. 2 23
      vendor/src/github.com/docker/libnetwork/driverapi/driverapi.go
  20. 56 0
      vendor/src/github.com/docker/libnetwork/driverapi/errors.go
  21. 27 27
      vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go
  22. 12 11
      vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge_test.go
  23. 0 201
      vendor/src/github.com/docker/libnetwork/drivers/bridge/error.go
  24. 341 0
      vendor/src/github.com/docker/libnetwork/drivers/bridge/errors.go
  25. 5 5
      vendor/src/github.com/docker/libnetwork/drivers/bridge/link.go
  26. 6 6
      vendor/src/github.com/docker/libnetwork/drivers/bridge/link_test.go
  27. 2 2
      vendor/src/github.com/docker/libnetwork/drivers/bridge/network_test.go
  28. 7 7
      vendor/src/github.com/docker/libnetwork/drivers/bridge/port_mapping.go
  29. 4 3
      vendor/src/github.com/docker/libnetwork/drivers/bridge/port_mapping_test.go
  30. 4 2
      vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_fixedcidrv4.go
  31. 4 2
      vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_fixedcidrv6.go
  32. 1 1
      vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ip_forwarding.go
  33. 1 1
      vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ip_forwarding_test.go
  34. 1 1
      vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ip_tables.go
  35. 2 2
      vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ipv4.go
  36. 3 3
      vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ipv6.go
  37. 5 3
      vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_verify.go
  38. 163 19
      vendor/src/github.com/docker/libnetwork/drivers/remote/driver.go
  39. 397 0
      vendor/src/github.com/docker/libnetwork/drivers/remote/driver_test.go
  40. 143 0
      vendor/src/github.com/docker/libnetwork/drivers/remote/messages.go
  41. 12 13
      vendor/src/github.com/docker/libnetwork/endpoint.go
  42. 19 19
      vendor/src/github.com/docker/libnetwork/endpoint_info.go
  43. 97 27
      vendor/src/github.com/docker/libnetwork/error.go
  44. 51 0
      vendor/src/github.com/docker/libnetwork/errors_test.go
  45. 1 1
      vendor/src/github.com/docker/libnetwork/iptables/iptables_test.go
  46. 68 26
      vendor/src/github.com/docker/libnetwork/libnetwork_test.go
  47. 0 175
      vendor/src/github.com/docker/libnetwork/netutils/utils.go
  48. 0 132
      vendor/src/github.com/docker/libnetwork/netutils/utils_test.go
  49. 5 5
      vendor/src/github.com/docker/libnetwork/network.go
  50. 9 9
      vendor/src/github.com/docker/libnetwork/portmapper/mapper.go
  51. 81 37
      vendor/src/github.com/docker/libnetwork/portmapper/mapper_test.go
  52. 48 0
      vendor/src/github.com/docker/libnetwork/portmapper/proxy.go
  53. 12 2
      vendor/src/github.com/docker/libnetwork/sandbox/namespace_linux.go
  54. 13 9
      vendor/src/github.com/docker/libnetwork/sandbox/sandbox.go
  55. 45 11
      vendor/src/github.com/docker/libnetwork/sandbox/sandbox_linux_test.go
  56. 340 0
      vendor/src/github.com/docker/libnetwork/types/types.go
  57. 99 0
      vendor/src/github.com/docker/libnetwork/types/types_test.go

+ 7 - 7
daemon/container_linux.go

@@ -30,8 +30,8 @@ import (
 	"github.com/docker/libcontainer/devices"
 	"github.com/docker/libnetwork"
 	"github.com/docker/libnetwork/netlabel"
-	"github.com/docker/libnetwork/netutils"
 	"github.com/docker/libnetwork/options"
+	"github.com/docker/libnetwork/types"
 )
 
 const DefaultPathEnv = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
@@ -495,7 +495,7 @@ func (container *Container) buildPortMapInfo(n libnetwork.Network, ep libnetwork
 		return networkSettings, nil
 	}
 
-	if portMapping, ok := mapData.([]netutils.PortBinding); ok {
+	if portMapping, ok := mapData.([]types.PortBinding); ok {
 		networkSettings.Ports = nat.PortMap{}
 		for _, pp := range portMapping {
 			natPort := nat.NewPort(pp.Proto.String(), strconv.Itoa(int(pp.Port)))
@@ -634,8 +634,8 @@ func (container *Container) buildCreateEndpointOptions() ([]libnetwork.EndpointO
 	var (
 		portSpecs     = make(nat.PortSet)
 		bindings      = make(nat.PortMap)
-		pbList        []netutils.PortBinding
-		exposeList    []netutils.TransportPort
+		pbList        []types.PortBinding
+		exposeList    []types.TransportPort
 		createOptions []libnetwork.EndpointOption
 	)
 
@@ -675,12 +675,12 @@ func (container *Container) buildCreateEndpointOptions() ([]libnetwork.EndpointO
 	}
 	nat.SortPortMap(ports, bindings)
 	for _, port := range ports {
-		expose := netutils.TransportPort{}
-		expose.Proto = netutils.ParseProtocol(port.Proto())
+		expose := types.TransportPort{}
+		expose.Proto = types.ParseProtocol(port.Proto())
 		expose.Port = uint16(port.Int())
 		exposeList = append(exposeList, expose)
 
-		pb := netutils.PortBinding{Port: expose.Port, Proto: expose.Proto}
+		pb := types.PortBinding{Port: expose.Port, Proto: expose.Proto}
 		binding := bindings[port]
 		for i := 0; i < len(binding); i++ {
 			pbCopy := pb.GetCopy()

+ 1 - 1
hack/vendor.sh

@@ -55,7 +55,7 @@ clone hg code.google.com/p/go.net 84a4013f96e0
 clone hg code.google.com/p/gosqlite 74691fb6f837
 
 #get libnetwork packages
-clone git github.com/docker/libnetwork b39597744b0978fe4aeb9f3a099ba42f7b6c4a1f
+clone git github.com/docker/libnetwork 67438080724b17b641b411322822c00d0d3c3201
 clone git github.com/vishvananda/netns 008d17ae001344769b031375bdb38a86219154c6
 clone git github.com/vishvananda/netlink 8eb64238879fed52fd51c5b30ad20b928fb4c36c
 

+ 1 - 1
vendor/src/github.com/docker/libnetwork/Makefile

@@ -22,7 +22,7 @@ build: ${build_image}.created
 	${docker} make build-local
 
 build-local:
-	$(shell which godep) go build ./...
+	$(shell which godep) go build -tags experimental ./...
 
 check: ${build_image}.created
 	${docker} make check-local

+ 122 - 62
vendor/src/github.com/docker/libnetwork/api/api.go

@@ -5,8 +5,10 @@ import (
 	"fmt"
 	"io/ioutil"
 	"net/http"
+	"strings"
 
 	"github.com/docker/libnetwork"
+	"github.com/docker/libnetwork/types"
 	"github.com/gorilla/mux"
 )
 
@@ -14,13 +16,28 @@ var (
 	successResponse  = responseStatus{Status: "Success", StatusCode: http.StatusOK}
 	createdResponse  = responseStatus{Status: "Created", StatusCode: http.StatusCreated}
 	mismatchResponse = responseStatus{Status: "Body/URI parameter mismatch", StatusCode: http.StatusBadRequest}
+	badQueryresponse = responseStatus{Status: "Unsupported query", StatusCode: http.StatusBadRequest}
 )
 
 const (
-	urlNwName = "name"
-	urlNwID   = "id"
+	// Resource name regex
+	regex = "[a-zA-Z_0-9-]+"
+	// Router URL variable definition
+	nwName = "{" + urlNwName + ":" + regex + "}"
+	nwID   = "{" + urlNwID + ":" + regex + "}"
+	nwPID  = "{" + urlNwPID + ":" + regex + "}"
+	epName = "{" + urlEpName + ":" + regex + "}"
+	epID   = "{" + urlEpID + ":" + regex + "}"
+	epPID  = "{" + urlEpPID + ":" + regex + "}"
+	cnID   = "{" + urlCnID + ":" + regex + "}"
+
+	// Internal URL variable name, they can be anything
+	urlNwName = "network-name"
+	urlNwID   = "network-id"
+	urlNwPID  = "network-partial-id"
 	urlEpName = "endpoint-name"
 	urlEpID   = "endpoint-id"
+	urlEpPID  = "endpoint-partial-id"
 	urlCnID   = "container-id"
 )
 
@@ -59,42 +76,41 @@ func (h *httpHandler) handleRequest(w http.ResponseWriter, req *http.Request) {
 }
 
 func (h *httpHandler) initRouter() {
-	m := map[string]map[string]processor{
+	m := map[string][]struct {
+		url string
+		qrs []string
+		fct processor
+	}{
 		"GET": {
-			"/networks":                                                                   procGetNetworks,
-			"/networks/name/{" + urlNwName + ":.*}":                                       procGetNetwork,
-			"/networks/id/{" + urlNwID + ":.*}":                                           procGetNetwork,
-			"/networks/name/{" + urlNwName + ":.*}/endpoints/":                            procGetEndpoints,
-			"/networks/id/{" + urlNwID + ":.*}/endpoints/":                                procGetEndpoints,
-			"/networks/name/{" + urlNwName + ":.*}/endpoints/name/{" + urlEpName + ":.*}": procGetEndpoint,
-			"/networks/id/{" + urlNwID + ":.*}/endpoints/name/{" + urlEpName + ":.*}":     procGetEndpoint,
-			"/networks/name/{" + urlNwName + ":.*}/endpoints/id/{" + urlEpID + ":.*}":     procGetEndpoint,
-			"/networks/id/{" + urlNwID + ":.*}/endpoints/id/{" + urlEpID + ":.*}":         procGetEndpoint,
+			// Order matters
+			{"/networks", []string{"name", nwName}, procGetNetworks},
+			{"/networks", []string{"partial-id", nwPID}, procGetNetworks},
+			{"/networks", nil, procGetNetworks},
+			{"/networks/" + nwID, nil, procGetNetwork},
+			{"/networks/" + nwID + "/endpoints", []string{"name", epName}, procGetEndpoints},
+			{"/networks/" + nwID + "/endpoints", []string{"partial-id", epPID}, procGetEndpoints},
+			{"/networks/" + nwID + "/endpoints", nil, procGetEndpoints},
+			{"/networks/" + nwID + "/endpoints/" + epID, nil, procGetEndpoint},
 		},
 		"POST": {
-			"/networks/name/{" + urlNwName + ":.*}":                                                                     procCreateNetwork,
-			"/networks/name/{" + urlNwName + ":.*}/endpoint/name/{" + urlEpName + ":.*}":                                procCreateEndpoint,
-			"/networks/name/{" + urlNwName + ":.*}/endpoint/name/{" + urlEpName + ":.*}/container/{" + urlCnID + ":.*}": procJoinEndpoint,
+			{"/networks", nil, procCreateNetwork},
+			{"/networks/" + nwID + "/endpoints", nil, procCreateEndpoint},
+			{"/networks/" + nwID + "/endpoints/" + epID + "/containers", nil, procJoinEndpoint},
 		},
 		"DELETE": {
-			"/networks/name/{" + urlNwName + ":.*}":                                                                     procDeleteNetwork,
-			"/networks/id/{" + urlNwID + ":.*}":                                                                         procDeleteNetwork,
-			"/networks/name/{" + urlNwName + ":.*}/endpoints/name/{" + urlEpName + ":.*}":                               procDeleteEndpoint,
-			"/networks/name/{" + urlNwName + ":.*}/endpoints/id/{" + urlEpID + ":.*}":                                   procDeleteEndpoint,
-			"/networks/id/{" + urlNwID + ":.*}/endpoints/name/{" + urlEpName + ":.*}":                                   procDeleteEndpoint,
-			"/networks/id/{" + urlNwID + ":.*}/endpoints/id/{" + urlEpID + ":.*}":                                       procDeleteEndpoint,
-			"/networks/name/{" + urlNwName + ":.*}/endpoint/name/{" + urlEpName + ":.*}/container/{" + urlCnID + ":.*}": procLeaveEndpoint,
-			"/networks/name/{" + urlNwName + ":.*}/endpoint/id/{" + urlEpID + ":.*}/container/{" + urlCnID + ":.*}":     procLeaveEndpoint,
-			"/networks/id/{" + urlNwID + ":.*}/endpoint/name/{" + urlEpName + ":.*}/container/{" + urlCnID + ":.*}":     procLeaveEndpoint,
-			"/networks/id/{" + urlNwID + ":.*}/endpoint/id/{" + urlEpID + ":.*}/container/{" + urlCnID + ":.*}":         procLeaveEndpoint,
+			{"/networks/" + nwID, nil, procDeleteNetwork},
+			{"/networks/" + nwID + "/endpoints/" + epID, nil, procDeleteEndpoint},
+			{"/networks/id/" + nwID + "/endpoints/" + epID + "/containers/" + cnID, nil, procLeaveEndpoint},
 		},
 	}
 
 	h.r = mux.NewRouter()
 	for method, routes := range m {
-		for route, fct := range routes {
-			f := makeHandler(h.c, fct)
-			h.r.Path(route).Methods(method).HandlerFunc(f)
+		for _, route := range routes {
+			r := h.r.Path("/{.*}" + route.url).Methods(method).HandlerFunc(makeHandler(h.c, route.fct))
+			if route.qrs != nil {
+				r.Queries(route.qrs...)
+			}
 		}
 	}
 }
@@ -208,12 +224,7 @@ func procCreateNetwork(c libnetwork.NetworkController, vars map[string]string, b
 		return "", &responseStatus{Status: "Invalid body: " + err.Error(), StatusCode: http.StatusBadRequest}
 	}
 
-	name := vars[urlNwName]
-	if name != create.Name {
-		return "", &mismatchResponse
-	}
-
-	nw, err := c.NewNetwork(create.NetworkType, name, nil)
+	nw, err := c.NewNetwork(create.NetworkType, create.Name, nil)
 	if err != nil {
 		return "", convertNetworkError(err)
 	}
@@ -232,10 +243,33 @@ func procGetNetwork(c libnetwork.NetworkController, vars map[string]string, body
 
 func procGetNetworks(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
 	var list []*networkResource
-	for _, nw := range c.Networks() {
-		nwr := buildNetworkResource(nw)
-		list = append(list, nwr)
+
+	// Look for query filters and validate
+	name, queryByName := vars[urlNwName]
+	shortID, queryByPid := vars[urlNwPID]
+	if queryByName && queryByPid {
+		return nil, &badQueryresponse
+	}
+
+	if queryByName {
+		if nw, errRsp := findNetwork(c, name, byName); errRsp.isOK() {
+			list = append(list, buildNetworkResource(nw))
+		}
+	} else if queryByPid {
+		// Return all the prefix-matching networks
+		l := func(nw libnetwork.Network) bool {
+			if strings.HasPrefix(nw.ID(), shortID) {
+				list = append(list, buildNetworkResource(nw))
+			}
+			return false
+		}
+		c.WalkNetworks(l)
+	} else {
+		for _, nw := range c.Networks() {
+			list = append(list, buildNetworkResource(nw))
+		}
 	}
+
 	return list, &successResponse
 }
 
@@ -250,21 +284,12 @@ func procCreateEndpoint(c libnetwork.NetworkController, vars map[string]string,
 		return "", &responseStatus{Status: "Invalid body: " + err.Error(), StatusCode: http.StatusBadRequest}
 	}
 
-	epn := vars[urlEpName]
-	if ec.Name != epn {
-		return "", &mismatchResponse
-	}
-
 	nwT, nwBy := detectNetworkTarget(vars)
 	n, errRsp := findNetwork(c, nwT, nwBy)
 	if !errRsp.isOK() {
 		return "", errRsp
 	}
 
-	if ec.NetworkID != n.ID() {
-		return "", &mismatchResponse
-	}
-
 	var setFctList []libnetwork.EndpointOption
 	if ec.ExposedPorts != nil {
 		setFctList = append(setFctList, libnetwork.CreateOptionExposedPorts(ec.ExposedPorts))
@@ -273,7 +298,7 @@ func procCreateEndpoint(c libnetwork.NetworkController, vars map[string]string,
 		setFctList = append(setFctList, libnetwork.CreateOptionPortMapping(ec.PortMapping))
 	}
 
-	ep, err := n.CreateEndpoint(epn, setFctList...)
+	ep, err := n.CreateEndpoint(ec.Name, setFctList...)
 	if err != nil {
 		return "", convertNetworkError(err)
 	}
@@ -294,17 +319,40 @@ func procGetEndpoint(c libnetwork.NetworkController, vars map[string]string, bod
 }
 
 func procGetEndpoints(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
-	target, by := detectNetworkTarget(vars)
+	// Look for query filters and validate
+	name, queryByName := vars[urlEpName]
+	shortID, queryByPid := vars[urlEpPID]
+	if queryByName && queryByPid {
+		return nil, &badQueryresponse
+	}
 
-	nw, errRsp := findNetwork(c, target, by)
+	nwT, nwBy := detectNetworkTarget(vars)
+	nw, errRsp := findNetwork(c, nwT, nwBy)
 	if !errRsp.isOK() {
 		return nil, errRsp
 	}
 
 	var list []*endpointResource
-	for _, ep := range nw.Endpoints() {
-		epr := buildEndpointResource(ep)
-		list = append(list, epr)
+
+	// If query parameter is specified, return a filtered collection
+	if queryByName {
+		if ep, errRsp := findEndpoint(c, nwT, name, nwBy, byName); errRsp.isOK() {
+			list = append(list, buildEndpointResource(ep))
+		}
+	} else if queryByPid {
+		// Return all the prefix-matching networks
+		l := func(ep libnetwork.Endpoint) bool {
+			if strings.HasPrefix(ep.ID(), shortID) {
+				list = append(list, buildEndpointResource(ep))
+			}
+			return false
+		}
+		nw.WalkEndpoints(l)
+	} else {
+		for _, ep := range nw.Endpoints() {
+			epr := buildEndpointResource(ep)
+			list = append(list, epr)
+		}
 	}
 
 	return list, &successResponse
@@ -336,11 +384,6 @@ func procJoinEndpoint(c libnetwork.NetworkController, vars map[string]string, bo
 		return nil, &responseStatus{Status: "Invalid body: " + err.Error(), StatusCode: http.StatusBadRequest}
 	}
 
-	cid := vars[urlCnID]
-	if ej.ContainerID != cid {
-		return "", &mismatchResponse
-	}
-
 	nwT, nwBy := detectNetworkTarget(vars)
 	epT, epBy := detectEndpointTarget(vars)
 
@@ -434,7 +477,7 @@ func findNetwork(c libnetwork.NetworkController, s string, by int) (libnetwork.N
 		panic(fmt.Sprintf("unexpected selector for network search: %d", by))
 	}
 	if err != nil {
-		if err == libnetwork.ErrNoSuchNetwork {
+		if _, ok := err.(libnetwork.ErrNoSuchNetwork); ok {
 			return nil, &responseStatus{Status: "Resource not found: Network", StatusCode: http.StatusNotFound}
 		}
 		return nil, &responseStatus{Status: err.Error(), StatusCode: http.StatusBadRequest}
@@ -460,7 +503,7 @@ func findEndpoint(c libnetwork.NetworkController, ns, es string, nwBy, epBy int)
 		panic(fmt.Sprintf("unexpected selector for endpoint search: %d", epBy))
 	}
 	if err != nil {
-		if err == libnetwork.ErrNoSuchEndpoint {
+		if _, ok := err.(libnetwork.ErrNoSuchEndpoint); ok {
 			return nil, &responseStatus{Status: "Resource not found: Endpoint", StatusCode: http.StatusNotFound}
 		}
 		return nil, &responseStatus{Status: err.Error(), StatusCode: http.StatusBadRequest}
@@ -469,9 +512,26 @@ func findEndpoint(c libnetwork.NetworkController, ns, es string, nwBy, epBy int)
 }
 
 func convertNetworkError(err error) *responseStatus {
-	// No real libnetwork error => http error code conversion for now.
-	// Will came in later when new interface for libnetwork error is vailable
-	return &responseStatus{Status: err.Error(), StatusCode: http.StatusBadRequest}
+	var code int
+	switch err.(type) {
+	case types.BadRequestError:
+		code = http.StatusBadRequest
+	case types.ForbiddenError:
+		code = http.StatusForbidden
+	case types.NotFoundError:
+		code = http.StatusNotFound
+	case types.TimeoutError:
+		code = http.StatusRequestTimeout
+	case types.NotImplementedError:
+		code = http.StatusNotImplemented
+	case types.NoServiceError:
+		code = http.StatusServiceUnavailable
+	case types.InternalError:
+		code = http.StatusInternalServerError
+	default:
+		code = http.StatusInternalServerError
+	}
+	return &responseStatus{Status: err.Error(), StatusCode: code}
 }
 
 func writeJSON(w http.ResponseWriter, code int, v interface{}) error {

+ 406 - 146
vendor/src/github.com/docker/libnetwork/api/api_test.go

@@ -16,6 +16,7 @@ import (
 	"github.com/docker/libnetwork/netlabel"
 	"github.com/docker/libnetwork/netutils"
 	"github.com/docker/libnetwork/options"
+	"github.com/docker/libnetwork/types"
 )
 
 const (
@@ -111,7 +112,7 @@ func TestJoinOptionParser(t *testing.T) {
 }
 
 func TestJson(t *testing.T) {
-	nc := networkCreate{Name: "mynet", NetworkType: bridgeNetType}
+	nc := networkCreate{NetworkType: bridgeNetType}
 	b, err := json.Marshal(nc)
 	if err != nil {
 		t.Fatal(err)
@@ -123,26 +124,10 @@ func TestJson(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	if nc.Name != ncp.Name || nc.NetworkType != ncp.NetworkType {
+	if nc.NetworkType != ncp.NetworkType {
 		t.Fatalf("Incorrect networkCreate after json encoding/deconding: %v", ncp)
 	}
 
-	ec := endpointCreate{Name: "mioEp", NetworkID: "0xabcde"}
-	b, err = json.Marshal(ec)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	var ecp endpointCreate
-	err = json.Unmarshal(b, &ecp)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	if ec.Name != ecp.Name || ec.NetworkID != ecp.NetworkID {
-		t.Fatalf("Incorrect endpointCreate after json encoding/deconding: %v", ecp)
-	}
-
 	jl := endpointJoin{ContainerID: "abcdef456789"}
 	b, err = json.Marshal(jl)
 	if err != nil {
@@ -156,7 +141,7 @@ func TestJson(t *testing.T) {
 	}
 
 	if jl.ContainerID != jld.ContainerID {
-		t.Fatalf("Incorrect endpointJoin after json encoding/deconding: %v", ecp)
+		t.Fatalf("Incorrect endpointJoin after json encoding/deconding: %v", jld)
 	}
 }
 
@@ -177,68 +162,55 @@ func TestCreateDeleteNetwork(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	goodVars := map[string]string{urlNwName: "myNet"}
-	_, errRsp := procCreateNetwork(c, goodVars, badBody)
+	vars := make(map[string]string)
+	_, errRsp := procCreateNetwork(c, nil, badBody)
 	if errRsp == &createdResponse {
 		t.Fatalf("Expected to fail but succeeded")
 	}
+	if errRsp.StatusCode != http.StatusBadRequest {
+		t.Fatalf("Expected StatusBadRequest status code, got: %v", errRsp)
+	}
 
-	incompleteBody, err := json.Marshal(networkCreate{Name: "myNet"})
+	incompleteBody, err := json.Marshal(networkCreate{})
 	if err != nil {
 		t.Fatal(err)
 	}
 
-	_, errRsp = procCreateNetwork(c, goodVars, incompleteBody)
+	_, errRsp = procCreateNetwork(c, vars, incompleteBody)
 	if errRsp == &createdResponse {
 		t.Fatalf("Expected to fail but succeeded")
 	}
 	if errRsp.StatusCode != http.StatusBadRequest {
-		t.Fatalf("Expected StatusBadRequest status code, got: %v", errRsp.StatusCode)
+		t.Fatalf("Expected StatusBadRequest status code, got: %v", errRsp)
 	}
 
 	ops := make(map[string]interface{})
 	ops[netlabel.GenericData] = options.Generic{}
-	nc := networkCreate{Name: "myNet", NetworkType: bridgeNetType, Options: ops}
+	nc := networkCreate{Name: "network_1", NetworkType: bridgeNetType, Options: ops}
 	goodBody, err := json.Marshal(nc)
 	if err != nil {
 		t.Fatal(err)
 	}
 
-	badVars := map[string]string{urlNwName: ""}
-	_, errRsp = procCreateNetwork(c, badVars, goodBody)
-	if errRsp == &createdResponse {
-		t.Fatalf("Expected to fail but succeeded")
-	}
-	if errRsp.StatusCode != http.StatusBadRequest {
-		t.Fatalf("Expected StatusBadRequest status code, got: %v", errRsp.StatusCode)
-	}
-
-	badVars[urlNwName] = "badNetworkName"
-	_, errRsp = procCreateNetwork(c, badVars, goodBody)
-	if errRsp == &createdResponse {
-		t.Fatalf("Expected to fail but succeeded")
-	}
-	if errRsp.StatusCode != http.StatusBadRequest {
-		t.Fatalf("Expected StatusBadRequest status code, got: %v", errRsp.StatusCode)
-	}
-
-	_, errRsp = procCreateNetwork(c, goodVars, goodBody)
+	_, errRsp = procCreateNetwork(c, vars, goodBody)
 	if errRsp != &createdResponse {
 		t.Fatalf("Unexepected failure: %v", errRsp)
 	}
 
-	_, errRsp = procDeleteNetwork(c, badVars, nil)
+	vars[urlNwName] = ""
+	_, errRsp = procDeleteNetwork(c, vars, nil)
 	if errRsp == &successResponse {
 		t.Fatalf("Expected to fail but succeeded")
 	}
 
-	badVars[urlNwName] = ""
-	_, errRsp = procDeleteNetwork(c, badVars, nil)
+	vars[urlNwName] = "abc"
+	_, errRsp = procDeleteNetwork(c, vars, nil)
 	if errRsp == &successResponse {
 		t.Fatalf("Expected to fail but succeeded")
 	}
 
-	_, errRsp = procDeleteNetwork(c, goodVars, nil)
+	vars[urlNwName] = "network_1"
+	_, errRsp = procDeleteNetwork(c, vars, nil)
 	if errRsp != &successResponse {
 		t.Fatalf("Unexepected failure: %v", errRsp)
 	}
@@ -262,7 +234,7 @@ func TestGetNetworksAndEndpoints(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	vars := map[string]string{urlNwName: "sh"}
+	vars := make(map[string]string)
 	inid, errRsp := procCreateNetwork(c, vars, body)
 	if errRsp != &createdResponse {
 		t.Fatalf("Unexepected failure: %v", errRsp)
@@ -273,29 +245,29 @@ func TestGetNetworksAndEndpoints(t *testing.T) {
 	}
 
 	ec1 := endpointCreate{
-		Name:      "ep1",
-		NetworkID: string(nid),
-		ExposedPorts: []netutils.TransportPort{
-			netutils.TransportPort{Proto: netutils.TCP, Port: uint16(5000)},
-			netutils.TransportPort{Proto: netutils.UDP, Port: uint16(400)},
-			netutils.TransportPort{Proto: netutils.TCP, Port: uint16(600)},
+		Name: "ep1",
+		ExposedPorts: []types.TransportPort{
+			types.TransportPort{Proto: types.TCP, Port: uint16(5000)},
+			types.TransportPort{Proto: types.UDP, Port: uint16(400)},
+			types.TransportPort{Proto: types.TCP, Port: uint16(600)},
 		},
-		PortMapping: []netutils.PortBinding{
-			netutils.PortBinding{Proto: netutils.TCP, Port: uint16(230), HostPort: uint16(23000)},
-			netutils.PortBinding{Proto: netutils.UDP, Port: uint16(200), HostPort: uint16(22000)},
-			netutils.PortBinding{Proto: netutils.TCP, Port: uint16(120), HostPort: uint16(12000)},
+		PortMapping: []types.PortBinding{
+			types.PortBinding{Proto: types.TCP, Port: uint16(230), HostPort: uint16(23000)},
+			types.PortBinding{Proto: types.UDP, Port: uint16(200), HostPort: uint16(22000)},
+			types.PortBinding{Proto: types.TCP, Port: uint16(120), HostPort: uint16(12000)},
 		},
 	}
 	b1, err := json.Marshal(ec1)
 	if err != nil {
 		t.Fatal(err)
 	}
-	ec2 := endpointCreate{Name: "ep2", NetworkID: nid}
+	ec2 := endpointCreate{Name: "ep2"}
 	b2, err := json.Marshal(ec2)
 	if err != nil {
 		t.Fatal(err)
 	}
 
+	vars[urlNwName] = "sh"
 	vars[urlEpName] = "ep1"
 	ieid1, errRsp := procCreateEndpoint(c, vars, b1)
 	if errRsp != &createdResponse {
@@ -471,6 +443,7 @@ func TestGetNetworksAndEndpoints(t *testing.T) {
 	if errRsp != &successResponse {
 		t.Fatalf("Unexepected failure: %v", errRsp)
 	}
+	delete(vars, urlEpName)
 	iepList, errRsp = procGetEndpoints(c, vars, nil)
 	if errRsp != &successResponse {
 		t.Fatalf("Unexepected failure: %v", errRsp)
@@ -509,6 +482,43 @@ func TestGetNetworksAndEndpoints(t *testing.T) {
 	}
 }
 
+func TestDetectGetNetworksInvalidQueryComposition(t *testing.T) {
+	c, err := libnetwork.New()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	vars := map[string]string{urlNwName: "x", urlNwPID: "y"}
+	_, errRsp := procGetNetworks(c, vars, nil)
+	if errRsp.StatusCode != http.StatusBadRequest {
+		t.Fatalf("Expected %d. Got: %v", http.StatusBadRequest, errRsp)
+	}
+}
+
+func TestDetectGetEndpointsInvalidQueryComposition(t *testing.T) {
+	defer netutils.SetupTestNetNS(t)()
+
+	c, err := libnetwork.New()
+	if err != nil {
+		t.Fatal(err)
+	}
+	err = c.ConfigureNetworkDriver(bridgeNetType, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	_, err = c.NewNetwork(bridgeNetType, "network", nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	vars := map[string]string{urlNwName: "network", urlEpName: "x", urlEpPID: "y"}
+	_, errRsp := procGetEndpoints(c, vars, nil)
+	if errRsp.StatusCode != http.StatusBadRequest {
+		t.Fatalf("Expected %d. Got: %v", http.StatusBadRequest, errRsp)
+	}
+}
+
 func TestFindNetworkUtil(t *testing.T) {
 	defer netutils.SetupTestNetNS(t)()
 
@@ -603,85 +613,46 @@ func TestCreateDeleteEndpoints(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	vars := map[string]string{urlNwName: "firstNet"}
+	vars := make(map[string]string)
 	i, errRsp := procCreateNetwork(c, vars, body)
 	if errRsp != &createdResponse {
 		t.Fatalf("Unexepected failure: %v", errRsp)
 	}
 	nid := i2s(i)
 
-	vbad, err := json.Marshal("bad endppint create data")
+	vbad, err := json.Marshal("bad endppoint create data")
 	if err != nil {
 		t.Fatal(err)
 	}
 
-	vars[urlEpName] = "ep1"
+	vars[urlNwName] = "firstNet"
 	_, errRsp = procCreateEndpoint(c, vars, vbad)
 	if errRsp == &createdResponse {
 		t.Fatalf("Expected to fail but succeeded")
 	}
 
-	bad, err := json.Marshal(endpointCreate{Name: "ep1", NetworkID: "123456"})
-	if err != nil {
-		t.Fatal(err)
-	}
-	_, errRsp = procCreateEndpoint(c, vars, bad)
-	if errRsp == &createdResponse {
-		t.Fatalf("Expected to fail but succeeded")
-	}
-
-	soso, err := json.Marshal(endpointCreate{Name: "ep11", NetworkID: nid})
-	if err != nil {
-		t.Fatal(err)
-	}
-	_, errRsp = procCreateEndpoint(c, vars, soso)
-	if errRsp != &mismatchResponse {
-		t.Fatalf("Expected to fail with \"mismatchResponse\", but got: %v", errRsp)
-	}
-
-	bla, err := json.Marshal(endpointCreate{Name: "", NetworkID: nid})
-	if err != nil {
-		t.Fatal(err)
-	}
-	vars[urlNwName] = "firstNet"
-	vars[urlEpName] = ""
-	_, errRsp = procCreateEndpoint(c, vars, bla)
-	if errRsp == &createdResponse {
-		t.Fatalf("Expected to fail but succeeded: %v", errRsp)
-	}
-
-	b, err := json.Marshal(endpointCreate{Name: "firstEp", NetworkID: nid})
+	b, err := json.Marshal(endpointCreate{Name: ""})
 	if err != nil {
 		t.Fatal(err)
 	}
 
 	vars[urlNwName] = "secondNet"
-	vars[urlEpName] = "firstEp"
 	_, errRsp = procCreateEndpoint(c, vars, b)
 	if errRsp == &createdResponse {
 		t.Fatalf("Expected to fail but succeeded")
 	}
 
 	vars[urlNwName] = "firstNet"
-	vars[urlEpName] = "ep1"
-	_, errRsp = procCreateEndpoint(c, vars, b)
-	if errRsp != &mismatchResponse {
-		t.Fatalf("Expected to fail with \"mismatchResponse\", but got: %v", errRsp)
-	}
-
-	vars = make(map[string]string)
 	_, errRsp = procCreateEndpoint(c, vars, b)
 	if errRsp == &successResponse {
 		t.Fatalf("Expected failure but succeeded: %v", errRsp)
 	}
 
-	vars[urlNwName] = "firstNet"
-	_, errRsp = procCreateEndpoint(c, vars, b)
-	if errRsp == &successResponse {
-		t.Fatalf("Expected failure but succeeded: %v", errRsp)
+	b, err = json.Marshal(endpointCreate{Name: "firstEp"})
+	if err != nil {
+		t.Fatal(err)
 	}
 
-	vars[urlEpName] = "firstEp"
 	i, errRsp = procCreateEndpoint(c, vars, b)
 	if errRsp != &createdResponse {
 		t.Fatalf("Unexepected failure: %v", errRsp)
@@ -713,8 +684,8 @@ func TestCreateDeleteEndpoints(t *testing.T) {
 		t.Fatalf("Unexepected failure: %v", errRsp)
 	}
 
-	if ep0 != ep1 || ep0 != ep2 || ep0 != ep3 {
-		t.Fatalf("Diffenrent queries returned different endpoints")
+	if ep0.ID() != ep1.ID() || ep0.ID() != ep2.ID() || ep0.ID() != ep3.ID() {
+		t.Fatalf("Diffenrent queries returned different endpoints: \nep0: %v\nep1: %v\nep2: %v\nep3: %v", ep0, ep1, ep2, ep3)
 	}
 
 	vars = make(map[string]string)
@@ -766,18 +737,17 @@ func TestJoinLeave(t *testing.T) {
 	if err != nil {
 		t.Fatal(err)
 	}
-	vars := map[string]string{urlNwName: "network"}
-	i, errRsp := procCreateNetwork(c, vars, nb)
+	vars := make(map[string]string)
+	_, errRsp := procCreateNetwork(c, vars, nb)
 	if errRsp != &createdResponse {
 		t.Fatalf("Unexepected failure: %v", errRsp)
 	}
-	nid := i2s(i)
 
-	vars[urlEpName] = "epoint"
-	eb, err := json.Marshal(endpointCreate{Name: "epoint", NetworkID: nid})
+	eb, err := json.Marshal(endpointCreate{Name: "endpoint"})
 	if err != nil {
 		t.Fatal(err)
 	}
+	vars[urlNwName] = "network"
 	_, errRsp = procCreateEndpoint(c, vars, eb)
 	if errRsp != &createdResponse {
 		t.Fatalf("Unexepected failure: %v", errRsp)
@@ -792,6 +762,7 @@ func TestJoinLeave(t *testing.T) {
 		t.Fatalf("Expected failure, got: %v", errRsp)
 	}
 
+	vars[urlEpName] = "endpoint"
 	bad, err := json.Marshal(endpointJoin{})
 	if err != nil {
 		t.Fatal(err)
@@ -811,44 +782,30 @@ func TestJoinLeave(t *testing.T) {
 	vars = make(map[string]string)
 	vars[urlNwName] = ""
 	vars[urlEpName] = ""
-	vars[urlCnID] = cid
-	_, errRsp = procJoinEndpoint(c, vars, jlb)
-	if errRsp == &successResponse {
-		t.Fatalf("Expected failure, got: %v", errRsp)
-	}
-
-	vars[urlNwName] = "network1"
-	vars[urlEpName] = ""
 	_, errRsp = procJoinEndpoint(c, vars, jlb)
 	if errRsp == &successResponse {
 		t.Fatalf("Expected failure, got: %v", errRsp)
 	}
 
 	vars[urlNwName] = "network"
-	vars[urlEpName] = "endpoint"
+	vars[urlEpName] = ""
 	_, errRsp = procJoinEndpoint(c, vars, jlb)
 	if errRsp == &successResponse {
 		t.Fatalf("Expected failure, got: %v", errRsp)
 	}
 
 	vars[urlEpName] = "epoint"
-	delete(vars, urlCnID)
 	_, errRsp = procJoinEndpoint(c, vars, jlb)
 	if errRsp == &successResponse {
 		t.Fatalf("Expected failure, got: %v", errRsp)
 	}
 
-	vars[urlCnID] = "who?"
-	_, errRsp = procJoinEndpoint(c, vars, jlb)
-	if errRsp == &successResponse {
-		t.Fatalf("Expected failure, got: %v", errRsp)
-	}
-
-	vars[urlCnID] = cid
+	vars[urlEpName] = "endpoint"
 	cdi, errRsp := procJoinEndpoint(c, vars, jlb)
 	if errRsp != &successResponse {
-		t.Fatalf("Unexpected failure, got: %v", errRsp)
+		t.Fatalf("Expected failure, got: %v", errRsp)
 	}
+
 	cd := i2c(cdi)
 	if cd.SandboxKey == "" {
 		t.Fatalf("Empty sandbox key")
@@ -897,6 +854,7 @@ func TestJoinLeave(t *testing.T) {
 	}
 
 	delete(vars, urlCnID)
+	vars[urlEpName] = "endpoint"
 	_, errRsp = procLeaveEndpoint(c, vars, jlb)
 	if errRsp == &successResponse {
 		t.Fatalf("Expected failure, got: %v", errRsp)
@@ -1178,7 +1136,7 @@ func TestHttpHandlerUninit(t *testing.T) {
 	}
 
 	rsp := newWriter()
-	req, err := http.NewRequest("GET", "/networks", nil)
+	req, err := http.NewRequest("GET", "/v1.19/networks", nil)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1193,15 +1151,24 @@ func TestHttpHandlerUninit(t *testing.T) {
 
 	handleRequest(rsp, req)
 	if rsp.statusCode != http.StatusOK {
-		t.Fatalf("Unexpectded failure: (%d): %s", rsp.statusCode, rsp.body)
+		t.Fatalf("Expected (%d). Got: (%d): %s", http.StatusOK, rsp.statusCode, rsp.body)
 	}
 
-	n, err := c.NewNetwork(bridgeNetType, "onenet", nil)
+	var list []*networkResource
+	err = json.Unmarshal(rsp.body, &list)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if len(list) != 0 {
+		t.Fatalf("Expected empty list. Got %v", list)
+	}
+
+	n, err := c.NewNetwork(bridgeNetType, "didietro", nil)
 	if err != nil {
 		t.Fatal(err)
 	}
 	nwr := buildNetworkResource(n)
-	expected, err := json.Marshal([]networkResource{*nwr})
+	expected, err := json.Marshal([]*networkResource{nwr})
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1229,7 +1196,7 @@ func TestHttpHandlerBadBody(t *testing.T) {
 	}
 	handleRequest := NewHTTPHandler(c)
 
-	req, err := http.NewRequest("POST", "/networks/name/zero-network", &localReader{beBad: true})
+	req, err := http.NewRequest("POST", "/v1.19/networks", &localReader{beBad: true})
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1240,7 +1207,7 @@ func TestHttpHandlerBadBody(t *testing.T) {
 
 	body := []byte{}
 	lr := newLocalReader(body)
-	req, err = http.NewRequest("POST", "/networks/name/zero-network", lr)
+	req, err = http.NewRequest("POST", "/v1.19/networks", lr)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1250,7 +1217,7 @@ func TestHttpHandlerBadBody(t *testing.T) {
 	}
 }
 
-func TestHttpHandlerGood(t *testing.T) {
+func TestEndToEnd(t *testing.T) {
 	defer netutils.SetupTestNetNS(t)()
 
 	rsp := newWriter()
@@ -1261,14 +1228,14 @@ func TestHttpHandlerGood(t *testing.T) {
 	}
 	handleRequest := NewHTTPHandler(c)
 
-	nc := networkCreate{Name: "zero-network", NetworkType: bridgeNetType}
+	// Create network
+	nc := networkCreate{Name: "network-fiftyfive", NetworkType: bridgeNetType}
 	body, err := json.Marshal(nc)
 	if err != nil {
 		t.Fatal(err)
 	}
-
 	lr := newLocalReader(body)
-	req, err := http.NewRequest("POST", "/networks/name/zero-network", lr)
+	req, err := http.NewRequest("POST", "/v1.19/networks", lr)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1280,13 +1247,102 @@ func TestHttpHandlerGood(t *testing.T) {
 		t.Fatalf("Empty response body")
 	}
 
-	var id string
-	err = json.Unmarshal(rsp.body, &id)
+	var nid string
+	err = json.Unmarshal(rsp.body, &nid)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// Query networks collection
+	req, err = http.NewRequest("GET", "/v1.19/networks", nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	handleRequest(rsp, req)
+	if rsp.statusCode != http.StatusOK {
+		t.Fatalf("Expected StatusOK. Got (%d): %s", rsp.statusCode, rsp.body)
+	}
+
+	b0 := make([]byte, len(rsp.body))
+	copy(b0, rsp.body)
+
+	req, err = http.NewRequest("GET", "/v1.19/networks?name=network-fiftyfive", nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	handleRequest(rsp, req)
+	if rsp.statusCode != http.StatusOK {
+		t.Fatalf("Expected StatusOK. Got (%d): %s", rsp.statusCode, rsp.body)
+	}
+
+	if !bytes.Equal(b0, rsp.body) {
+		t.Fatalf("Expected same body from GET /networks and GET /networks?name=<nw> when only network <nw> exist.")
+	}
+
+	// Query network by name
+	req, err = http.NewRequest("GET", "/v1.19/networks?name=culo", nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	handleRequest(rsp, req)
+	if rsp.statusCode != http.StatusOK {
+		t.Fatalf("Expected StatusOK. Got (%d): %s", rsp.statusCode, rsp.body)
+	}
+
+	var list []*networkResource
+	err = json.Unmarshal(rsp.body, &list)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if len(list) != 0 {
+		t.Fatalf("Expected empty list. Got %v", list)
+	}
+
+	req, err = http.NewRequest("GET", "/v1.19/networks?name=network-fiftyfive", nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	handleRequest(rsp, req)
+	if rsp.statusCode != http.StatusOK {
+		t.Fatalf("Unexpectded failure: (%d): %s", rsp.statusCode, rsp.body)
+	}
+
+	err = json.Unmarshal(rsp.body, &list)
 	if err != nil {
 		t.Fatal(err)
 	}
+	if len(list) == 0 {
+		t.Fatalf("Expected non empty list")
+	}
+	if list[0].Name != "network-fiftyfive" || nid != list[0].ID {
+		t.Fatalf("Incongruent resource found: %v", list[0])
+	}
 
-	req, err = http.NewRequest("GET", "/networks/id/"+id, nil)
+	// Query network by partial id
+	chars := []byte(nid)
+	partial := string(chars[0 : len(chars)/2])
+	req, err = http.NewRequest("GET", "/v1.19/networks?partial-id="+partial, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	handleRequest(rsp, req)
+	if rsp.statusCode != http.StatusOK {
+		t.Fatalf("Unexpectded failure: (%d): %s", rsp.statusCode, rsp.body)
+	}
+
+	err = json.Unmarshal(rsp.body, &list)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if len(list) == 0 {
+		t.Fatalf("Expected non empty list")
+	}
+	if list[0].Name != "network-fiftyfive" || nid != list[0].ID {
+		t.Fatalf("Incongruent resource found: %v", list[0])
+	}
+
+	// Get network by id
+	req, err = http.NewRequest("GET", "/v1.19/networks/"+nid, nil)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1300,7 +1356,211 @@ func TestHttpHandlerGood(t *testing.T) {
 	if err != nil {
 		t.Fatal(err)
 	}
-	if nwr.Name != "zero-network" || id != nwr.ID {
-		t.Fatalf("Incongruent resource found")
+	if nwr.Name != "network-fiftyfive" || nid != nwr.ID {
+		t.Fatalf("Incongruent resource found: %v", nwr)
+	}
+
+	// Create endpoint
+	eb, err := json.Marshal(endpointCreate{Name: "ep-TwentyTwo"})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	lr = newLocalReader(eb)
+	req, err = http.NewRequest("POST", "/v1.19/networks/"+nid+"/endpoints", lr)
+	if err != nil {
+		t.Fatal(err)
+	}
+	handleRequest(rsp, req)
+	if rsp.statusCode != http.StatusCreated {
+		t.Fatalf("Unexpectded status code. Expected (%d). Got (%d): %s.", http.StatusCreated, rsp.statusCode, string(rsp.body))
+	}
+	if len(rsp.body) == 0 {
+		t.Fatalf("Empty response body")
+	}
+
+	var eid string
+	err = json.Unmarshal(rsp.body, &eid)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// Query endpoint(s)
+	req, err = http.NewRequest("GET", "/v1.19/networks/"+nid+"/endpoints", nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	handleRequest(rsp, req)
+	if rsp.statusCode != http.StatusOK {
+		t.Fatalf("Expected StatusOK. Got (%d): %s", rsp.statusCode, rsp.body)
+	}
+
+	req, err = http.NewRequest("GET", "/v1.19/networks/"+nid+"/endpoints?name=bla", nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	handleRequest(rsp, req)
+	if rsp.statusCode != http.StatusOK {
+		t.Fatalf("Unexpectded failure: (%d): %s", rsp.statusCode, rsp.body)
+	}
+	var epList []*endpointResource
+	err = json.Unmarshal(rsp.body, &epList)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if len(epList) != 0 {
+		t.Fatalf("Expected empty list. Got %v", epList)
+	}
+
+	// Query endpoint by name
+	req, err = http.NewRequest("GET", "/v1.19/networks/"+nid+"/endpoints?name=ep-TwentyTwo", nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	handleRequest(rsp, req)
+	if rsp.statusCode != http.StatusOK {
+		t.Fatalf("Unexpectded failure: (%d): %s", rsp.statusCode, rsp.body)
+	}
+
+	err = json.Unmarshal(rsp.body, &epList)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if len(epList) == 0 {
+		t.Fatalf("Empty response body")
+	}
+	if epList[0].Name != "ep-TwentyTwo" || eid != epList[0].ID {
+		t.Fatalf("Incongruent resource found: %v", epList[0])
+	}
+
+	// Query endpoint by partial id
+	chars = []byte(eid)
+	partial = string(chars[0 : len(chars)/2])
+	req, err = http.NewRequest("GET", "/v1.19/networks/"+nid+"/endpoints?partial-id="+partial, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	handleRequest(rsp, req)
+	if rsp.statusCode != http.StatusOK {
+		t.Fatalf("Unexpectded failure: (%d): %s", rsp.statusCode, rsp.body)
+	}
+
+	err = json.Unmarshal(rsp.body, &epList)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if len(epList) == 0 {
+		t.Fatalf("Empty response body")
+	}
+	if epList[0].Name != "ep-TwentyTwo" || eid != epList[0].ID {
+		t.Fatalf("Incongruent resource found: %v", epList[0])
+	}
+
+	// Get endpoint by id
+	req, err = http.NewRequest("GET", "/v1.19/networks/"+nid+"/endpoints/"+eid, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	handleRequest(rsp, req)
+	if rsp.statusCode != http.StatusOK {
+		t.Fatalf("Unexpectded failure: (%d): %s", rsp.statusCode, rsp.body)
+	}
+
+	var epr endpointResource
+	err = json.Unmarshal(rsp.body, &epr)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if epr.Name != "ep-TwentyTwo" || epr.ID != eid {
+		t.Fatalf("Incongruent resource found: %v", epr)
+	}
+}
+
+type bre struct{}
+
+func (b *bre) Error() string {
+	return "I am a bad request error"
+}
+func (b *bre) BadRequest() {}
+
+type nfe struct{}
+
+func (n *nfe) Error() string {
+	return "I am a not found error"
+}
+func (n *nfe) NotFound() {}
+
+type forb struct{}
+
+func (f *forb) Error() string {
+	return "I am a bad request error"
+}
+func (f *forb) Forbidden() {}
+
+type notimpl struct{}
+
+func (nip *notimpl) Error() string {
+	return "I am a not implemented error"
+}
+func (nip *notimpl) NotImplemented() {}
+
+type inter struct{}
+
+func (it *inter) Error() string {
+	return "I am a internal error"
+}
+func (it *inter) Internal() {}
+
+type tout struct{}
+
+func (to *tout) Error() string {
+	return "I am a timeout error"
+}
+func (to *tout) Timeout() {}
+
+type noserv struct{}
+
+func (nos *noserv) Error() string {
+	return "I am a no service error"
+}
+func (nos *noserv) NoService() {}
+
+type notclassified struct{}
+
+func (noc *notclassified) Error() string {
+	return "I am a non classified error"
+}
+
+func TestErrorConversion(t *testing.T) {
+	if convertNetworkError(new(bre)).StatusCode != http.StatusBadRequest {
+		t.Fatalf("Failed to recognize BadRequest error")
+	}
+
+	if convertNetworkError(new(nfe)).StatusCode != http.StatusNotFound {
+		t.Fatalf("Failed to recognize NotFound error")
+	}
+
+	if convertNetworkError(new(forb)).StatusCode != http.StatusForbidden {
+		t.Fatalf("Failed to recognize Forbidden error")
+	}
+
+	if convertNetworkError(new(notimpl)).StatusCode != http.StatusNotImplemented {
+		t.Fatalf("Failed to recognize NotImplemented error")
+	}
+
+	if convertNetworkError(new(inter)).StatusCode != http.StatusInternalServerError {
+		t.Fatalf("Failed to recognize Internal error")
+	}
+
+	if convertNetworkError(new(tout)).StatusCode != http.StatusRequestTimeout {
+		t.Fatalf("Failed to recognize Timeout error")
+	}
+
+	if convertNetworkError(new(noserv)).StatusCode != http.StatusServiceUnavailable {
+		t.Fatalf("Failed to recognize No Service error")
+	}
+
+	if convertNetworkError(new(notclassified)).StatusCode != http.StatusInternalServerError {
+		t.Fatalf("Failed to recognize not classified error as Internal error")
 	}
 }

+ 3 - 4
vendor/src/github.com/docker/libnetwork/api/types.go

@@ -1,6 +1,6 @@
 package api
 
-import "github.com/docker/libnetwork/netutils"
+import "github.com/docker/libnetwork/types"
 
 /***********
  Resources
@@ -35,9 +35,8 @@ type networkCreate struct {
 // endpointCreate represents the body of the "create endpoint" http request message
 type endpointCreate struct {
 	Name         string
-	NetworkID    string
-	ExposedPorts []netutils.TransportPort
-	PortMapping  []netutils.PortBinding
+	ExposedPorts []types.TransportPort
+	PortMapping  []types.PortBinding
 }
 
 // endpointJoin represents the expected body of the "join endpoint" or "leave endpoint" http request messages

+ 6 - 0
vendor/src/github.com/docker/libnetwork/client/client.go

@@ -49,6 +49,12 @@ func (cli *NetworkCli) getMethod(args ...string) (func(string, ...string) error,
 // Cmd is borrowed from Docker UI and acts as the entry point for network UI commands.
 // network UI commands are designed to be invoked from multiple parent chains
 func (cli *NetworkCli) Cmd(chain string, args ...string) error {
+	if len(args) > 2 {
+		method, exists := cli.getMethod(args[:3]...)
+		if exists {
+			return method(chain+" "+args[0]+" "+args[1], args[3:]...)
+		}
+	}
 	if len(args) > 1 {
 		method, exists := cli.getMethod(args[:2]...)
 		if exists {

+ 124 - 0
vendor/src/github.com/docker/libnetwork/client/client_experimental_test.go

@@ -0,0 +1,124 @@
+// +build experimental
+
+package client
+
+import (
+	"bytes"
+	"testing"
+
+	_ "github.com/docker/libnetwork/netutils"
+)
+
+func TestClientNetworkServiceInvalidCommand(t *testing.T) {
+	var out, errOut bytes.Buffer
+	cli := NewNetworkCli(&out, &errOut, callbackFunc)
+
+	err := cli.Cmd("docker", "network", "service", "invalid")
+	if err == nil {
+		t.Fatalf("Passing invalid commands must fail")
+	}
+}
+
+func TestClientNetworkServiceCreate(t *testing.T) {
+	var out, errOut bytes.Buffer
+	cli := NewNetworkCli(&out, &errOut, callbackFunc)
+
+	err := cli.Cmd("docker", "network", "service", "create", mockServiceName, mockNwName)
+	if err != nil {
+		t.Fatal(err.Error())
+	}
+}
+
+func TestClientNetworkServiceRm(t *testing.T) {
+	var out, errOut bytes.Buffer
+	cli := NewNetworkCli(&out, &errOut, callbackFunc)
+
+	err := cli.Cmd("docker", "network", "service", "rm", mockServiceName, mockNwName)
+	if err != nil {
+		t.Fatal(err.Error())
+	}
+}
+
+func TestClientNetworkServiceLs(t *testing.T) {
+	var out, errOut bytes.Buffer
+	cli := NewNetworkCli(&out, &errOut, callbackFunc)
+
+	err := cli.Cmd("docker", "network", "service", "ls", mockNwName)
+	if err != nil {
+		t.Fatal(err.Error())
+	}
+}
+
+func TestClientNetworkServiceInfo(t *testing.T) {
+	var out, errOut bytes.Buffer
+	cli := NewNetworkCli(&out, &errOut, callbackFunc)
+
+	err := cli.Cmd("docker", "network", "service", "info", mockServiceName, mockNwName)
+	if err != nil {
+		t.Fatal(err.Error())
+	}
+}
+
+func TestClientNetworkServiceInfoById(t *testing.T) {
+	var out, errOut bytes.Buffer
+	cli := NewNetworkCli(&out, &errOut, callbackFunc)
+
+	err := cli.Cmd("docker", "network", "service", "info", mockServiceID, mockNwID)
+	if err != nil {
+		t.Fatal(err.Error())
+	}
+}
+
+func TestClientNetworkServiceJoin(t *testing.T) {
+	var out, errOut bytes.Buffer
+	cli := NewNetworkCli(&out, &errOut, callbackFunc)
+
+	err := cli.Cmd("docker", "network", "service", "join", mockContainerID, mockServiceName, mockNwName)
+	if err != nil {
+		t.Fatal(err.Error())
+	}
+}
+
+func TestClientNetworkServiceLeave(t *testing.T) {
+	var out, errOut bytes.Buffer
+	cli := NewNetworkCli(&out, &errOut, callbackFunc)
+
+	err := cli.Cmd("docker", "network", "service", "leave", mockContainerID, mockServiceName, mockNwName)
+	if err != nil {
+		t.Fatal(err.Error())
+	}
+}
+
+// Docker Flag processing in flag.go uses os.Exit() frequently, even for --help
+// TODO : Handle the --help test-case in the IT when CLI is available
+/*
+func TestClientNetworkServiceCreateHelp(t *testing.T) {
+	var out, errOut bytes.Buffer
+	cFunc := func(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, int, error) {
+		return nil, 0, nil
+	}
+	cli := NewNetworkCli(&out, &errOut, callbackFunc)
+
+	err := cli.Cmd("docker", "network", "create", "--help")
+	if err != nil {
+		t.Fatalf(err.Error())
+	}
+}
+*/
+
+// Docker flag processing in flag.go uses os.Exit(1) for incorrect parameter case.
+// TODO : Handle the missing argument case in the IT when CLI is available
+/*
+func TestClientNetworkServiceCreateMissingArgument(t *testing.T) {
+	var out, errOut bytes.Buffer
+	cFunc := func(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, int, error) {
+		return nil, 0, nil
+	}
+	cli := NewNetworkCli(&out, &errOut, callbackFunc)
+
+	err := cli.Cmd("docker", "network", "create")
+	if err != nil {
+		t.Fatal(err.Error())
+	}
+}
+*/

+ 102 - 44
vendor/src/github.com/docker/libnetwork/client/client_test.go

@@ -2,7 +2,11 @@ package client
 
 import (
 	"bytes"
+	"encoding/json"
+	"fmt"
 	"io"
+	"os"
+	"strings"
 	"testing"
 
 	_ "github.com/docker/libnetwork/netutils"
@@ -15,12 +19,82 @@ type nopCloser struct {
 
 func (nopCloser) Close() error { return nil }
 
+func TestMain(m *testing.M) {
+	setupMockHTTPCallback()
+	os.Exit(m.Run())
+}
+
+var callbackFunc func(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, int, error)
+var mockNwJSON, mockNwListJSON, mockServiceJSON, mockServiceListJSON []byte
+var mockNwName = "test"
+var mockNwID = "2a3456789"
+var mockServiceName = "testSrv"
+var mockServiceID = "2a3456789"
+var mockContainerID = "2a3456789"
+
+func setupMockHTTPCallback() {
+	var list []networkResource
+	nw := networkResource{Name: mockNwName, ID: mockNwID}
+	mockNwJSON, _ = json.Marshal(nw)
+	list = append(list, nw)
+	mockNwListJSON, _ = json.Marshal(list)
+
+	var srvList []endpointResource
+	ep := endpointResource{Name: mockServiceName, ID: mockServiceID, Network: mockNwName}
+	mockServiceJSON, _ = json.Marshal(ep)
+	srvList = append(srvList, ep)
+	mockServiceListJSON, _ = json.Marshal(srvList)
+
+	callbackFunc = func(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, int, error) {
+		var rsp string
+		switch method {
+		case "GET":
+			if strings.Contains(path, fmt.Sprintf("networks?name=%s", mockNwName)) {
+				rsp = string(mockNwListJSON)
+			} else if strings.Contains(path, "networks?name=") {
+				rsp = "[]"
+			} else if strings.Contains(path, fmt.Sprintf("networks?partial-id=%s", mockNwID)) {
+				rsp = string(mockNwListJSON)
+			} else if strings.Contains(path, "networks?partial-id=") {
+				rsp = "[]"
+			} else if strings.HasSuffix(path, "networks") {
+				rsp = string(mockNwListJSON)
+			} else if strings.HasSuffix(path, "networks/"+mockNwID) {
+				rsp = string(mockNwJSON)
+			} else if strings.Contains(path, fmt.Sprintf("endpoints?name=%s", mockServiceName)) {
+				rsp = string(mockServiceListJSON)
+			} else if strings.Contains(path, "endpoints?name=") {
+				rsp = "[]"
+			} else if strings.Contains(path, fmt.Sprintf("endpoints?partial-id=%s", mockServiceID)) {
+				rsp = string(mockServiceListJSON)
+			} else if strings.Contains(path, "endpoints?partial-id=") {
+				rsp = "[]"
+			} else if strings.HasSuffix(path, "endpoints") {
+				rsp = string(mockServiceListJSON)
+			} else if strings.HasSuffix(path, "endpoints/"+mockServiceID) {
+				rsp = string(mockServiceJSON)
+			}
+		case "POST":
+			var data []byte
+			if strings.HasSuffix(path, "networks") {
+				data, _ = json.Marshal(mockNwID)
+			} else if strings.HasSuffix(path, "endpoints") {
+				data, _ = json.Marshal(mockServiceID)
+			} else if strings.HasSuffix(path, "containers") {
+				data, _ = json.Marshal(mockContainerID)
+			}
+			rsp = string(data)
+		case "PUT":
+		case "DELETE":
+			rsp = ""
+		}
+		return nopCloser{bytes.NewBufferString(rsp)}, 200, nil
+	}
+}
+
 func TestClientDummyCommand(t *testing.T) {
 	var out, errOut bytes.Buffer
-	cFunc := func(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, int, error) {
-		return nopCloser{bytes.NewBufferString("")}, 200, nil
-	}
-	cli := NewNetworkCli(&out, &errOut, cFunc)
+	cli := NewNetworkCli(&out, &errOut, callbackFunc)
 
 	err := cli.Cmd("docker", "dummy")
 	if err == nil {
@@ -30,10 +104,7 @@ func TestClientDummyCommand(t *testing.T) {
 
 func TestClientNetworkInvalidCommand(t *testing.T) {
 	var out, errOut bytes.Buffer
-	cFunc := func(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, int, error) {
-		return nopCloser{bytes.NewBufferString("")}, 200, nil
-	}
-	cli := NewNetworkCli(&out, &errOut, cFunc)
+	cli := NewNetworkCli(&out, &errOut, callbackFunc)
 
 	err := cli.Cmd("docker", "network", "invalid")
 	if err == nil {
@@ -43,12 +114,9 @@ func TestClientNetworkInvalidCommand(t *testing.T) {
 
 func TestClientNetworkCreate(t *testing.T) {
 	var out, errOut bytes.Buffer
-	cFunc := func(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, int, error) {
-		return nopCloser{bytes.NewBufferString("")}, 200, nil
-	}
-	cli := NewNetworkCli(&out, &errOut, cFunc)
+	cli := NewNetworkCli(&out, &errOut, callbackFunc)
 
-	err := cli.Cmd("docker", "network", "create", "test")
+	err := cli.Cmd("docker", "network", "create", mockNwName)
 	if err != nil {
 		t.Fatal(err.Error())
 	}
@@ -56,17 +124,14 @@ func TestClientNetworkCreate(t *testing.T) {
 
 func TestClientNetworkCreateWithDriver(t *testing.T) {
 	var out, errOut bytes.Buffer
-	cFunc := func(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, int, error) {
-		return nopCloser{bytes.NewBufferString("")}, 200, nil
-	}
-	cli := NewNetworkCli(&out, &errOut, cFunc)
+	cli := NewNetworkCli(&out, &errOut, callbackFunc)
 
-	err := cli.Cmd("docker", "network", "create", "-f=dummy", "test")
+	err := cli.Cmd("docker", "network", "create", "-f=dummy", mockNwName)
 	if err == nil {
 		t.Fatalf("Passing incorrect flags to the create command must fail")
 	}
 
-	err = cli.Cmd("docker", "network", "create", "-d=dummy", "test")
+	err = cli.Cmd("docker", "network", "create", "-d=dummy", mockNwName)
 	if err != nil {
 		t.Fatalf(err.Error())
 	}
@@ -74,12 +139,9 @@ func TestClientNetworkCreateWithDriver(t *testing.T) {
 
 func TestClientNetworkRm(t *testing.T) {
 	var out, errOut bytes.Buffer
-	cFunc := func(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, int, error) {
-		return nopCloser{bytes.NewBufferString("")}, 200, nil
-	}
-	cli := NewNetworkCli(&out, &errOut, cFunc)
+	cli := NewNetworkCli(&out, &errOut, callbackFunc)
 
-	err := cli.Cmd("docker", "network", "rm", "test")
+	err := cli.Cmd("docker", "network", "rm", mockNwName)
 	if err != nil {
 		t.Fatal(err.Error())
 	}
@@ -87,47 +149,43 @@ func TestClientNetworkRm(t *testing.T) {
 
 func TestClientNetworkLs(t *testing.T) {
 	var out, errOut bytes.Buffer
-	networks := "db,web,test"
-	cFunc := func(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, int, error) {
-		return nopCloser{bytes.NewBufferString(networks)}, 200, nil
-	}
-	cli := NewNetworkCli(&out, &errOut, cFunc)
+	cli := NewNetworkCli(&out, &errOut, callbackFunc)
 
 	err := cli.Cmd("docker", "network", "ls")
 	if err != nil {
 		t.Fatal(err.Error())
 	}
-	if out.String() != networks {
-		t.Fatal("Network List command fail to return the intended list")
-	}
 }
 
 func TestClientNetworkInfo(t *testing.T) {
 	var out, errOut bytes.Buffer
-	info := "dummy info"
-	cFunc := func(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, int, error) {
-		return nopCloser{bytes.NewBufferString(info)}, 200, nil
-	}
-	cli := NewNetworkCli(&out, &errOut, cFunc)
+	cli := NewNetworkCli(&out, &errOut, callbackFunc)
 
-	err := cli.Cmd("docker", "network", "info", "test")
+	err := cli.Cmd("docker", "network", "info", mockNwName)
 	if err != nil {
 		t.Fatal(err.Error())
 	}
-	if out.String() != info {
-		t.Fatal("Network List command fail to return the intended list")
+}
+
+func TestClientNetworkInfoById(t *testing.T) {
+	var out, errOut bytes.Buffer
+	cli := NewNetworkCli(&out, &errOut, callbackFunc)
+
+	err := cli.Cmd("docker", "network", "info", mockNwID)
+	if err != nil {
+		t.Fatal(err.Error())
 	}
 }
 
 // Docker Flag processing in flag.go uses os.Exit() frequently, even for --help
 // TODO : Handle the --help test-case in the IT when CLI is available
 /*
-func TestClientNetworkCreateHelp(t *testing.T) {
+func TestClientNetworkServiceCreateHelp(t *testing.T) {
 	var out, errOut bytes.Buffer
 	cFunc := func(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, int, error) {
 		return nil, 0, nil
 	}
-	cli := NewNetworkCli(&out, &errOut, cFunc)
+	cli := NewNetworkCli(&out, &errOut, callbackFunc)
 
 	err := cli.Cmd("docker", "network", "create", "--help")
 	if err != nil {
@@ -139,12 +197,12 @@ func TestClientNetworkCreateHelp(t *testing.T) {
 // Docker flag processing in flag.go uses os.Exit(1) for incorrect parameter case.
 // TODO : Handle the missing argument case in the IT when CLI is available
 /*
-func TestClientNetworkCreateMissingArgument(t *testing.T) {
+func TestClientNetworkServiceCreateMissingArgument(t *testing.T) {
 	var out, errOut bytes.Buffer
 	cFunc := func(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, int, error) {
 		return nil, 0, nil
 	}
-	cli := NewNetworkCli(&out, &errOut, cFunc)
+	cli := NewNetworkCli(&out, &errOut, callbackFunc)
 
 	err := cli.Cmd("docker", "network", "create")
 	if err != nil {

+ 125 - 16
vendor/src/github.com/docker/libnetwork/client/network.go

@@ -2,10 +2,13 @@ package client
 
 import (
 	"bytes"
+	"encoding/json"
 	"fmt"
-	"io"
+	"net/http"
+	"text/tabwriter"
 
 	flag "github.com/docker/docker/pkg/mflag"
+	"github.com/docker/docker/pkg/stringid"
 )
 
 const (
@@ -33,7 +36,7 @@ func (cli *NetworkCli) CmdNetwork(chain string, args ...string) error {
 	err := cmd.ParseFlags(args, true)
 	if err == nil {
 		cmd.Usage()
-		return fmt.Errorf("Invalid command : %v", args)
+		return fmt.Errorf("invalid command : %v", args)
 	}
 	return err
 }
@@ -53,31 +56,33 @@ func (cli *NetworkCli) CmdNetworkCreate(chain string, args ...string) error {
 
 	nc := networkCreate{Name: cmd.Arg(0), NetworkType: *flDriver}
 
-	obj, _, err := readBody(cli.call("POST", "/networks/name/"+cmd.Arg(0), nc, nil))
+	obj, _, err := readBody(cli.call("POST", "/networks", nc, nil))
 	if err != nil {
-		fmt.Fprintf(cli.err, "%s", err.Error())
 		return err
 	}
-	if _, err := io.Copy(cli.out, bytes.NewReader(obj)); err != nil {
+	var replyID string
+	err = json.Unmarshal(obj, &replyID)
+	if err != nil {
 		return err
 	}
+	fmt.Fprintf(cli.out, "%s\n", replyID)
 	return nil
 }
 
 // CmdNetworkRm handles Network Delete UI
 func (cli *NetworkCli) CmdNetworkRm(chain string, args ...string) error {
-	cmd := cli.Subcmd(chain, "rm", "NETWORK-NAME", "Deletes a network", false)
+	cmd := cli.Subcmd(chain, "rm", "NETWORK", "Deletes a network", false)
 	cmd.Require(flag.Min, 1)
 	err := cmd.ParseFlags(args, true)
 	if err != nil {
 		return err
 	}
-	obj, _, err := readBody(cli.call("DELETE", "/networks/name/"+cmd.Arg(0), nil, nil))
+	id, err := lookupNetworkID(cli, cmd.Arg(0))
 	if err != nil {
-		fmt.Fprintf(cli.err, "%s", err.Error())
 		return err
 	}
-	if _, err := io.Copy(cli.out, bytes.NewReader(obj)); err != nil {
+	_, _, err = readBody(cli.call("DELETE", "/networks/"+id, nil, nil))
+	if err != nil {
 		return err
 	}
 	return nil
@@ -86,45 +91,149 @@ func (cli *NetworkCli) CmdNetworkRm(chain string, args ...string) error {
 // CmdNetworkLs handles Network List UI
 func (cli *NetworkCli) CmdNetworkLs(chain string, args ...string) error {
 	cmd := cli.Subcmd(chain, "ls", "", "Lists all the networks created by the user", false)
+	quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only display numeric IDs")
+	noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Do not truncate the output")
+	nLatest := cmd.Bool([]string{"l", "-latest"}, false, "Show the latest network created")
+	last := cmd.Int([]string{"n"}, -1, "Show n last created networks")
 	err := cmd.ParseFlags(args, true)
 	if err != nil {
 		return err
 	}
 	obj, _, err := readBody(cli.call("GET", "/networks", nil, nil))
 	if err != nil {
-		fmt.Fprintf(cli.err, "%s", err.Error())
 		return err
 	}
-	if _, err := io.Copy(cli.out, bytes.NewReader(obj)); err != nil {
+	if *last == -1 && *nLatest {
+		*last = 1
+	}
+
+	var networkResources []networkResource
+	err = json.Unmarshal(obj, &networkResources)
+	if err != nil {
 		return err
 	}
+
+	wr := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
+
+	// unless quiet (-q) is specified, print field titles
+	if !*quiet {
+		fmt.Fprintln(wr, "NETWORK ID\tNAME\tTYPE")
+	}
+
+	for _, networkResource := range networkResources {
+		ID := networkResource.ID
+		netName := networkResource.Name
+		if !*noTrunc {
+			ID = stringid.TruncateID(ID)
+		}
+		if *quiet {
+			fmt.Fprintln(wr, ID)
+			continue
+		}
+		netType := networkResource.Type
+		fmt.Fprintf(wr, "%s\t%s\t%s\t",
+			ID,
+			netName,
+			netType)
+		fmt.Fprint(wr, "\n")
+	}
+	wr.Flush()
 	return nil
 }
 
 // CmdNetworkInfo handles Network Info UI
 func (cli *NetworkCli) CmdNetworkInfo(chain string, args ...string) error {
-	cmd := cli.Subcmd(chain, "info", "NETWORK-NAME", "Displays detailed information on a network", false)
+	cmd := cli.Subcmd(chain, "info", "NETWORK", "Displays detailed information on a network", false)
 	cmd.Require(flag.Min, 1)
 	err := cmd.ParseFlags(args, true)
 	if err != nil {
 		return err
 	}
-	obj, _, err := readBody(cli.call("GET", "/networks/name/"+cmd.Arg(0), nil, nil))
+
+	id, err := lookupNetworkID(cli, cmd.Arg(0))
+	if err != nil {
+		return err
+	}
+
+	obj, _, err := readBody(cli.call("GET", "/networks/"+id, nil, nil))
 	if err != nil {
-		fmt.Fprintf(cli.err, "%s", err.Error())
 		return err
 	}
-	if _, err := io.Copy(cli.out, bytes.NewReader(obj)); err != nil {
+	networkResource := &networkResource{}
+	if err := json.NewDecoder(bytes.NewReader(obj)).Decode(networkResource); err != nil {
 		return err
 	}
+	fmt.Fprintf(cli.out, "Network Id: %s\n", networkResource.ID)
+	fmt.Fprintf(cli.out, "Name: %s\n", networkResource.Name)
+	fmt.Fprintf(cli.out, "Type: %s\n", networkResource.Type)
+	if networkResource.Endpoints != nil {
+		for _, endpointResource := range networkResource.Endpoints {
+			fmt.Fprintf(cli.out, "  Service Id: %s\n", endpointResource.ID)
+			fmt.Fprintf(cli.out, "\tName: %s\n", endpointResource.Name)
+		}
+	}
+
 	return nil
 }
 
+// Helper function to predict if a string is a name or id or partial-id
+// This provides a best-effort mechanism to identify a id with the help of GET Filter APIs
+// Being a UI, its most likely that name will be used by the user, which is used to lookup
+// the corresponding ID. If ID is not found, this function will assume that the passed string
+// is an ID by itself.
+
+func lookupNetworkID(cli *NetworkCli, nameID string) (string, error) {
+	obj, statusCode, err := readBody(cli.call("GET", "/networks?name="+nameID, nil, nil))
+	if err != nil {
+		return "", err
+	}
+
+	if statusCode != http.StatusOK {
+		return "", fmt.Errorf("name query failed for %s due to : statuscode(%d) %v", nameID, statusCode, string(obj))
+	}
+
+	var list []*networkResource
+	err = json.Unmarshal(obj, &list)
+	if err != nil {
+		return "", err
+	}
+	if len(list) > 0 {
+		// name query filter will always return a single-element collection
+		return list[0].ID, nil
+	}
+
+	// Check for Partial-id
+	obj, statusCode, err = readBody(cli.call("GET", "/networks?partial-id="+nameID, nil, nil))
+	if err != nil {
+		return "", err
+	}
+
+	if statusCode != http.StatusOK {
+		return "", fmt.Errorf("partial-id match query failed for %s due to : statuscode(%d) %v", nameID, statusCode, string(obj))
+	}
+
+	err = json.Unmarshal(obj, &list)
+	if err != nil {
+		return "", err
+	}
+	if len(list) == 0 {
+		return "", fmt.Errorf("resource not found %s", nameID)
+	}
+	if len(list) > 1 {
+		return "", fmt.Errorf("multiple Networks matching the partial identifier (%s). Please use full identifier", nameID)
+	}
+	return list[0].ID, nil
+}
+
 func networkUsage(chain string) string {
 	help := "Commands:\n"
 
 	for _, cmd := range networkCommands {
-		help += fmt.Sprintf("    %-10.10s%s\n", cmd.name, cmd.description)
+		help += fmt.Sprintf("    %-25.25s%s\n", cmd.name, cmd.description)
+	}
+
+	for _, cmd := range serviceCommands {
+		help += fmt.Sprintf("    %-25.25s%s\n", "service "+cmd.name, cmd.description)
 	}
 
 	help += fmt.Sprintf("\nRun '%s network COMMAND --help' for more information on a command.", chain)

+ 7 - 0
vendor/src/github.com/docker/libnetwork/client/service.go

@@ -0,0 +1,7 @@
+// +build !experimental
+
+package client
+
+var (
+	serviceCommands = []command{}
+)

+ 317 - 0
vendor/src/github.com/docker/libnetwork/client/service_experimental.go

@@ -0,0 +1,317 @@
+// +build experimental
+
+package client
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"net/http"
+	"text/tabwriter"
+
+	flag "github.com/docker/docker/pkg/mflag"
+	"github.com/docker/docker/pkg/stringid"
+)
+
+var (
+	serviceCommands = []command{
+		{"create", "Create a service endpoint"},
+		{"rm", "Remove a service endpoint"},
+		{"join", "Join a container to a service endpoint"},
+		{"leave", "Leave a container from a service endpoint"},
+		{"ls", "Lists all service endpoints on a network"},
+		{"info", "Display information of a service endpoint"},
+	}
+)
+
+func lookupServiceID(cli *NetworkCli, networkID string, nameID string) (string, error) {
+	obj, statusCode, err := readBody(cli.call("GET", fmt.Sprintf("/networks/%s/endpoints?name=%s", networkID, nameID), nil, nil))
+	if err != nil {
+		return "", err
+	}
+
+	if statusCode != http.StatusOK {
+		return "", fmt.Errorf("name query failed for %s due to : statuscode(%d) %v", nameID, statusCode, string(obj))
+	}
+
+	var list []*networkResource
+	err = json.Unmarshal(obj, &list)
+	if err != nil {
+		return "", err
+	}
+	if len(list) > 0 {
+		// name query filter will always return a single-element collection
+		return list[0].ID, nil
+	}
+
+	// Check for Partial-id
+	obj, statusCode, err = readBody(cli.call("GET", fmt.Sprintf("/networks/%s/endpoints?partial-id=%s", networkID, nameID), nil, nil))
+	if err != nil {
+		return "", err
+	}
+
+	if statusCode != http.StatusOK {
+		return "", fmt.Errorf("partial-id match query failed for %s due to : statuscode(%d) %v", nameID, statusCode, string(obj))
+	}
+
+	err = json.Unmarshal(obj, &list)
+	if err != nil {
+		return "", err
+	}
+	if len(list) == 0 {
+		return "", fmt.Errorf("resource not found %s", nameID)
+	}
+	if len(list) > 1 {
+		return "", fmt.Errorf("multiple services matching the partial identifier (%s). Please use full identifier", nameID)
+	}
+	return list[0].ID, nil
+}
+
+func lookupContainerID(cli *NetworkCli, nameID string) (string, error) {
+	// TODO : containerID to sandbox-key ?
+	return nameID, nil
+}
+
+// CmdNetworkService handles the network service UI
+func (cli *NetworkCli) CmdNetworkService(chain string, args ...string) error {
+	cmd := cli.Subcmd(chain, "service", "COMMAND [OPTIONS] [arg...]", serviceUsage(chain), false)
+	cmd.Require(flag.Min, 1)
+	err := cmd.ParseFlags(args, true)
+	if err == nil {
+		cmd.Usage()
+		return fmt.Errorf("Invalid command : %v", args)
+	}
+	return err
+}
+
+// CmdNetworkServiceCreate handles service create UI
+func (cli *NetworkCli) CmdNetworkServiceCreate(chain string, args ...string) error {
+	cmd := cli.Subcmd(chain, "create", "SERVICE NETWORK", "Creates a new service on a network", false)
+	cmd.Require(flag.Min, 2)
+	err := cmd.ParseFlags(args, true)
+	if err != nil {
+		return err
+	}
+
+	networkID, err := lookupNetworkID(cli, cmd.Arg(1))
+	if err != nil {
+		return err
+	}
+
+	ec := endpointCreate{Name: cmd.Arg(0), NetworkID: networkID}
+
+	obj, _, err := readBody(cli.call("POST", "/networks/"+networkID+"/endpoints", ec, nil))
+	if err != nil {
+		return err
+	}
+
+	var replyID string
+	err = json.Unmarshal(obj, &replyID)
+	if err != nil {
+		return err
+	}
+
+	fmt.Fprintf(cli.out, "%s\n", replyID)
+	return nil
+}
+
+// CmdNetworkServiceRm handles service delete UI
+func (cli *NetworkCli) CmdNetworkServiceRm(chain string, args ...string) error {
+	cmd := cli.Subcmd(chain, "rm", "SERVICE NETWORK", "Deletes a service", false)
+	cmd.Require(flag.Min, 2)
+	err := cmd.ParseFlags(args, true)
+	if err != nil {
+		return err
+	}
+
+	networkID, err := lookupNetworkID(cli, cmd.Arg(1))
+	if err != nil {
+		return err
+	}
+
+	serviceID, err := lookupServiceID(cli, networkID, cmd.Arg(0))
+	if err != nil {
+		return err
+	}
+
+	_, _, err = readBody(cli.call("DELETE", "/networks/"+networkID+"/endpoints/"+serviceID, nil, nil))
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+// CmdNetworkServiceLs handles service list UI
+func (cli *NetworkCli) CmdNetworkServiceLs(chain string, args ...string) error {
+	cmd := cli.Subcmd(chain, "ls", "NETWORK", "Lists all the services on a network", false)
+	quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only display numeric IDs")
+	noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Do not truncate the output")
+	nLatest := cmd.Bool([]string{"l", "-latest"}, false, "Show the latest network created")
+	last := cmd.Int([]string{"n"}, -1, "Show n last created networks")
+	err := cmd.ParseFlags(args, true)
+	if err != nil {
+		return err
+	}
+
+	cmd.Require(flag.Min, 1)
+
+	networkID, err := lookupNetworkID(cli, cmd.Arg(0))
+	if err != nil {
+		return err
+	}
+
+	obj, _, err := readBody(cli.call("GET", "/networks/"+networkID+"/endpoints", nil, nil))
+	if err != nil {
+		fmt.Fprintf(cli.err, "%s", err.Error())
+		return err
+	}
+	if *last == -1 && *nLatest {
+		*last = 1
+	}
+
+	var endpointResources []endpointResource
+	err = json.Unmarshal(obj, &endpointResources)
+	if err != nil {
+		return err
+	}
+
+	wr := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
+	// unless quiet (-q) is specified, print field titles
+	if !*quiet {
+		fmt.Fprintln(wr, "NETWORK SERVICE ID\tNAME\tNETWORK")
+	}
+
+	for _, networkResource := range endpointResources {
+		ID := networkResource.ID
+		netName := networkResource.Name
+		if !*noTrunc {
+			ID = stringid.TruncateID(ID)
+		}
+		if *quiet {
+			fmt.Fprintln(wr, ID)
+			continue
+		}
+		network := networkResource.Network
+		fmt.Fprintf(wr, "%s\t%s\t%s",
+			ID,
+			netName,
+			network)
+		fmt.Fprint(wr, "\n")
+	}
+	wr.Flush()
+
+	return nil
+}
+
+// CmdNetworkServiceInfo handles service info UI
+func (cli *NetworkCli) CmdNetworkServiceInfo(chain string, args ...string) error {
+	cmd := cli.Subcmd(chain, "info", "SERVICE NETWORK", "Displays detailed information on a service", false)
+	cmd.Require(flag.Min, 2)
+	err := cmd.ParseFlags(args, true)
+	if err != nil {
+		return err
+	}
+
+	networkID, err := lookupNetworkID(cli, cmd.Arg(1))
+	if err != nil {
+		return err
+	}
+
+	serviceID, err := lookupServiceID(cli, networkID, cmd.Arg(0))
+	if err != nil {
+		return err
+	}
+
+	obj, _, err := readBody(cli.call("GET", "/networks/"+networkID+"/endpoints/"+serviceID, nil, nil))
+	if err != nil {
+		fmt.Fprintf(cli.err, "%s", err.Error())
+		return err
+	}
+
+	endpointResource := &endpointResource{}
+	if err := json.NewDecoder(bytes.NewReader(obj)).Decode(endpointResource); err != nil {
+		return err
+	}
+	fmt.Fprintf(cli.out, "Service Id: %s\n", endpointResource.ID)
+	fmt.Fprintf(cli.out, "\tName: %s\n", endpointResource.Name)
+	fmt.Fprintf(cli.out, "\tNetwork: %s\n", endpointResource.Network)
+
+	return nil
+}
+
+// CmdNetworkServiceJoin handles service join UI
+func (cli *NetworkCli) CmdNetworkServiceJoin(chain string, args ...string) error {
+	cmd := cli.Subcmd(chain, "join", "CONTAINER SERVICE NETWORK", "Sets a container as a service backend", false)
+	cmd.Require(flag.Min, 3)
+	err := cmd.ParseFlags(args, true)
+	if err != nil {
+		return err
+	}
+
+	containerID, err := lookupContainerID(cli, cmd.Arg(0))
+	if err != nil {
+		return err
+	}
+
+	networkID, err := lookupNetworkID(cli, cmd.Arg(2))
+	if err != nil {
+		return err
+	}
+
+	serviceID, err := lookupServiceID(cli, networkID, cmd.Arg(1))
+	if err != nil {
+		return err
+	}
+
+	nc := endpointJoin{ContainerID: containerID}
+
+	_, _, err = readBody(cli.call("POST", "/networks/"+networkID+"/endpoints/"+serviceID+"/containers", nc, nil))
+	if err != nil {
+		fmt.Fprintf(cli.err, "%s", err.Error())
+		return err
+	}
+	return nil
+}
+
+// CmdNetworkServiceLeave handles service leave UI
+func (cli *NetworkCli) CmdNetworkServiceLeave(chain string, args ...string) error {
+	cmd := cli.Subcmd(chain, "leave", "CONTAINER SERVICE NETWORK", "Removes a container from service backend", false)
+	cmd.Require(flag.Min, 3)
+	err := cmd.ParseFlags(args, true)
+	if err != nil {
+		return err
+	}
+
+	containerID, err := lookupContainerID(cli, cmd.Arg(0))
+	if err != nil {
+		return err
+	}
+
+	networkID, err := lookupNetworkID(cli, cmd.Arg(2))
+	if err != nil {
+		return err
+	}
+
+	serviceID, err := lookupServiceID(cli, networkID, cmd.Arg(1))
+	if err != nil {
+		return err
+	}
+
+	_, _, err = readBody(cli.call("DELETE", "/networks/"+networkID+"/endpoints/"+serviceID+"/containers/"+containerID, nil, nil))
+	if err != nil {
+		fmt.Fprintf(cli.err, "%s", err.Error())
+		return err
+	}
+	return nil
+}
+
+func serviceUsage(chain string) string {
+	help := "Commands:\n"
+
+	for _, cmd := range serviceCommands {
+		help += fmt.Sprintf("    %-10.10s%s\n", cmd, cmd.description)
+	}
+
+	help += fmt.Sprintf("\nRun '%s service COMMAND --help' for more information on a command.", chain)
+	return help
+}

+ 36 - 2
vendor/src/github.com/docker/libnetwork/client/types.go

@@ -1,6 +1,6 @@
 package client
 
-import "github.com/docker/libnetwork/sandbox"
+import "github.com/docker/libnetwork/types"
 
 /***********
  Resources
@@ -19,7 +19,6 @@ type endpointResource struct {
 	Name    string
 	ID      string
 	Network string
-	Info    sandbox.Info
 }
 
 /***********
@@ -32,3 +31,38 @@ type networkCreate struct {
 	NetworkType string
 	Options     map[string]interface{}
 }
+
+// endpointCreate represents the body of the "create endpoint" http request message
+type endpointCreate struct {
+	Name         string
+	NetworkID    string
+	ExposedPorts []types.TransportPort
+	PortMapping  []types.PortBinding
+}
+
+// endpointJoin represents the expected body of the "join endpoint" or "leave endpoint" http request messages
+type endpointJoin struct {
+	ContainerID       string
+	HostName          string
+	DomainName        string
+	HostsPath         string
+	ResolvConfPath    string
+	DNS               []string
+	ExtraHosts        []endpointExtraHost
+	ParentUpdates     []endpointParentUpdate
+	UseDefaultSandbox bool
+}
+
+// EndpointExtraHost represents the extra host object
+type endpointExtraHost struct {
+	Name    string
+	Address string
+}
+
+// EndpointParentUpdate is the object carrying the information about the
+// endpoint parent that needs to be updated
+type endpointParentUpdate struct {
+	EndpointID string
+	Name       string
+	Address    string
+}

+ 5 - 7
vendor/src/github.com/docker/libnetwork/cmd/dnet/dnet.go

@@ -113,10 +113,8 @@ func (d *dnetConnection) dnetDaemon() error {
 	}
 	httpHandler := api.NewHTTPHandler(controller)
 	r := mux.NewRouter().StrictSlash(false)
-	post := r.PathPrefix("/networks").Subrouter()
-	post.Methods("GET").HandlerFunc(httpHandler)
-	post.Methods("PUT", "POST").HandlerFunc(httpHandler)
-	post.Methods("DELETE").HandlerFunc(httpHandler)
+	post := r.PathPrefix("/{.*}/networks").Subrouter()
+	post.Methods("GET", "PUT", "POST", "DELETE").HandlerFunc(httpHandler)
 	return http.ListenAndServe(d.addr, r)
 }
 
@@ -143,7 +141,7 @@ func (d *dnetConnection) httpCall(method, path string, data interface{}, headers
 		return nil, -1, err
 	}
 
-	req, err := http.NewRequest(method, fmt.Sprintf("%s", path), in)
+	req, err := http.NewRequest(method, fmt.Sprintf("/dnet%s", path), in)
 	if err != nil {
 		return nil, -1, err
 	}
@@ -160,7 +158,7 @@ func (d *dnetConnection) httpCall(method, path string, data interface{}, headers
 		statusCode = resp.StatusCode
 	}
 	if err != nil {
-		return nil, statusCode, fmt.Errorf("An error occurred trying to connect: %v", err)
+		return nil, statusCode, fmt.Errorf("error when trying to connect: %v", err)
 	}
 
 	if statusCode < 200 || statusCode >= 400 {
@@ -168,7 +166,7 @@ func (d *dnetConnection) httpCall(method, path string, data interface{}, headers
 		if err != nil {
 			return nil, statusCode, err
 		}
-		return nil, statusCode, fmt.Errorf("Error response from daemon: %s", bytes.TrimSpace(body))
+		return nil, statusCode, fmt.Errorf("error : %s", bytes.TrimSpace(body))
 	}
 
 	return resp.Body, statusCode, nil

+ 1 - 1
vendor/src/github.com/docker/libnetwork/cmd/dnet/flags.go

@@ -16,7 +16,7 @@ type byName []command
 
 var (
 	flDaemon   = flag.Bool([]string{"d", "-daemon"}, false, "Enable daemon mode")
-	flHost     = flag.String([]string{"H", "-Host"}, "", "Daemon socket to connect to")
+	flHost     = flag.String([]string{"H", "-host"}, "", "Daemon socket to connect to")
 	flLogLevel = flag.String([]string{"l", "-log-level"}, "info", "Set the logging level")
 	flDebug    = flag.Bool([]string{"D", "-debug"}, false, "Enable debug mode")
 	flHelp     = flag.Bool([]string{"h", "-help"}, false, "Print usage")

+ 2 - 2
vendor/src/github.com/docker/libnetwork/cmd/readme_test/readme.go

@@ -5,8 +5,8 @@ import (
 
 	"github.com/docker/libnetwork"
 	"github.com/docker/libnetwork/netlabel"
-	"github.com/docker/libnetwork/netutils"
 	"github.com/docker/libnetwork/options"
+	"github.com/docker/libnetwork/types"
 )
 
 func main() {
@@ -58,7 +58,7 @@ func main() {
 	epInfo, err := ep.DriverInfo()
 	mapData, ok := epInfo[netlabel.PortMap]
 	if ok {
-		portMapping, ok := mapData.([]netutils.PortBinding)
+		portMapping, ok := mapData.([]types.PortBinding)
 		if ok {
 			fmt.Printf("Current port mapping for endpoint %s: %v", ep.Name(), portMapping)
 		}

+ 9 - 6
vendor/src/github.com/docker/libnetwork/controller.go

@@ -134,7 +134,7 @@ func (c *controller) RegisterDriver(networkType string, driver driverapi.Driver)
 // are network specific and modeled in a generic way.
 func (c *controller) NewNetwork(networkType, name string, options ...NetworkOption) (Network, error) {
 	if name == "" {
-		return nil, ErrInvalidName
+		return nil, ErrInvalidName(name)
 	}
 	// Check if a driver for the specified network type is available
 	c.Lock()
@@ -203,7 +203,7 @@ func (c *controller) WalkNetworks(walker NetworkWalker) {
 
 func (c *controller) NetworkByName(name string) (Network, error) {
 	if name == "" {
-		return nil, ErrInvalidName
+		return nil, ErrInvalidName(name)
 	}
 	var n Network
 
@@ -218,7 +218,7 @@ func (c *controller) NetworkByName(name string) (Network, error) {
 	c.WalkNetworks(s)
 
 	if n == nil {
-		return nil, ErrNoSuchNetwork
+		return nil, ErrNoSuchNetwork(name)
 	}
 
 	return n, nil
@@ -226,14 +226,14 @@ func (c *controller) NetworkByName(name string) (Network, error) {
 
 func (c *controller) NetworkByID(id string) (Network, error) {
 	if id == "" {
-		return nil, ErrInvalidID
+		return nil, ErrInvalidID(id)
 	}
 	c.Lock()
 	defer c.Unlock()
 	if n, ok := c.networks[types.UUID(id)]; ok {
 		return n, nil
 	}
-	return nil, ErrNoSuchNetwork
+	return nil, ErrNoSuchNetwork(id)
 }
 
 func (c *controller) sandboxAdd(key string, create bool) (sandbox.Sandbox, error) {
@@ -286,13 +286,16 @@ func (c *controller) loadDriver(networkType string) (driverapi.Driver, error) {
 	// As per the design, this Get call will result in remote driver discovery if there is a corresponding plugin available.
 	_, err := plugins.Get(networkType, driverapi.NetworkPluginEndpointType)
 	if err != nil {
+		if err == plugins.ErrNotFound {
+			return nil, types.NotFoundErrorf(err.Error())
+		}
 		return nil, err
 	}
 	c.Lock()
 	defer c.Unlock()
 	d, ok := c.drivers[networkType]
 	if !ok {
-		return nil, ErrInvalidNetworkDriver
+		return nil, ErrInvalidNetworkDriver(networkType)
 	}
 	return d, nil
 }

+ 1 - 1
vendor/src/github.com/docker/libnetwork/docs/design.md

@@ -6,7 +6,7 @@ This document describes how libnetwork has been designed in order to acheive thi
 Requirements for individual releases can be found on the [Project Page](https://github.com/docker/libnetwork/wiki)
 
 Many of the design decisions are inspired by the learnings from the Docker networking design as of Docker v1.6.
-Please refer to this [Docker v1.6 Design](https://github.com/docker/libnetwork/blob/docs/legacy.md) document for more information on networking design as of Docker v1.6.
+Please refer to this [Docker v1.6 Design](legacy.md) document for more information on networking design as of Docker v1.6.
 
 ## Goal
 

+ 2 - 23
vendor/src/github.com/docker/libnetwork/driverapi/driverapi.go

@@ -1,24 +1,11 @@
 package driverapi
 
 import (
-	"errors"
-	"fmt"
 	"net"
 
 	"github.com/docker/libnetwork/types"
 )
 
-var (
-	// ErrEndpointExists is returned if more than one endpoint is added to the network
-	ErrEndpointExists = errors.New("Endpoint already exists (Only one endpoint allowed)")
-	// ErrNoNetwork is returned if no network with the specified id exists
-	ErrNoNetwork = errors.New("No network exists")
-	// ErrNoEndpoint is returned if no endpoint with the specified id exists
-	ErrNoEndpoint = errors.New("No endpoint exists")
-	// ErrNotImplemented is returned when a Driver has not implemented an API yet
-	ErrNotImplemented = errors.New("The API is not implemented yet")
-)
-
 // NetworkPluginEndpointType represents the Endpoint Type used by Plugin system
 const NetworkPluginEndpointType = "NetworkDriver"
 
@@ -96,8 +83,8 @@ type InterfaceInfo interface {
 // InterfaceNameInfo provides a go interface for the drivers to assign names
 // to interfaces.
 type InterfaceNameInfo interface {
-	// SetNames method assigns the srcName and dstName for the interface.
-	SetNames(srcName, dstName string) error
+	// SetNames method assigns the srcName and dstPrefix for the interface.
+	SetNames(srcName, dstPrefix string) error
 
 	// ID returns the numerical id that was assigned to the interface by the driver
 	// CreateEndpoint.
@@ -124,14 +111,6 @@ type JoinInfo interface {
 	SetResolvConfPath(string) error
 }
 
-// ErrActiveRegistration represents an error when a driver is registered to a networkType that is previously registered
-type ErrActiveRegistration string
-
-// Error interface for ErrActiveRegistration
-func (ar ErrActiveRegistration) Error() string {
-	return fmt.Sprintf("Driver already registered for type %q", string(ar))
-}
-
 // DriverCallback provides a Callback interface for Drivers into LibNetwork
 type DriverCallback interface {
 	// RegisterDriver provides a way for Remote drivers to dynamically register new NetworkType and associate with a driver instance

+ 56 - 0
vendor/src/github.com/docker/libnetwork/driverapi/errors.go

@@ -0,0 +1,56 @@
+package driverapi
+
+import (
+	"fmt"
+)
+
+// ErrNoNetwork is returned if no network with the specified id exists
+type ErrNoNetwork string
+
+func (enn ErrNoNetwork) Error() string {
+	return fmt.Sprintf("No network (%s) exists", string(enn))
+}
+
+// NotFound denotes the type of this error
+func (enn ErrNoNetwork) NotFound() {}
+
+// ErrEndpointExists is returned if more than one endpoint is added to the network
+type ErrEndpointExists string
+
+func (ee ErrEndpointExists) Error() string {
+	return fmt.Sprintf("Endpoint (%s) already exists (Only one endpoint allowed)", string(ee))
+}
+
+// Forbidden denotes the type of this error
+func (ee ErrEndpointExists) Forbidden() {}
+
+// ErrNotImplemented is returned when a Driver has not implemented an API yet
+type ErrNotImplemented struct{}
+
+func (eni *ErrNotImplemented) Error() string {
+	return "The API is not implemented yet"
+}
+
+// NotImplemented denotes the type of this error
+func (eni *ErrNotImplemented) NotImplemented() {}
+
+// ErrNoEndpoint is returned if no endpoint with the specified id exists
+type ErrNoEndpoint string
+
+func (ene ErrNoEndpoint) Error() string {
+	return fmt.Sprintf("No endpoint (%s) exists", string(ene))
+}
+
+// NotFound denotes the type of this error
+func (ene ErrNoEndpoint) NotFound() {}
+
+// ErrActiveRegistration represents an error when a driver is registered to a networkType that is previously registered
+type ErrActiveRegistration string
+
+// Error interface for ErrActiveRegistration
+func (ar ErrActiveRegistration) Error() string {
+	return fmt.Sprintf("Driver already registered for type %q", string(ar))
+}
+
+// Forbidden denotes the type of this error
+func (ar ErrActiveRegistration) Forbidden() {}

+ 27 - 27
vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go

@@ -21,7 +21,7 @@ const (
 	networkType             = "bridge"
 	vethPrefix              = "veth"
 	vethLen                 = 7
-	containerVeth           = "eth0"
+	containerVethPrefix     = "eth"
 	maxAllocatePortAttempts = 10
 	ifaceID                 = 1
 )
@@ -57,8 +57,8 @@ type NetworkConfiguration struct {
 // EndpointConfiguration represents the user specified configuration for the sandbox endpoint
 type EndpointConfiguration struct {
 	MacAddress   net.HardwareAddr
-	PortBindings []netutils.PortBinding
-	ExposedPorts []netutils.TransportPort
+	PortBindings []types.PortBinding
+	ExposedPorts []types.TransportPort
 }
 
 // ContainerConfiguration represents the user specified configuration for a container
@@ -73,7 +73,7 @@ type bridgeEndpoint struct {
 	macAddress      net.HardwareAddr
 	config          *EndpointConfiguration // User specified parameters
 	containerConfig *ContainerConfiguration
-	portMapping     []netutils.PortBinding // Operation port bindings
+	portMapping     []types.PortBinding // Operation port bindings
 }
 
 type bridgeNetwork struct {
@@ -109,7 +109,7 @@ func Init(dc driverapi.DriverCallback) error {
 // Whatever can be assessed a priori before attempting any programming.
 func (c *NetworkConfiguration) Validate() error {
 	if c.Mtu < 0 {
-		return ErrInvalidMtu
+		return ErrInvalidMtu(c.Mtu)
 	}
 
 	// If bridge v4 subnet is specified
@@ -118,19 +118,19 @@ func (c *NetworkConfiguration) Validate() error {
 		if c.FixedCIDR != nil {
 			// Check Network address
 			if !c.AddressIPv4.Contains(c.FixedCIDR.IP) {
-				return ErrInvalidContainerSubnet
+				return &ErrInvalidContainerSubnet{}
 			}
 			// Check it is effectively a subset
 			brNetLen, _ := c.AddressIPv4.Mask.Size()
 			cnNetLen, _ := c.FixedCIDR.Mask.Size()
 			if brNetLen > cnNetLen {
-				return ErrInvalidContainerSubnet
+				return &ErrInvalidContainerSubnet{}
 			}
 		}
 		// If default gw is specified, it must be part of bridge subnet
 		if c.DefaultGatewayIPv4 != nil {
 			if !c.AddressIPv4.Contains(c.DefaultGatewayIPv4) {
-				return ErrInvalidGateway
+				return &ErrInvalidGateway{}
 			}
 		}
 	}
@@ -138,7 +138,7 @@ func (c *NetworkConfiguration) Validate() error {
 	// If default v6 gw is specified, FixedCIDRv6 must be specified and gw must belong to FixedCIDRv6 subnet
 	if c.EnableIPv6 && c.DefaultGatewayIPv6 != nil {
 		if c.FixedCIDRv6 == nil || !c.FixedCIDRv6.Contains(c.DefaultGatewayIPv6) {
-			return ErrInvalidGateway
+			return &ErrInvalidGateway{}
 		}
 	}
 
@@ -167,7 +167,7 @@ func (d *driver) Config(option map[string]interface{}) error {
 	defer d.Unlock()
 
 	if d.config != nil {
-		return ErrConfigExists
+		return &ErrConfigExists{}
 	}
 
 	genericData, ok := option[netlabel.GenericData]
@@ -182,7 +182,7 @@ func (d *driver) Config(option map[string]interface{}) error {
 		case *Configuration:
 			config = opt
 		default:
-			return ErrInvalidDriverConfig
+			return &ErrInvalidDriverConfig{}
 		}
 
 		d.config = config
@@ -220,7 +220,7 @@ func parseNetworkOptions(option options.Generic) (*NetworkConfiguration, error)
 		case *NetworkConfiguration:
 			config = opt
 		default:
-			return nil, ErrInvalidNetworkConfig
+			return nil, &ErrInvalidNetworkConfig{}
 		}
 
 		if err := config.Validate(); err != nil {
@@ -247,7 +247,7 @@ func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) err
 	// Sanity checks
 	if d.network != nil {
 		d.Unlock()
-		return ErrNetworkExists
+		return &ErrNetworkExists{}
 	}
 
 	// Create and set network handler in driver
@@ -361,7 +361,7 @@ func (d *driver) DeleteNetwork(nid types.UUID) error {
 
 	// Sanity check
 	if n == nil {
-		err = driverapi.ErrNoNetwork
+		err = driverapi.ErrNoNetwork(nid)
 		return err
 	}
 
@@ -397,7 +397,7 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn
 	config := n.config
 	d.Unlock()
 	if n == nil {
-		return driverapi.ErrNoNetwork
+		return driverapi.ErrNoNetwork(nid)
 	}
 
 	// Sanity check
@@ -416,7 +416,7 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn
 
 	// Endpoint with that id exists either on desired or other sandbox
 	if ep != nil {
-		return driverapi.ErrEndpointExists
+		return driverapi.ErrEndpointExists(eid)
 	}
 
 	// Try to convert the options to endpoint configuration
@@ -545,7 +545,7 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn
 	// Create the sandbox side pipe interface
 	intf := &sandbox.Interface{}
 	intf.SrcName = name2
-	intf.DstName = containerVeth
+	intf.DstName = containerVethPrefix
 	intf.Address = ipv4Addr
 
 	if config.EnableIPv6 {
@@ -578,7 +578,7 @@ func (d *driver) DeleteEndpoint(nid, eid types.UUID) error {
 	config := n.config
 	d.Unlock()
 	if n == nil {
-		return driverapi.ErrNoNetwork
+		return driverapi.ErrNoNetwork(nid)
 	}
 
 	// Sanity Check
@@ -648,7 +648,7 @@ func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{},
 	n := d.network
 	d.Unlock()
 	if n == nil {
-		return nil, driverapi.ErrNoNetwork
+		return nil, driverapi.ErrNoNetwork(nid)
 	}
 
 	// Sanity check
@@ -665,14 +665,14 @@ func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{},
 		return nil, err
 	}
 	if ep == nil {
-		return nil, driverapi.ErrNoEndpoint
+		return nil, driverapi.ErrNoEndpoint(eid)
 	}
 
 	m := make(map[string]interface{})
 
 	if ep.portMapping != nil {
 		// Return a copy of the operational data
-		pmc := make([]netutils.PortBinding, 0, len(ep.portMapping))
+		pmc := make([]types.PortBinding, 0, len(ep.portMapping))
 		for _, pm := range ep.portMapping {
 			pmc = append(pmc, pm.GetCopy())
 		}
@@ -856,23 +856,23 @@ func parseEndpointOptions(epOptions map[string]interface{}) (*EndpointConfigurat
 		if mac, ok := opt.(net.HardwareAddr); ok {
 			ec.MacAddress = mac
 		} else {
-			return nil, ErrInvalidEndpointConfig
+			return nil, &ErrInvalidEndpointConfig{}
 		}
 	}
 
 	if opt, ok := epOptions[netlabel.PortMap]; ok {
-		if bs, ok := opt.([]netutils.PortBinding); ok {
+		if bs, ok := opt.([]types.PortBinding); ok {
 			ec.PortBindings = bs
 		} else {
-			return nil, ErrInvalidEndpointConfig
+			return nil, &ErrInvalidEndpointConfig{}
 		}
 	}
 
 	if opt, ok := epOptions[netlabel.ExposedPorts]; ok {
-		if ports, ok := opt.([]netutils.TransportPort); ok {
+		if ports, ok := opt.([]types.TransportPort); ok {
 			ec.ExposedPorts = ports
 		} else {
-			return nil, ErrInvalidEndpointConfig
+			return nil, &ErrInvalidEndpointConfig{}
 		}
 	}
 
@@ -924,5 +924,5 @@ func generateIfaceName() (string, error) {
 			return "", err
 		}
 	}
-	return "", ErrIfaceName
+	return "", &ErrIfaceName{}
 }

+ 12 - 11
vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge_test.go

@@ -11,6 +11,7 @@ import (
 	"github.com/docker/libnetwork/iptables"
 	"github.com/docker/libnetwork/netlabel"
 	"github.com/docker/libnetwork/netutils"
+	"github.com/docker/libnetwork/types"
 	"github.com/vishvananda/netlink"
 )
 
@@ -202,7 +203,7 @@ func testQueryEndpointInfo(t *testing.T, ulPxyEnabled bool) {
 	if !ok {
 		t.Fatalf("Endpoint operational data does not contain port mapping data")
 	}
-	pm, ok := pmd.([]netutils.PortBinding)
+	pm, ok := pmd.([]types.PortBinding)
 	if !ok {
 		t.Fatalf("Unexpected format for port mapping in endpoint operational data")
 	}
@@ -261,19 +262,19 @@ func TestCreateLinkWithOptions(t *testing.T) {
 	}
 }
 
-func getExposedPorts() []netutils.TransportPort {
-	return []netutils.TransportPort{
-		netutils.TransportPort{Proto: netutils.TCP, Port: uint16(5000)},
-		netutils.TransportPort{Proto: netutils.UDP, Port: uint16(400)},
-		netutils.TransportPort{Proto: netutils.TCP, Port: uint16(600)},
+func getExposedPorts() []types.TransportPort {
+	return []types.TransportPort{
+		types.TransportPort{Proto: types.TCP, Port: uint16(5000)},
+		types.TransportPort{Proto: types.UDP, Port: uint16(400)},
+		types.TransportPort{Proto: types.TCP, Port: uint16(600)},
 	}
 }
 
-func getPortMapping() []netutils.PortBinding {
-	return []netutils.PortBinding{
-		netutils.PortBinding{Proto: netutils.TCP, Port: uint16(230), HostPort: uint16(23000)},
-		netutils.PortBinding{Proto: netutils.UDP, Port: uint16(200), HostPort: uint16(22000)},
-		netutils.PortBinding{Proto: netutils.TCP, Port: uint16(120), HostPort: uint16(12000)},
+func getPortMapping() []types.PortBinding {
+	return []types.PortBinding{
+		types.PortBinding{Proto: types.TCP, Port: uint16(230), HostPort: uint16(23000)},
+		types.PortBinding{Proto: types.UDP, Port: uint16(200), HostPort: uint16(22000)},
+		types.PortBinding{Proto: types.TCP, Port: uint16(120), HostPort: uint16(12000)},
 	}
 }
 

+ 0 - 201
vendor/src/github.com/docker/libnetwork/drivers/bridge/error.go

@@ -1,201 +0,0 @@
-package bridge
-
-import (
-	"errors"
-	"fmt"
-	"net"
-)
-
-var (
-	// ErrConfigExists error is returned when driver already has a config applied.
-	ErrConfigExists = errors.New("configuration already exists, bridge configuration can be applied only once")
-
-	// ErrInvalidDriverConfig error is returned when Bridge Driver is passed an invalid config
-	ErrInvalidDriverConfig = errors.New("Invalid configuration passed to Bridge Driver")
-
-	// ErrInvalidNetworkConfig error is returned when a network is created on a driver without valid config.
-	ErrInvalidNetworkConfig = errors.New("trying to create a network on a driver without valid config")
-
-	// ErrInvalidContainerConfig error is returned when a endpoint create is attempted with an invalid configuration.
-	ErrInvalidContainerConfig = errors.New("Error in joining a container due to invalid configuration")
-
-	// ErrInvalidEndpointConfig error is returned when a endpoint create is attempted with an invalid endpoint configuration.
-	ErrInvalidEndpointConfig = errors.New("trying to create an endpoint with an invalid endpoint configuration")
-
-	// ErrNetworkExists error is returned when a network already exists and another network is created.
-	ErrNetworkExists = errors.New("network already exists, bridge can only have one network")
-
-	// ErrIfaceName error is returned when a new name could not be generated.
-	ErrIfaceName = errors.New("failed to find name for new interface")
-
-	// ErrNoIPAddr error is returned when bridge has no IPv4 address configured.
-	ErrNoIPAddr = errors.New("bridge has no IPv4 address configured")
-
-	// ErrInvalidGateway is returned when the user provided default gateway (v4/v6) is not not valid.
-	ErrInvalidGateway = errors.New("default gateway ip must be part of the network")
-
-	// ErrInvalidContainerSubnet is returned when the container subnet (FixedCIDR) is not valid.
-	ErrInvalidContainerSubnet = errors.New("container subnet must be a subset of bridge network")
-
-	// ErrInvalidMtu is returned when the user provided MTU is not valid.
-	ErrInvalidMtu = errors.New("invalid MTU number")
-
-	// ErrIPFwdCfg is returned when ip forwarding setup is invoked when the configuration
-	// not enabled.
-	ErrIPFwdCfg = errors.New("unexpected request to enable IP Forwarding")
-)
-
-// ErrInvalidPort is returned when the container or host port specified in the port binding is not valid.
-type ErrInvalidPort string
-
-func (ip ErrInvalidPort) Error() string {
-	return fmt.Sprintf("invalid transport port: %s", string(ip))
-}
-
-// ErrUnsupportedAddressType is returned when the specified address type is not supported.
-type ErrUnsupportedAddressType string
-
-func (uat ErrUnsupportedAddressType) Error() string {
-	return fmt.Sprintf("unsupported address type: %s", string(uat))
-}
-
-// ErrInvalidAddressBinding is returned when the host address specified in the port binding is not valid.
-type ErrInvalidAddressBinding string
-
-func (iab ErrInvalidAddressBinding) Error() string {
-	return fmt.Sprintf("invalid host address in port binding: %s", string(iab))
-}
-
-// ActiveEndpointsError is returned when there are
-// still active endpoints in the network being deleted.
-type ActiveEndpointsError string
-
-func (aee ActiveEndpointsError) Error() string {
-	return fmt.Sprintf("network %s has active endpoint", string(aee))
-}
-
-// InvalidNetworkIDError is returned when the passed
-// network id for an existing network is not a known id.
-type InvalidNetworkIDError string
-
-func (inie InvalidNetworkIDError) Error() string {
-	return fmt.Sprintf("invalid network id %s", string(inie))
-}
-
-// InvalidEndpointIDError is returned when the passed
-// endpoint id is not valid.
-type InvalidEndpointIDError string
-
-func (ieie InvalidEndpointIDError) Error() string {
-	return fmt.Sprintf("invalid endpoint id: %s", string(ieie))
-}
-
-// InvalidSandboxIDError is returned when the passed
-// sandbox id valid.
-type InvalidSandboxIDError string
-
-func (isie InvalidSandboxIDError) Error() string {
-	return fmt.Sprintf("invalid sanbox id: %s", string(isie))
-}
-
-// EndpointNotFoundError is returned when the no endpoint
-// with the passed endpoint id is found.
-type EndpointNotFoundError string
-
-func (enfe EndpointNotFoundError) Error() string {
-	return fmt.Sprintf("endpoint not found: %s", string(enfe))
-}
-
-// NonDefaultBridgeExistError is returned when a non-default
-// bridge config is passed but it does not already exist.
-type NonDefaultBridgeExistError string
-
-func (ndbee NonDefaultBridgeExistError) Error() string {
-	return fmt.Sprintf("bridge device with non default name %s must be created manually", string(ndbee))
-}
-
-// FixedCIDRv4Error is returned when fixed-cidrv4 configuration
-// failed.
-type FixedCIDRv4Error struct {
-	net    *net.IPNet
-	subnet *net.IPNet
-	err    error
-}
-
-func (fcv4 *FixedCIDRv4Error) Error() string {
-	return fmt.Sprintf("setup FixedCIDRv4 failed for subnet %s in %s: %v", fcv4.subnet, fcv4.net, fcv4.err)
-}
-
-// FixedCIDRv6Error is returned when fixed-cidrv6 configuration
-// failed.
-type FixedCIDRv6Error struct {
-	net *net.IPNet
-	err error
-}
-
-func (fcv6 *FixedCIDRv6Error) Error() string {
-	return fmt.Sprintf("setup FixedCIDRv6 failed for subnet %s in %s: %v", fcv6.net, fcv6.net, fcv6.err)
-}
-
-type ipTableCfgError string
-
-func (name ipTableCfgError) Error() string {
-	return fmt.Sprintf("unexpected request to set IP tables for interface: %s", string(name))
-}
-
-type invalidIPTablesCfgError string
-
-func (action invalidIPTablesCfgError) Error() string {
-	return fmt.Sprintf("Invalid IPTables action '%s'", string(action))
-}
-
-// IPv4AddrRangeError is returned when a valid IP address range couldn't be found.
-type IPv4AddrRangeError string
-
-func (name IPv4AddrRangeError) Error() string {
-	return fmt.Sprintf("can't find an address range for interface %q", string(name))
-}
-
-// IPv4AddrAddError is returned when IPv4 address could not be added to the bridge.
-type IPv4AddrAddError struct {
-	ip  *net.IPNet
-	err error
-}
-
-func (ipv4 *IPv4AddrAddError) Error() string {
-	return fmt.Sprintf("failed to add IPv4 address %s to bridge: %v", ipv4.ip, ipv4.err)
-}
-
-// IPv6AddrAddError is returned when IPv6 address could not be added to the bridge.
-type IPv6AddrAddError struct {
-	ip  *net.IPNet
-	err error
-}
-
-func (ipv6 *IPv6AddrAddError) Error() string {
-	return fmt.Sprintf("failed to add IPv6 address %s to bridge: %v", ipv6.ip, ipv6.err)
-}
-
-// IPv4AddrNoMatchError is returned when the bridge's IPv4 address does not match configured.
-type IPv4AddrNoMatchError struct {
-	ip    net.IP
-	cfgIP net.IP
-}
-
-func (ipv4 *IPv4AddrNoMatchError) Error() string {
-	return fmt.Sprintf("bridge IPv4 (%s) does not match requested configuration %s", ipv4.ip, ipv4.cfgIP)
-}
-
-// IPv6AddrNoMatchError is returned when the bridge's IPv6 address does not match configured.
-type IPv6AddrNoMatchError net.IPNet
-
-func (ipv6 *IPv6AddrNoMatchError) Error() string {
-	return fmt.Sprintf("bridge IPv6 addresses do not match the expected bridge configuration %s", (*net.IPNet)(ipv6).String())
-}
-
-// InvalidLinkIPAddrError is returned when a link is configured to a container with an invalid ip address
-type InvalidLinkIPAddrError string
-
-func (address InvalidLinkIPAddrError) Error() string {
-	return fmt.Sprintf("Cannot link to a container with Invalid IP Address '%s'", string(address))
-}

+ 341 - 0
vendor/src/github.com/docker/libnetwork/drivers/bridge/errors.go

@@ -0,0 +1,341 @@
+package bridge
+
+import (
+	"fmt"
+	"net"
+)
+
+// ErrConfigExists error is returned when driver already has a config applied.
+type ErrConfigExists struct{}
+
+func (ece *ErrConfigExists) Error() string {
+	return "configuration already exists, bridge configuration can be applied only once"
+}
+
+// Forbidden denotes the type of this error
+func (ece *ErrConfigExists) Forbidden() {}
+
+// ErrInvalidDriverConfig error is returned when Bridge Driver is passed an invalid config
+type ErrInvalidDriverConfig struct{}
+
+func (eidc *ErrInvalidDriverConfig) Error() string {
+	return "Invalid configuration passed to Bridge Driver"
+}
+
+// BadRequest denotes the type of this error
+func (eidc *ErrInvalidDriverConfig) BadRequest() {}
+
+// ErrInvalidNetworkConfig error is returned when a network is created on a driver without valid config.
+type ErrInvalidNetworkConfig struct{}
+
+func (einc *ErrInvalidNetworkConfig) Error() string {
+	return "trying to create a network on a driver without valid config"
+}
+
+// Forbidden denotes the type of this error
+func (einc *ErrInvalidNetworkConfig) Forbidden() {}
+
+// ErrInvalidContainerConfig error is returned when a endpoint create is attempted with an invalid configuration.
+type ErrInvalidContainerConfig struct{}
+
+func (eicc *ErrInvalidContainerConfig) Error() string {
+	return "Error in joining a container due to invalid configuration"
+}
+
+// BadRequest denotes the type of this error
+func (eicc *ErrInvalidContainerConfig) BadRequest() {}
+
+// ErrInvalidEndpointConfig error is returned when a endpoint create is attempted with an invalid endpoint configuration.
+type ErrInvalidEndpointConfig struct{}
+
+func (eiec *ErrInvalidEndpointConfig) Error() string {
+	return "trying to create an endpoint with an invalid endpoint configuration"
+}
+
+// BadRequest denotes the type of this error
+func (eiec *ErrInvalidEndpointConfig) BadRequest() {}
+
+// ErrNetworkExists error is returned when a network already exists and another network is created.
+type ErrNetworkExists struct{}
+
+func (ene *ErrNetworkExists) Error() string {
+	return "network already exists, bridge can only have one network"
+}
+
+// Forbidden denotes the type of this error
+func (ene *ErrNetworkExists) Forbidden() {}
+
+// ErrIfaceName error is returned when a new name could not be generated.
+type ErrIfaceName struct{}
+
+func (ein *ErrIfaceName) Error() string {
+	return "failed to find name for new interface"
+}
+
+// InternalError denotes the type of this error
+func (ein *ErrIfaceName) InternalError() {}
+
+// ErrNoIPAddr error is returned when bridge has no IPv4 address configured.
+type ErrNoIPAddr struct{}
+
+func (enip *ErrNoIPAddr) Error() string {
+	return "bridge has no IPv4 address configured"
+}
+
+// InternalError denotes the type of this error
+func (enip *ErrNoIPAddr) InternalError() {}
+
+// ErrInvalidGateway is returned when the user provided default gateway (v4/v6) is not not valid.
+type ErrInvalidGateway struct{}
+
+func (eig *ErrInvalidGateway) Error() string {
+	return "default gateway ip must be part of the network"
+}
+
+// BadRequest denotes the type of this error
+func (eig *ErrInvalidGateway) BadRequest() {}
+
+// ErrInvalidContainerSubnet is returned when the container subnet (FixedCIDR) is not valid.
+type ErrInvalidContainerSubnet struct{}
+
+func (eis *ErrInvalidContainerSubnet) Error() string {
+	return "container subnet must be a subset of bridge network"
+}
+
+// BadRequest denotes the type of this error
+func (eis *ErrInvalidContainerSubnet) BadRequest() {}
+
+// ErrInvalidMtu is returned when the user provided MTU is not valid.
+type ErrInvalidMtu int
+
+func (eim ErrInvalidMtu) Error() string {
+	return fmt.Sprintf("invalid MTU number: %d", int(eim))
+}
+
+// BadRequest denotes the type of this error
+func (eim ErrInvalidMtu) BadRequest() {}
+
+// ErrIPFwdCfg is returned when ip forwarding setup is invoked when the configuration
+// not enabled.
+type ErrIPFwdCfg struct{}
+
+func (eipf *ErrIPFwdCfg) Error() string {
+	return "unexpected request to enable IP Forwarding"
+}
+
+// BadRequest denotes the type of this error
+func (eipf *ErrIPFwdCfg) BadRequest() {}
+
+// ErrInvalidPort is returned when the container or host port specified in the port binding is not valid.
+type ErrInvalidPort string
+
+func (ip ErrInvalidPort) Error() string {
+	return fmt.Sprintf("invalid transport port: %s", string(ip))
+}
+
+// BadRequest denotes the type of this error
+func (ip ErrInvalidPort) BadRequest() {}
+
+// ErrUnsupportedAddressType is returned when the specified address type is not supported.
+type ErrUnsupportedAddressType string
+
+func (uat ErrUnsupportedAddressType) Error() string {
+	return fmt.Sprintf("unsupported address type: %s", string(uat))
+}
+
+// BadRequest denotes the type of this error
+func (uat ErrUnsupportedAddressType) BadRequest() {}
+
+// ErrInvalidAddressBinding is returned when the host address specified in the port binding is not valid.
+type ErrInvalidAddressBinding string
+
+func (iab ErrInvalidAddressBinding) Error() string {
+	return fmt.Sprintf("invalid host address in port binding: %s", string(iab))
+}
+
+// BadRequest denotes the type of this error
+func (iab ErrInvalidAddressBinding) BadRequest() {}
+
+// ActiveEndpointsError is returned when there are
+// still active endpoints in the network being deleted.
+type ActiveEndpointsError string
+
+func (aee ActiveEndpointsError) Error() string {
+	return fmt.Sprintf("network %s has active endpoint", string(aee))
+}
+
+// Forbidden denotes the type of this error
+func (aee ActiveEndpointsError) Forbidden() {}
+
+// InvalidNetworkIDError is returned when the passed
+// network id for an existing network is not a known id.
+type InvalidNetworkIDError string
+
+func (inie InvalidNetworkIDError) Error() string {
+	return fmt.Sprintf("invalid network id %s", string(inie))
+}
+
+// NotFound denotes the type of this error
+func (inie InvalidNetworkIDError) NotFound() {}
+
+// InvalidEndpointIDError is returned when the passed
+// endpoint id is not valid.
+type InvalidEndpointIDError string
+
+func (ieie InvalidEndpointIDError) Error() string {
+	return fmt.Sprintf("invalid endpoint id: %s", string(ieie))
+}
+
+// BadRequest denotes the type of this error
+func (ieie InvalidEndpointIDError) BadRequest() {}
+
+// InvalidSandboxIDError is returned when the passed
+// sandbox id is not valid.
+type InvalidSandboxIDError string
+
+func (isie InvalidSandboxIDError) Error() string {
+	return fmt.Sprintf("invalid sanbox id: %s", string(isie))
+}
+
+// BadRequest denotes the type of this error
+func (isie InvalidSandboxIDError) BadRequest() {}
+
+// EndpointNotFoundError is returned when the no endpoint
+// with the passed endpoint id is found.
+type EndpointNotFoundError string
+
+func (enfe EndpointNotFoundError) Error() string {
+	return fmt.Sprintf("endpoint not found: %s", string(enfe))
+}
+
+// NotFound denotes the type of this error
+func (enfe EndpointNotFoundError) NotFound() {}
+
+// NonDefaultBridgeExistError is returned when a non-default
+// bridge config is passed but it does not already exist.
+type NonDefaultBridgeExistError string
+
+func (ndbee NonDefaultBridgeExistError) Error() string {
+	return fmt.Sprintf("bridge device with non default name %s must be created manually", string(ndbee))
+}
+
+// Forbidden denotes the type of this error
+func (ndbee NonDefaultBridgeExistError) Forbidden() {}
+
+// FixedCIDRv4Error is returned when fixed-cidrv4 configuration
+// failed.
+type FixedCIDRv4Error struct {
+	Net    *net.IPNet
+	Subnet *net.IPNet
+	Err    error
+}
+
+func (fcv4 *FixedCIDRv4Error) Error() string {
+	return fmt.Sprintf("setup FixedCIDRv4 failed for subnet %s in %s: %v", fcv4.Subnet, fcv4.Net, fcv4.Err)
+}
+
+// InternalError denotes the type of this error
+func (fcv4 *FixedCIDRv4Error) InternalError() {}
+
+// FixedCIDRv6Error is returned when fixed-cidrv6 configuration
+// failed.
+type FixedCIDRv6Error struct {
+	Net *net.IPNet
+	Err error
+}
+
+func (fcv6 *FixedCIDRv6Error) Error() string {
+	return fmt.Sprintf("setup FixedCIDRv6 failed for subnet %s in %s: %v", fcv6.Net, fcv6.Net, fcv6.Err)
+}
+
+// InternalError denotes the type of this error
+func (fcv6 *FixedCIDRv6Error) InternalError() {}
+
+// IPTableCfgError is returned when an unexpected ip tables configuration is entered
+type IPTableCfgError string
+
+func (name IPTableCfgError) Error() string {
+	return fmt.Sprintf("unexpected request to set IP tables for interface: %s", string(name))
+}
+
+// BadRequest denotes the type of this error
+func (name IPTableCfgError) BadRequest() {}
+
+// InvalidIPTablesCfgError is returned when an invalid ip tables configuration is entered
+type InvalidIPTablesCfgError string
+
+func (action InvalidIPTablesCfgError) Error() string {
+	return fmt.Sprintf("Invalid IPTables action '%s'", string(action))
+}
+
+// BadRequest denotes the type of this error
+func (action InvalidIPTablesCfgError) BadRequest() {}
+
+// IPv4AddrRangeError is returned when a valid IP address range couldn't be found.
+type IPv4AddrRangeError string
+
+func (name IPv4AddrRangeError) Error() string {
+	return fmt.Sprintf("can't find an address range for interface %q", string(name))
+}
+
+// BadRequest denotes the type of this error
+func (name IPv4AddrRangeError) BadRequest() {}
+
+// IPv4AddrAddError is returned when IPv4 address could not be added to the bridge.
+type IPv4AddrAddError struct {
+	IP  *net.IPNet
+	Err error
+}
+
+func (ipv4 *IPv4AddrAddError) Error() string {
+	return fmt.Sprintf("failed to add IPv4 address %s to bridge: %v", ipv4.IP, ipv4.Err)
+}
+
+// InternalError denotes the type of this error
+func (ipv4 *IPv4AddrAddError) InternalError() {}
+
+// IPv6AddrAddError is returned when IPv6 address could not be added to the bridge.
+type IPv6AddrAddError struct {
+	IP  *net.IPNet
+	Err error
+}
+
+func (ipv6 *IPv6AddrAddError) Error() string {
+	return fmt.Sprintf("failed to add IPv6 address %s to bridge: %v", ipv6.IP, ipv6.Err)
+}
+
+// InternalError denotes the type of this error
+func (ipv6 *IPv6AddrAddError) InternalError() {}
+
+// IPv4AddrNoMatchError is returned when the bridge's IPv4 address does not match configured.
+type IPv4AddrNoMatchError struct {
+	IP    net.IP
+	CfgIP net.IP
+}
+
+func (ipv4 *IPv4AddrNoMatchError) Error() string {
+	return fmt.Sprintf("bridge IPv4 (%s) does not match requested configuration %s", ipv4.IP, ipv4.CfgIP)
+}
+
+// BadRequest denotes the type of this error
+func (ipv4 *IPv4AddrNoMatchError) BadRequest() {}
+
+// IPv6AddrNoMatchError is returned when the bridge's IPv6 address does not match configured.
+type IPv6AddrNoMatchError net.IPNet
+
+func (ipv6 *IPv6AddrNoMatchError) Error() string {
+	return fmt.Sprintf("bridge IPv6 addresses do not match the expected bridge configuration %s", (*net.IPNet)(ipv6).String())
+}
+
+// BadRequest denotes the type of this error
+func (ipv6 *IPv6AddrNoMatchError) BadRequest() {}
+
+// InvalidLinkIPAddrError is returned when a link is configured to a container with an invalid ip address
+type InvalidLinkIPAddrError string
+
+func (address InvalidLinkIPAddrError) Error() string {
+	return fmt.Sprintf("Cannot link to a container with Invalid IP Address '%s'", string(address))
+}
+
+// BadRequest denotes the type of this error
+func (address InvalidLinkIPAddrError) BadRequest() {}

+ 5 - 5
vendor/src/github.com/docker/libnetwork/drivers/bridge/link.go

@@ -6,13 +6,13 @@ import (
 
 	log "github.com/Sirupsen/logrus"
 	"github.com/docker/libnetwork/iptables"
-	"github.com/docker/libnetwork/netutils"
+	"github.com/docker/libnetwork/types"
 )
 
 type link struct {
 	parentIP string
 	childIP  string
-	ports    []netutils.TransportPort
+	ports    []types.TransportPort
 	bridge   string
 }
 
@@ -20,7 +20,7 @@ func (l *link) String() string {
 	return fmt.Sprintf("%s <-> %s [%v] on %s", l.parentIP, l.childIP, l.ports, l.bridge)
 }
 
-func newLink(parentIP, childIP string, ports []netutils.TransportPort, bridge string) *link {
+func newLink(parentIP, childIP string, ports []types.TransportPort, bridge string) *link {
 	return &link{
 		childIP:  childIP,
 		parentIP: parentIP,
@@ -45,7 +45,7 @@ func (l *link) Disable() {
 	// that returns typed errors
 }
 
-func linkContainers(action, parentIP, childIP string, ports []netutils.TransportPort, bridge string,
+func linkContainers(action, parentIP, childIP string, ports []types.TransportPort, bridge string,
 	ignoreErrors bool) error {
 	var nfAction iptables.Action
 
@@ -57,7 +57,7 @@ func linkContainers(action, parentIP, childIP string, ports []netutils.Transport
 	case "-D":
 		nfAction = iptables.Delete
 	default:
-		return invalidIPTablesCfgError(action)
+		return InvalidIPTablesCfgError(action)
 	}
 
 	ip1 := net.ParseIP(parentIP)

+ 6 - 6
vendor/src/github.com/docker/libnetwork/drivers/bridge/link_test.go

@@ -3,14 +3,14 @@ package bridge
 import (
 	"testing"
 
-	"github.com/docker/libnetwork/netutils"
+	"github.com/docker/libnetwork/types"
 )
 
-func getPorts() []netutils.TransportPort {
-	return []netutils.TransportPort{
-		netutils.TransportPort{Proto: netutils.TCP, Port: uint16(5000)},
-		netutils.TransportPort{Proto: netutils.UDP, Port: uint16(400)},
-		netutils.TransportPort{Proto: netutils.TCP, Port: uint16(600)},
+func getPorts() []types.TransportPort {
+	return []types.TransportPort{
+		types.TransportPort{Proto: types.TCP, Port: uint16(5000)},
+		types.TransportPort{Proto: types.UDP, Port: uint16(400)},
+		types.TransportPort{Proto: types.TCP, Port: uint16(600)},
 	}
 }
 

+ 2 - 2
vendor/src/github.com/docker/libnetwork/drivers/bridge/network_test.go

@@ -125,8 +125,8 @@ func TestLinkCreateTwo(t *testing.T) {
 	te2 := &testEndpoint{ifaces: []*testInterface{}}
 	err = d.CreateEndpoint("dummy", "ep", te2, nil)
 	if err != nil {
-		if err != driverapi.ErrEndpointExists {
-			t.Fatalf("Failed with a wrong error :%s", err.Error())
+		if _, ok := err.(driverapi.ErrEndpointExists); !ok {
+			t.Fatalf("Failed with a wrong error: %s", err.Error())
 		}
 	} else {
 		t.Fatalf("Expected to fail while trying to add same endpoint twice")

+ 7 - 7
vendor/src/github.com/docker/libnetwork/drivers/bridge/port_mapping.go

@@ -7,15 +7,15 @@ import (
 	"net"
 
 	"github.com/Sirupsen/logrus"
-	"github.com/docker/libnetwork/netutils"
 	"github.com/docker/libnetwork/sandbox"
+	"github.com/docker/libnetwork/types"
 )
 
 var (
 	defaultBindingIP = net.IPv4(0, 0, 0, 0)
 )
 
-func allocatePorts(epConfig *EndpointConfiguration, intf *sandbox.Interface, reqDefBindIP net.IP, ulPxyEnabled bool) ([]netutils.PortBinding, error) {
+func allocatePorts(epConfig *EndpointConfiguration, intf *sandbox.Interface, reqDefBindIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {
 	if epConfig == nil || epConfig.PortBindings == nil {
 		return nil, nil
 	}
@@ -28,8 +28,8 @@ func allocatePorts(epConfig *EndpointConfiguration, intf *sandbox.Interface, req
 	return allocatePortsInternal(epConfig.PortBindings, intf.Address.IP, defHostIP, ulPxyEnabled)
 }
 
-func allocatePortsInternal(bindings []netutils.PortBinding, containerIP, defHostIP net.IP, ulPxyEnabled bool) ([]netutils.PortBinding, error) {
-	bs := make([]netutils.PortBinding, 0, len(bindings))
+func allocatePortsInternal(bindings []types.PortBinding, containerIP, defHostIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {
+	bs := make([]types.PortBinding, 0, len(bindings))
 	for _, c := range bindings {
 		b := c.GetCopy()
 		if err := allocatePort(&b, containerIP, defHostIP, ulPxyEnabled); err != nil {
@@ -44,7 +44,7 @@ func allocatePortsInternal(bindings []netutils.PortBinding, containerIP, defHost
 	return bs, nil
 }
 
-func allocatePort(bnd *netutils.PortBinding, containerIP, defHostIP net.IP, ulPxyEnabled bool) error {
+func allocatePort(bnd *types.PortBinding, containerIP, defHostIP net.IP, ulPxyEnabled bool) error {
 	var (
 		host net.Addr
 		err  error
@@ -98,7 +98,7 @@ func releasePorts(ep *bridgeEndpoint) error {
 	return releasePortsInternal(ep.portMapping)
 }
 
-func releasePortsInternal(bindings []netutils.PortBinding) error {
+func releasePortsInternal(bindings []types.PortBinding) error {
 	var errorBuf bytes.Buffer
 
 	// Attempt to release all port bindings, do not stop on failure
@@ -114,7 +114,7 @@ func releasePortsInternal(bindings []netutils.PortBinding) error {
 	return nil
 }
 
-func releasePort(bnd netutils.PortBinding) error {
+func releasePort(bnd types.PortBinding) error {
 	// Construct the host side transport address
 	host, err := bnd.HostAddr()
 	if err != nil {

+ 4 - 3
vendor/src/github.com/docker/libnetwork/drivers/bridge/port_mapping_test.go

@@ -7,6 +7,7 @@ import (
 	"github.com/docker/docker/pkg/reexec"
 	"github.com/docker/libnetwork/netlabel"
 	"github.com/docker/libnetwork/netutils"
+	"github.com/docker/libnetwork/types"
 )
 
 func TestMain(m *testing.M) {
@@ -20,9 +21,9 @@ func TestPortMappingConfig(t *testing.T) {
 	defer netutils.SetupTestNetNS(t)()
 	d := newDriver()
 
-	binding1 := netutils.PortBinding{Proto: netutils.UDP, Port: uint16(400), HostPort: uint16(54000)}
-	binding2 := netutils.PortBinding{Proto: netutils.TCP, Port: uint16(500), HostPort: uint16(65000)}
-	portBindings := []netutils.PortBinding{binding1, binding2}
+	binding1 := types.PortBinding{Proto: types.UDP, Port: uint16(400), HostPort: uint16(54000)}
+	binding2 := types.PortBinding{Proto: types.TCP, Port: uint16(500), HostPort: uint16(65000)}
+	portBindings := []types.PortBinding{binding1, binding2}
 
 	epOptions := make(map[string]interface{})
 	epOptions[netlabel.PortMap] = portBindings

+ 4 - 2
vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_fixedcidrv4.go

@@ -1,6 +1,8 @@
 package bridge
 
-import log "github.com/Sirupsen/logrus"
+import (
+	log "github.com/Sirupsen/logrus"
+)
 
 func setupFixedCIDRv4(config *NetworkConfiguration, i *bridgeInterface) error {
 	addrv4, _, err := i.addresses()
@@ -10,7 +12,7 @@ func setupFixedCIDRv4(config *NetworkConfiguration, i *bridgeInterface) error {
 
 	log.Debugf("Using IPv4 subnet: %v", config.FixedCIDR)
 	if err := ipAllocator.RegisterSubnet(addrv4.IPNet, config.FixedCIDR); err != nil {
-		return &FixedCIDRv4Error{subnet: config.FixedCIDR, net: addrv4.IPNet, err: err}
+		return &FixedCIDRv4Error{Subnet: config.FixedCIDR, Net: addrv4.IPNet, Err: err}
 	}
 
 	return nil

+ 4 - 2
vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_fixedcidrv6.go

@@ -1,11 +1,13 @@
 package bridge
 
-import log "github.com/Sirupsen/logrus"
+import (
+	log "github.com/Sirupsen/logrus"
+)
 
 func setupFixedCIDRv6(config *NetworkConfiguration, i *bridgeInterface) error {
 	log.Debugf("Using IPv6 subnet: %v", config.FixedCIDRv6)
 	if err := ipAllocator.RegisterSubnet(config.FixedCIDRv6, config.FixedCIDRv6); err != nil {
-		return &FixedCIDRv6Error{net: config.FixedCIDRv6, err: err}
+		return &FixedCIDRv6Error{Net: config.FixedCIDRv6, Err: err}
 	}
 
 	return nil

+ 1 - 1
vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ip_forwarding.go

@@ -13,7 +13,7 @@ const (
 func setupIPForwarding(config *Configuration) error {
 	// Sanity Check
 	if config.EnableIPForwarding == false {
-		return ErrIPFwdCfg
+		return &ErrIPFwdCfg{}
 	}
 
 	// Enable IPv4 forwarding

+ 1 - 1
vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ip_forwarding_test.go

@@ -47,7 +47,7 @@ func TestUnexpectedSetupIPForwarding(t *testing.T) {
 		t.Fatal("Setup IP forwarding was expected to fail")
 	}
 
-	if err != ErrIPFwdCfg {
+	if _, ok := err.(*ErrIPFwdCfg); !ok {
 		t.Fatalf("Setup IP forwarding failed with unexpected error: %v", err)
 	}
 }

+ 1 - 1
vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ip_tables.go

@@ -16,7 +16,7 @@ const (
 func setupIPTables(config *NetworkConfiguration, i *bridgeInterface) error {
 	// Sanity check.
 	if config.EnableIPTables == false {
-		return ipTableCfgError(config.BridgeName)
+		return IPTableCfgError(config.BridgeName)
 	}
 
 	hairpinMode := !config.EnableUserlandProxy

+ 2 - 2
vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ipv4.go

@@ -71,7 +71,7 @@ func setupBridgeIPv4(config *NetworkConfiguration, i *bridgeInterface) error {
 
 	log.Debugf("Creating bridge interface %q with network %s", config.BridgeName, bridgeIPv4)
 	if err := netlink.AddrAdd(i.Link, &netlink.Addr{IPNet: bridgeIPv4}); err != nil {
-		return &IPv4AddrAddError{ip: bridgeIPv4, err: err}
+		return &IPv4AddrAddError{IP: bridgeIPv4, Err: err}
 	}
 
 	// Store bridge network and default gateway
@@ -114,7 +114,7 @@ func electBridgeIPv4(config *NetworkConfiguration) (*net.IPNet, error) {
 
 func setupGatewayIPv4(config *NetworkConfiguration, i *bridgeInterface) error {
 	if !i.bridgeIPv4.Contains(config.DefaultGatewayIPv4) {
-		return ErrInvalidGateway
+		return &ErrInvalidGateway{}
 	}
 	if _, err := ipAllocator.RequestIP(i.bridgeIPv4, config.DefaultGatewayIPv4); err != nil {
 		return err

+ 3 - 3
vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ipv6.go

@@ -37,7 +37,7 @@ func setupBridgeIPv6(config *NetworkConfiguration, i *bridgeInterface) error {
 	// Add the default link local ipv6 address if it doesn't exist
 	if !findIPv6Address(netlink.Addr{IPNet: bridgeIPv6}, addrsv6) {
 		if err := netlink.AddrAdd(i.Link, &netlink.Addr{IPNet: bridgeIPv6}); err != nil {
-			return &IPv6AddrAddError{ip: bridgeIPv6, err: err}
+			return &IPv6AddrAddError{IP: bridgeIPv6, Err: err}
 		}
 	}
 
@@ -50,10 +50,10 @@ func setupBridgeIPv6(config *NetworkConfiguration, i *bridgeInterface) error {
 
 func setupGatewayIPv6(config *NetworkConfiguration, i *bridgeInterface) error {
 	if config.FixedCIDRv6 == nil {
-		return ErrInvalidContainerSubnet
+		return &ErrInvalidContainerSubnet{}
 	}
 	if !config.FixedCIDRv6.Contains(config.DefaultGatewayIPv6) {
-		return ErrInvalidGateway
+		return &ErrInvalidGateway{}
 	}
 	if _, err := ipAllocator.RequestIP(config.FixedCIDRv6, config.DefaultGatewayIPv6); err != nil {
 		return err

+ 5 - 3
vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_verify.go

@@ -1,6 +1,8 @@
 package bridge
 
-import "github.com/vishvananda/netlink"
+import (
+	"github.com/vishvananda/netlink"
+)
 
 func setupVerifyAndReconcile(config *NetworkConfiguration, i *bridgeInterface) error {
 	// Fetch a single IPv4 and a slice of IPv6 addresses from the bridge.
@@ -11,12 +13,12 @@ func setupVerifyAndReconcile(config *NetworkConfiguration, i *bridgeInterface) e
 
 	// Verify that the bridge does have an IPv4 address.
 	if addrv4.IPNet == nil {
-		return ErrNoIPAddr
+		return &ErrNoIPAddr{}
 	}
 
 	// Verify that the bridge IPv4 address matches the requested configuration.
 	if config.AddressIPv4 != nil && !addrv4.IP.Equal(config.AddressIPv4.IP) {
-		return &IPv4AddrNoMatchError{ip: addrv4.IP, cfgIP: config.AddressIPv4.IP}
+		return &IPv4AddrNoMatchError{IP: addrv4.IP, CfgIP: config.AddressIPv4.IP}
 	}
 
 	// Verify that one of the bridge IPv6 addresses matches the requested

+ 163 - 19
vendor/src/github.com/docker/libnetwork/drivers/remote/driver.go

@@ -1,7 +1,8 @@
 package remote
 
 import (
-	"errors"
+	"fmt"
+	"net"
 
 	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/pkg/plugins"
@@ -9,59 +10,202 @@ import (
 	"github.com/docker/libnetwork/types"
 )
 
-var errNoCallback = errors.New("No Callback handler registered with Driver")
-
 type driver struct {
 	endpoint    *plugins.Client
 	networkType string
 }
 
-// Init does the necessary work to register remote drivers
+func newDriver(name string, client *plugins.Client) driverapi.Driver {
+	return &driver{networkType: name, endpoint: client}
+}
+
+// Init makes sure a remote driver is registered when a network driver
+// plugin is activated.
 func Init(dc driverapi.DriverCallback) error {
 	plugins.Handle(driverapi.NetworkPluginEndpointType, func(name string, client *plugins.Client) {
-
-		// TODO : Handhake with the Remote Plugin goes here
-
-		newDriver := &driver{networkType: name, endpoint: client}
-		if err := dc.RegisterDriver(name, newDriver); err != nil {
-			log.Errorf("Error registering Driver for %s due to %v", name, err)
+		if err := dc.RegisterDriver(name, newDriver(name, client)); err != nil {
+			log.Errorf("error registering driver for %s due to %v", name, err)
 		}
 	})
 	return nil
 }
 
+// Config is not implemented for remote drivers, since it is assumed
+// to be supplied to the remote process out-of-band (e.g., as command
+// line arguments).
 func (d *driver) Config(option map[string]interface{}) error {
-	return driverapi.ErrNotImplemented
+	return &driverapi.ErrNotImplemented{}
+}
+
+func (d *driver) call(methodName string, arg interface{}, retVal maybeError) error {
+	method := driverapi.NetworkPluginEndpointType + "." + methodName
+	err := d.endpoint.Call(method, arg, retVal)
+	if err != nil {
+		return err
+	}
+	if e := retVal.getError(); e != "" {
+		return fmt.Errorf("remote: %s", e)
+	}
+	return nil
 }
 
-func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) error {
-	return driverapi.ErrNotImplemented
+func (d *driver) CreateNetwork(id types.UUID, options map[string]interface{}) error {
+	create := &createNetworkRequest{
+		NetworkID: string(id),
+		Options:   options,
+	}
+	return d.call("CreateNetwork", create, &createNetworkResponse{})
 }
 
 func (d *driver) DeleteNetwork(nid types.UUID) error {
-	return driverapi.ErrNotImplemented
+	delete := &deleteNetworkRequest{NetworkID: string(nid)}
+	return d.call("DeleteNetwork", delete, &deleteNetworkResponse{})
 }
 
 func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error {
-	return driverapi.ErrNotImplemented
+	if epInfo == nil {
+		return fmt.Errorf("must not be called with nil EndpointInfo")
+	}
+
+	reqIfaces := make([]*endpointInterface, len(epInfo.Interfaces()))
+	for i, iface := range epInfo.Interfaces() {
+		addr4 := iface.Address()
+		addr6 := iface.AddressIPv6()
+		reqIfaces[i] = &endpointInterface{
+			ID:          iface.ID(),
+			Address:     addr4.String(),
+			AddressIPv6: addr6.String(),
+			MacAddress:  iface.MacAddress().String(),
+		}
+	}
+	create := &createEndpointRequest{
+		NetworkID:  string(nid),
+		EndpointID: string(eid),
+		Interfaces: reqIfaces,
+		Options:    epOptions,
+	}
+	var res createEndpointResponse
+	if err := d.call("CreateEndpoint", create, &res); err != nil {
+		return err
+	}
+
+	ifaces, err := res.parseInterfaces()
+	if err != nil {
+		return err
+	}
+	if len(reqIfaces) > 0 && len(ifaces) > 0 {
+		// We're not supposed to add interfaces if there already are
+		// some. Attempt to roll back
+		return errorWithRollback("driver attempted to add more interfaces", d.DeleteEndpoint(nid, eid))
+	}
+	for _, iface := range ifaces {
+		var addr4, addr6 net.IPNet
+		if iface.Address != nil {
+			addr4 = *(iface.Address)
+		}
+		if iface.AddressIPv6 != nil {
+			addr6 = *(iface.AddressIPv6)
+		}
+		if err := epInfo.AddInterface(iface.ID, iface.MacAddress, addr4, addr6); err != nil {
+			return errorWithRollback(fmt.Sprintf("failed to AddInterface %v: %s", iface, err), d.DeleteEndpoint(nid, eid))
+		}
+	}
+	return nil
+}
+
+func errorWithRollback(msg string, err error) error {
+	rollback := "rolled back"
+	if err != nil {
+		rollback = "failed to roll back: " + err.Error()
+	}
+	return fmt.Errorf("%s; %s", msg, rollback)
 }
 
 func (d *driver) DeleteEndpoint(nid, eid types.UUID) error {
-	return driverapi.ErrNotImplemented
+	delete := &deleteEndpointRequest{
+		NetworkID:  string(nid),
+		EndpointID: string(eid),
+	}
+	return d.call("DeleteEndpoint", delete, &deleteEndpointResponse{})
 }
 
 func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{}, error) {
-	return nil, driverapi.ErrNotImplemented
+	info := &endpointInfoRequest{
+		NetworkID:  string(nid),
+		EndpointID: string(eid),
+	}
+	var res endpointInfoResponse
+	if err := d.call("EndpointOperInfo", info, &res); err != nil {
+		return nil, err
+	}
+	return res.Value, nil
 }
 
 // Join method is invoked when a Sandbox is attached to an endpoint.
 func (d *driver) Join(nid, eid types.UUID, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
-	return driverapi.ErrNotImplemented
+	join := &joinRequest{
+		NetworkID:  string(nid),
+		EndpointID: string(eid),
+		SandboxKey: sboxKey,
+		Options:    options,
+	}
+	var (
+		res joinResponse
+		err error
+	)
+	if err = d.call("Join", join, &res); err != nil {
+		return err
+	}
+
+	// Expect each interface ID given by CreateEndpoint to have an
+	// entry at that index in the names supplied here. In other words,
+	// if you supply 0..n interfaces with IDs 0..n above, you should
+	// supply the names in the same order.
+	ifaceNames := res.InterfaceNames
+	for _, iface := range jinfo.InterfaceNames() {
+		i := iface.ID()
+		if i >= len(ifaceNames) || i < 0 {
+			return fmt.Errorf("no correlating interface %d in supplied interface names", i)
+		}
+		supplied := ifaceNames[i]
+		if err := iface.SetNames(supplied.SrcName, supplied.DstName); err != nil {
+			return errorWithRollback(fmt.Sprintf("failed to set interface name: %s", err), d.Leave(nid, eid))
+		}
+	}
+
+	var addr net.IP
+	if res.Gateway != "" {
+		if addr = net.ParseIP(res.Gateway); addr == nil {
+			return fmt.Errorf(`unable to parse Gateway "%s"`, res.Gateway)
+		}
+		if jinfo.SetGateway(addr) != nil {
+			return errorWithRollback(fmt.Sprintf("failed to set gateway: %v", addr), d.Leave(nid, eid))
+		}
+	}
+	if res.GatewayIPv6 != "" {
+		if addr = net.ParseIP(res.GatewayIPv6); addr == nil {
+			return fmt.Errorf(`unable to parse GatewayIPv6 "%s"`, res.GatewayIPv6)
+		}
+		if jinfo.SetGatewayIPv6(addr) != nil {
+			return errorWithRollback(fmt.Sprintf("failed to set gateway IPv6: %v", addr), d.Leave(nid, eid))
+		}
+	}
+	if jinfo.SetHostsPath(res.HostsPath) != nil {
+		return errorWithRollback(fmt.Sprintf("failed to set hosts path: %s", res.HostsPath), d.Leave(nid, eid))
+	}
+	if jinfo.SetResolvConfPath(res.ResolvConfPath) != nil {
+		return errorWithRollback(fmt.Sprintf("failed to set resolv.conf path: %s", res.ResolvConfPath), d.Leave(nid, eid))
+	}
+	return nil
 }
 
 // Leave method is invoked when a Sandbox detaches from an endpoint.
 func (d *driver) Leave(nid, eid types.UUID) error {
-	return driverapi.ErrNotImplemented
+	leave := &leaveRequest{
+		NetworkID:  string(nid),
+		EndpointID: string(eid),
+	}
+	return d.call("Leave", leave, &leaveResponse{})
 }
 
 func (d *driver) Type() string {

+ 397 - 0
vendor/src/github.com/docker/libnetwork/drivers/remote/driver_test.go

@@ -0,0 +1,397 @@
+package remote
+
+import (
+	"encoding/json"
+	"fmt"
+	"net"
+	"net/http"
+	"os"
+	"testing"
+
+	"github.com/docker/docker/pkg/plugins"
+	"github.com/docker/libnetwork/driverapi"
+	_ "github.com/docker/libnetwork/netutils"
+	"github.com/docker/libnetwork/types"
+)
+
+func decodeToMap(r *http.Request) (res map[string]interface{}, err error) {
+	err = json.NewDecoder(r.Body).Decode(&res)
+	return
+}
+
+func handle(t *testing.T, mux *http.ServeMux, method string, h func(map[string]interface{}) interface{}) {
+	mux.HandleFunc(fmt.Sprintf("/%s.%s", driverapi.NetworkPluginEndpointType, method), func(w http.ResponseWriter, r *http.Request) {
+		ask, err := decodeToMap(r)
+		if err != nil {
+			t.Fatal(err)
+		}
+		answer := h(ask)
+		err = json.NewEncoder(w).Encode(&answer)
+		if err != nil {
+			t.Fatal(err)
+		}
+	})
+}
+
+func setupPlugin(t *testing.T, name string, mux *http.ServeMux) func() {
+	if err := os.MkdirAll("/usr/share/docker/plugins", 0755); err != nil {
+		t.Fatal(err)
+	}
+
+	listener, err := net.Listen("unix", fmt.Sprintf("/usr/share/docker/plugins/%s.sock", name))
+	if err != nil {
+		t.Fatal("Could not listen to the plugin socket")
+	}
+
+	mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) {
+		fmt.Fprintf(w, `{"Implements": ["%s"]}`, driverapi.NetworkPluginEndpointType)
+	})
+
+	go http.Serve(listener, mux)
+
+	return func() {
+		listener.Close()
+		if err := os.RemoveAll("/usr/share/docker/plugins"); err != nil {
+			t.Fatal(err)
+		}
+	}
+}
+
+type testEndpoint struct {
+	t              *testing.T
+	id             int
+	src            string
+	dst            string
+	address        string
+	addressIPv6    string
+	macAddress     string
+	gateway        string
+	gatewayIPv6    string
+	resolvConfPath string
+	hostsPath      string
+}
+
+func (test *testEndpoint) Interfaces() []driverapi.InterfaceInfo {
+	// return an empty one so we don't trip the check for existing
+	// interfaces; we don't care about this after that
+	return []driverapi.InterfaceInfo{}
+}
+
+func (test *testEndpoint) AddInterface(ID int, mac net.HardwareAddr, ipv4 net.IPNet, ipv6 net.IPNet) error {
+	if ID != test.id {
+		test.t.Fatalf("Wrong ID passed to AddInterface: %d", ID)
+	}
+	ip4, net4, _ := net.ParseCIDR(test.address)
+	ip6, net6, _ := net.ParseCIDR(test.addressIPv6)
+	if ip4 != nil {
+		net4.IP = ip4
+		if !types.CompareIPNet(net4, &ipv4) {
+			test.t.Fatalf("Wrong address given %+v", ipv4)
+		}
+	}
+	if ip6 != nil {
+		net6.IP = ip6
+		if !types.CompareIPNet(net6, &ipv6) {
+			test.t.Fatalf("Wrong address (IPv6) given %+v", ipv6)
+		}
+	}
+	if test.macAddress != "" && mac.String() != test.macAddress {
+		test.t.Fatalf("Wrong MAC address given %v", mac)
+	}
+	return nil
+}
+
+func (test *testEndpoint) InterfaceNames() []driverapi.InterfaceNameInfo {
+	return []driverapi.InterfaceNameInfo{test}
+}
+
+func compareIPs(t *testing.T, kind string, shouldBe string, supplied net.IP) {
+	ip := net.ParseIP(shouldBe)
+	if ip == nil {
+		t.Fatalf(`Invalid IP to test against: "%s"`, shouldBe)
+	}
+	if !ip.Equal(supplied) {
+		t.Fatalf(`%s IPs are not equal: expected "%s", got %v`, kind, shouldBe, supplied)
+	}
+}
+
+func (test *testEndpoint) SetGateway(ipv4 net.IP) error {
+	compareIPs(test.t, "Gateway", test.gateway, ipv4)
+	return nil
+}
+
+func (test *testEndpoint) SetGatewayIPv6(ipv6 net.IP) error {
+	compareIPs(test.t, "GatewayIPv6", test.gatewayIPv6, ipv6)
+	return nil
+}
+
+func (test *testEndpoint) SetHostsPath(p string) error {
+	if p != test.hostsPath {
+		test.t.Fatalf(`Wrong HostsPath; expected "%s", got "%s"`, test.hostsPath, p)
+	}
+	return nil
+}
+
+func (test *testEndpoint) SetResolvConfPath(p string) error {
+	if p != test.resolvConfPath {
+		test.t.Fatalf(`Wrong ResolvConfPath; expected "%s", got "%s"`, test.resolvConfPath, p)
+	}
+	return nil
+}
+
+func (test *testEndpoint) SetNames(src string, dst string) error {
+	if test.src != src {
+		test.t.Fatalf(`Wrong SrcName; expected "%s", got "%s"`, test.src, src)
+	}
+	if test.dst != dst {
+		test.t.Fatalf(`Wrong DstName; expected "%s", got "%s"`, test.dst, dst)
+	}
+	return nil
+}
+
+func (test *testEndpoint) ID() int {
+	return test.id
+}
+
+func TestRemoteDriver(t *testing.T) {
+	var plugin = "test-net-driver"
+
+	ep := &testEndpoint{
+		t:              t,
+		src:            "vethsrc",
+		dst:            "vethdst",
+		address:        "192.168.5.7/16",
+		addressIPv6:    "2001:DB8::5:7/48",
+		macAddress:     "7a:56:78:34:12:da",
+		gateway:        "192.168.0.1",
+		gatewayIPv6:    "2001:DB8::1",
+		hostsPath:      "/here/comes/the/host/path",
+		resolvConfPath: "/there/goes/the/resolv/conf",
+	}
+
+	mux := http.NewServeMux()
+	defer setupPlugin(t, plugin, mux)()
+
+	var networkID string
+
+	handle(t, mux, "CreateNetwork", func(msg map[string]interface{}) interface{} {
+		nid := msg["NetworkID"]
+		var ok bool
+		if networkID, ok = nid.(string); !ok {
+			t.Fatal("RPC did not include network ID string")
+		}
+		return map[string]interface{}{}
+	})
+	handle(t, mux, "DeleteNetwork", func(msg map[string]interface{}) interface{} {
+		if nid, ok := msg["NetworkID"]; !ok || nid != networkID {
+			t.Fatal("Network ID missing or does not match that created")
+		}
+		return map[string]interface{}{}
+	})
+	handle(t, mux, "CreateEndpoint", func(msg map[string]interface{}) interface{} {
+		iface := map[string]interface{}{
+			"ID":          ep.id,
+			"Address":     ep.address,
+			"AddressIPv6": ep.addressIPv6,
+			"MacAddress":  ep.macAddress,
+		}
+		return map[string]interface{}{
+			"Interfaces": []interface{}{iface},
+		}
+	})
+	handle(t, mux, "Join", func(msg map[string]interface{}) interface{} {
+		options := msg["Options"].(map[string]interface{})
+		foo, ok := options["foo"].(string)
+		if !ok || foo != "fooValue" {
+			t.Fatalf("Did not receive expected foo string in request options: %+v", msg)
+		}
+		return map[string]interface{}{
+			"Gateway":        ep.gateway,
+			"GatewayIPv6":    ep.gatewayIPv6,
+			"HostsPath":      ep.hostsPath,
+			"ResolvConfPath": ep.resolvConfPath,
+			"InterfaceNames": []map[string]interface{}{
+				map[string]interface{}{
+					"SrcName": ep.src,
+					"DstName": ep.dst,
+				},
+			},
+		}
+	})
+	handle(t, mux, "Leave", func(msg map[string]interface{}) interface{} {
+		return map[string]string{}
+	})
+	handle(t, mux, "DeleteEndpoint", func(msg map[string]interface{}) interface{} {
+		return map[string]interface{}{}
+	})
+	handle(t, mux, "EndpointOperInfo", func(msg map[string]interface{}) interface{} {
+		return map[string]interface{}{
+			"Value": map[string]string{
+				"Arbitrary": "key",
+				"Value":     "pairs?",
+			},
+		}
+	})
+
+	p, err := plugins.Get(plugin, driverapi.NetworkPluginEndpointType)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	driver := newDriver(plugin, p.Client)
+	if driver.Type() != plugin {
+		t.Fatal("Driver type does not match that given")
+	}
+
+	netID := types.UUID("dummy-network")
+	err = driver.CreateNetwork(netID, map[string]interface{}{})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	endID := types.UUID("dummy-endpoint")
+	err = driver.CreateEndpoint(netID, endID, ep, map[string]interface{}{})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	joinOpts := map[string]interface{}{"foo": "fooValue"}
+	err = driver.Join(netID, endID, "sandbox-key", ep, joinOpts)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if _, err = driver.EndpointOperInfo(netID, endID); err != nil {
+		t.Fatal(err)
+	}
+	if err = driver.Leave(netID, endID); err != nil {
+		t.Fatal(err)
+	}
+	if err = driver.DeleteEndpoint(netID, endID); err != nil {
+		t.Fatal(err)
+	}
+	if err = driver.DeleteNetwork(netID); err != nil {
+		t.Fatal(err)
+	}
+}
+
+type failEndpoint struct {
+	t *testing.T
+}
+
+func (f *failEndpoint) Interfaces() []*driverapi.InterfaceInfo {
+	f.t.Fatal("Unexpected call of Interfaces")
+	return nil
+}
+func (f *failEndpoint) AddInterface(int, net.HardwareAddr, net.IPNet, net.IPNet) error {
+	f.t.Fatal("Unexpected call of AddInterface")
+	return nil
+}
+
+func TestDriverError(t *testing.T) {
+	var plugin = "test-net-driver-error"
+
+	mux := http.NewServeMux()
+	defer setupPlugin(t, plugin, mux)()
+
+	handle(t, mux, "CreateEndpoint", func(msg map[string]interface{}) interface{} {
+		return map[string]interface{}{
+			"Err": "this should get raised as an error",
+		}
+	})
+
+	p, err := plugins.Get(plugin, driverapi.NetworkPluginEndpointType)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	driver := newDriver(plugin, p.Client)
+
+	if err := driver.CreateEndpoint(types.UUID("dummy"), types.UUID("dummy"), &testEndpoint{t: t}, map[string]interface{}{}); err == nil {
+		t.Fatalf("Expected error from driver")
+	}
+}
+
+func TestMissingValues(t *testing.T) {
+	var plugin = "test-net-driver-missing"
+
+	mux := http.NewServeMux()
+	defer setupPlugin(t, plugin, mux)()
+
+	ep := &testEndpoint{
+		t:  t,
+		id: 0,
+	}
+
+	handle(t, mux, "CreateEndpoint", func(msg map[string]interface{}) interface{} {
+		iface := map[string]interface{}{
+			"ID":          ep.id,
+			"Address":     ep.address,
+			"AddressIPv6": ep.addressIPv6,
+			"MacAddress":  ep.macAddress,
+		}
+		return map[string]interface{}{
+			"Interfaces": []interface{}{iface},
+		}
+	})
+
+	p, err := plugins.Get(plugin, driverapi.NetworkPluginEndpointType)
+	if err != nil {
+		t.Fatal(err)
+	}
+	driver := newDriver(plugin, p.Client)
+
+	if err := driver.CreateEndpoint(types.UUID("dummy"), types.UUID("dummy"), ep, map[string]interface{}{}); err != nil {
+		t.Fatal(err)
+	}
+}
+
+type rollbackEndpoint struct {
+}
+
+func (r *rollbackEndpoint) Interfaces() []driverapi.InterfaceInfo {
+	return []driverapi.InterfaceInfo{}
+}
+
+func (r *rollbackEndpoint) AddInterface(_ int, _ net.HardwareAddr, _ net.IPNet, _ net.IPNet) error {
+	return fmt.Errorf("fail this to trigger a rollback")
+}
+
+func TestRollback(t *testing.T) {
+	var plugin = "test-net-driver-rollback"
+
+	mux := http.NewServeMux()
+	defer setupPlugin(t, plugin, mux)()
+
+	rolledback := false
+
+	handle(t, mux, "CreateEndpoint", func(msg map[string]interface{}) interface{} {
+		iface := map[string]interface{}{
+			"ID":          0,
+			"Address":     "192.168.4.5/16",
+			"AddressIPv6": "",
+			"MacAddress":  "7a:12:34:56:78:90",
+		}
+		return map[string]interface{}{
+			"Interfaces": []interface{}{iface},
+		}
+	})
+	handle(t, mux, "DeleteEndpoint", func(msg map[string]interface{}) interface{} {
+		rolledback = true
+		return map[string]interface{}{}
+	})
+
+	p, err := plugins.Get(plugin, driverapi.NetworkPluginEndpointType)
+	if err != nil {
+		t.Fatal(err)
+	}
+	driver := newDriver(plugin, p.Client)
+
+	ep := &rollbackEndpoint{}
+
+	if err := driver.CreateEndpoint(types.UUID("dummy"), types.UUID("dummy"), ep, map[string]interface{}{}); err == nil {
+		t.Fatalf("Expected error from driver")
+	}
+	if !rolledback {
+		t.Fatalf("Expected to have had DeleteEndpoint called")
+	}
+}

+ 143 - 0
vendor/src/github.com/docker/libnetwork/drivers/remote/messages.go

@@ -0,0 +1,143 @@
+package remote
+
+import "net"
+
+type response struct {
+	Err string
+}
+
+type maybeError interface {
+	getError() string
+}
+
+func (r *response) getError() string {
+	return r.Err
+}
+
+type createNetworkRequest struct {
+	NetworkID string
+	Options   map[string]interface{}
+}
+
+type createNetworkResponse struct {
+	response
+}
+
+type deleteNetworkRequest struct {
+	NetworkID string
+}
+
+type deleteNetworkResponse struct {
+	response
+}
+
+type createEndpointRequest struct {
+	NetworkID  string
+	EndpointID string
+	Interfaces []*endpointInterface
+	Options    map[string]interface{}
+}
+
+type endpointInterface struct {
+	ID          int
+	Address     string
+	AddressIPv6 string
+	MacAddress  string
+}
+
+type createEndpointResponse struct {
+	response
+	Interfaces []*endpointInterface
+}
+
+func toAddr(ipAddr string) (*net.IPNet, error) {
+	ip, ipnet, err := net.ParseCIDR(ipAddr)
+	if err != nil {
+		return nil, err
+	}
+	ipnet.IP = ip
+	return ipnet, nil
+}
+
+type iface struct {
+	ID          int
+	Address     *net.IPNet
+	AddressIPv6 *net.IPNet
+	MacAddress  net.HardwareAddr
+}
+
+func (r *createEndpointResponse) parseInterfaces() ([]*iface, error) {
+	var (
+		ifaces = make([]*iface, len(r.Interfaces))
+	)
+	for i, inIf := range r.Interfaces {
+		var err error
+		outIf := &iface{ID: inIf.ID}
+		if inIf.Address != "" {
+			if outIf.Address, err = toAddr(inIf.Address); err != nil {
+				return nil, err
+			}
+		}
+		if inIf.AddressIPv6 != "" {
+			if outIf.AddressIPv6, err = toAddr(inIf.AddressIPv6); err != nil {
+				return nil, err
+			}
+		}
+		if inIf.MacAddress != "" {
+			if outIf.MacAddress, err = net.ParseMAC(inIf.MacAddress); err != nil {
+				return nil, err
+			}
+		}
+		ifaces[i] = outIf
+	}
+	return ifaces, nil
+}
+
+type deleteEndpointRequest struct {
+	NetworkID  string
+	EndpointID string
+}
+
+type deleteEndpointResponse struct {
+	response
+}
+
+type endpointInfoRequest struct {
+	NetworkID  string
+	EndpointID string
+}
+
+type endpointInfoResponse struct {
+	response
+	Value map[string]interface{}
+}
+
+type joinRequest struct {
+	NetworkID  string
+	EndpointID string
+	SandboxKey string
+	Options    map[string]interface{}
+}
+
+type ifaceName struct {
+	SrcName string
+	DstName string
+}
+
+type joinResponse struct {
+	response
+	InterfaceNames []*ifaceName
+	Gateway        string
+	GatewayIPv6    string
+	HostsPath      string
+	ResolvConfPath string
+}
+
+type leaveRequest struct {
+	NetworkID  string
+	EndpointID string
+}
+
+type leaveResponse struct {
+	response
+}

+ 12 - 13
vendor/src/github.com/docker/libnetwork/endpoint.go

@@ -12,7 +12,6 @@ import (
 	"github.com/docker/docker/pkg/ioutils"
 	"github.com/docker/libnetwork/etchosts"
 	"github.com/docker/libnetwork/netlabel"
-	"github.com/docker/libnetwork/netutils"
 	"github.com/docker/libnetwork/resolvconf"
 	"github.com/docker/libnetwork/sandbox"
 	"github.com/docker/libnetwork/types"
@@ -106,7 +105,7 @@ type endpoint struct {
 	iFaces        []*endpointInterface
 	joinInfo      *endpointJoinInfo
 	container     *containerInfo
-	exposedPorts  []netutils.TransportPort
+	exposedPorts  []types.TransportPort
 	generic       map[string]interface{}
 	joinLeaveDone chan struct{}
 	sync.Mutex
@@ -217,7 +216,7 @@ func (ep *endpoint) Join(containerID string, options ...EndpointOption) (*Contai
 	ep.Lock()
 	if ep.container != nil {
 		ep.Unlock()
-		return nil, ErrInvalidJoin
+		return nil, ErrInvalidJoin{}
 	}
 
 	ep.container = &containerInfo{
@@ -292,7 +291,7 @@ func (ep *endpoint) Join(containerID string, options ...EndpointOption) (*Contai
 	for _, i := range ifaces {
 		iface := &sandbox.Interface{
 			SrcName: i.srcName,
-			DstName: i.dstName,
+			DstName: i.dstPrefix,
 			Address: &i.addr,
 		}
 		if i.addrv6.IP.To16() != nil {
@@ -335,7 +334,7 @@ func (ep *endpoint) Leave(containerID string, options ...EndpointOption) error {
 	if container == nil || container.id == "" ||
 		containerID == "" || container.id != containerID {
 		if container == nil {
-			err = ErrNoContainer
+			err = ErrNoContainer{}
 		} else {
 			err = InvalidContainerIDError(containerID)
 		}
@@ -413,7 +412,7 @@ func (ep *endpoint) buildHostsFiles() error {
 	ep.Unlock()
 
 	if container == nil {
-		return ErrNoContainer
+		return ErrNoContainer{}
 	}
 
 	if container.config.hostsPath == "" {
@@ -463,7 +462,7 @@ func (ep *endpoint) updateParentHosts() error {
 	ep.Unlock()
 
 	if container == nil {
-		return ErrNoContainer
+		return ErrNoContainer{}
 	}
 
 	for _, update := range container.config.parentUpdates {
@@ -496,7 +495,7 @@ func (ep *endpoint) updateDNS(resolvConf []byte) error {
 	ep.Unlock()
 
 	if container == nil {
-		return ErrNoContainer
+		return ErrNoContainer{}
 	}
 
 	oldHash := []byte{}
@@ -574,7 +573,7 @@ func (ep *endpoint) setupDNS() error {
 	ep.Unlock()
 
 	if container == nil {
-		return ErrNoContainer
+		return ErrNoContainer{}
 	}
 
 	if container.config.resolvConfPath == "" {
@@ -697,10 +696,10 @@ func JoinOptionUseDefaultSandbox() EndpointOption {
 
 // CreateOptionExposedPorts function returns an option setter for the container exposed
 // ports option to be passed to network.CreateEndpoint() method.
-func CreateOptionExposedPorts(exposedPorts []netutils.TransportPort) EndpointOption {
+func CreateOptionExposedPorts(exposedPorts []types.TransportPort) EndpointOption {
 	return func(ep *endpoint) {
 		// Defensive copy
-		eps := make([]netutils.TransportPort, len(exposedPorts))
+		eps := make([]types.TransportPort, len(exposedPorts))
 		copy(eps, exposedPorts)
 		// Store endpoint label and in generic because driver needs it
 		ep.exposedPorts = eps
@@ -710,10 +709,10 @@ func CreateOptionExposedPorts(exposedPorts []netutils.TransportPort) EndpointOpt
 
 // CreateOptionPortMapping function returns an option setter for the mapping
 // ports option to be passed to network.CreateEndpoint() method.
-func CreateOptionPortMapping(portBindings []netutils.PortBinding) EndpointOption {
+func CreateOptionPortMapping(portBindings []types.PortBinding) EndpointOption {
 	return func(ep *endpoint) {
 		// Store a copy of the bindings as generic data to pass to the driver
-		pbs := make([]netutils.PortBinding, len(portBindings))
+		pbs := make([]types.PortBinding, len(portBindings))
 		copy(pbs, portBindings)
 		ep.generic[netlabel.PortMap] = pbs
 	}

+ 19 - 19
vendor/src/github.com/docker/libnetwork/endpoint_info.go

@@ -4,7 +4,7 @@ import (
 	"net"
 
 	"github.com/docker/libnetwork/driverapi"
-	"github.com/docker/libnetwork/netutils"
+	"github.com/docker/libnetwork/types"
 )
 
 // EndpointInfo provides an interface to retrieve network resources bound to the endpoint.
@@ -40,12 +40,12 @@ type InterfaceInfo interface {
 }
 
 type endpointInterface struct {
-	id      int
-	mac     net.HardwareAddr
-	addr    net.IPNet
-	addrv6  net.IPNet
-	srcName string
-	dstName string
+	id        int
+	mac       net.HardwareAddr
+	addr      net.IPNet
+	addrv6    net.IPNet
+	srcName   string
+	dstPrefix string
 }
 
 type endpointJoinInfo struct {
@@ -105,10 +105,10 @@ func (ep *endpoint) AddInterface(id int, mac net.HardwareAddr, ipv4 net.IPNet, i
 
 	iface := &endpointInterface{
 		id:     id,
-		addr:   *netutils.GetIPNetCopy(&ipv4),
-		addrv6: *netutils.GetIPNetCopy(&ipv6),
+		addr:   *types.GetIPNetCopy(&ipv4),
+		addrv6: *types.GetIPNetCopy(&ipv6),
 	}
-	iface.mac = netutils.GetMacCopy(mac)
+	iface.mac = types.GetMacCopy(mac)
 
 	ep.iFaces = append(ep.iFaces, iface)
 	return nil
@@ -119,20 +119,20 @@ func (i *endpointInterface) ID() int {
 }
 
 func (i *endpointInterface) MacAddress() net.HardwareAddr {
-	return netutils.GetMacCopy(i.mac)
+	return types.GetMacCopy(i.mac)
 }
 
 func (i *endpointInterface) Address() net.IPNet {
-	return (*netutils.GetIPNetCopy(&i.addr))
+	return (*types.GetIPNetCopy(&i.addr))
 }
 
 func (i *endpointInterface) AddressIPv6() net.IPNet {
-	return (*netutils.GetIPNetCopy(&i.addrv6))
+	return (*types.GetIPNetCopy(&i.addrv6))
 }
 
-func (i *endpointInterface) SetNames(srcName string, dstName string) error {
+func (i *endpointInterface) SetNames(srcName string, dstPrefix string) error {
 	i.srcName = srcName
-	i.dstName = dstName
+	i.dstPrefix = dstPrefix
 	return nil
 }
 
@@ -168,7 +168,7 @@ func (ep *endpoint) Gateway() net.IP {
 		return net.IP{}
 	}
 
-	return netutils.GetIPCopy(ep.joinInfo.gw)
+	return types.GetIPCopy(ep.joinInfo.gw)
 }
 
 func (ep *endpoint) GatewayIPv6() net.IP {
@@ -179,14 +179,14 @@ func (ep *endpoint) GatewayIPv6() net.IP {
 		return net.IP{}
 	}
 
-	return netutils.GetIPCopy(ep.joinInfo.gw6)
+	return types.GetIPCopy(ep.joinInfo.gw6)
 }
 
 func (ep *endpoint) SetGateway(gw net.IP) error {
 	ep.Lock()
 	defer ep.Unlock()
 
-	ep.joinInfo.gw = netutils.GetIPCopy(gw)
+	ep.joinInfo.gw = types.GetIPCopy(gw)
 	return nil
 }
 
@@ -194,7 +194,7 @@ func (ep *endpoint) SetGatewayIPv6(gw6 net.IP) error {
 	ep.Lock()
 	defer ep.Unlock()
 
-	ep.joinInfo.gw6 = netutils.GetIPCopy(gw6)
+	ep.joinInfo.gw6 = types.GetIPCopy(gw6)
 	return nil
 }
 

+ 97 - 27
vendor/src/github.com/docker/libnetwork/error.go

@@ -1,34 +1,83 @@
 package libnetwork
 
 import (
-	"errors"
 	"fmt"
 )
 
-var (
-	// ErrNoSuchNetwork is returned when a network query finds no result
-	ErrNoSuchNetwork = errors.New("network not found")
-	// ErrNoSuchEndpoint is returned when a endpoint query finds no result
-	ErrNoSuchEndpoint = errors.New("endpoint not found")
-	// ErrNilNetworkDriver is returned if a nil network driver
-	// is passed to NewNetwork api.
-	ErrNilNetworkDriver = errors.New("nil NetworkDriver instance")
-	// ErrInvalidNetworkDriver is returned if an invalid driver
-	// instance is passed.
-	ErrInvalidNetworkDriver = errors.New("invalid driver bound to network")
-	// ErrInvalidJoin is returned if a join is attempted on an endpoint
-	// which already has a container joined.
-	ErrInvalidJoin = errors.New("a container has already joined the endpoint")
-	// ErrNoContainer is returned when the endpoint has no container
-	// attached to it.
-	ErrNoContainer = errors.New("no container attached to the endpoint")
-	// ErrInvalidID is returned when a query-by-id method is being invoked
-	// with an empty id parameter
-	ErrInvalidID = errors.New("invalid ID")
-	// ErrInvalidName is returned when a query-by-name or resource create method is
-	// invoked with an empty name parameter
-	ErrInvalidName = errors.New("invalid Name")
-)
+// ErrNoSuchNetwork is returned when a network query finds no result
+type ErrNoSuchNetwork string
+
+func (nsn ErrNoSuchNetwork) Error() string {
+	return fmt.Sprintf("network %s not found", string(nsn))
+}
+
+// BadRequest denotes the type of this error
+func (nsn ErrNoSuchNetwork) BadRequest() {}
+
+// ErrNoSuchEndpoint is returned when a endpoint query finds no result
+type ErrNoSuchEndpoint string
+
+func (nse ErrNoSuchEndpoint) Error() string {
+	return fmt.Sprintf("endpoint %s not found", string(nse))
+}
+
+// BadRequest denotes the type of this error
+func (nse ErrNoSuchEndpoint) BadRequest() {}
+
+// ErrInvalidNetworkDriver is returned if an invalid driver
+// name is passed.
+type ErrInvalidNetworkDriver string
+
+func (ind ErrInvalidNetworkDriver) Error() string {
+	return fmt.Sprintf("invalid driver bound to network: %s", string(ind))
+}
+
+// BadRequest denotes the type of this error
+func (ind ErrInvalidNetworkDriver) BadRequest() {}
+
+// ErrInvalidJoin is returned if a join is attempted on an endpoint
+// which already has a container joined.
+type ErrInvalidJoin struct{}
+
+func (ij ErrInvalidJoin) Error() string {
+	return "a container has already joined the endpoint"
+}
+
+// BadRequest denotes the type of this error
+func (ij ErrInvalidJoin) BadRequest() {}
+
+// ErrNoContainer is returned when the endpoint has no container
+// attached to it.
+type ErrNoContainer struct{}
+
+func (nc ErrNoContainer) Error() string {
+	return "a container has already joined the endpoint"
+}
+
+// Maskable denotes the type of this error
+func (nc ErrNoContainer) Maskable() {}
+
+// ErrInvalidID is returned when a query-by-id method is being invoked
+// with an empty id parameter
+type ErrInvalidID string
+
+func (ii ErrInvalidID) Error() string {
+	return fmt.Sprintf("invalid id: %s", string(ii))
+}
+
+// BadRequest denotes the type of this error
+func (ii ErrInvalidID) BadRequest() {}
+
+// ErrInvalidName is returned when a query-by-name or resource create method is
+// invoked with an empty name parameter
+type ErrInvalidName string
+
+func (in ErrInvalidName) Error() string {
+	return fmt.Sprintf("invalid name: %s", string(in))
+}
+
+// BadRequest denotes the type of this error
+func (in ErrInvalidName) BadRequest() {}
 
 // NetworkTypeError type is returned when the network type string is not
 // known to libnetwork.
@@ -38,13 +87,19 @@ func (nt NetworkTypeError) Error() string {
 	return fmt.Sprintf("unknown driver %q", string(nt))
 }
 
+// NotFound denotes the type of this error
+func (nt NetworkTypeError) NotFound() {}
+
 // NetworkNameError is returned when a network with the same name already exists.
 type NetworkNameError string
 
-func (name NetworkNameError) Error() string {
-	return fmt.Sprintf("network with name %s already exists", string(name))
+func (nnr NetworkNameError) Error() string {
+	return fmt.Sprintf("network with name %s already exists", string(nnr))
 }
 
+// Forbidden denotes the type of this error
+func (nnr NetworkNameError) Forbidden() {}
+
 // UnknownNetworkError is returned when libnetwork could not find in it's database
 // a network with the same name and id.
 type UnknownNetworkError struct {
@@ -56,6 +111,9 @@ func (une *UnknownNetworkError) Error() string {
 	return fmt.Sprintf("unknown network %s id %s", une.name, une.id)
 }
 
+// NotFound denotes the type of this error
+func (une *UnknownNetworkError) NotFound() {}
+
 // ActiveEndpointsError is returned when a network is deleted which has active
 // endpoints in it.
 type ActiveEndpointsError struct {
@@ -67,6 +125,9 @@ func (aee *ActiveEndpointsError) Error() string {
 	return fmt.Sprintf("network with name %s id %s has active endpoints", aee.name, aee.id)
 }
 
+// Forbidden denotes the type of this error
+func (aee *ActiveEndpointsError) Forbidden() {}
+
 // UnknownEndpointError is returned when libnetwork could not find in it's database
 // an endpoint with the same name and id.
 type UnknownEndpointError struct {
@@ -78,6 +139,9 @@ func (uee *UnknownEndpointError) Error() string {
 	return fmt.Sprintf("unknown endpoint %s id %s", uee.name, uee.id)
 }
 
+// NotFound denotes the type of this error
+func (uee *UnknownEndpointError) NotFound() {}
+
 // ActiveContainerError is returned when an endpoint is deleted which has active
 // containers attached to it.
 type ActiveContainerError struct {
@@ -89,6 +153,9 @@ func (ace *ActiveContainerError) Error() string {
 	return fmt.Sprintf("endpoint with name %s id %s has active containers", ace.name, ace.id)
 }
 
+// Forbidden denotes the type of this error
+func (ace *ActiveContainerError) Forbidden() {}
+
 // InvalidContainerIDError is returned when an invalid container id is passed
 // in Join/Leave
 type InvalidContainerIDError string
@@ -96,3 +163,6 @@ type InvalidContainerIDError string
 func (id InvalidContainerIDError) Error() string {
 	return fmt.Sprintf("invalid container id %s", string(id))
 }
+
+// BadRequest denotes the type of this error
+func (id InvalidContainerIDError) BadRequest() {}

+ 51 - 0
vendor/src/github.com/docker/libnetwork/errors_test.go

@@ -0,0 +1,51 @@
+package libnetwork
+
+import (
+	"testing"
+
+	"github.com/docker/libnetwork/types"
+)
+
+func TestErrorInterfaces(t *testing.T) {
+
+	badRequestErrorList := []error{ErrInvalidID(""), ErrInvalidName(""), ErrInvalidJoin{}, ErrInvalidNetworkDriver(""), InvalidContainerIDError(""), ErrNoSuchNetwork(""), ErrNoSuchEndpoint("")}
+	for _, err := range badRequestErrorList {
+		switch u := err.(type) {
+		case types.BadRequestError:
+			return
+		default:
+			t.Fatalf("Failed to detect err %v is of type BadRequestError. Got type: %T", err, u)
+		}
+	}
+
+	maskableErrorList := []error{ErrNoContainer{}}
+	for _, err := range maskableErrorList {
+		switch u := err.(type) {
+		case types.MaskableError:
+			return
+		default:
+			t.Fatalf("Failed to detect err %v is of type MaskableError. Got type: %T", err, u)
+		}
+	}
+
+	notFoundErrorList := []error{NetworkTypeError(""), &UnknownNetworkError{}, &UnknownEndpointError{}}
+	for _, err := range notFoundErrorList {
+		switch u := err.(type) {
+		case types.NotFoundError:
+			return
+		default:
+			t.Fatalf("Failed to detect err %v is of type NotFoundError. Got type: %T", err, u)
+		}
+	}
+
+	forbiddenErrorList := []error{NetworkTypeError(""), &UnknownNetworkError{}, &UnknownEndpointError{}}
+	for _, err := range forbiddenErrorList {
+		switch u := err.(type) {
+		case types.ForbiddenError:
+			return
+		default:
+			t.Fatalf("Failed to detect err %v is of type ForbiddenError. Got type: %T", err, u)
+		}
+	}
+
+}

+ 1 - 1
vendor/src/github.com/docker/libnetwork/iptables/iptables_test.go

@@ -11,7 +11,7 @@ import (
 	_ "github.com/docker/libnetwork/netutils"
 )
 
-const chainName = "DOCKER-TEST"
+const chainName = "DOCKEREST"
 
 var natChain *Chain
 var filterChain *Chain

+ 68 - 26
vendor/src/github.com/docker/libnetwork/libnetwork_test.go

@@ -22,6 +22,8 @@ import (
 	"github.com/docker/libnetwork/netlabel"
 	"github.com/docker/libnetwork/netutils"
 	"github.com/docker/libnetwork/options"
+	"github.com/docker/libnetwork/types"
+	"github.com/vishvananda/netlink"
 	"github.com/vishvananda/netns"
 )
 
@@ -65,11 +67,11 @@ func getEmptyGenericOption() map[string]interface{} {
 	return genericOption
 }
 
-func getPortMapping() []netutils.PortBinding {
-	return []netutils.PortBinding{
-		netutils.PortBinding{Proto: netutils.TCP, Port: uint16(230), HostPort: uint16(23000)},
-		netutils.PortBinding{Proto: netutils.UDP, Port: uint16(200), HostPort: uint16(22000)},
-		netutils.PortBinding{Proto: netutils.TCP, Port: uint16(120), HostPort: uint16(12000)},
+func getPortMapping() []types.PortBinding {
+	return []types.PortBinding{
+		types.PortBinding{Proto: types.TCP, Port: uint16(230), HostPort: uint16(23000)},
+		types.PortBinding{Proto: types.UDP, Port: uint16(200), HostPort: uint16(22000)},
+		types.PortBinding{Proto: types.TCP, Port: uint16(120), HostPort: uint16(12000)},
 	}
 }
 
@@ -245,7 +247,7 @@ func TestBridge(t *testing.T) {
 	if !ok {
 		t.Fatalf("Could not find expected info in endpoint data")
 	}
-	pm, ok := pmd.([]netutils.PortBinding)
+	pm, ok := pmd.([]types.PortBinding)
 	if !ok {
 		t.Fatalf("Unexpected format for port mapping in endpoint operational data")
 	}
@@ -289,7 +291,7 @@ func TestNilRemoteDriver(t *testing.T) {
 		t.Fatal("Expected to fail. But instead succeeded")
 	}
 
-	if err != plugins.ErrNotFound {
+	if _, ok := err.(types.NotFoundError); !ok {
 		t.Fatalf("Did not fail with expected error. Actual error: %v", err)
 	}
 }
@@ -337,8 +339,9 @@ func TestNetworkName(t *testing.T) {
 	if err == nil {
 		t.Fatal("Expected to fail. But instead succeeded")
 	}
-	if err != libnetwork.ErrInvalidName {
-		t.Fatal("Expected to fail with ErrInvalidName error")
+
+	if _, ok := err.(libnetwork.ErrInvalidName); !ok {
+		t.Fatalf("Expected to fail with ErrInvalidName error. Got %v", err)
 	}
 
 	networkName := "testnetwork"
@@ -474,8 +477,8 @@ func TestUnknownEndpoint(t *testing.T) {
 	if err == nil {
 		t.Fatal("Expected to fail. But instead succeeded")
 	}
-	if err != libnetwork.ErrInvalidName {
-		t.Fatal("Expected to fail with ErrInvalidName error")
+	if _, ok := err.(libnetwork.ErrInvalidName); !ok {
+		t.Fatalf("Expected to fail with ErrInvalidName error. Actual error: %v", err)
 	}
 
 	ep, err := network.CreateEndpoint("testep")
@@ -612,15 +615,15 @@ func TestControllerQuery(t *testing.T) {
 	if err == nil {
 		t.Fatalf("NetworkByName() succeeded with invalid target name")
 	}
-	if err != libnetwork.ErrInvalidName {
-		t.Fatalf("NetworkByName() failed with unexpected error: %v", err)
+	if _, ok := err.(libnetwork.ErrInvalidName); !ok {
+		t.Fatalf("Expected NetworkByName() to fail with ErrInvalidName error. Got: %v", err)
 	}
 
 	_, err = controller.NetworkByID("")
 	if err == nil {
 		t.Fatalf("NetworkByID() succeeded with invalid target id")
 	}
-	if err != libnetwork.ErrInvalidID {
+	if _, ok := err.(libnetwork.ErrInvalidID); !ok {
 		t.Fatalf("NetworkByID() failed with unexpected error: %v", err)
 	}
 
@@ -628,7 +631,7 @@ func TestControllerQuery(t *testing.T) {
 	if err == nil {
 		t.Fatalf("Unexpected success for NetworkByID(): %v", g)
 	}
-	if err != libnetwork.ErrNoSuchNetwork {
+	if _, ok := err.(libnetwork.ErrNoSuchNetwork); !ok {
 		t.Fatalf("NetworkByID() failed with unexpected error: %v", err)
 	}
 
@@ -694,15 +697,15 @@ func TestNetworkQuery(t *testing.T) {
 	if err == nil {
 		t.Fatalf("EndpointByName() succeeded with invalid target name")
 	}
-	if err != libnetwork.ErrInvalidName {
-		t.Fatalf("EndpointByName() failed with unexpected error: %v", err)
+	if _, ok := err.(libnetwork.ErrInvalidName); !ok {
+		t.Fatalf("Expected EndpointByName() to fail with ErrInvalidName error. Got: %v", err)
 	}
 
 	e, err = net1.EndpointByName("IamNotAnEndpoint")
 	if err == nil {
 		t.Fatalf("EndpointByName() succeeded with unknown target name")
 	}
-	if err != libnetwork.ErrNoSuchEndpoint {
+	if _, ok := err.(libnetwork.ErrNoSuchEndpoint); !ok {
 		t.Fatal(err)
 	}
 	if e != nil {
@@ -721,13 +724,42 @@ func TestNetworkQuery(t *testing.T) {
 	if err == nil {
 		t.Fatalf("EndpointByID() succeeded with invalid target id")
 	}
-	if err != libnetwork.ErrInvalidID {
+	if _, ok := err.(libnetwork.ErrInvalidID); !ok {
 		t.Fatalf("EndpointByID() failed with unexpected error: %v", err)
 	}
 }
 
 const containerID = "valid_container"
 
+func checkSandbox(t *testing.T, info libnetwork.EndpointInfo) {
+	origns, err := netns.Get()
+	if err != nil {
+		t.Fatalf("Could not get the current netns: %v", err)
+	}
+	defer origns.Close()
+
+	key := info.SandboxKey()
+	f, err := os.OpenFile(key, os.O_RDONLY, 0)
+	if err != nil {
+		t.Fatalf("Failed to open network namespace path %q: %v", key, err)
+	}
+	defer f.Close()
+
+	runtime.LockOSThread()
+	defer runtime.UnlockOSThread()
+
+	nsFD := f.Fd()
+	if err = netns.Set(netns.NsHandle(nsFD)); err != nil {
+		t.Fatalf("Setting to the namespace pointed to by the sandbox %s failed: %v", key, err)
+	}
+	defer netns.Set(origns)
+
+	_, err = netlink.LinkByName("eth0")
+	if err != nil {
+		t.Fatalf("Could not find the interface eth0 inside the sandbox: %v", err)
+	}
+}
+
 func TestEndpointJoin(t *testing.T) {
 	if !netutils.IsRunningInContainer() {
 		defer netutils.SetupTestNetNS(t)()
@@ -784,6 +816,8 @@ func TestEndpointJoin(t *testing.T) {
 	if info.SandboxKey() == "" {
 		t.Fatalf("Expected an non-empty sandbox key for a joined endpoint. Instead found a empty sandbox key")
 	}
+
+	checkSandbox(t, info)
 }
 
 func TestEndpointJoinInvalidContainerId(t *testing.T) {
@@ -890,7 +924,7 @@ func TestEndpointMultipleJoins(t *testing.T) {
 		t.Fatal("Expected to fail multiple joins for the same endpoint")
 	}
 
-	if err != libnetwork.ErrInvalidJoin {
+	if _, ok := err.(libnetwork.ErrInvalidJoin); !ok {
 		t.Fatalf("Failed for unexpected reason: %v", err)
 	}
 }
@@ -916,7 +950,7 @@ func TestEndpointInvalidLeave(t *testing.T) {
 	}
 
 	if _, ok := err.(libnetwork.InvalidContainerIDError); !ok {
-		if err != libnetwork.ErrNoContainer {
+		if _, ok := err.(libnetwork.ErrNoContainer); !ok {
 			t.Fatalf("Failed for unexpected reason: %v", err)
 		}
 	}
@@ -1275,6 +1309,10 @@ func TestValidRemoteDriver(t *testing.T) {
 		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
 		fmt.Fprintf(w, `{"Implements": ["%s"]}`, driverapi.NetworkPluginEndpointType)
 	})
+	mux.HandleFunc(fmt.Sprintf("/%s.CreateNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
+		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
+		fmt.Fprintf(w, "null")
+	})
 
 	if err := os.MkdirAll("/usr/share/docker/plugins", 0755); err != nil {
 		t.Fatal(err)
@@ -1296,7 +1334,7 @@ func TestValidRemoteDriver(t *testing.T) {
 
 	_, err = controller.NewNetwork("valid-network-driver", "dummy",
 		libnetwork.NetworkOptionGeneric(getEmptyGenericOption()))
-	if err != nil && err != driverapi.ErrNotImplemented {
+	if err != nil {
 		t.Fatal(err)
 	}
 }
@@ -1370,8 +1408,10 @@ func parallelJoin(t *testing.T, ep libnetwork.Endpoint, thrNumber int) {
 	_, err := ep.Join("racing_container")
 	runtime.LockOSThread()
 	if err != nil {
-		if err != libnetwork.ErrNoContainer && err != libnetwork.ErrInvalidJoin {
-			t.Fatal(err)
+		if _, ok := err.(libnetwork.ErrNoContainer); !ok {
+			if _, ok := err.(libnetwork.ErrInvalidJoin); !ok {
+				t.Fatal(err)
+			}
 		}
 		debugf("JE%d(%v).", thrNumber, err)
 	}
@@ -1383,8 +1423,10 @@ func parallelLeave(t *testing.T, ep libnetwork.Endpoint, thrNumber int) {
 	err := ep.Leave("racing_container")
 	runtime.LockOSThread()
 	if err != nil {
-		if err != libnetwork.ErrNoContainer && err != libnetwork.ErrInvalidJoin {
-			t.Fatal(err)
+		if _, ok := err.(libnetwork.ErrNoContainer); !ok {
+			if _, ok := err.(libnetwork.ErrInvalidJoin); !ok {
+				t.Fatal(err)
+			}
 		}
 		debugf("LE%d(%v).", thrNumber, err)
 	}

+ 0 - 175
vendor/src/github.com/docker/libnetwork/netutils/utils.go

@@ -3,14 +3,12 @@
 package netutils
 
 import (
-	"bytes"
 	"crypto/rand"
 	"encoding/hex"
 	"errors"
 	"fmt"
 	"io"
 	"net"
-	"strings"
 
 	"github.com/vishvananda/netlink"
 )
@@ -26,144 +24,6 @@ var (
 	networkGetRoutesFct = netlink.RouteList
 )
 
-// ErrInvalidProtocolBinding is returned when the port binding protocol is not valid.
-type ErrInvalidProtocolBinding string
-
-func (ipb ErrInvalidProtocolBinding) Error() string {
-	return fmt.Sprintf("invalid transport protocol: %s", string(ipb))
-}
-
-// TransportPort represent a local Layer 4 endpoint
-type TransportPort struct {
-	Proto Protocol
-	Port  uint16
-}
-
-// GetCopy returns a copy of this TransportPort structure instance
-func (t *TransportPort) GetCopy() TransportPort {
-	return TransportPort{Proto: t.Proto, Port: t.Port}
-}
-
-// PortBinding represent a port binding between the container an the host
-type PortBinding struct {
-	Proto    Protocol
-	IP       net.IP
-	Port     uint16
-	HostIP   net.IP
-	HostPort uint16
-}
-
-// HostAddr returns the host side transport address
-func (p PortBinding) HostAddr() (net.Addr, error) {
-	switch p.Proto {
-	case UDP:
-		return &net.UDPAddr{IP: p.HostIP, Port: int(p.HostPort)}, nil
-	case TCP:
-		return &net.TCPAddr{IP: p.HostIP, Port: int(p.HostPort)}, nil
-	default:
-		return nil, ErrInvalidProtocolBinding(p.Proto.String())
-	}
-}
-
-// ContainerAddr returns the container side transport address
-func (p PortBinding) ContainerAddr() (net.Addr, error) {
-	switch p.Proto {
-	case UDP:
-		return &net.UDPAddr{IP: p.IP, Port: int(p.Port)}, nil
-	case TCP:
-		return &net.TCPAddr{IP: p.IP, Port: int(p.Port)}, nil
-	default:
-		return nil, ErrInvalidProtocolBinding(p.Proto.String())
-	}
-}
-
-// GetCopy returns a copy of this PortBinding structure instance
-func (p *PortBinding) GetCopy() PortBinding {
-	return PortBinding{
-		Proto:    p.Proto,
-		IP:       GetIPCopy(p.IP),
-		Port:     p.Port,
-		HostIP:   GetIPCopy(p.HostIP),
-		HostPort: p.HostPort,
-	}
-}
-
-// Equal checks if this instance of PortBinding is equal to the passed one
-func (p *PortBinding) Equal(o *PortBinding) bool {
-	if p == o {
-		return true
-	}
-
-	if o == nil {
-		return false
-	}
-
-	if p.Proto != o.Proto || p.Port != o.Port || p.HostPort != o.HostPort {
-		return false
-	}
-
-	if p.IP != nil {
-		if !p.IP.Equal(o.IP) {
-			return false
-		}
-	} else {
-		if o.IP != nil {
-			return false
-		}
-	}
-
-	if p.HostIP != nil {
-		if !p.HostIP.Equal(o.HostIP) {
-			return false
-		}
-	} else {
-		if o.HostIP != nil {
-			return false
-		}
-	}
-
-	return true
-}
-
-const (
-	// ICMP is for the ICMP ip protocol
-	ICMP = 1
-	// TCP is for the TCP ip protocol
-	TCP = 6
-	// UDP is for the UDP ip protocol
-	UDP = 17
-)
-
-// Protocol represents a IP protocol number
-type Protocol uint8
-
-func (p Protocol) String() string {
-	switch p {
-	case ICMP:
-		return "icmp"
-	case TCP:
-		return "tcp"
-	case UDP:
-		return "udp"
-	default:
-		return fmt.Sprintf("%d", p)
-	}
-}
-
-// ParseProtocol returns the respective Protocol type for the passed string
-func ParseProtocol(s string) Protocol {
-	switch strings.ToLower(s) {
-	case "icmp":
-		return ICMP
-	case "udp":
-		return UDP
-	case "tcp":
-		return TCP
-	default:
-		return 0
-	}
-}
-
 // CheckNameserverOverlaps checks whether the passed network overlaps with any of the nameservers
 func CheckNameserverOverlaps(nameservers []string, toCheck *net.IPNet) error {
 	if len(nameservers) > 0 {
@@ -287,38 +147,3 @@ func GenerateRandomName(prefix string, size int) (string, error) {
 	}
 	return prefix + hex.EncodeToString(id)[:size], nil
 }
-
-// GetMacCopy returns a copy of the passed MAC address
-func GetMacCopy(from net.HardwareAddr) net.HardwareAddr {
-	to := make(net.HardwareAddr, len(from))
-	copy(to, from)
-	return to
-}
-
-// GetIPCopy returns a copy of the passed IP address
-func GetIPCopy(from net.IP) net.IP {
-	to := make(net.IP, len(from))
-	copy(to, from)
-	return to
-}
-
-// GetIPNetCopy returns a copy of the passed IP Network
-func GetIPNetCopy(from *net.IPNet) *net.IPNet {
-	if from == nil {
-		return nil
-	}
-	bm := make(net.IPMask, len(from.Mask))
-	copy(bm, from.Mask)
-	return &net.IPNet{IP: GetIPCopy(from.IP), Mask: bm}
-}
-
-// CompareIPNet returns equal if the two IP Networks are equal
-func CompareIPNet(a, b *net.IPNet) bool {
-	if a == b {
-		return true
-	}
-	if a == nil || b == nil {
-		return false
-	}
-	return a.IP.Equal(b.IP) && bytes.Equal(a.Mask, b.Mask)
-}

+ 0 - 132
vendor/src/github.com/docker/libnetwork/netutils/utils_test.go

@@ -209,135 +209,3 @@ func TestUtilGenerateRandomMAC(t *testing.T) {
 		t.Fatalf("mac1 %s should not equal mac2 %s", mac1, mac2)
 	}
 }
-
-func TestCompareIPNet(t *testing.T) {
-	if CompareIPNet(nil, nil) == false {
-		t.Fatalf("Failed to detect two nil net.IPNets are equal")
-	}
-
-	_, net1, _ := net.ParseCIDR("192.168.30.22/24")
-	if CompareIPNet(net1, net1) == false {
-		t.Fatalf("Failed to detect same net.IPNet pointers equality")
-	}
-
-	_, net2, _ := net.ParseCIDR("192.168.30.22/24")
-	if CompareIPNet(net1, net2) == false {
-		t.Fatalf("Failed to detect same net.IPNet object equality")
-	}
-
-	_, net3, _ := net.ParseCIDR("192.168.30.33/24")
-	if CompareIPNet(net1, net3) == false {
-		t.Fatalf("Failed to detect semantically equivalent net.IPNets")
-	}
-
-	_, net3, _ = net.ParseCIDR("192.168.31.33/24")
-	if CompareIPNet(net2, net3) == true {
-		t.Fatalf("Failed to detect different net.IPNets")
-	}
-}
-
-func TestIPCopyFunctions(t *testing.T) {
-	ip := net.ParseIP("172.28.30.134")
-	cp := GetIPCopy(ip)
-
-	if !ip.Equal(cp) {
-		t.Fatalf("Failed to return a copy of net.IP")
-	}
-
-	if &ip == &cp {
-		t.Fatalf("Failed to return a true copy of net.IP")
-	}
-}
-
-func TestNetIPCopyFunctions(t *testing.T) {
-	_, net, _ := net.ParseCIDR("192.168.30.23/24")
-	cp := GetIPNetCopy(net)
-
-	if CompareIPNet(net, cp) == false {
-		t.Fatalf("Failed to return a copy of net.IPNet")
-	}
-
-	if net == cp {
-		t.Fatalf("Failed to return a true copy of net.IPNet")
-	}
-}
-
-func TestPortBindingEqual(t *testing.T) {
-	pb1 := &PortBinding{
-		Proto:    TCP,
-		IP:       net.ParseIP("172.17.0.1"),
-		Port:     80,
-		HostIP:   net.ParseIP("192.168.100.1"),
-		HostPort: 8080,
-	}
-
-	pb2 := &PortBinding{
-		Proto:    UDP,
-		IP:       net.ParseIP("172.17.0.1"),
-		Port:     22,
-		HostIP:   net.ParseIP("192.168.100.1"),
-		HostPort: 2222,
-	}
-	if !pb1.Equal(pb1) {
-		t.Fatalf("PortBinding.Equal() returned false negative")
-	}
-
-	if pb1.Equal(nil) {
-		t.Fatalf("PortBinding.Equal() returned false negative")
-	}
-
-	if pb1.Equal(pb2) {
-		t.Fatalf("PortBinding.Equal() returned false positive")
-	}
-
-	if pb1.Equal(pb2) != pb2.Equal(pb1) {
-		t.Fatalf("PortBinding.Equal() failed commutative check")
-	}
-}
-
-func TestPortBindingGetCopy(t *testing.T) {
-	pb := &PortBinding{
-		Proto:    TCP,
-		IP:       net.ParseIP("172.17.0.1"),
-		Port:     80,
-		HostIP:   net.ParseIP("192.168.100.1"),
-		HostPort: 8080,
-	}
-	cp := pb.GetCopy()
-
-	if !pb.Equal(&cp) {
-		t.Fatalf("Failed to return a copy of PortBinding")
-	}
-
-	if pb == &cp {
-		t.Fatalf("Failed to return a true copy of PortBinding")
-	}
-}
-
-func TestPortBindingContainerAddr(t *testing.T) {
-	pb := PortBinding{
-		Proto:    TCP,
-		IP:       net.ParseIP("172.17.0.1"),
-		Port:     80,
-		HostIP:   net.ParseIP("192.168.100.1"),
-		HostPort: 8080,
-	}
-
-	container, err := pb.ContainerAddr()
-
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	switch netAddr := container.(type) {
-	case *net.TCPAddr:
-		if !pb.IP.Equal(netAddr.IP) {
-			t.Fatalf("PortBinding.ContainerAddr() Failed to return a ContainerAddr")
-		}
-		if int(pb.Port) != netAddr.Port {
-			t.Fatalf("PortBinding.ContainerAddr() Failed to return a ContainerAddr")
-		}
-	case *net.UDPAddr:
-		t.Fatalf("PortBinding.ContainerAddr() Failed to check correct proto")
-	}
-}

+ 5 - 5
vendor/src/github.com/docker/libnetwork/network.go

@@ -133,7 +133,7 @@ func (n *network) Delete() error {
 
 func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoint, error) {
 	if name == "" {
-		return nil, ErrInvalidName
+		return nil, ErrInvalidName(name)
 	}
 	ep := &endpoint{name: name, iFaces: []*endpointInterface{}, generic: make(map[string]interface{})}
 	ep.id = types.UUID(stringid.GenerateRandomID())
@@ -173,7 +173,7 @@ func (n *network) WalkEndpoints(walker EndpointWalker) {
 
 func (n *network) EndpointByName(name string) (Endpoint, error) {
 	if name == "" {
-		return nil, ErrInvalidName
+		return nil, ErrInvalidName(name)
 	}
 	var e Endpoint
 
@@ -188,7 +188,7 @@ func (n *network) EndpointByName(name string) (Endpoint, error) {
 	n.WalkEndpoints(s)
 
 	if e == nil {
-		return nil, ErrNoSuchEndpoint
+		return nil, ErrNoSuchEndpoint(name)
 	}
 
 	return e, nil
@@ -196,12 +196,12 @@ func (n *network) EndpointByName(name string) (Endpoint, error) {
 
 func (n *network) EndpointByID(id string) (Endpoint, error) {
 	if id == "" {
-		return nil, ErrInvalidID
+		return nil, ErrInvalidID(id)
 	}
 	n.Lock()
 	defer n.Unlock()
 	if e, ok := n.endpoints[types.UUID(id)]; ok {
 		return e, nil
 	}
-	return nil, ErrNoSuchEndpoint
+	return nil, ErrNoSuchEndpoint(id)
 }

+ 9 - 9
vendor/src/github.com/docker/libnetwork/portmapper/mapper.go

@@ -84,6 +84,8 @@ func (pm *PortMapper) Map(container net.Addr, hostIP net.IP, hostPort int, usePr
 
 		if useProxy {
 			m.userlandProxy = newProxy(proto, hostIP, allocatedHostPort, container.(*net.TCPAddr).IP, container.(*net.TCPAddr).Port)
+		} else {
+			m.userlandProxy = newDummyProxy(proto, hostIP, allocatedHostPort)
 		}
 	case *net.UDPAddr:
 		proto = "udp"
@@ -99,6 +101,8 @@ func (pm *PortMapper) Map(container net.Addr, hostIP net.IP, hostPort int, usePr
 
 		if useProxy {
 			m.userlandProxy = newProxy(proto, hostIP, allocatedHostPort, container.(*net.UDPAddr).IP, container.(*net.UDPAddr).Port)
+		} else {
+			m.userlandProxy = newDummyProxy(proto, hostIP, allocatedHostPort)
 		}
 	default:
 		return nil, ErrUnknownBackendAddressType
@@ -123,9 +127,7 @@ func (pm *PortMapper) Map(container net.Addr, hostIP net.IP, hostPort int, usePr
 
 	cleanup := func() error {
 		// need to undo the iptables rules before we return
-		if m.userlandProxy != nil {
-			m.userlandProxy.Stop()
-		}
+		m.userlandProxy.Stop()
 		pm.forward(iptables.Delete, m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort)
 		if err := pm.Allocator.ReleasePort(hostIP, m.proto, allocatedHostPort); err != nil {
 			return err
@@ -134,13 +136,11 @@ func (pm *PortMapper) Map(container net.Addr, hostIP net.IP, hostPort int, usePr
 		return nil
 	}
 
-	if m.userlandProxy != nil {
-		if err := m.userlandProxy.Start(); err != nil {
-			if err := cleanup(); err != nil {
-				return nil, fmt.Errorf("Error during port allocation cleanup: %v", err)
-			}
-			return nil, err
+	if err := m.userlandProxy.Start(); err != nil {
+		if err := cleanup(); err != nil {
+			return nil, fmt.Errorf("Error during port allocation cleanup: %v", err)
 		}
+		return nil, err
 	}
 
 	pm.currentMappings[key] = m

+ 81 - 37
vendor/src/github.com/docker/libnetwork/portmapper/mapper_test.go

@@ -2,20 +2,16 @@ package portmapper
 
 import (
 	"net"
-	"os"
+	"strings"
 	"testing"
-	"time"
 
-	"github.com/docker/docker/pkg/reexec"
 	"github.com/docker/libnetwork/iptables"
-	"github.com/docker/libnetwork/netutils"
+	_ "github.com/docker/libnetwork/netutils"
 )
 
-func TestMain(m *testing.M) {
-	if reexec.Init() {
-		return
-	}
-	os.Exit(m.Run())
+func init() {
+	// override this func to mock out the proxy server
+	newProxy = newMockProxyCommand
 }
 
 func TestSetIptablesChain(t *testing.T) {
@@ -37,7 +33,6 @@ func TestSetIptablesChain(t *testing.T) {
 }
 
 func TestMapTCPPorts(t *testing.T) {
-	defer netutils.SetupTestNetNS(t)()
 	pm := New()
 	dstIP1 := net.ParseIP("192.168.0.1")
 	dstIP2 := net.ParseIP("192.168.0.2")
@@ -117,7 +112,6 @@ func TestGetUDPIPAndPort(t *testing.T) {
 }
 
 func TestMapUDPPorts(t *testing.T) {
-	defer netutils.SetupTestNetNS(t)()
 	pm := New()
 	dstIP1 := net.ParseIP("192.168.0.1")
 	dstIP2 := net.ParseIP("192.168.0.2")
@@ -164,11 +158,6 @@ func TestMapUDPPorts(t *testing.T) {
 }
 
 func TestMapAllPortsSingleInterface(t *testing.T) {
-	newProxy = newMockProxyCommand
-	defer func() {
-		newProxy = newProxyCommand
-	}()
-	defer netutils.SetupTestNetNS(t)()
 	pm := New()
 	dstIP1 := net.ParseIP("0.0.0.0")
 	srcAddr1 := &net.TCPAddr{Port: 1080, IP: net.ParseIP("172.16.0.1")}
@@ -177,6 +166,12 @@ func TestMapAllPortsSingleInterface(t *testing.T) {
 	var host net.Addr
 	var err error
 
+	defer func() {
+		for _, val := range hosts {
+			pm.Unmap(val)
+		}
+	}()
+
 	for i := 0; i < 10; i++ {
 		start, end := pm.Allocator.Begin, pm.Allocator.End
 		for i := start; i < end; i++ {
@@ -201,27 +196,76 @@ func TestMapAllPortsSingleInterface(t *testing.T) {
 	}
 }
 
-func TestExecProxy(t *testing.T) {
-	defer netutils.SetupTestNetNS(t)()
-	args := []string{
-		userlandProxyCommandName,
-		"-proto", "tcp",
-		"-host-ip", "0.0.0.0",
-		"-host-port", "9999",
-		"-container-ip", "172.168.1.1",
-		"-container-port", "8888",
-	}
-	os.Args = args
-	doneChan := make(chan bool)
-	go func() {
-		execProxy()
-		doneChan <- true
-	}()
+func TestMapTCPDummyListen(t *testing.T) {
+	pm := New()
+	dstIP := net.ParseIP("0.0.0.0")
+	dstAddr := &net.TCPAddr{IP: dstIP, Port: 80}
+
+	// no-op for dummy
+	srcAddr := &net.TCPAddr{Port: 1080, IP: net.ParseIP("172.16.0.1")}
+
+	addrEqual := func(addr1, addr2 net.Addr) bool {
+		return (addr1.Network() == addr2.Network()) && (addr1.String() == addr2.String())
+	}
 
-	select {
-	case <-doneChan:
-		t.Fatal("execProxy is not supposed to exit")
-	case <-time.After(3 * time.Second):
-		return
+	if host, err := pm.Map(srcAddr, dstIP, 80, false); err != nil {
+		t.Fatalf("Failed to allocate port: %s", err)
+	} else if !addrEqual(dstAddr, host) {
+		t.Fatalf("Incorrect mapping result: expected %s:%s, got %s:%s",
+			dstAddr.String(), dstAddr.Network(), host.String(), host.Network())
+	}
+	if _, err := net.Listen("tcp", "0.0.0.0:80"); err == nil {
+		t.Fatal("Listen on mapped port without proxy should fail")
+	} else {
+		if !strings.Contains(err.Error(), "address already in use") {
+			t.Fatalf("Error should be about address already in use, got %v", err)
+		}
+	}
+	if _, err := net.Listen("tcp", "0.0.0.0:81"); err != nil {
+		t.Fatal(err)
+	}
+	if host, err := pm.Map(srcAddr, dstIP, 81, false); err == nil {
+		t.Fatalf("Bound port shouldn't be allocated, but it was on: %v", host)
+	} else {
+		if !strings.Contains(err.Error(), "address already in use") {
+			t.Fatalf("Error should be about address already in use, got %v", err)
+		}
+	}
+}
+
+func TestMapUDPDummyListen(t *testing.T) {
+	pm := New()
+	dstIP := net.ParseIP("0.0.0.0")
+	dstAddr := &net.UDPAddr{IP: dstIP, Port: 80}
+
+	// no-op for dummy
+	srcAddr := &net.UDPAddr{Port: 1080, IP: net.ParseIP("172.16.0.1")}
+
+	addrEqual := func(addr1, addr2 net.Addr) bool {
+		return (addr1.Network() == addr2.Network()) && (addr1.String() == addr2.String())
+	}
+
+	if host, err := pm.Map(srcAddr, dstIP, 80, false); err != nil {
+		t.Fatalf("Failed to allocate port: %s", err)
+	} else if !addrEqual(dstAddr, host) {
+		t.Fatalf("Incorrect mapping result: expected %s:%s, got %s:%s",
+			dstAddr.String(), dstAddr.Network(), host.String(), host.Network())
+	}
+	if _, err := net.ListenUDP("udp", &net.UDPAddr{IP: dstIP, Port: 80}); err == nil {
+		t.Fatal("Listen on mapped port without proxy should fail")
+	} else {
+		if !strings.Contains(err.Error(), "address already in use") {
+			t.Fatalf("Error should be about address already in use, got %v", err)
+		}
+	}
+	if _, err := net.ListenUDP("udp", &net.UDPAddr{IP: dstIP, Port: 81}); err != nil {
+		t.Fatal(err)
+	}
+	if host, err := pm.Map(srcAddr, dstIP, 81, false); err == nil {
+		t.Fatalf("Bound port shouldn't be allocated, but it was on: %v", host)
+	} else {
+		if !strings.Contains(err.Error(), "address already in use") {
+			t.Fatalf("Error should be about address already in use, got %v", err)
+		}
 	}
 }

+ 48 - 0
vendor/src/github.com/docker/libnetwork/portmapper/proxy.go

@@ -3,6 +3,7 @@ package portmapper
 import (
 	"flag"
 	"fmt"
+	"io"
 	"io/ioutil"
 	"log"
 	"net"
@@ -159,3 +160,50 @@ func (p *proxyCommand) Stop() error {
 	}
 	return nil
 }
+
+// dummyProxy just listen on some port, it is needed to prevent accidental
+// port allocations on bound port, because without userland proxy we using
+// iptables rules and not net.Listen
+type dummyProxy struct {
+	listener io.Closer
+	addr     net.Addr
+}
+
+func newDummyProxy(proto string, hostIP net.IP, hostPort int) userlandProxy {
+	switch proto {
+	case "tcp":
+		addr := &net.TCPAddr{IP: hostIP, Port: hostPort}
+		return &dummyProxy{addr: addr}
+	case "udp":
+		addr := &net.UDPAddr{IP: hostIP, Port: hostPort}
+		return &dummyProxy{addr: addr}
+	}
+	return nil
+}
+
+func (p *dummyProxy) Start() error {
+	switch addr := p.addr.(type) {
+	case *net.TCPAddr:
+		l, err := net.ListenTCP("tcp", addr)
+		if err != nil {
+			return err
+		}
+		p.listener = l
+	case *net.UDPAddr:
+		l, err := net.ListenUDP("udp", addr)
+		if err != nil {
+			return err
+		}
+		p.listener = l
+	default:
+		return fmt.Errorf("Unknown addr type: %T", p.addr)
+	}
+	return nil
+}
+
+func (p *dummyProxy) Stop() error {
+	if p.listener != nil {
+		return p.listener.Close()
+	}
+	return nil
+}

+ 12 - 2
vendor/src/github.com/docker/libnetwork/sandbox/namespace_linux.go

@@ -20,8 +20,10 @@ var once sync.Once
 // interface. It represents a linux network namespace, and moves an interface
 // into it when called on method AddInterface or sets the gateway etc.
 type networkNamespace struct {
-	path  string
-	sinfo *Info
+	path        string
+	sinfo       *Info
+	nextIfIndex int
+	sync.Mutex
 }
 
 func createBasePath() {
@@ -167,6 +169,11 @@ func (n *networkNamespace) RemoveInterface(i *Interface) error {
 }
 
 func (n *networkNamespace) AddInterface(i *Interface) error {
+	n.Lock()
+	i.DstName = fmt.Sprintf("%s%d", i.DstName, n.nextIfIndex)
+	n.nextIfIndex++
+	n.Unlock()
+
 	runtime.LockOSThread()
 	defer runtime.UnlockOSThread()
 
@@ -214,7 +221,10 @@ func (n *networkNamespace) AddInterface(i *Interface) error {
 		return err
 	}
 
+	n.Lock()
 	n.sinfo.Interfaces = append(n.sinfo.Interfaces, i)
+	n.Unlock()
+
 	return nil
 }
 

+ 13 - 9
vendor/src/github.com/docker/libnetwork/sandbox/sandbox.go

@@ -3,7 +3,7 @@ package sandbox
 import (
 	"net"
 
-	"github.com/docker/libnetwork/netutils"
+	"github.com/docker/libnetwork/types"
 )
 
 // Sandbox represents a network sandbox, identified by a specific key.  It
@@ -20,7 +20,9 @@ type Sandbox interface {
 
 	// Add an existing Interface to this sandbox. The operation will rename
 	// from the Interface SrcName to DstName as it moves, and reconfigure the
-	// interface according to the specified settings.
+	// interface according to the specified settings. The caller is expected
+	// to only provide a prefix for DstName. The AddInterface api will auto-generate
+	// an appropriate suffix for the DstName to disambiguate.
 	AddInterface(*Interface) error
 
 	// Remove an interface from the sandbox by renamin to original name
@@ -62,7 +64,9 @@ type Interface struct {
 	SrcName string
 
 	// The name that will be assigned to the interface once moves inside a
-	// network namespace.
+	// network namespace. When the caller passes in a DstName, it is only
+	// expected to pass a prefix. The name will modified with an appropriately
+	// auto-generated suffix.
 	DstName string
 
 	// IPv4 address for the interface.
@@ -77,8 +81,8 @@ func (i *Interface) GetCopy() *Interface {
 	return &Interface{
 		SrcName:     i.SrcName,
 		DstName:     i.DstName,
-		Address:     netutils.GetIPNetCopy(i.Address),
-		AddressIPv6: netutils.GetIPNetCopy(i.AddressIPv6),
+		Address:     types.GetIPNetCopy(i.Address),
+		AddressIPv6: types.GetIPNetCopy(i.AddressIPv6),
 	}
 }
 
@@ -96,11 +100,11 @@ func (i *Interface) Equal(o *Interface) bool {
 		return false
 	}
 
-	if !netutils.CompareIPNet(i.Address, o.Address) {
+	if !types.CompareIPNet(i.Address, o.Address) {
 		return false
 	}
 
-	if !netutils.CompareIPNet(i.AddressIPv6, o.AddressIPv6) {
+	if !types.CompareIPNet(i.AddressIPv6, o.AddressIPv6) {
 		return false
 	}
 
@@ -113,8 +117,8 @@ func (s *Info) GetCopy() *Info {
 	for i, iface := range s.Interfaces {
 		list[i] = iface.GetCopy()
 	}
-	gw := netutils.GetIPCopy(s.Gateway)
-	gw6 := netutils.GetIPCopy(s.GatewayIPv6)
+	gw := types.GetIPCopy(s.Gateway)
+	gw6 := types.GetIPCopy(s.GatewayIPv6)
 
 	return &Info{Interfaces: list, Gateway: gw, GatewayIPv6: gw6}
 }

+ 45 - 11
vendor/src/github.com/docker/libnetwork/sandbox/sandbox_linux_test.go

@@ -15,6 +15,8 @@ import (
 const (
 	vethName1     = "wierdlongname1"
 	vethName2     = "wierdlongname2"
+	vethName3     = "wierdlongname3"
+	vethName4     = "wierdlongname4"
 	sboxIfaceName = "containername"
 )
 
@@ -36,33 +38,59 @@ func newInfo(t *testing.T) (*Info, error) {
 	veth := &netlink.Veth{
 		LinkAttrs: netlink.LinkAttrs{Name: vethName1, TxQLen: 0},
 		PeerName:  vethName2}
-	err := netlink.LinkAdd(veth)
-	if err != nil {
+	if err := netlink.LinkAdd(veth); err != nil {
 		return nil, err
 	}
 
 	// Store the sandbox side pipe interface
 	// This is needed for cleanup on DeleteEndpoint()
-	intf := &Interface{}
-	intf.SrcName = vethName2
-	intf.DstName = sboxIfaceName
+	intf1 := &Interface{}
+	intf1.SrcName = vethName2
+	intf1.DstName = sboxIfaceName
 
 	ip4, addr, err := net.ParseCIDR("192.168.1.100/24")
 	if err != nil {
 		return nil, err
 	}
-	intf.Address = addr
-	intf.Address.IP = ip4
+	intf1.Address = addr
+	intf1.Address.IP = ip4
 
 	// ip6, addrv6, err := net.ParseCIDR("2001:DB8::ABCD/48")
 	ip6, addrv6, err := net.ParseCIDR("fe80::2/64")
 	if err != nil {
 		return nil, err
 	}
-	intf.AddressIPv6 = addrv6
-	intf.AddressIPv6.IP = ip6
+	intf1.AddressIPv6 = addrv6
+	intf1.AddressIPv6.IP = ip6
+
+	veth = &netlink.Veth{
+		LinkAttrs: netlink.LinkAttrs{Name: vethName3, TxQLen: 0},
+		PeerName:  vethName4}
+
+	if err := netlink.LinkAdd(veth); err != nil {
+		return nil, err
+	}
+
+	intf2 := &Interface{}
+	intf2.SrcName = vethName4
+	intf2.DstName = sboxIfaceName
+
+	ip4, addr, err = net.ParseCIDR("192.168.2.100/24")
+	if err != nil {
+		return nil, err
+	}
+	intf2.Address = addr
+	intf2.Address.IP = ip4
 
-	sinfo := &Info{Interfaces: []*Interface{intf}}
+	// ip6, addrv6, err := net.ParseCIDR("2001:DB8::ABCD/48")
+	ip6, addrv6, err = net.ParseCIDR("fe80::3/64")
+	if err != nil {
+		return nil, err
+	}
+	intf2.AddressIPv6 = addrv6
+	intf2.AddressIPv6.IP = ip6
+
+	sinfo := &Info{Interfaces: []*Interface{intf1, intf2}}
 	sinfo.Gateway = net.ParseIP("192.168.1.1")
 	// sinfo.GatewayIPv6 = net.ParseIP("2001:DB8::1")
 	sinfo.GatewayIPv6 = net.ParseIP("fe80::1")
@@ -97,7 +125,13 @@ func verifySandbox(t *testing.T, s Sandbox) {
 	}
 	defer netns.Set(origns)
 
-	_, err = netlink.LinkByName(sboxIfaceName)
+	_, err = netlink.LinkByName(sboxIfaceName + "0")
+	if err != nil {
+		t.Fatalf("Could not find the interface %s inside the sandbox: %v", sboxIfaceName,
+			err)
+	}
+
+	_, err = netlink.LinkByName(sboxIfaceName + "1")
 	if err != nil {
 		t.Fatalf("Could not find the interface %s inside the sandbox: %v", sboxIfaceName,
 			err)

+ 340 - 0
vendor/src/github.com/docker/libnetwork/types/types.go

@@ -1,5 +1,345 @@
 // Package types contains types that are common across libnetwork project
 package types
 
+import (
+	"bytes"
+	"fmt"
+	"net"
+	"strings"
+)
+
 // UUID represents a globally unique ID of various resources like network and endpoint
 type UUID string
+
+// TransportPort represent a local Layer 4 endpoint
+type TransportPort struct {
+	Proto Protocol
+	Port  uint16
+}
+
+// GetCopy returns a copy of this TransportPort structure instance
+func (t *TransportPort) GetCopy() TransportPort {
+	return TransportPort{Proto: t.Proto, Port: t.Port}
+}
+
+// PortBinding represent a port binding between the container an the host
+type PortBinding struct {
+	Proto    Protocol
+	IP       net.IP
+	Port     uint16
+	HostIP   net.IP
+	HostPort uint16
+}
+
+// HostAddr returns the host side transport address
+func (p PortBinding) HostAddr() (net.Addr, error) {
+	switch p.Proto {
+	case UDP:
+		return &net.UDPAddr{IP: p.HostIP, Port: int(p.HostPort)}, nil
+	case TCP:
+		return &net.TCPAddr{IP: p.HostIP, Port: int(p.HostPort)}, nil
+	default:
+		return nil, ErrInvalidProtocolBinding(p.Proto.String())
+	}
+}
+
+// ContainerAddr returns the container side transport address
+func (p PortBinding) ContainerAddr() (net.Addr, error) {
+	switch p.Proto {
+	case UDP:
+		return &net.UDPAddr{IP: p.IP, Port: int(p.Port)}, nil
+	case TCP:
+		return &net.TCPAddr{IP: p.IP, Port: int(p.Port)}, nil
+	default:
+		return nil, ErrInvalidProtocolBinding(p.Proto.String())
+	}
+}
+
+// GetCopy returns a copy of this PortBinding structure instance
+func (p *PortBinding) GetCopy() PortBinding {
+	return PortBinding{
+		Proto:    p.Proto,
+		IP:       GetIPCopy(p.IP),
+		Port:     p.Port,
+		HostIP:   GetIPCopy(p.HostIP),
+		HostPort: p.HostPort,
+	}
+}
+
+// Equal checks if this instance of PortBinding is equal to the passed one
+func (p *PortBinding) Equal(o *PortBinding) bool {
+	if p == o {
+		return true
+	}
+
+	if o == nil {
+		return false
+	}
+
+	if p.Proto != o.Proto || p.Port != o.Port || p.HostPort != o.HostPort {
+		return false
+	}
+
+	if p.IP != nil {
+		if !p.IP.Equal(o.IP) {
+			return false
+		}
+	} else {
+		if o.IP != nil {
+			return false
+		}
+	}
+
+	if p.HostIP != nil {
+		if !p.HostIP.Equal(o.HostIP) {
+			return false
+		}
+	} else {
+		if o.HostIP != nil {
+			return false
+		}
+	}
+
+	return true
+}
+
+// ErrInvalidProtocolBinding is returned when the port binding protocol is not valid.
+type ErrInvalidProtocolBinding string
+
+func (ipb ErrInvalidProtocolBinding) Error() string {
+	return fmt.Sprintf("invalid transport protocol: %s", string(ipb))
+}
+
+const (
+	// ICMP is for the ICMP ip protocol
+	ICMP = 1
+	// TCP is for the TCP ip protocol
+	TCP = 6
+	// UDP is for the UDP ip protocol
+	UDP = 17
+)
+
+// Protocol represents a IP protocol number
+type Protocol uint8
+
+func (p Protocol) String() string {
+	switch p {
+	case ICMP:
+		return "icmp"
+	case TCP:
+		return "tcp"
+	case UDP:
+		return "udp"
+	default:
+		return fmt.Sprintf("%d", p)
+	}
+}
+
+// ParseProtocol returns the respective Protocol type for the passed string
+func ParseProtocol(s string) Protocol {
+	switch strings.ToLower(s) {
+	case "icmp":
+		return ICMP
+	case "udp":
+		return UDP
+	case "tcp":
+		return TCP
+	default:
+		return 0
+	}
+}
+
+// GetMacCopy returns a copy of the passed MAC address
+func GetMacCopy(from net.HardwareAddr) net.HardwareAddr {
+	to := make(net.HardwareAddr, len(from))
+	copy(to, from)
+	return to
+}
+
+// GetIPCopy returns a copy of the passed IP address
+func GetIPCopy(from net.IP) net.IP {
+	to := make(net.IP, len(from))
+	copy(to, from)
+	return to
+}
+
+// GetIPNetCopy returns a copy of the passed IP Network
+func GetIPNetCopy(from *net.IPNet) *net.IPNet {
+	if from == nil {
+		return nil
+	}
+	bm := make(net.IPMask, len(from.Mask))
+	copy(bm, from.Mask)
+	return &net.IPNet{IP: GetIPCopy(from.IP), Mask: bm}
+}
+
+// CompareIPNet returns equal if the two IP Networks are equal
+func CompareIPNet(a, b *net.IPNet) bool {
+	if a == b {
+		return true
+	}
+	if a == nil || b == nil {
+		return false
+	}
+	return a.IP.Equal(b.IP) && bytes.Equal(a.Mask, b.Mask)
+}
+
+/******************************
+ * Well-known Error Interfaces
+ ******************************/
+
+// MaskableError is an interface for errors which can be ignored by caller
+type MaskableError interface {
+	// Maskable makes implementer into MaskableError type
+	Maskable()
+}
+
+// BadRequestError is an interface for errors originated by a bad request
+type BadRequestError interface {
+	// BadRequest makes implementer into BadRequestError type
+	BadRequest()
+}
+
+// NotFoundError is an interface for errors raised because a needed resource is not available
+type NotFoundError interface {
+	// NotFound makes implementer into NotFoundError type
+	NotFound()
+}
+
+// ForbiddenError is an interface for errors which denote an valid request that cannot be honored
+type ForbiddenError interface {
+	// Forbidden makes implementer into ForbiddenError type
+	Forbidden()
+}
+
+// NoServiceError  is an interface for errors returned when the required service is not available
+type NoServiceError interface {
+	// NoService makes implementer into NoServiceError type
+	NoService()
+}
+
+// TimeoutError  is an interface for errors raised because of timeout
+type TimeoutError interface {
+	// Timeout makes implementer into TimeoutError type
+	Timeout()
+}
+
+// NotImplementedError  is an interface for errors raised because of requested functionality is not yet implemented
+type NotImplementedError interface {
+	// NotImplemented makes implementer into NotImplementedError type
+	NotImplemented()
+}
+
+// InternalError is an interface for errors raised because of an internal error
+type InternalError interface {
+	// Internal makes implementer into InternalError type
+	Internal()
+}
+
+/******************************
+ * Weel-known Error Formatters
+ ******************************/
+
+// BadRequestErrorf creates an instance of BadRequestError
+func BadRequestErrorf(format string, params ...interface{}) error {
+	return badRequest(fmt.Sprintf(format, params...))
+}
+
+// NotFoundErrorf creates an instance of NotFoundError
+func NotFoundErrorf(format string, params ...interface{}) error {
+	return notFound(fmt.Sprintf(format, params...))
+}
+
+// ForbiddenErrorf creates an instance of ForbiddenError
+func ForbiddenErrorf(format string, params ...interface{}) error {
+	return forbidden(fmt.Sprintf(format, params...))
+}
+
+// NoServiceErrorf creates an instance of NoServiceError
+func NoServiceErrorf(format string, params ...interface{}) error {
+	return noService(fmt.Sprintf(format, params...))
+}
+
+// NotImplementedErrorf creates an instance of NotImplementedError
+func NotImplementedErrorf(format string, params ...interface{}) error {
+	return notImpl(fmt.Sprintf(format, params...))
+}
+
+// TimeoutErrorf creates an instance of TimeoutError
+func TimeoutErrorf(format string, params ...interface{}) error {
+	return timeout(fmt.Sprintf(format, params...))
+}
+
+// InternalErrorf creates an instance of InternalError
+func InternalErrorf(format string, params ...interface{}) error {
+	return internal(fmt.Sprintf(format, params...))
+}
+
+// InternalMaskableErrorf creates an instance of InternalError and MaskableError
+func InternalMaskableErrorf(format string, params ...interface{}) error {
+	return maskInternal(fmt.Sprintf(format, params...))
+}
+
+/***********************
+ * Internal Error Types
+ ***********************/
+type badRequest string
+
+func (br badRequest) Error() string {
+	return string(br)
+}
+func (br badRequest) BadRequest() {}
+
+type maskBadRequest string
+
+type notFound string
+
+func (nf notFound) Error() string {
+	return string(nf)
+}
+func (nf notFound) NotFound() {}
+
+type forbidden string
+
+func (frb forbidden) Error() string {
+	return string(frb)
+}
+func (frb forbidden) Forbidden() {}
+
+type noService string
+
+func (ns noService) Error() string {
+	return string(ns)
+}
+func (ns noService) NoService() {}
+
+type maskNoService string
+
+type timeout string
+
+func (to timeout) Error() string {
+	return string(to)
+}
+func (to timeout) Timeout() {}
+
+type notImpl string
+
+func (ni notImpl) Error() string {
+	return string(ni)
+}
+func (ni notImpl) NotImplemented() {}
+
+type internal string
+
+func (nt internal) Error() string {
+	return string(nt)
+}
+func (nt internal) Internal() {}
+
+type maskInternal string
+
+func (mnt maskInternal) Error() string {
+	return string(mnt)
+}
+func (mnt maskInternal) Internal() {}
+func (mnt maskInternal) Maskable() {}

+ 99 - 0
vendor/src/github.com/docker/libnetwork/types/types_test.go

@@ -0,0 +1,99 @@
+package types
+
+import (
+	"testing"
+
+	_ "github.com/docker/libnetwork/netutils"
+)
+
+func TestErrorConstructors(t *testing.T) {
+	var err error
+
+	err = BadRequestErrorf("Io ho %d uccello", 1)
+	if err.Error() != "Io ho 1 uccello" {
+		t.Fatal(err)
+	}
+	if _, ok := err.(BadRequestError); !ok {
+		t.Fatal(err)
+	}
+	if _, ok := err.(MaskableError); ok {
+		t.Fatal(err)
+	}
+
+	err = NotFoundErrorf("Can't find the %s", "keys")
+	if err.Error() != "Can't find the keys" {
+		t.Fatal(err)
+	}
+	if _, ok := err.(NotFoundError); !ok {
+		t.Fatal(err)
+	}
+	if _, ok := err.(MaskableError); ok {
+		t.Fatal(err)
+	}
+
+	err = ForbiddenErrorf("Can't open door %d", 2)
+	if err.Error() != "Can't open door 2" {
+		t.Fatal(err)
+	}
+	if _, ok := err.(ForbiddenError); !ok {
+		t.Fatal(err)
+	}
+	if _, ok := err.(MaskableError); ok {
+		t.Fatal(err)
+	}
+
+	err = NotImplementedErrorf("Functionality %s is not implemented", "x")
+	if err.Error() != "Functionality x is not implemented" {
+		t.Fatal(err)
+	}
+	if _, ok := err.(NotImplementedError); !ok {
+		t.Fatal(err)
+	}
+	if _, ok := err.(MaskableError); ok {
+		t.Fatal(err)
+	}
+
+	err = TimeoutErrorf("Process %s timed out", "abc")
+	if err.Error() != "Process abc timed out" {
+		t.Fatal(err)
+	}
+	if _, ok := err.(TimeoutError); !ok {
+		t.Fatal(err)
+	}
+	if _, ok := err.(MaskableError); ok {
+		t.Fatal(err)
+	}
+
+	err = NoServiceErrorf("Driver %s is not available", "mh")
+	if err.Error() != "Driver mh is not available" {
+		t.Fatal(err)
+	}
+	if _, ok := err.(NoServiceError); !ok {
+		t.Fatal(err)
+	}
+	if _, ok := err.(MaskableError); ok {
+		t.Fatal(err)
+	}
+
+	err = InternalErrorf("Not sure what happened")
+	if err.Error() != "Not sure what happened" {
+		t.Fatal(err)
+	}
+	if _, ok := err.(InternalError); !ok {
+		t.Fatal(err)
+	}
+	if _, ok := err.(MaskableError); ok {
+		t.Fatal(err)
+	}
+
+	err = InternalMaskableErrorf("Minor issue, it can be ignored")
+	if err.Error() != "Minor issue, it can be ignored" {
+		t.Fatal(err)
+	}
+	if _, ok := err.(InternalError); !ok {
+		t.Fatal(err)
+	}
+	if _, ok := err.(MaskableError); !ok {
+		t.Fatal(err)
+	}
+}