瀏覽代碼

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/libcontainer/devices"
 	"github.com/docker/libnetwork"
 	"github.com/docker/libnetwork"
 	"github.com/docker/libnetwork/netlabel"
 	"github.com/docker/libnetwork/netlabel"
-	"github.com/docker/libnetwork/netutils"
 	"github.com/docker/libnetwork/options"
 	"github.com/docker/libnetwork/options"
+	"github.com/docker/libnetwork/types"
 )
 )
 
 
 const DefaultPathEnv = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
 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
 		return networkSettings, nil
 	}
 	}
 
 
-	if portMapping, ok := mapData.([]netutils.PortBinding); ok {
+	if portMapping, ok := mapData.([]types.PortBinding); ok {
 		networkSettings.Ports = nat.PortMap{}
 		networkSettings.Ports = nat.PortMap{}
 		for _, pp := range portMapping {
 		for _, pp := range portMapping {
 			natPort := nat.NewPort(pp.Proto.String(), strconv.Itoa(int(pp.Port)))
 			natPort := nat.NewPort(pp.Proto.String(), strconv.Itoa(int(pp.Port)))
@@ -634,8 +634,8 @@ func (container *Container) buildCreateEndpointOptions() ([]libnetwork.EndpointO
 	var (
 	var (
 		portSpecs     = make(nat.PortSet)
 		portSpecs     = make(nat.PortSet)
 		bindings      = make(nat.PortMap)
 		bindings      = make(nat.PortMap)
-		pbList        []netutils.PortBinding
-		exposeList    []netutils.TransportPort
+		pbList        []types.PortBinding
+		exposeList    []types.TransportPort
 		createOptions []libnetwork.EndpointOption
 		createOptions []libnetwork.EndpointOption
 	)
 	)
 
 
@@ -675,12 +675,12 @@ func (container *Container) buildCreateEndpointOptions() ([]libnetwork.EndpointO
 	}
 	}
 	nat.SortPortMap(ports, bindings)
 	nat.SortPortMap(ports, bindings)
 	for _, port := range ports {
 	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())
 		expose.Port = uint16(port.Int())
 		exposeList = append(exposeList, expose)
 		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]
 		binding := bindings[port]
 		for i := 0; i < len(binding); i++ {
 		for i := 0; i < len(binding); i++ {
 			pbCopy := pb.GetCopy()
 			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
 clone hg code.google.com/p/gosqlite 74691fb6f837
 
 
 #get libnetwork packages
 #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/netns 008d17ae001344769b031375bdb38a86219154c6
 clone git github.com/vishvananda/netlink 8eb64238879fed52fd51c5b30ad20b928fb4c36c
 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
 	${docker} make build-local
 
 
 build-local:
 build-local:
-	$(shell which godep) go build ./...
+	$(shell which godep) go build -tags experimental ./...
 
 
 check: ${build_image}.created
 check: ${build_image}.created
 	${docker} make check-local
 	${docker} make check-local

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

@@ -5,8 +5,10 @@ import (
 	"fmt"
 	"fmt"
 	"io/ioutil"
 	"io/ioutil"
 	"net/http"
 	"net/http"
+	"strings"
 
 
 	"github.com/docker/libnetwork"
 	"github.com/docker/libnetwork"
+	"github.com/docker/libnetwork/types"
 	"github.com/gorilla/mux"
 	"github.com/gorilla/mux"
 )
 )
 
 
@@ -14,13 +16,28 @@ var (
 	successResponse  = responseStatus{Status: "Success", StatusCode: http.StatusOK}
 	successResponse  = responseStatus{Status: "Success", StatusCode: http.StatusOK}
 	createdResponse  = responseStatus{Status: "Created", StatusCode: http.StatusCreated}
 	createdResponse  = responseStatus{Status: "Created", StatusCode: http.StatusCreated}
 	mismatchResponse = responseStatus{Status: "Body/URI parameter mismatch", StatusCode: http.StatusBadRequest}
 	mismatchResponse = responseStatus{Status: "Body/URI parameter mismatch", StatusCode: http.StatusBadRequest}
+	badQueryresponse = responseStatus{Status: "Unsupported query", StatusCode: http.StatusBadRequest}
 )
 )
 
 
 const (
 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"
 	urlEpName = "endpoint-name"
 	urlEpID   = "endpoint-id"
 	urlEpID   = "endpoint-id"
+	urlEpPID  = "endpoint-partial-id"
 	urlCnID   = "container-id"
 	urlCnID   = "container-id"
 )
 )
 
 
@@ -59,42 +76,41 @@ func (h *httpHandler) handleRequest(w http.ResponseWriter, req *http.Request) {
 }
 }
 
 
 func (h *httpHandler) initRouter() {
 func (h *httpHandler) initRouter() {
-	m := map[string]map[string]processor{
+	m := map[string][]struct {
+		url string
+		qrs []string
+		fct processor
+	}{
 		"GET": {
 		"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": {
 		"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": {
 		"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()
 	h.r = mux.NewRouter()
 	for method, routes := range m {
 	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}
 		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 {
 	if err != nil {
 		return "", convertNetworkError(err)
 		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) {
 func procGetNetworks(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
 	var list []*networkResource
 	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
 	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}
 		return "", &responseStatus{Status: "Invalid body: " + err.Error(), StatusCode: http.StatusBadRequest}
 	}
 	}
 
 
-	epn := vars[urlEpName]
-	if ec.Name != epn {
-		return "", &mismatchResponse
-	}
-
 	nwT, nwBy := detectNetworkTarget(vars)
 	nwT, nwBy := detectNetworkTarget(vars)
 	n, errRsp := findNetwork(c, nwT, nwBy)
 	n, errRsp := findNetwork(c, nwT, nwBy)
 	if !errRsp.isOK() {
 	if !errRsp.isOK() {
 		return "", errRsp
 		return "", errRsp
 	}
 	}
 
 
-	if ec.NetworkID != n.ID() {
-		return "", &mismatchResponse
-	}
-
 	var setFctList []libnetwork.EndpointOption
 	var setFctList []libnetwork.EndpointOption
 	if ec.ExposedPorts != nil {
 	if ec.ExposedPorts != nil {
 		setFctList = append(setFctList, libnetwork.CreateOptionExposedPorts(ec.ExposedPorts))
 		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))
 		setFctList = append(setFctList, libnetwork.CreateOptionPortMapping(ec.PortMapping))
 	}
 	}
 
 
-	ep, err := n.CreateEndpoint(epn, setFctList...)
+	ep, err := n.CreateEndpoint(ec.Name, setFctList...)
 	if err != nil {
 	if err != nil {
 		return "", convertNetworkError(err)
 		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) {
 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() {
 	if !errRsp.isOK() {
 		return nil, errRsp
 		return nil, errRsp
 	}
 	}
 
 
 	var list []*endpointResource
 	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
 	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}
 		return nil, &responseStatus{Status: "Invalid body: " + err.Error(), StatusCode: http.StatusBadRequest}
 	}
 	}
 
 
-	cid := vars[urlCnID]
-	if ej.ContainerID != cid {
-		return "", &mismatchResponse
-	}
-
 	nwT, nwBy := detectNetworkTarget(vars)
 	nwT, nwBy := detectNetworkTarget(vars)
 	epT, epBy := detectEndpointTarget(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))
 		panic(fmt.Sprintf("unexpected selector for network search: %d", by))
 	}
 	}
 	if err != nil {
 	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: "Resource not found: Network", StatusCode: http.StatusNotFound}
 		}
 		}
 		return nil, &responseStatus{Status: err.Error(), StatusCode: http.StatusBadRequest}
 		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))
 		panic(fmt.Sprintf("unexpected selector for endpoint search: %d", epBy))
 	}
 	}
 	if err != nil {
 	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: "Resource not found: Endpoint", StatusCode: http.StatusNotFound}
 		}
 		}
 		return nil, &responseStatus{Status: err.Error(), StatusCode: http.StatusBadRequest}
 		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 {
 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 {
 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/netlabel"
 	"github.com/docker/libnetwork/netutils"
 	"github.com/docker/libnetwork/netutils"
 	"github.com/docker/libnetwork/options"
 	"github.com/docker/libnetwork/options"
+	"github.com/docker/libnetwork/types"
 )
 )
 
 
 const (
 const (
@@ -111,7 +112,7 @@ func TestJoinOptionParser(t *testing.T) {
 }
 }
 
 
 func TestJson(t *testing.T) {
 func TestJson(t *testing.T) {
-	nc := networkCreate{Name: "mynet", NetworkType: bridgeNetType}
+	nc := networkCreate{NetworkType: bridgeNetType}
 	b, err := json.Marshal(nc)
 	b, err := json.Marshal(nc)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -123,26 +124,10 @@ func TestJson(t *testing.T) {
 		t.Fatal(err)
 		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)
 		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"}
 	jl := endpointJoin{ContainerID: "abcdef456789"}
 	b, err = json.Marshal(jl)
 	b, err = json.Marshal(jl)
 	if err != nil {
 	if err != nil {
@@ -156,7 +141,7 @@ func TestJson(t *testing.T) {
 	}
 	}
 
 
 	if jl.ContainerID != jld.ContainerID {
 	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)
 		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 {
 	if errRsp == &createdResponse {
 		t.Fatalf("Expected to fail but succeeded")
 		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 {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 
 
-	_, errRsp = procCreateNetwork(c, goodVars, incompleteBody)
+	_, errRsp = procCreateNetwork(c, vars, incompleteBody)
 	if errRsp == &createdResponse {
 	if errRsp == &createdResponse {
 		t.Fatalf("Expected to fail but succeeded")
 		t.Fatalf("Expected to fail but succeeded")
 	}
 	}
 	if errRsp.StatusCode != http.StatusBadRequest {
 	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 := make(map[string]interface{})
 	ops[netlabel.GenericData] = options.Generic{}
 	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)
 	goodBody, err := json.Marshal(nc)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		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 {
 	if errRsp != &createdResponse {
 		t.Fatalf("Unexepected failure: %v", errRsp)
 		t.Fatalf("Unexepected failure: %v", errRsp)
 	}
 	}
 
 
-	_, errRsp = procDeleteNetwork(c, badVars, nil)
+	vars[urlNwName] = ""
+	_, errRsp = procDeleteNetwork(c, vars, nil)
 	if errRsp == &successResponse {
 	if errRsp == &successResponse {
 		t.Fatalf("Expected to fail but succeeded")
 		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 {
 	if errRsp == &successResponse {
 		t.Fatalf("Expected to fail but succeeded")
 		t.Fatalf("Expected to fail but succeeded")
 	}
 	}
 
 
-	_, errRsp = procDeleteNetwork(c, goodVars, nil)
+	vars[urlNwName] = "network_1"
+	_, errRsp = procDeleteNetwork(c, vars, nil)
 	if errRsp != &successResponse {
 	if errRsp != &successResponse {
 		t.Fatalf("Unexepected failure: %v", errRsp)
 		t.Fatalf("Unexepected failure: %v", errRsp)
 	}
 	}
@@ -262,7 +234,7 @@ func TestGetNetworksAndEndpoints(t *testing.T) {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 
 
-	vars := map[string]string{urlNwName: "sh"}
+	vars := make(map[string]string)
 	inid, errRsp := procCreateNetwork(c, vars, body)
 	inid, errRsp := procCreateNetwork(c, vars, body)
 	if errRsp != &createdResponse {
 	if errRsp != &createdResponse {
 		t.Fatalf("Unexepected failure: %v", errRsp)
 		t.Fatalf("Unexepected failure: %v", errRsp)
@@ -273,29 +245,29 @@ func TestGetNetworksAndEndpoints(t *testing.T) {
 	}
 	}
 
 
 	ec1 := endpointCreate{
 	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)
 	b1, err := json.Marshal(ec1)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
-	ec2 := endpointCreate{Name: "ep2", NetworkID: nid}
+	ec2 := endpointCreate{Name: "ep2"}
 	b2, err := json.Marshal(ec2)
 	b2, err := json.Marshal(ec2)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 
 
+	vars[urlNwName] = "sh"
 	vars[urlEpName] = "ep1"
 	vars[urlEpName] = "ep1"
 	ieid1, errRsp := procCreateEndpoint(c, vars, b1)
 	ieid1, errRsp := procCreateEndpoint(c, vars, b1)
 	if errRsp != &createdResponse {
 	if errRsp != &createdResponse {
@@ -471,6 +443,7 @@ func TestGetNetworksAndEndpoints(t *testing.T) {
 	if errRsp != &successResponse {
 	if errRsp != &successResponse {
 		t.Fatalf("Unexepected failure: %v", errRsp)
 		t.Fatalf("Unexepected failure: %v", errRsp)
 	}
 	}
+	delete(vars, urlEpName)
 	iepList, errRsp = procGetEndpoints(c, vars, nil)
 	iepList, errRsp = procGetEndpoints(c, vars, nil)
 	if errRsp != &successResponse {
 	if errRsp != &successResponse {
 		t.Fatalf("Unexepected failure: %v", errRsp)
 		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) {
 func TestFindNetworkUtil(t *testing.T) {
 	defer netutils.SetupTestNetNS(t)()
 	defer netutils.SetupTestNetNS(t)()
 
 
@@ -603,85 +613,46 @@ func TestCreateDeleteEndpoints(t *testing.T) {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 
 
-	vars := map[string]string{urlNwName: "firstNet"}
+	vars := make(map[string]string)
 	i, errRsp := procCreateNetwork(c, vars, body)
 	i, errRsp := procCreateNetwork(c, vars, body)
 	if errRsp != &createdResponse {
 	if errRsp != &createdResponse {
 		t.Fatalf("Unexepected failure: %v", errRsp)
 		t.Fatalf("Unexepected failure: %v", errRsp)
 	}
 	}
 	nid := i2s(i)
 	nid := i2s(i)
 
 
-	vbad, err := json.Marshal("bad endppint create data")
+	vbad, err := json.Marshal("bad endppoint create data")
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 
 
-	vars[urlEpName] = "ep1"
+	vars[urlNwName] = "firstNet"
 	_, errRsp = procCreateEndpoint(c, vars, vbad)
 	_, errRsp = procCreateEndpoint(c, vars, vbad)
 	if errRsp == &createdResponse {
 	if errRsp == &createdResponse {
 		t.Fatalf("Expected to fail but succeeded")
 		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 {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 
 
 	vars[urlNwName] = "secondNet"
 	vars[urlNwName] = "secondNet"
-	vars[urlEpName] = "firstEp"
 	_, errRsp = procCreateEndpoint(c, vars, b)
 	_, errRsp = procCreateEndpoint(c, vars, b)
 	if errRsp == &createdResponse {
 	if errRsp == &createdResponse {
 		t.Fatalf("Expected to fail but succeeded")
 		t.Fatalf("Expected to fail but succeeded")
 	}
 	}
 
 
 	vars[urlNwName] = "firstNet"
 	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)
 	_, errRsp = procCreateEndpoint(c, vars, b)
 	if errRsp == &successResponse {
 	if errRsp == &successResponse {
 		t.Fatalf("Expected failure but succeeded: %v", errRsp)
 		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)
 	i, errRsp = procCreateEndpoint(c, vars, b)
 	if errRsp != &createdResponse {
 	if errRsp != &createdResponse {
 		t.Fatalf("Unexepected failure: %v", errRsp)
 		t.Fatalf("Unexepected failure: %v", errRsp)
@@ -713,8 +684,8 @@ func TestCreateDeleteEndpoints(t *testing.T) {
 		t.Fatalf("Unexepected failure: %v", errRsp)
 		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)
 	vars = make(map[string]string)
@@ -766,18 +737,17 @@ func TestJoinLeave(t *testing.T) {
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		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 {
 	if errRsp != &createdResponse {
 		t.Fatalf("Unexepected failure: %v", errRsp)
 		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 {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
+	vars[urlNwName] = "network"
 	_, errRsp = procCreateEndpoint(c, vars, eb)
 	_, errRsp = procCreateEndpoint(c, vars, eb)
 	if errRsp != &createdResponse {
 	if errRsp != &createdResponse {
 		t.Fatalf("Unexepected failure: %v", errRsp)
 		t.Fatalf("Unexepected failure: %v", errRsp)
@@ -792,6 +762,7 @@ func TestJoinLeave(t *testing.T) {
 		t.Fatalf("Expected failure, got: %v", errRsp)
 		t.Fatalf("Expected failure, got: %v", errRsp)
 	}
 	}
 
 
+	vars[urlEpName] = "endpoint"
 	bad, err := json.Marshal(endpointJoin{})
 	bad, err := json.Marshal(endpointJoin{})
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -811,44 +782,30 @@ func TestJoinLeave(t *testing.T) {
 	vars = make(map[string]string)
 	vars = make(map[string]string)
 	vars[urlNwName] = ""
 	vars[urlNwName] = ""
 	vars[urlEpName] = ""
 	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)
 	_, errRsp = procJoinEndpoint(c, vars, jlb)
 	if errRsp == &successResponse {
 	if errRsp == &successResponse {
 		t.Fatalf("Expected failure, got: %v", errRsp)
 		t.Fatalf("Expected failure, got: %v", errRsp)
 	}
 	}
 
 
 	vars[urlNwName] = "network"
 	vars[urlNwName] = "network"
-	vars[urlEpName] = "endpoint"
+	vars[urlEpName] = ""
 	_, errRsp = procJoinEndpoint(c, vars, jlb)
 	_, errRsp = procJoinEndpoint(c, vars, jlb)
 	if errRsp == &successResponse {
 	if errRsp == &successResponse {
 		t.Fatalf("Expected failure, got: %v", errRsp)
 		t.Fatalf("Expected failure, got: %v", errRsp)
 	}
 	}
 
 
 	vars[urlEpName] = "epoint"
 	vars[urlEpName] = "epoint"
-	delete(vars, urlCnID)
 	_, errRsp = procJoinEndpoint(c, vars, jlb)
 	_, errRsp = procJoinEndpoint(c, vars, jlb)
 	if errRsp == &successResponse {
 	if errRsp == &successResponse {
 		t.Fatalf("Expected failure, got: %v", errRsp)
 		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)
 	cdi, errRsp := procJoinEndpoint(c, vars, jlb)
 	if errRsp != &successResponse {
 	if errRsp != &successResponse {
-		t.Fatalf("Unexpected failure, got: %v", errRsp)
+		t.Fatalf("Expected failure, got: %v", errRsp)
 	}
 	}
+
 	cd := i2c(cdi)
 	cd := i2c(cdi)
 	if cd.SandboxKey == "" {
 	if cd.SandboxKey == "" {
 		t.Fatalf("Empty sandbox key")
 		t.Fatalf("Empty sandbox key")
@@ -897,6 +854,7 @@ func TestJoinLeave(t *testing.T) {
 	}
 	}
 
 
 	delete(vars, urlCnID)
 	delete(vars, urlCnID)
+	vars[urlEpName] = "endpoint"
 	_, errRsp = procLeaveEndpoint(c, vars, jlb)
 	_, errRsp = procLeaveEndpoint(c, vars, jlb)
 	if errRsp == &successResponse {
 	if errRsp == &successResponse {
 		t.Fatalf("Expected failure, got: %v", errRsp)
 		t.Fatalf("Expected failure, got: %v", errRsp)
@@ -1178,7 +1136,7 @@ func TestHttpHandlerUninit(t *testing.T) {
 	}
 	}
 
 
 	rsp := newWriter()
 	rsp := newWriter()
-	req, err := http.NewRequest("GET", "/networks", nil)
+	req, err := http.NewRequest("GET", "/v1.19/networks", nil)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -1193,15 +1151,24 @@ func TestHttpHandlerUninit(t *testing.T) {
 
 
 	handleRequest(rsp, req)
 	handleRequest(rsp, req)
 	if rsp.statusCode != http.StatusOK {
 	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 {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 	nwr := buildNetworkResource(n)
 	nwr := buildNetworkResource(n)
-	expected, err := json.Marshal([]networkResource{*nwr})
+	expected, err := json.Marshal([]*networkResource{nwr})
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -1229,7 +1196,7 @@ func TestHttpHandlerBadBody(t *testing.T) {
 	}
 	}
 	handleRequest := NewHTTPHandler(c)
 	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 {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -1240,7 +1207,7 @@ func TestHttpHandlerBadBody(t *testing.T) {
 
 
 	body := []byte{}
 	body := []byte{}
 	lr := newLocalReader(body)
 	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 {
 	if err != nil {
 		t.Fatal(err)
 		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)()
 	defer netutils.SetupTestNetNS(t)()
 
 
 	rsp := newWriter()
 	rsp := newWriter()
@@ -1261,14 +1228,14 @@ func TestHttpHandlerGood(t *testing.T) {
 	}
 	}
 	handleRequest := NewHTTPHandler(c)
 	handleRequest := NewHTTPHandler(c)
 
 
-	nc := networkCreate{Name: "zero-network", NetworkType: bridgeNetType}
+	// Create network
+	nc := networkCreate{Name: "network-fiftyfive", NetworkType: bridgeNetType}
 	body, err := json.Marshal(nc)
 	body, err := json.Marshal(nc)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
-
 	lr := newLocalReader(body)
 	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 {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -1280,13 +1247,102 @@ func TestHttpHandlerGood(t *testing.T) {
 		t.Fatalf("Empty response body")
 		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 {
 	if err != nil {
 		t.Fatal(err)
 		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 {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -1300,7 +1356,211 @@ func TestHttpHandlerGood(t *testing.T) {
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		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
 package api
 
 
-import "github.com/docker/libnetwork/netutils"
+import "github.com/docker/libnetwork/types"
 
 
 /***********
 /***********
  Resources
  Resources
@@ -35,9 +35,8 @@ type networkCreate struct {
 // endpointCreate represents the body of the "create endpoint" http request message
 // endpointCreate represents the body of the "create endpoint" http request message
 type endpointCreate struct {
 type endpointCreate struct {
 	Name         string
 	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
 // 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.
 // 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
 // network UI commands are designed to be invoked from multiple parent chains
 func (cli *NetworkCli) Cmd(chain string, args ...string) error {
 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 {
 	if len(args) > 1 {
 		method, exists := cli.getMethod(args[:2]...)
 		method, exists := cli.getMethod(args[:2]...)
 		if exists {
 		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 (
 import (
 	"bytes"
 	"bytes"
+	"encoding/json"
+	"fmt"
 	"io"
 	"io"
+	"os"
+	"strings"
 	"testing"
 	"testing"
 
 
 	_ "github.com/docker/libnetwork/netutils"
 	_ "github.com/docker/libnetwork/netutils"
@@ -15,12 +19,82 @@ type nopCloser struct {
 
 
 func (nopCloser) Close() error { return nil }
 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) {
 func TestClientDummyCommand(t *testing.T) {
 	var out, errOut bytes.Buffer
 	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")
 	err := cli.Cmd("docker", "dummy")
 	if err == nil {
 	if err == nil {
@@ -30,10 +104,7 @@ func TestClientDummyCommand(t *testing.T) {
 
 
 func TestClientNetworkInvalidCommand(t *testing.T) {
 func TestClientNetworkInvalidCommand(t *testing.T) {
 	var out, errOut bytes.Buffer
 	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")
 	err := cli.Cmd("docker", "network", "invalid")
 	if err == nil {
 	if err == nil {
@@ -43,12 +114,9 @@ func TestClientNetworkInvalidCommand(t *testing.T) {
 
 
 func TestClientNetworkCreate(t *testing.T) {
 func TestClientNetworkCreate(t *testing.T) {
 	var out, errOut bytes.Buffer
 	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 {
 	if err != nil {
 		t.Fatal(err.Error())
 		t.Fatal(err.Error())
 	}
 	}
@@ -56,17 +124,14 @@ func TestClientNetworkCreate(t *testing.T) {
 
 
 func TestClientNetworkCreateWithDriver(t *testing.T) {
 func TestClientNetworkCreateWithDriver(t *testing.T) {
 	var out, errOut bytes.Buffer
 	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 {
 	if err == nil {
 		t.Fatalf("Passing incorrect flags to the create command must fail")
 		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 {
 	if err != nil {
 		t.Fatalf(err.Error())
 		t.Fatalf(err.Error())
 	}
 	}
@@ -74,12 +139,9 @@ func TestClientNetworkCreateWithDriver(t *testing.T) {
 
 
 func TestClientNetworkRm(t *testing.T) {
 func TestClientNetworkRm(t *testing.T) {
 	var out, errOut bytes.Buffer
 	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 {
 	if err != nil {
 		t.Fatal(err.Error())
 		t.Fatal(err.Error())
 	}
 	}
@@ -87,47 +149,43 @@ func TestClientNetworkRm(t *testing.T) {
 
 
 func TestClientNetworkLs(t *testing.T) {
 func TestClientNetworkLs(t *testing.T) {
 	var out, errOut bytes.Buffer
 	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")
 	err := cli.Cmd("docker", "network", "ls")
 	if err != nil {
 	if err != nil {
 		t.Fatal(err.Error())
 		t.Fatal(err.Error())
 	}
 	}
-	if out.String() != networks {
-		t.Fatal("Network List command fail to return the intended list")
-	}
 }
 }
 
 
 func TestClientNetworkInfo(t *testing.T) {
 func TestClientNetworkInfo(t *testing.T) {
 	var out, errOut bytes.Buffer
 	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 {
 	if err != nil {
 		t.Fatal(err.Error())
 		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
 // 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
 // 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
 	var out, errOut bytes.Buffer
 	cFunc := func(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, int, error) {
 	cFunc := func(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, int, error) {
 		return nil, 0, nil
 		return nil, 0, nil
 	}
 	}
-	cli := NewNetworkCli(&out, &errOut, cFunc)
+	cli := NewNetworkCli(&out, &errOut, callbackFunc)
 
 
 	err := cli.Cmd("docker", "network", "create", "--help")
 	err := cli.Cmd("docker", "network", "create", "--help")
 	if err != nil {
 	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.
 // 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
 // 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
 	var out, errOut bytes.Buffer
 	cFunc := func(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, int, error) {
 	cFunc := func(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, int, error) {
 		return nil, 0, nil
 		return nil, 0, nil
 	}
 	}
-	cli := NewNetworkCli(&out, &errOut, cFunc)
+	cli := NewNetworkCli(&out, &errOut, callbackFunc)
 
 
 	err := cli.Cmd("docker", "network", "create")
 	err := cli.Cmd("docker", "network", "create")
 	if err != nil {
 	if err != nil {

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

@@ -2,10 +2,13 @@ package client
 
 
 import (
 import (
 	"bytes"
 	"bytes"
+	"encoding/json"
 	"fmt"
 	"fmt"
-	"io"
+	"net/http"
+	"text/tabwriter"
 
 
 	flag "github.com/docker/docker/pkg/mflag"
 	flag "github.com/docker/docker/pkg/mflag"
+	"github.com/docker/docker/pkg/stringid"
 )
 )
 
 
 const (
 const (
@@ -33,7 +36,7 @@ func (cli *NetworkCli) CmdNetwork(chain string, args ...string) error {
 	err := cmd.ParseFlags(args, true)
 	err := cmd.ParseFlags(args, true)
 	if err == nil {
 	if err == nil {
 		cmd.Usage()
 		cmd.Usage()
-		return fmt.Errorf("Invalid command : %v", args)
+		return fmt.Errorf("invalid command : %v", args)
 	}
 	}
 	return err
 	return err
 }
 }
@@ -53,31 +56,33 @@ func (cli *NetworkCli) CmdNetworkCreate(chain string, args ...string) error {
 
 
 	nc := networkCreate{Name: cmd.Arg(0), NetworkType: *flDriver}
 	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 {
 	if err != nil {
-		fmt.Fprintf(cli.err, "%s", err.Error())
 		return err
 		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
 		return err
 	}
 	}
+	fmt.Fprintf(cli.out, "%s\n", replyID)
 	return nil
 	return nil
 }
 }
 
 
 // CmdNetworkRm handles Network Delete UI
 // CmdNetworkRm handles Network Delete UI
 func (cli *NetworkCli) CmdNetworkRm(chain string, args ...string) error {
 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)
 	cmd.Require(flag.Min, 1)
 	err := cmd.ParseFlags(args, true)
 	err := cmd.ParseFlags(args, true)
 	if err != nil {
 	if err != nil {
 		return err
 		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 {
 	if err != nil {
-		fmt.Fprintf(cli.err, "%s", err.Error())
 		return err
 		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 err
 	}
 	}
 	return nil
 	return nil
@@ -86,45 +91,149 @@ func (cli *NetworkCli) CmdNetworkRm(chain string, args ...string) error {
 // CmdNetworkLs handles Network List UI
 // CmdNetworkLs handles Network List UI
 func (cli *NetworkCli) CmdNetworkLs(chain string, args ...string) error {
 func (cli *NetworkCli) CmdNetworkLs(chain string, args ...string) error {
 	cmd := cli.Subcmd(chain, "ls", "", "Lists all the networks created by the user", false)
 	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)
 	err := cmd.ParseFlags(args, true)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 	obj, _, err := readBody(cli.call("GET", "/networks", nil, nil))
 	obj, _, err := readBody(cli.call("GET", "/networks", nil, nil))
 	if err != nil {
 	if err != nil {
-		fmt.Fprintf(cli.err, "%s", err.Error())
 		return err
 		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
 		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
 	return nil
 }
 }
 
 
 // CmdNetworkInfo handles Network Info UI
 // CmdNetworkInfo handles Network Info UI
 func (cli *NetworkCli) CmdNetworkInfo(chain string, args ...string) error {
 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)
 	cmd.Require(flag.Min, 1)
 	err := cmd.ParseFlags(args, true)
 	err := cmd.ParseFlags(args, true)
 	if err != nil {
 	if err != nil {
 		return err
 		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 {
 	if err != nil {
-		fmt.Fprintf(cli.err, "%s", err.Error())
 		return err
 		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
 		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
 	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 {
 func networkUsage(chain string) string {
 	help := "Commands:\n"
 	help := "Commands:\n"
 
 
 	for _, cmd := range networkCommands {
 	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)
 	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
 package client
 
 
-import "github.com/docker/libnetwork/sandbox"
+import "github.com/docker/libnetwork/types"
 
 
 /***********
 /***********
  Resources
  Resources
@@ -19,7 +19,6 @@ type endpointResource struct {
 	Name    string
 	Name    string
 	ID      string
 	ID      string
 	Network string
 	Network string
-	Info    sandbox.Info
 }
 }
 
 
 /***********
 /***********
@@ -32,3 +31,38 @@ type networkCreate struct {
 	NetworkType string
 	NetworkType string
 	Options     map[string]interface{}
 	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)
 	httpHandler := api.NewHTTPHandler(controller)
 	r := mux.NewRouter().StrictSlash(false)
 	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)
 	return http.ListenAndServe(d.addr, r)
 }
 }
 
 
@@ -143,7 +141,7 @@ func (d *dnetConnection) httpCall(method, path string, data interface{}, headers
 		return nil, -1, err
 		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 {
 	if err != nil {
 		return nil, -1, err
 		return nil, -1, err
 	}
 	}
@@ -160,7 +158,7 @@ func (d *dnetConnection) httpCall(method, path string, data interface{}, headers
 		statusCode = resp.StatusCode
 		statusCode = resp.StatusCode
 	}
 	}
 	if err != nil {
 	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 {
 	if statusCode < 200 || statusCode >= 400 {
@@ -168,7 +166,7 @@ func (d *dnetConnection) httpCall(method, path string, data interface{}, headers
 		if err != nil {
 		if err != nil {
 			return nil, statusCode, err
 			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
 	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 (
 var (
 	flDaemon   = flag.Bool([]string{"d", "-daemon"}, false, "Enable daemon mode")
 	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")
 	flLogLevel = flag.String([]string{"l", "-log-level"}, "info", "Set the logging level")
 	flDebug    = flag.Bool([]string{"D", "-debug"}, false, "Enable debug mode")
 	flDebug    = flag.Bool([]string{"D", "-debug"}, false, "Enable debug mode")
 	flHelp     = flag.Bool([]string{"h", "-help"}, false, "Print usage")
 	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"
 	"github.com/docker/libnetwork/netlabel"
 	"github.com/docker/libnetwork/netlabel"
-	"github.com/docker/libnetwork/netutils"
 	"github.com/docker/libnetwork/options"
 	"github.com/docker/libnetwork/options"
+	"github.com/docker/libnetwork/types"
 )
 )
 
 
 func main() {
 func main() {
@@ -58,7 +58,7 @@ func main() {
 	epInfo, err := ep.DriverInfo()
 	epInfo, err := ep.DriverInfo()
 	mapData, ok := epInfo[netlabel.PortMap]
 	mapData, ok := epInfo[netlabel.PortMap]
 	if ok {
 	if ok {
-		portMapping, ok := mapData.([]netutils.PortBinding)
+		portMapping, ok := mapData.([]types.PortBinding)
 		if ok {
 		if ok {
 			fmt.Printf("Current port mapping for endpoint %s: %v", ep.Name(), portMapping)
 			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.
 // are network specific and modeled in a generic way.
 func (c *controller) NewNetwork(networkType, name string, options ...NetworkOption) (Network, error) {
 func (c *controller) NewNetwork(networkType, name string, options ...NetworkOption) (Network, error) {
 	if name == "" {
 	if name == "" {
-		return nil, ErrInvalidName
+		return nil, ErrInvalidName(name)
 	}
 	}
 	// Check if a driver for the specified network type is available
 	// Check if a driver for the specified network type is available
 	c.Lock()
 	c.Lock()
@@ -203,7 +203,7 @@ func (c *controller) WalkNetworks(walker NetworkWalker) {
 
 
 func (c *controller) NetworkByName(name string) (Network, error) {
 func (c *controller) NetworkByName(name string) (Network, error) {
 	if name == "" {
 	if name == "" {
-		return nil, ErrInvalidName
+		return nil, ErrInvalidName(name)
 	}
 	}
 	var n Network
 	var n Network
 
 
@@ -218,7 +218,7 @@ func (c *controller) NetworkByName(name string) (Network, error) {
 	c.WalkNetworks(s)
 	c.WalkNetworks(s)
 
 
 	if n == nil {
 	if n == nil {
-		return nil, ErrNoSuchNetwork
+		return nil, ErrNoSuchNetwork(name)
 	}
 	}
 
 
 	return n, nil
 	return n, nil
@@ -226,14 +226,14 @@ func (c *controller) NetworkByName(name string) (Network, error) {
 
 
 func (c *controller) NetworkByID(id string) (Network, error) {
 func (c *controller) NetworkByID(id string) (Network, error) {
 	if id == "" {
 	if id == "" {
-		return nil, ErrInvalidID
+		return nil, ErrInvalidID(id)
 	}
 	}
 	c.Lock()
 	c.Lock()
 	defer c.Unlock()
 	defer c.Unlock()
 	if n, ok := c.networks[types.UUID(id)]; ok {
 	if n, ok := c.networks[types.UUID(id)]; ok {
 		return n, nil
 		return n, nil
 	}
 	}
-	return nil, ErrNoSuchNetwork
+	return nil, ErrNoSuchNetwork(id)
 }
 }
 
 
 func (c *controller) sandboxAdd(key string, create bool) (sandbox.Sandbox, error) {
 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.
 	// 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)
 	_, err := plugins.Get(networkType, driverapi.NetworkPluginEndpointType)
 	if err != nil {
 	if err != nil {
+		if err == plugins.ErrNotFound {
+			return nil, types.NotFoundErrorf(err.Error())
+		}
 		return nil, err
 		return nil, err
 	}
 	}
 	c.Lock()
 	c.Lock()
 	defer c.Unlock()
 	defer c.Unlock()
 	d, ok := c.drivers[networkType]
 	d, ok := c.drivers[networkType]
 	if !ok {
 	if !ok {
-		return nil, ErrInvalidNetworkDriver
+		return nil, ErrInvalidNetworkDriver(networkType)
 	}
 	}
 	return d, nil
 	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)
 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.
 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
 ## Goal
 
 

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

@@ -1,24 +1,11 @@
 package driverapi
 package driverapi
 
 
 import (
 import (
-	"errors"
-	"fmt"
 	"net"
 	"net"
 
 
 	"github.com/docker/libnetwork/types"
 	"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
 // NetworkPluginEndpointType represents the Endpoint Type used by Plugin system
 const NetworkPluginEndpointType = "NetworkDriver"
 const NetworkPluginEndpointType = "NetworkDriver"
 
 
@@ -96,8 +83,8 @@ type InterfaceInfo interface {
 // InterfaceNameInfo provides a go interface for the drivers to assign names
 // InterfaceNameInfo provides a go interface for the drivers to assign names
 // to interfaces.
 // to interfaces.
 type InterfaceNameInfo interface {
 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
 	// ID returns the numerical id that was assigned to the interface by the driver
 	// CreateEndpoint.
 	// CreateEndpoint.
@@ -124,14 +111,6 @@ type JoinInfo interface {
 	SetResolvConfPath(string) error
 	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
 // DriverCallback provides a Callback interface for Drivers into LibNetwork
 type DriverCallback interface {
 type DriverCallback interface {
 	// RegisterDriver provides a way for Remote drivers to dynamically register new NetworkType and associate with a driver instance
 	// 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"
 	networkType             = "bridge"
 	vethPrefix              = "veth"
 	vethPrefix              = "veth"
 	vethLen                 = 7
 	vethLen                 = 7
-	containerVeth           = "eth0"
+	containerVethPrefix     = "eth"
 	maxAllocatePortAttempts = 10
 	maxAllocatePortAttempts = 10
 	ifaceID                 = 1
 	ifaceID                 = 1
 )
 )
@@ -57,8 +57,8 @@ type NetworkConfiguration struct {
 // EndpointConfiguration represents the user specified configuration for the sandbox endpoint
 // EndpointConfiguration represents the user specified configuration for the sandbox endpoint
 type EndpointConfiguration struct {
 type EndpointConfiguration struct {
 	MacAddress   net.HardwareAddr
 	MacAddress   net.HardwareAddr
-	PortBindings []netutils.PortBinding
-	ExposedPorts []netutils.TransportPort
+	PortBindings []types.PortBinding
+	ExposedPorts []types.TransportPort
 }
 }
 
 
 // ContainerConfiguration represents the user specified configuration for a container
 // ContainerConfiguration represents the user specified configuration for a container
@@ -73,7 +73,7 @@ type bridgeEndpoint struct {
 	macAddress      net.HardwareAddr
 	macAddress      net.HardwareAddr
 	config          *EndpointConfiguration // User specified parameters
 	config          *EndpointConfiguration // User specified parameters
 	containerConfig *ContainerConfiguration
 	containerConfig *ContainerConfiguration
-	portMapping     []netutils.PortBinding // Operation port bindings
+	portMapping     []types.PortBinding // Operation port bindings
 }
 }
 
 
 type bridgeNetwork struct {
 type bridgeNetwork struct {
@@ -109,7 +109,7 @@ func Init(dc driverapi.DriverCallback) error {
 // Whatever can be assessed a priori before attempting any programming.
 // Whatever can be assessed a priori before attempting any programming.
 func (c *NetworkConfiguration) Validate() error {
 func (c *NetworkConfiguration) Validate() error {
 	if c.Mtu < 0 {
 	if c.Mtu < 0 {
-		return ErrInvalidMtu
+		return ErrInvalidMtu(c.Mtu)
 	}
 	}
 
 
 	// If bridge v4 subnet is specified
 	// If bridge v4 subnet is specified
@@ -118,19 +118,19 @@ func (c *NetworkConfiguration) Validate() error {
 		if c.FixedCIDR != nil {
 		if c.FixedCIDR != nil {
 			// Check Network address
 			// Check Network address
 			if !c.AddressIPv4.Contains(c.FixedCIDR.IP) {
 			if !c.AddressIPv4.Contains(c.FixedCIDR.IP) {
-				return ErrInvalidContainerSubnet
+				return &ErrInvalidContainerSubnet{}
 			}
 			}
 			// Check it is effectively a subset
 			// Check it is effectively a subset
 			brNetLen, _ := c.AddressIPv4.Mask.Size()
 			brNetLen, _ := c.AddressIPv4.Mask.Size()
 			cnNetLen, _ := c.FixedCIDR.Mask.Size()
 			cnNetLen, _ := c.FixedCIDR.Mask.Size()
 			if brNetLen > cnNetLen {
 			if brNetLen > cnNetLen {
-				return ErrInvalidContainerSubnet
+				return &ErrInvalidContainerSubnet{}
 			}
 			}
 		}
 		}
 		// If default gw is specified, it must be part of bridge subnet
 		// If default gw is specified, it must be part of bridge subnet
 		if c.DefaultGatewayIPv4 != nil {
 		if c.DefaultGatewayIPv4 != nil {
 			if !c.AddressIPv4.Contains(c.DefaultGatewayIPv4) {
 			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 default v6 gw is specified, FixedCIDRv6 must be specified and gw must belong to FixedCIDRv6 subnet
 	if c.EnableIPv6 && c.DefaultGatewayIPv6 != nil {
 	if c.EnableIPv6 && c.DefaultGatewayIPv6 != nil {
 		if c.FixedCIDRv6 == nil || !c.FixedCIDRv6.Contains(c.DefaultGatewayIPv6) {
 		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()
 	defer d.Unlock()
 
 
 	if d.config != nil {
 	if d.config != nil {
-		return ErrConfigExists
+		return &ErrConfigExists{}
 	}
 	}
 
 
 	genericData, ok := option[netlabel.GenericData]
 	genericData, ok := option[netlabel.GenericData]
@@ -182,7 +182,7 @@ func (d *driver) Config(option map[string]interface{}) error {
 		case *Configuration:
 		case *Configuration:
 			config = opt
 			config = opt
 		default:
 		default:
-			return ErrInvalidDriverConfig
+			return &ErrInvalidDriverConfig{}
 		}
 		}
 
 
 		d.config = config
 		d.config = config
@@ -220,7 +220,7 @@ func parseNetworkOptions(option options.Generic) (*NetworkConfiguration, error)
 		case *NetworkConfiguration:
 		case *NetworkConfiguration:
 			config = opt
 			config = opt
 		default:
 		default:
-			return nil, ErrInvalidNetworkConfig
+			return nil, &ErrInvalidNetworkConfig{}
 		}
 		}
 
 
 		if err := config.Validate(); err != nil {
 		if err := config.Validate(); err != nil {
@@ -247,7 +247,7 @@ func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) err
 	// Sanity checks
 	// Sanity checks
 	if d.network != nil {
 	if d.network != nil {
 		d.Unlock()
 		d.Unlock()
-		return ErrNetworkExists
+		return &ErrNetworkExists{}
 	}
 	}
 
 
 	// Create and set network handler in driver
 	// Create and set network handler in driver
@@ -361,7 +361,7 @@ func (d *driver) DeleteNetwork(nid types.UUID) error {
 
 
 	// Sanity check
 	// Sanity check
 	if n == nil {
 	if n == nil {
-		err = driverapi.ErrNoNetwork
+		err = driverapi.ErrNoNetwork(nid)
 		return err
 		return err
 	}
 	}
 
 
@@ -397,7 +397,7 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn
 	config := n.config
 	config := n.config
 	d.Unlock()
 	d.Unlock()
 	if n == nil {
 	if n == nil {
-		return driverapi.ErrNoNetwork
+		return driverapi.ErrNoNetwork(nid)
 	}
 	}
 
 
 	// Sanity check
 	// 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
 	// Endpoint with that id exists either on desired or other sandbox
 	if ep != nil {
 	if ep != nil {
-		return driverapi.ErrEndpointExists
+		return driverapi.ErrEndpointExists(eid)
 	}
 	}
 
 
 	// Try to convert the options to endpoint configuration
 	// 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
 	// Create the sandbox side pipe interface
 	intf := &sandbox.Interface{}
 	intf := &sandbox.Interface{}
 	intf.SrcName = name2
 	intf.SrcName = name2
-	intf.DstName = containerVeth
+	intf.DstName = containerVethPrefix
 	intf.Address = ipv4Addr
 	intf.Address = ipv4Addr
 
 
 	if config.EnableIPv6 {
 	if config.EnableIPv6 {
@@ -578,7 +578,7 @@ func (d *driver) DeleteEndpoint(nid, eid types.UUID) error {
 	config := n.config
 	config := n.config
 	d.Unlock()
 	d.Unlock()
 	if n == nil {
 	if n == nil {
-		return driverapi.ErrNoNetwork
+		return driverapi.ErrNoNetwork(nid)
 	}
 	}
 
 
 	// Sanity Check
 	// Sanity Check
@@ -648,7 +648,7 @@ func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{},
 	n := d.network
 	n := d.network
 	d.Unlock()
 	d.Unlock()
 	if n == nil {
 	if n == nil {
-		return nil, driverapi.ErrNoNetwork
+		return nil, driverapi.ErrNoNetwork(nid)
 	}
 	}
 
 
 	// Sanity check
 	// Sanity check
@@ -665,14 +665,14 @@ func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{},
 		return nil, err
 		return nil, err
 	}
 	}
 	if ep == nil {
 	if ep == nil {
-		return nil, driverapi.ErrNoEndpoint
+		return nil, driverapi.ErrNoEndpoint(eid)
 	}
 	}
 
 
 	m := make(map[string]interface{})
 	m := make(map[string]interface{})
 
 
 	if ep.portMapping != nil {
 	if ep.portMapping != nil {
 		// Return a copy of the operational data
 		// 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 {
 		for _, pm := range ep.portMapping {
 			pmc = append(pmc, pm.GetCopy())
 			pmc = append(pmc, pm.GetCopy())
 		}
 		}
@@ -856,23 +856,23 @@ func parseEndpointOptions(epOptions map[string]interface{}) (*EndpointConfigurat
 		if mac, ok := opt.(net.HardwareAddr); ok {
 		if mac, ok := opt.(net.HardwareAddr); ok {
 			ec.MacAddress = mac
 			ec.MacAddress = mac
 		} else {
 		} else {
-			return nil, ErrInvalidEndpointConfig
+			return nil, &ErrInvalidEndpointConfig{}
 		}
 		}
 	}
 	}
 
 
 	if opt, ok := epOptions[netlabel.PortMap]; ok {
 	if opt, ok := epOptions[netlabel.PortMap]; ok {
-		if bs, ok := opt.([]netutils.PortBinding); ok {
+		if bs, ok := opt.([]types.PortBinding); ok {
 			ec.PortBindings = bs
 			ec.PortBindings = bs
 		} else {
 		} else {
-			return nil, ErrInvalidEndpointConfig
+			return nil, &ErrInvalidEndpointConfig{}
 		}
 		}
 	}
 	}
 
 
 	if opt, ok := epOptions[netlabel.ExposedPorts]; ok {
 	if opt, ok := epOptions[netlabel.ExposedPorts]; ok {
-		if ports, ok := opt.([]netutils.TransportPort); ok {
+		if ports, ok := opt.([]types.TransportPort); ok {
 			ec.ExposedPorts = ports
 			ec.ExposedPorts = ports
 		} else {
 		} else {
-			return nil, ErrInvalidEndpointConfig
+			return nil, &ErrInvalidEndpointConfig{}
 		}
 		}
 	}
 	}
 
 
@@ -924,5 +924,5 @@ func generateIfaceName() (string, error) {
 			return "", err
 			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/iptables"
 	"github.com/docker/libnetwork/netlabel"
 	"github.com/docker/libnetwork/netlabel"
 	"github.com/docker/libnetwork/netutils"
 	"github.com/docker/libnetwork/netutils"
+	"github.com/docker/libnetwork/types"
 	"github.com/vishvananda/netlink"
 	"github.com/vishvananda/netlink"
 )
 )
 
 
@@ -202,7 +203,7 @@ func testQueryEndpointInfo(t *testing.T, ulPxyEnabled bool) {
 	if !ok {
 	if !ok {
 		t.Fatalf("Endpoint operational data does not contain port mapping data")
 		t.Fatalf("Endpoint operational data does not contain port mapping data")
 	}
 	}
-	pm, ok := pmd.([]netutils.PortBinding)
+	pm, ok := pmd.([]types.PortBinding)
 	if !ok {
 	if !ok {
 		t.Fatalf("Unexpected format for port mapping in endpoint operational data")
 		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"
 	log "github.com/Sirupsen/logrus"
 	"github.com/docker/libnetwork/iptables"
 	"github.com/docker/libnetwork/iptables"
-	"github.com/docker/libnetwork/netutils"
+	"github.com/docker/libnetwork/types"
 )
 )
 
 
 type link struct {
 type link struct {
 	parentIP string
 	parentIP string
 	childIP  string
 	childIP  string
-	ports    []netutils.TransportPort
+	ports    []types.TransportPort
 	bridge   string
 	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)
 	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{
 	return &link{
 		childIP:  childIP,
 		childIP:  childIP,
 		parentIP: parentIP,
 		parentIP: parentIP,
@@ -45,7 +45,7 @@ func (l *link) Disable() {
 	// that returns typed errors
 	// 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 {
 	ignoreErrors bool) error {
 	var nfAction iptables.Action
 	var nfAction iptables.Action
 
 
@@ -57,7 +57,7 @@ func linkContainers(action, parentIP, childIP string, ports []netutils.Transport
 	case "-D":
 	case "-D":
 		nfAction = iptables.Delete
 		nfAction = iptables.Delete
 	default:
 	default:
-		return invalidIPTablesCfgError(action)
+		return InvalidIPTablesCfgError(action)
 	}
 	}
 
 
 	ip1 := net.ParseIP(parentIP)
 	ip1 := net.ParseIP(parentIP)

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

@@ -3,14 +3,14 @@ package bridge
 import (
 import (
 	"testing"
 	"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{}}
 	te2 := &testEndpoint{ifaces: []*testInterface{}}
 	err = d.CreateEndpoint("dummy", "ep", te2, nil)
 	err = d.CreateEndpoint("dummy", "ep", te2, nil)
 	if err != 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 {
 	} else {
 		t.Fatalf("Expected to fail while trying to add same endpoint twice")
 		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"
 	"net"
 
 
 	"github.com/Sirupsen/logrus"
 	"github.com/Sirupsen/logrus"
-	"github.com/docker/libnetwork/netutils"
 	"github.com/docker/libnetwork/sandbox"
 	"github.com/docker/libnetwork/sandbox"
+	"github.com/docker/libnetwork/types"
 )
 )
 
 
 var (
 var (
 	defaultBindingIP = net.IPv4(0, 0, 0, 0)
 	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 {
 	if epConfig == nil || epConfig.PortBindings == nil {
 		return nil, 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)
 	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 {
 	for _, c := range bindings {
 		b := c.GetCopy()
 		b := c.GetCopy()
 		if err := allocatePort(&b, containerIP, defHostIP, ulPxyEnabled); err != nil {
 		if err := allocatePort(&b, containerIP, defHostIP, ulPxyEnabled); err != nil {
@@ -44,7 +44,7 @@ func allocatePortsInternal(bindings []netutils.PortBinding, containerIP, defHost
 	return bs, nil
 	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 (
 	var (
 		host net.Addr
 		host net.Addr
 		err  error
 		err  error
@@ -98,7 +98,7 @@ func releasePorts(ep *bridgeEndpoint) error {
 	return releasePortsInternal(ep.portMapping)
 	return releasePortsInternal(ep.portMapping)
 }
 }
 
 
-func releasePortsInternal(bindings []netutils.PortBinding) error {
+func releasePortsInternal(bindings []types.PortBinding) error {
 	var errorBuf bytes.Buffer
 	var errorBuf bytes.Buffer
 
 
 	// Attempt to release all port bindings, do not stop on failure
 	// Attempt to release all port bindings, do not stop on failure
@@ -114,7 +114,7 @@ func releasePortsInternal(bindings []netutils.PortBinding) error {
 	return nil
 	return nil
 }
 }
 
 
-func releasePort(bnd netutils.PortBinding) error {
+func releasePort(bnd types.PortBinding) error {
 	// Construct the host side transport address
 	// Construct the host side transport address
 	host, err := bnd.HostAddr()
 	host, err := bnd.HostAddr()
 	if err != nil {
 	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/docker/pkg/reexec"
 	"github.com/docker/libnetwork/netlabel"
 	"github.com/docker/libnetwork/netlabel"
 	"github.com/docker/libnetwork/netutils"
 	"github.com/docker/libnetwork/netutils"
+	"github.com/docker/libnetwork/types"
 )
 )
 
 
 func TestMain(m *testing.M) {
 func TestMain(m *testing.M) {
@@ -20,9 +21,9 @@ func TestPortMappingConfig(t *testing.T) {
 	defer netutils.SetupTestNetNS(t)()
 	defer netutils.SetupTestNetNS(t)()
 	d := newDriver()
 	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 := make(map[string]interface{})
 	epOptions[netlabel.PortMap] = portBindings
 	epOptions[netlabel.PortMap] = portBindings

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

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

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

@@ -1,11 +1,13 @@
 package bridge
 package bridge
 
 
-import log "github.com/Sirupsen/logrus"
+import (
+	log "github.com/Sirupsen/logrus"
+)
 
 
 func setupFixedCIDRv6(config *NetworkConfiguration, i *bridgeInterface) error {
 func setupFixedCIDRv6(config *NetworkConfiguration, i *bridgeInterface) error {
 	log.Debugf("Using IPv6 subnet: %v", config.FixedCIDRv6)
 	log.Debugf("Using IPv6 subnet: %v", config.FixedCIDRv6)
 	if err := ipAllocator.RegisterSubnet(config.FixedCIDRv6, config.FixedCIDRv6); err != nil {
 	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
 	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 {
 func setupIPForwarding(config *Configuration) error {
 	// Sanity Check
 	// Sanity Check
 	if config.EnableIPForwarding == false {
 	if config.EnableIPForwarding == false {
-		return ErrIPFwdCfg
+		return &ErrIPFwdCfg{}
 	}
 	}
 
 
 	// Enable IPv4 forwarding
 	// 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")
 		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)
 		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 {
 func setupIPTables(config *NetworkConfiguration, i *bridgeInterface) error {
 	// Sanity check.
 	// Sanity check.
 	if config.EnableIPTables == false {
 	if config.EnableIPTables == false {
-		return ipTableCfgError(config.BridgeName)
+		return IPTableCfgError(config.BridgeName)
 	}
 	}
 
 
 	hairpinMode := !config.EnableUserlandProxy
 	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)
 	log.Debugf("Creating bridge interface %q with network %s", config.BridgeName, bridgeIPv4)
 	if err := netlink.AddrAdd(i.Link, &netlink.Addr{IPNet: bridgeIPv4}); err != nil {
 	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
 	// Store bridge network and default gateway
@@ -114,7 +114,7 @@ func electBridgeIPv4(config *NetworkConfiguration) (*net.IPNet, error) {
 
 
 func setupGatewayIPv4(config *NetworkConfiguration, i *bridgeInterface) error {
 func setupGatewayIPv4(config *NetworkConfiguration, i *bridgeInterface) error {
 	if !i.bridgeIPv4.Contains(config.DefaultGatewayIPv4) {
 	if !i.bridgeIPv4.Contains(config.DefaultGatewayIPv4) {
-		return ErrInvalidGateway
+		return &ErrInvalidGateway{}
 	}
 	}
 	if _, err := ipAllocator.RequestIP(i.bridgeIPv4, config.DefaultGatewayIPv4); err != nil {
 	if _, err := ipAllocator.RequestIP(i.bridgeIPv4, config.DefaultGatewayIPv4); err != nil {
 		return err
 		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
 	// Add the default link local ipv6 address if it doesn't exist
 	if !findIPv6Address(netlink.Addr{IPNet: bridgeIPv6}, addrsv6) {
 	if !findIPv6Address(netlink.Addr{IPNet: bridgeIPv6}, addrsv6) {
 		if err := netlink.AddrAdd(i.Link, &netlink.Addr{IPNet: bridgeIPv6}); err != nil {
 		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 {
 func setupGatewayIPv6(config *NetworkConfiguration, i *bridgeInterface) error {
 	if config.FixedCIDRv6 == nil {
 	if config.FixedCIDRv6 == nil {
-		return ErrInvalidContainerSubnet
+		return &ErrInvalidContainerSubnet{}
 	}
 	}
 	if !config.FixedCIDRv6.Contains(config.DefaultGatewayIPv6) {
 	if !config.FixedCIDRv6.Contains(config.DefaultGatewayIPv6) {
-		return ErrInvalidGateway
+		return &ErrInvalidGateway{}
 	}
 	}
 	if _, err := ipAllocator.RequestIP(config.FixedCIDRv6, config.DefaultGatewayIPv6); err != nil {
 	if _, err := ipAllocator.RequestIP(config.FixedCIDRv6, config.DefaultGatewayIPv6); err != nil {
 		return err
 		return err

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

@@ -1,6 +1,8 @@
 package bridge
 package bridge
 
 
-import "github.com/vishvananda/netlink"
+import (
+	"github.com/vishvananda/netlink"
+)
 
 
 func setupVerifyAndReconcile(config *NetworkConfiguration, i *bridgeInterface) error {
 func setupVerifyAndReconcile(config *NetworkConfiguration, i *bridgeInterface) error {
 	// Fetch a single IPv4 and a slice of IPv6 addresses from the bridge.
 	// 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.
 	// Verify that the bridge does have an IPv4 address.
 	if addrv4.IPNet == nil {
 	if addrv4.IPNet == nil {
-		return ErrNoIPAddr
+		return &ErrNoIPAddr{}
 	}
 	}
 
 
 	// Verify that the bridge IPv4 address matches the requested configuration.
 	// Verify that the bridge IPv4 address matches the requested configuration.
 	if config.AddressIPv4 != nil && !addrv4.IP.Equal(config.AddressIPv4.IP) {
 	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
 	// 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
 package remote
 
 
 import (
 import (
-	"errors"
+	"fmt"
+	"net"
 
 
 	log "github.com/Sirupsen/logrus"
 	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/pkg/plugins"
 	"github.com/docker/docker/pkg/plugins"
@@ -9,59 +10,202 @@ import (
 	"github.com/docker/libnetwork/types"
 	"github.com/docker/libnetwork/types"
 )
 )
 
 
-var errNoCallback = errors.New("No Callback handler registered with Driver")
-
 type driver struct {
 type driver struct {
 	endpoint    *plugins.Client
 	endpoint    *plugins.Client
 	networkType string
 	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 {
 func Init(dc driverapi.DriverCallback) error {
 	plugins.Handle(driverapi.NetworkPluginEndpointType, func(name string, client *plugins.Client) {
 	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
 	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 {
 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 {
 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 {
 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 {
 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) {
 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.
 // 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 {
 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.
 // Leave method is invoked when a Sandbox detaches from an endpoint.
 func (d *driver) Leave(nid, eid types.UUID) error {
 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 {
 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/docker/pkg/ioutils"
 	"github.com/docker/libnetwork/etchosts"
 	"github.com/docker/libnetwork/etchosts"
 	"github.com/docker/libnetwork/netlabel"
 	"github.com/docker/libnetwork/netlabel"
-	"github.com/docker/libnetwork/netutils"
 	"github.com/docker/libnetwork/resolvconf"
 	"github.com/docker/libnetwork/resolvconf"
 	"github.com/docker/libnetwork/sandbox"
 	"github.com/docker/libnetwork/sandbox"
 	"github.com/docker/libnetwork/types"
 	"github.com/docker/libnetwork/types"
@@ -106,7 +105,7 @@ type endpoint struct {
 	iFaces        []*endpointInterface
 	iFaces        []*endpointInterface
 	joinInfo      *endpointJoinInfo
 	joinInfo      *endpointJoinInfo
 	container     *containerInfo
 	container     *containerInfo
-	exposedPorts  []netutils.TransportPort
+	exposedPorts  []types.TransportPort
 	generic       map[string]interface{}
 	generic       map[string]interface{}
 	joinLeaveDone chan struct{}
 	joinLeaveDone chan struct{}
 	sync.Mutex
 	sync.Mutex
@@ -217,7 +216,7 @@ func (ep *endpoint) Join(containerID string, options ...EndpointOption) (*Contai
 	ep.Lock()
 	ep.Lock()
 	if ep.container != nil {
 	if ep.container != nil {
 		ep.Unlock()
 		ep.Unlock()
-		return nil, ErrInvalidJoin
+		return nil, ErrInvalidJoin{}
 	}
 	}
 
 
 	ep.container = &containerInfo{
 	ep.container = &containerInfo{
@@ -292,7 +291,7 @@ func (ep *endpoint) Join(containerID string, options ...EndpointOption) (*Contai
 	for _, i := range ifaces {
 	for _, i := range ifaces {
 		iface := &sandbox.Interface{
 		iface := &sandbox.Interface{
 			SrcName: i.srcName,
 			SrcName: i.srcName,
-			DstName: i.dstName,
+			DstName: i.dstPrefix,
 			Address: &i.addr,
 			Address: &i.addr,
 		}
 		}
 		if i.addrv6.IP.To16() != nil {
 		if i.addrv6.IP.To16() != nil {
@@ -335,7 +334,7 @@ func (ep *endpoint) Leave(containerID string, options ...EndpointOption) error {
 	if container == nil || container.id == "" ||
 	if container == nil || container.id == "" ||
 		containerID == "" || container.id != containerID {
 		containerID == "" || container.id != containerID {
 		if container == nil {
 		if container == nil {
-			err = ErrNoContainer
+			err = ErrNoContainer{}
 		} else {
 		} else {
 			err = InvalidContainerIDError(containerID)
 			err = InvalidContainerIDError(containerID)
 		}
 		}
@@ -413,7 +412,7 @@ func (ep *endpoint) buildHostsFiles() error {
 	ep.Unlock()
 	ep.Unlock()
 
 
 	if container == nil {
 	if container == nil {
-		return ErrNoContainer
+		return ErrNoContainer{}
 	}
 	}
 
 
 	if container.config.hostsPath == "" {
 	if container.config.hostsPath == "" {
@@ -463,7 +462,7 @@ func (ep *endpoint) updateParentHosts() error {
 	ep.Unlock()
 	ep.Unlock()
 
 
 	if container == nil {
 	if container == nil {
-		return ErrNoContainer
+		return ErrNoContainer{}
 	}
 	}
 
 
 	for _, update := range container.config.parentUpdates {
 	for _, update := range container.config.parentUpdates {
@@ -496,7 +495,7 @@ func (ep *endpoint) updateDNS(resolvConf []byte) error {
 	ep.Unlock()
 	ep.Unlock()
 
 
 	if container == nil {
 	if container == nil {
-		return ErrNoContainer
+		return ErrNoContainer{}
 	}
 	}
 
 
 	oldHash := []byte{}
 	oldHash := []byte{}
@@ -574,7 +573,7 @@ func (ep *endpoint) setupDNS() error {
 	ep.Unlock()
 	ep.Unlock()
 
 
 	if container == nil {
 	if container == nil {
-		return ErrNoContainer
+		return ErrNoContainer{}
 	}
 	}
 
 
 	if container.config.resolvConfPath == "" {
 	if container.config.resolvConfPath == "" {
@@ -697,10 +696,10 @@ func JoinOptionUseDefaultSandbox() EndpointOption {
 
 
 // CreateOptionExposedPorts function returns an option setter for the container exposed
 // CreateOptionExposedPorts function returns an option setter for the container exposed
 // ports option to be passed to network.CreateEndpoint() method.
 // 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) {
 	return func(ep *endpoint) {
 		// Defensive copy
 		// Defensive copy
-		eps := make([]netutils.TransportPort, len(exposedPorts))
+		eps := make([]types.TransportPort, len(exposedPorts))
 		copy(eps, exposedPorts)
 		copy(eps, exposedPorts)
 		// Store endpoint label and in generic because driver needs it
 		// Store endpoint label and in generic because driver needs it
 		ep.exposedPorts = eps
 		ep.exposedPorts = eps
@@ -710,10 +709,10 @@ func CreateOptionExposedPorts(exposedPorts []netutils.TransportPort) EndpointOpt
 
 
 // CreateOptionPortMapping function returns an option setter for the mapping
 // CreateOptionPortMapping function returns an option setter for the mapping
 // ports option to be passed to network.CreateEndpoint() method.
 // 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) {
 	return func(ep *endpoint) {
 		// Store a copy of the bindings as generic data to pass to the driver
 		// 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)
 		copy(pbs, portBindings)
 		ep.generic[netlabel.PortMap] = pbs
 		ep.generic[netlabel.PortMap] = pbs
 	}
 	}

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

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

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

@@ -1,34 +1,83 @@
 package libnetwork
 package libnetwork
 
 
 import (
 import (
-	"errors"
 	"fmt"
 	"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
 // NetworkTypeError type is returned when the network type string is not
 // known to libnetwork.
 // known to libnetwork.
@@ -38,13 +87,19 @@ func (nt NetworkTypeError) Error() string {
 	return fmt.Sprintf("unknown driver %q", string(nt))
 	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.
 // NetworkNameError is returned when a network with the same name already exists.
 type NetworkNameError string
 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
 // UnknownNetworkError is returned when libnetwork could not find in it's database
 // a network with the same name and id.
 // a network with the same name and id.
 type UnknownNetworkError struct {
 type UnknownNetworkError struct {
@@ -56,6 +111,9 @@ func (une *UnknownNetworkError) Error() string {
 	return fmt.Sprintf("unknown network %s id %s", une.name, une.id)
 	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
 // ActiveEndpointsError is returned when a network is deleted which has active
 // endpoints in it.
 // endpoints in it.
 type ActiveEndpointsError struct {
 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)
 	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
 // UnknownEndpointError is returned when libnetwork could not find in it's database
 // an endpoint with the same name and id.
 // an endpoint with the same name and id.
 type UnknownEndpointError struct {
 type UnknownEndpointError struct {
@@ -78,6 +139,9 @@ func (uee *UnknownEndpointError) Error() string {
 	return fmt.Sprintf("unknown endpoint %s id %s", uee.name, uee.id)
 	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
 // ActiveContainerError is returned when an endpoint is deleted which has active
 // containers attached to it.
 // containers attached to it.
 type ActiveContainerError struct {
 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)
 	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
 // InvalidContainerIDError is returned when an invalid container id is passed
 // in Join/Leave
 // in Join/Leave
 type InvalidContainerIDError string
 type InvalidContainerIDError string
@@ -96,3 +163,6 @@ type InvalidContainerIDError string
 func (id InvalidContainerIDError) Error() string {
 func (id InvalidContainerIDError) Error() string {
 	return fmt.Sprintf("invalid container id %s", string(id))
 	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"
 	_ "github.com/docker/libnetwork/netutils"
 )
 )
 
 
-const chainName = "DOCKER-TEST"
+const chainName = "DOCKEREST"
 
 
 var natChain *Chain
 var natChain *Chain
 var filterChain *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/netlabel"
 	"github.com/docker/libnetwork/netutils"
 	"github.com/docker/libnetwork/netutils"
 	"github.com/docker/libnetwork/options"
 	"github.com/docker/libnetwork/options"
+	"github.com/docker/libnetwork/types"
+	"github.com/vishvananda/netlink"
 	"github.com/vishvananda/netns"
 	"github.com/vishvananda/netns"
 )
 )
 
 
@@ -65,11 +67,11 @@ func getEmptyGenericOption() map[string]interface{} {
 	return genericOption
 	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 {
 	if !ok {
 		t.Fatalf("Could not find expected info in endpoint data")
 		t.Fatalf("Could not find expected info in endpoint data")
 	}
 	}
-	pm, ok := pmd.([]netutils.PortBinding)
+	pm, ok := pmd.([]types.PortBinding)
 	if !ok {
 	if !ok {
 		t.Fatalf("Unexpected format for port mapping in endpoint operational data")
 		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")
 		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)
 		t.Fatalf("Did not fail with expected error. Actual error: %v", err)
 	}
 	}
 }
 }
@@ -337,8 +339,9 @@ func TestNetworkName(t *testing.T) {
 	if err == nil {
 	if err == nil {
 		t.Fatal("Expected to fail. But instead succeeded")
 		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"
 	networkName := "testnetwork"
@@ -474,8 +477,8 @@ func TestUnknownEndpoint(t *testing.T) {
 	if err == nil {
 	if err == nil {
 		t.Fatal("Expected to fail. But instead succeeded")
 		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")
 	ep, err := network.CreateEndpoint("testep")
@@ -612,15 +615,15 @@ func TestControllerQuery(t *testing.T) {
 	if err == nil {
 	if err == nil {
 		t.Fatalf("NetworkByName() succeeded with invalid target name")
 		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("")
 	_, err = controller.NetworkByID("")
 	if err == nil {
 	if err == nil {
 		t.Fatalf("NetworkByID() succeeded with invalid target id")
 		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)
 		t.Fatalf("NetworkByID() failed with unexpected error: %v", err)
 	}
 	}
 
 
@@ -628,7 +631,7 @@ func TestControllerQuery(t *testing.T) {
 	if err == nil {
 	if err == nil {
 		t.Fatalf("Unexpected success for NetworkByID(): %v", g)
 		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)
 		t.Fatalf("NetworkByID() failed with unexpected error: %v", err)
 	}
 	}
 
 
@@ -694,15 +697,15 @@ func TestNetworkQuery(t *testing.T) {
 	if err == nil {
 	if err == nil {
 		t.Fatalf("EndpointByName() succeeded with invalid target name")
 		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")
 	e, err = net1.EndpointByName("IamNotAnEndpoint")
 	if err == nil {
 	if err == nil {
 		t.Fatalf("EndpointByName() succeeded with unknown target name")
 		t.Fatalf("EndpointByName() succeeded with unknown target name")
 	}
 	}
-	if err != libnetwork.ErrNoSuchEndpoint {
+	if _, ok := err.(libnetwork.ErrNoSuchEndpoint); !ok {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 	if e != nil {
 	if e != nil {
@@ -721,13 +724,42 @@ func TestNetworkQuery(t *testing.T) {
 	if err == nil {
 	if err == nil {
 		t.Fatalf("EndpointByID() succeeded with invalid target id")
 		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)
 		t.Fatalf("EndpointByID() failed with unexpected error: %v", err)
 	}
 	}
 }
 }
 
 
 const containerID = "valid_container"
 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) {
 func TestEndpointJoin(t *testing.T) {
 	if !netutils.IsRunningInContainer() {
 	if !netutils.IsRunningInContainer() {
 		defer netutils.SetupTestNetNS(t)()
 		defer netutils.SetupTestNetNS(t)()
@@ -784,6 +816,8 @@ func TestEndpointJoin(t *testing.T) {
 	if info.SandboxKey() == "" {
 	if info.SandboxKey() == "" {
 		t.Fatalf("Expected an non-empty sandbox key for a joined endpoint. Instead found a empty sandbox key")
 		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) {
 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")
 		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)
 		t.Fatalf("Failed for unexpected reason: %v", err)
 	}
 	}
 }
 }
@@ -916,7 +950,7 @@ func TestEndpointInvalidLeave(t *testing.T) {
 	}
 	}
 
 
 	if _, ok := err.(libnetwork.InvalidContainerIDError); !ok {
 	if _, ok := err.(libnetwork.InvalidContainerIDError); !ok {
-		if err != libnetwork.ErrNoContainer {
+		if _, ok := err.(libnetwork.ErrNoContainer); !ok {
 			t.Fatalf("Failed for unexpected reason: %v", err)
 			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")
 		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
 		fmt.Fprintf(w, `{"Implements": ["%s"]}`, driverapi.NetworkPluginEndpointType)
 		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 {
 	if err := os.MkdirAll("/usr/share/docker/plugins", 0755); err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -1296,7 +1334,7 @@ func TestValidRemoteDriver(t *testing.T) {
 
 
 	_, err = controller.NewNetwork("valid-network-driver", "dummy",
 	_, err = controller.NewNetwork("valid-network-driver", "dummy",
 		libnetwork.NetworkOptionGeneric(getEmptyGenericOption()))
 		libnetwork.NetworkOptionGeneric(getEmptyGenericOption()))
-	if err != nil && err != driverapi.ErrNotImplemented {
+	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 }
 }
@@ -1370,8 +1408,10 @@ func parallelJoin(t *testing.T, ep libnetwork.Endpoint, thrNumber int) {
 	_, err := ep.Join("racing_container")
 	_, err := ep.Join("racing_container")
 	runtime.LockOSThread()
 	runtime.LockOSThread()
 	if err != nil {
 	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)
 		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")
 	err := ep.Leave("racing_container")
 	runtime.LockOSThread()
 	runtime.LockOSThread()
 	if err != nil {
 	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)
 		debugf("LE%d(%v).", thrNumber, err)
 	}
 	}

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

@@ -3,14 +3,12 @@
 package netutils
 package netutils
 
 
 import (
 import (
-	"bytes"
 	"crypto/rand"
 	"crypto/rand"
 	"encoding/hex"
 	"encoding/hex"
 	"errors"
 	"errors"
 	"fmt"
 	"fmt"
 	"io"
 	"io"
 	"net"
 	"net"
-	"strings"
 
 
 	"github.com/vishvananda/netlink"
 	"github.com/vishvananda/netlink"
 )
 )
@@ -26,144 +24,6 @@ var (
 	networkGetRoutesFct = netlink.RouteList
 	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
 // CheckNameserverOverlaps checks whether the passed network overlaps with any of the nameservers
 func CheckNameserverOverlaps(nameservers []string, toCheck *net.IPNet) error {
 func CheckNameserverOverlaps(nameservers []string, toCheck *net.IPNet) error {
 	if len(nameservers) > 0 {
 	if len(nameservers) > 0 {
@@ -287,38 +147,3 @@ func GenerateRandomName(prefix string, size int) (string, error) {
 	}
 	}
 	return prefix + hex.EncodeToString(id)[:size], nil
 	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)
 		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) {
 func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoint, error) {
 	if name == "" {
 	if name == "" {
-		return nil, ErrInvalidName
+		return nil, ErrInvalidName(name)
 	}
 	}
 	ep := &endpoint{name: name, iFaces: []*endpointInterface{}, generic: make(map[string]interface{})}
 	ep := &endpoint{name: name, iFaces: []*endpointInterface{}, generic: make(map[string]interface{})}
 	ep.id = types.UUID(stringid.GenerateRandomID())
 	ep.id = types.UUID(stringid.GenerateRandomID())
@@ -173,7 +173,7 @@ func (n *network) WalkEndpoints(walker EndpointWalker) {
 
 
 func (n *network) EndpointByName(name string) (Endpoint, error) {
 func (n *network) EndpointByName(name string) (Endpoint, error) {
 	if name == "" {
 	if name == "" {
-		return nil, ErrInvalidName
+		return nil, ErrInvalidName(name)
 	}
 	}
 	var e Endpoint
 	var e Endpoint
 
 
@@ -188,7 +188,7 @@ func (n *network) EndpointByName(name string) (Endpoint, error) {
 	n.WalkEndpoints(s)
 	n.WalkEndpoints(s)
 
 
 	if e == nil {
 	if e == nil {
-		return nil, ErrNoSuchEndpoint
+		return nil, ErrNoSuchEndpoint(name)
 	}
 	}
 
 
 	return e, nil
 	return e, nil
@@ -196,12 +196,12 @@ func (n *network) EndpointByName(name string) (Endpoint, error) {
 
 
 func (n *network) EndpointByID(id string) (Endpoint, error) {
 func (n *network) EndpointByID(id string) (Endpoint, error) {
 	if id == "" {
 	if id == "" {
-		return nil, ErrInvalidID
+		return nil, ErrInvalidID(id)
 	}
 	}
 	n.Lock()
 	n.Lock()
 	defer n.Unlock()
 	defer n.Unlock()
 	if e, ok := n.endpoints[types.UUID(id)]; ok {
 	if e, ok := n.endpoints[types.UUID(id)]; ok {
 		return e, nil
 		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 {
 		if useProxy {
 			m.userlandProxy = newProxy(proto, hostIP, allocatedHostPort, container.(*net.TCPAddr).IP, container.(*net.TCPAddr).Port)
 			m.userlandProxy = newProxy(proto, hostIP, allocatedHostPort, container.(*net.TCPAddr).IP, container.(*net.TCPAddr).Port)
+		} else {
+			m.userlandProxy = newDummyProxy(proto, hostIP, allocatedHostPort)
 		}
 		}
 	case *net.UDPAddr:
 	case *net.UDPAddr:
 		proto = "udp"
 		proto = "udp"
@@ -99,6 +101,8 @@ func (pm *PortMapper) Map(container net.Addr, hostIP net.IP, hostPort int, usePr
 
 
 		if useProxy {
 		if useProxy {
 			m.userlandProxy = newProxy(proto, hostIP, allocatedHostPort, container.(*net.UDPAddr).IP, container.(*net.UDPAddr).Port)
 			m.userlandProxy = newProxy(proto, hostIP, allocatedHostPort, container.(*net.UDPAddr).IP, container.(*net.UDPAddr).Port)
+		} else {
+			m.userlandProxy = newDummyProxy(proto, hostIP, allocatedHostPort)
 		}
 		}
 	default:
 	default:
 		return nil, ErrUnknownBackendAddressType
 		return nil, ErrUnknownBackendAddressType
@@ -123,9 +127,7 @@ func (pm *PortMapper) Map(container net.Addr, hostIP net.IP, hostPort int, usePr
 
 
 	cleanup := func() error {
 	cleanup := func() error {
 		// need to undo the iptables rules before we return
 		// 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)
 		pm.forward(iptables.Delete, m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort)
 		if err := pm.Allocator.ReleasePort(hostIP, m.proto, allocatedHostPort); err != nil {
 		if err := pm.Allocator.ReleasePort(hostIP, m.proto, allocatedHostPort); err != nil {
 			return err
 			return err
@@ -134,13 +136,11 @@ func (pm *PortMapper) Map(container net.Addr, hostIP net.IP, hostPort int, usePr
 		return nil
 		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
 	pm.currentMappings[key] = m

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

@@ -2,20 +2,16 @@ package portmapper
 
 
 import (
 import (
 	"net"
 	"net"
-	"os"
+	"strings"
 	"testing"
 	"testing"
-	"time"
 
 
-	"github.com/docker/docker/pkg/reexec"
 	"github.com/docker/libnetwork/iptables"
 	"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) {
 func TestSetIptablesChain(t *testing.T) {
@@ -37,7 +33,6 @@ func TestSetIptablesChain(t *testing.T) {
 }
 }
 
 
 func TestMapTCPPorts(t *testing.T) {
 func TestMapTCPPorts(t *testing.T) {
-	defer netutils.SetupTestNetNS(t)()
 	pm := New()
 	pm := New()
 	dstIP1 := net.ParseIP("192.168.0.1")
 	dstIP1 := net.ParseIP("192.168.0.1")
 	dstIP2 := net.ParseIP("192.168.0.2")
 	dstIP2 := net.ParseIP("192.168.0.2")
@@ -117,7 +112,6 @@ func TestGetUDPIPAndPort(t *testing.T) {
 }
 }
 
 
 func TestMapUDPPorts(t *testing.T) {
 func TestMapUDPPorts(t *testing.T) {
-	defer netutils.SetupTestNetNS(t)()
 	pm := New()
 	pm := New()
 	dstIP1 := net.ParseIP("192.168.0.1")
 	dstIP1 := net.ParseIP("192.168.0.1")
 	dstIP2 := net.ParseIP("192.168.0.2")
 	dstIP2 := net.ParseIP("192.168.0.2")
@@ -164,11 +158,6 @@ func TestMapUDPPorts(t *testing.T) {
 }
 }
 
 
 func TestMapAllPortsSingleInterface(t *testing.T) {
 func TestMapAllPortsSingleInterface(t *testing.T) {
-	newProxy = newMockProxyCommand
-	defer func() {
-		newProxy = newProxyCommand
-	}()
-	defer netutils.SetupTestNetNS(t)()
 	pm := New()
 	pm := New()
 	dstIP1 := net.ParseIP("0.0.0.0")
 	dstIP1 := net.ParseIP("0.0.0.0")
 	srcAddr1 := &net.TCPAddr{Port: 1080, IP: net.ParseIP("172.16.0.1")}
 	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 host net.Addr
 	var err error
 	var err error
 
 
+	defer func() {
+		for _, val := range hosts {
+			pm.Unmap(val)
+		}
+	}()
+
 	for i := 0; i < 10; i++ {
 	for i := 0; i < 10; i++ {
 		start, end := pm.Allocator.Begin, pm.Allocator.End
 		start, end := pm.Allocator.Begin, pm.Allocator.End
 		for i := start; i < end; i++ {
 		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 (
 import (
 	"flag"
 	"flag"
 	"fmt"
 	"fmt"
+	"io"
 	"io/ioutil"
 	"io/ioutil"
 	"log"
 	"log"
 	"net"
 	"net"
@@ -159,3 +160,50 @@ func (p *proxyCommand) Stop() error {
 	}
 	}
 	return nil
 	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
 // interface. It represents a linux network namespace, and moves an interface
 // into it when called on method AddInterface or sets the gateway etc.
 // into it when called on method AddInterface or sets the gateway etc.
 type networkNamespace struct {
 type networkNamespace struct {
-	path  string
-	sinfo *Info
+	path        string
+	sinfo       *Info
+	nextIfIndex int
+	sync.Mutex
 }
 }
 
 
 func createBasePath() {
 func createBasePath() {
@@ -167,6 +169,11 @@ func (n *networkNamespace) RemoveInterface(i *Interface) error {
 }
 }
 
 
 func (n *networkNamespace) AddInterface(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()
 	runtime.LockOSThread()
 	defer runtime.UnlockOSThread()
 	defer runtime.UnlockOSThread()
 
 
@@ -214,7 +221,10 @@ func (n *networkNamespace) AddInterface(i *Interface) error {
 		return err
 		return err
 	}
 	}
 
 
+	n.Lock()
 	n.sinfo.Interfaces = append(n.sinfo.Interfaces, i)
 	n.sinfo.Interfaces = append(n.sinfo.Interfaces, i)
+	n.Unlock()
+
 	return nil
 	return nil
 }
 }
 
 

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

@@ -3,7 +3,7 @@ package sandbox
 import (
 import (
 	"net"
 	"net"
 
 
-	"github.com/docker/libnetwork/netutils"
+	"github.com/docker/libnetwork/types"
 )
 )
 
 
 // Sandbox represents a network sandbox, identified by a specific key.  It
 // 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
 	// Add an existing Interface to this sandbox. The operation will rename
 	// from the Interface SrcName to DstName as it moves, and reconfigure the
 	// 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
 	AddInterface(*Interface) error
 
 
 	// Remove an interface from the sandbox by renamin to original name
 	// Remove an interface from the sandbox by renamin to original name
@@ -62,7 +64,9 @@ type Interface struct {
 	SrcName string
 	SrcName string
 
 
 	// The name that will be assigned to the interface once moves inside a
 	// 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
 	DstName string
 
 
 	// IPv4 address for the interface.
 	// IPv4 address for the interface.
@@ -77,8 +81,8 @@ func (i *Interface) GetCopy() *Interface {
 	return &Interface{
 	return &Interface{
 		SrcName:     i.SrcName,
 		SrcName:     i.SrcName,
 		DstName:     i.DstName,
 		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
 		return false
 	}
 	}
 
 
-	if !netutils.CompareIPNet(i.Address, o.Address) {
+	if !types.CompareIPNet(i.Address, o.Address) {
 		return false
 		return false
 	}
 	}
 
 
-	if !netutils.CompareIPNet(i.AddressIPv6, o.AddressIPv6) {
+	if !types.CompareIPNet(i.AddressIPv6, o.AddressIPv6) {
 		return false
 		return false
 	}
 	}
 
 
@@ -113,8 +117,8 @@ func (s *Info) GetCopy() *Info {
 	for i, iface := range s.Interfaces {
 	for i, iface := range s.Interfaces {
 		list[i] = iface.GetCopy()
 		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}
 	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 (
 const (
 	vethName1     = "wierdlongname1"
 	vethName1     = "wierdlongname1"
 	vethName2     = "wierdlongname2"
 	vethName2     = "wierdlongname2"
+	vethName3     = "wierdlongname3"
+	vethName4     = "wierdlongname4"
 	sboxIfaceName = "containername"
 	sboxIfaceName = "containername"
 )
 )
 
 
@@ -36,33 +38,59 @@ func newInfo(t *testing.T) (*Info, error) {
 	veth := &netlink.Veth{
 	veth := &netlink.Veth{
 		LinkAttrs: netlink.LinkAttrs{Name: vethName1, TxQLen: 0},
 		LinkAttrs: netlink.LinkAttrs{Name: vethName1, TxQLen: 0},
 		PeerName:  vethName2}
 		PeerName:  vethName2}
-	err := netlink.LinkAdd(veth)
-	if err != nil {
+	if err := netlink.LinkAdd(veth); err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
 
 
 	// Store the sandbox side pipe interface
 	// Store the sandbox side pipe interface
 	// This is needed for cleanup on DeleteEndpoint()
 	// 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")
 	ip4, addr, err := net.ParseCIDR("192.168.1.100/24")
 	if err != nil {
 	if err != nil {
 		return nil, err
 		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("2001:DB8::ABCD/48")
 	ip6, addrv6, err := net.ParseCIDR("fe80::2/64")
 	ip6, addrv6, err := net.ParseCIDR("fe80::2/64")
 	if err != nil {
 	if err != nil {
 		return nil, err
 		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.Gateway = net.ParseIP("192.168.1.1")
 	// sinfo.GatewayIPv6 = net.ParseIP("2001:DB8::1")
 	// sinfo.GatewayIPv6 = net.ParseIP("2001:DB8::1")
 	sinfo.GatewayIPv6 = net.ParseIP("fe80::1")
 	sinfo.GatewayIPv6 = net.ParseIP("fe80::1")
@@ -97,7 +125,13 @@ func verifySandbox(t *testing.T, s Sandbox) {
 	}
 	}
 	defer netns.Set(origns)
 	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 {
 	if err != nil {
 		t.Fatalf("Could not find the interface %s inside the sandbox: %v", sboxIfaceName,
 		t.Fatalf("Could not find the interface %s inside the sandbox: %v", sboxIfaceName,
 			err)
 			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 contains types that are common across libnetwork project
 package types
 package types
 
 
+import (
+	"bytes"
+	"fmt"
+	"net"
+	"strings"
+)
+
 // UUID represents a globally unique ID of various resources like network and endpoint
 // UUID represents a globally unique ID of various resources like network and endpoint
 type UUID string
 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)
+	}
+}