diff --git a/daemon/container_linux.go b/daemon/container_linux.go index 72e8409275..a944f50584 100644 --- a/daemon/container_linux.go +++ b/daemon/container_linux.go @@ -30,8 +30,8 @@ import ( "github.com/docker/libcontainer/devices" "github.com/docker/libnetwork" "github.com/docker/libnetwork/netlabel" - "github.com/docker/libnetwork/netutils" "github.com/docker/libnetwork/options" + "github.com/docker/libnetwork/types" ) const DefaultPathEnv = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" @@ -502,7 +502,7 @@ func (container *Container) buildPortMapInfo(n libnetwork.Network, ep libnetwork return networkSettings, nil } - if portMapping, ok := mapData.([]netutils.PortBinding); ok { + if portMapping, ok := mapData.([]types.PortBinding); ok { networkSettings.Ports = nat.PortMap{} for _, pp := range portMapping { natPort := nat.NewPort(pp.Proto.String(), strconv.Itoa(int(pp.Port))) @@ -641,8 +641,8 @@ func (container *Container) buildCreateEndpointOptions() ([]libnetwork.EndpointO var ( portSpecs = make(nat.PortSet) bindings = make(nat.PortMap) - pbList []netutils.PortBinding - exposeList []netutils.TransportPort + pbList []types.PortBinding + exposeList []types.TransportPort createOptions []libnetwork.EndpointOption ) @@ -682,12 +682,12 @@ func (container *Container) buildCreateEndpointOptions() ([]libnetwork.EndpointO } nat.SortPortMap(ports, bindings) for _, port := range ports { - expose := netutils.TransportPort{} - expose.Proto = netutils.ParseProtocol(port.Proto()) + expose := types.TransportPort{} + expose.Proto = types.ParseProtocol(port.Proto()) expose.Port = uint16(port.Int()) exposeList = append(exposeList, expose) - pb := netutils.PortBinding{Port: expose.Port, Proto: expose.Proto} + pb := types.PortBinding{Port: expose.Port, Proto: expose.Proto} binding := bindings[port] for i := 0; i < len(binding); i++ { pbCopy := pb.GetCopy() diff --git a/hack/vendor.sh b/hack/vendor.sh index a98e3bcfe9..63a2f460f9 100755 --- a/hack/vendor.sh +++ b/hack/vendor.sh @@ -55,7 +55,7 @@ clone hg code.google.com/p/go.net 84a4013f96e0 clone hg code.google.com/p/gosqlite 74691fb6f837 #get libnetwork packages -clone git github.com/docker/libnetwork b39597744b0978fe4aeb9f3a099ba42f7b6c4a1f +clone git github.com/docker/libnetwork 67438080724b17b641b411322822c00d0d3c3201 clone git github.com/vishvananda/netns 008d17ae001344769b031375bdb38a86219154c6 clone git github.com/vishvananda/netlink 8eb64238879fed52fd51c5b30ad20b928fb4c36c diff --git a/vendor/src/github.com/docker/libnetwork/Makefile b/vendor/src/github.com/docker/libnetwork/Makefile index 892d827dbf..59c181ecdc 100644 --- a/vendor/src/github.com/docker/libnetwork/Makefile +++ b/vendor/src/github.com/docker/libnetwork/Makefile @@ -22,7 +22,7 @@ build: ${build_image}.created ${docker} make build-local build-local: - $(shell which godep) go build ./... + $(shell which godep) go build -tags experimental ./... check: ${build_image}.created ${docker} make check-local diff --git a/vendor/src/github.com/docker/libnetwork/api/api.go b/vendor/src/github.com/docker/libnetwork/api/api.go index 0eebf4d197..97305d34fc 100644 --- a/vendor/src/github.com/docker/libnetwork/api/api.go +++ b/vendor/src/github.com/docker/libnetwork/api/api.go @@ -5,8 +5,10 @@ import ( "fmt" "io/ioutil" "net/http" + "strings" "github.com/docker/libnetwork" + "github.com/docker/libnetwork/types" "github.com/gorilla/mux" ) @@ -14,13 +16,28 @@ var ( successResponse = responseStatus{Status: "Success", StatusCode: http.StatusOK} createdResponse = responseStatus{Status: "Created", StatusCode: http.StatusCreated} mismatchResponse = responseStatus{Status: "Body/URI parameter mismatch", StatusCode: http.StatusBadRequest} + badQueryresponse = responseStatus{Status: "Unsupported query", StatusCode: http.StatusBadRequest} ) const ( - urlNwName = "name" - urlNwID = "id" + // Resource name regex + regex = "[a-zA-Z_0-9-]+" + // Router URL variable definition + nwName = "{" + urlNwName + ":" + regex + "}" + nwID = "{" + urlNwID + ":" + regex + "}" + nwPID = "{" + urlNwPID + ":" + regex + "}" + epName = "{" + urlEpName + ":" + regex + "}" + epID = "{" + urlEpID + ":" + regex + "}" + epPID = "{" + urlEpPID + ":" + regex + "}" + cnID = "{" + urlCnID + ":" + regex + "}" + + // Internal URL variable name, they can be anything + urlNwName = "network-name" + urlNwID = "network-id" + urlNwPID = "network-partial-id" urlEpName = "endpoint-name" urlEpID = "endpoint-id" + urlEpPID = "endpoint-partial-id" urlCnID = "container-id" ) @@ -59,42 +76,41 @@ func (h *httpHandler) handleRequest(w http.ResponseWriter, req *http.Request) { } func (h *httpHandler) initRouter() { - m := map[string]map[string]processor{ + m := map[string][]struct { + url string + qrs []string + fct processor + }{ "GET": { - "/networks": procGetNetworks, - "/networks/name/{" + urlNwName + ":.*}": procGetNetwork, - "/networks/id/{" + urlNwID + ":.*}": procGetNetwork, - "/networks/name/{" + urlNwName + ":.*}/endpoints/": procGetEndpoints, - "/networks/id/{" + urlNwID + ":.*}/endpoints/": procGetEndpoints, - "/networks/name/{" + urlNwName + ":.*}/endpoints/name/{" + urlEpName + ":.*}": procGetEndpoint, - "/networks/id/{" + urlNwID + ":.*}/endpoints/name/{" + urlEpName + ":.*}": procGetEndpoint, - "/networks/name/{" + urlNwName + ":.*}/endpoints/id/{" + urlEpID + ":.*}": procGetEndpoint, - "/networks/id/{" + urlNwID + ":.*}/endpoints/id/{" + urlEpID + ":.*}": procGetEndpoint, + // Order matters + {"/networks", []string{"name", nwName}, procGetNetworks}, + {"/networks", []string{"partial-id", nwPID}, procGetNetworks}, + {"/networks", nil, procGetNetworks}, + {"/networks/" + nwID, nil, procGetNetwork}, + {"/networks/" + nwID + "/endpoints", []string{"name", epName}, procGetEndpoints}, + {"/networks/" + nwID + "/endpoints", []string{"partial-id", epPID}, procGetEndpoints}, + {"/networks/" + nwID + "/endpoints", nil, procGetEndpoints}, + {"/networks/" + nwID + "/endpoints/" + epID, nil, procGetEndpoint}, }, "POST": { - "/networks/name/{" + urlNwName + ":.*}": procCreateNetwork, - "/networks/name/{" + urlNwName + ":.*}/endpoint/name/{" + urlEpName + ":.*}": procCreateEndpoint, - "/networks/name/{" + urlNwName + ":.*}/endpoint/name/{" + urlEpName + ":.*}/container/{" + urlCnID + ":.*}": procJoinEndpoint, + {"/networks", nil, procCreateNetwork}, + {"/networks/" + nwID + "/endpoints", nil, procCreateEndpoint}, + {"/networks/" + nwID + "/endpoints/" + epID + "/containers", nil, procJoinEndpoint}, }, "DELETE": { - "/networks/name/{" + urlNwName + ":.*}": procDeleteNetwork, - "/networks/id/{" + urlNwID + ":.*}": procDeleteNetwork, - "/networks/name/{" + urlNwName + ":.*}/endpoints/name/{" + urlEpName + ":.*}": procDeleteEndpoint, - "/networks/name/{" + urlNwName + ":.*}/endpoints/id/{" + urlEpID + ":.*}": procDeleteEndpoint, - "/networks/id/{" + urlNwID + ":.*}/endpoints/name/{" + urlEpName + ":.*}": procDeleteEndpoint, - "/networks/id/{" + urlNwID + ":.*}/endpoints/id/{" + urlEpID + ":.*}": procDeleteEndpoint, - "/networks/name/{" + urlNwName + ":.*}/endpoint/name/{" + urlEpName + ":.*}/container/{" + urlCnID + ":.*}": procLeaveEndpoint, - "/networks/name/{" + urlNwName + ":.*}/endpoint/id/{" + urlEpID + ":.*}/container/{" + urlCnID + ":.*}": procLeaveEndpoint, - "/networks/id/{" + urlNwID + ":.*}/endpoint/name/{" + urlEpName + ":.*}/container/{" + urlCnID + ":.*}": procLeaveEndpoint, - "/networks/id/{" + urlNwID + ":.*}/endpoint/id/{" + urlEpID + ":.*}/container/{" + urlCnID + ":.*}": procLeaveEndpoint, + {"/networks/" + nwID, nil, procDeleteNetwork}, + {"/networks/" + nwID + "/endpoints/" + epID, nil, procDeleteEndpoint}, + {"/networks/id/" + nwID + "/endpoints/" + epID + "/containers/" + cnID, nil, procLeaveEndpoint}, }, } h.r = mux.NewRouter() for method, routes := range m { - for route, fct := range routes { - f := makeHandler(h.c, fct) - h.r.Path(route).Methods(method).HandlerFunc(f) + for _, route := range routes { + r := h.r.Path("/{.*}" + route.url).Methods(method).HandlerFunc(makeHandler(h.c, route.fct)) + if route.qrs != nil { + r.Queries(route.qrs...) + } } } } @@ -208,12 +224,7 @@ func procCreateNetwork(c libnetwork.NetworkController, vars map[string]string, b return "", &responseStatus{Status: "Invalid body: " + err.Error(), StatusCode: http.StatusBadRequest} } - name := vars[urlNwName] - if name != create.Name { - return "", &mismatchResponse - } - - nw, err := c.NewNetwork(create.NetworkType, name, nil) + nw, err := c.NewNetwork(create.NetworkType, create.Name, nil) if err != nil { return "", convertNetworkError(err) } @@ -232,10 +243,33 @@ func procGetNetwork(c libnetwork.NetworkController, vars map[string]string, body func procGetNetworks(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) { var list []*networkResource - for _, nw := range c.Networks() { - nwr := buildNetworkResource(nw) - list = append(list, nwr) + + // Look for query filters and validate + name, queryByName := vars[urlNwName] + shortID, queryByPid := vars[urlNwPID] + if queryByName && queryByPid { + return nil, &badQueryresponse } + + if queryByName { + if nw, errRsp := findNetwork(c, name, byName); errRsp.isOK() { + list = append(list, buildNetworkResource(nw)) + } + } else if queryByPid { + // Return all the prefix-matching networks + l := func(nw libnetwork.Network) bool { + if strings.HasPrefix(nw.ID(), shortID) { + list = append(list, buildNetworkResource(nw)) + } + return false + } + c.WalkNetworks(l) + } else { + for _, nw := range c.Networks() { + list = append(list, buildNetworkResource(nw)) + } + } + return list, &successResponse } @@ -250,21 +284,12 @@ func procCreateEndpoint(c libnetwork.NetworkController, vars map[string]string, return "", &responseStatus{Status: "Invalid body: " + err.Error(), StatusCode: http.StatusBadRequest} } - epn := vars[urlEpName] - if ec.Name != epn { - return "", &mismatchResponse - } - nwT, nwBy := detectNetworkTarget(vars) n, errRsp := findNetwork(c, nwT, nwBy) if !errRsp.isOK() { return "", errRsp } - if ec.NetworkID != n.ID() { - return "", &mismatchResponse - } - var setFctList []libnetwork.EndpointOption if ec.ExposedPorts != nil { setFctList = append(setFctList, libnetwork.CreateOptionExposedPorts(ec.ExposedPorts)) @@ -273,7 +298,7 @@ func procCreateEndpoint(c libnetwork.NetworkController, vars map[string]string, setFctList = append(setFctList, libnetwork.CreateOptionPortMapping(ec.PortMapping)) } - ep, err := n.CreateEndpoint(epn, setFctList...) + ep, err := n.CreateEndpoint(ec.Name, setFctList...) if err != nil { return "", convertNetworkError(err) } @@ -294,17 +319,40 @@ func procGetEndpoint(c libnetwork.NetworkController, vars map[string]string, bod } func procGetEndpoints(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) { - target, by := detectNetworkTarget(vars) + // Look for query filters and validate + name, queryByName := vars[urlEpName] + shortID, queryByPid := vars[urlEpPID] + if queryByName && queryByPid { + return nil, &badQueryresponse + } - nw, errRsp := findNetwork(c, target, by) + nwT, nwBy := detectNetworkTarget(vars) + nw, errRsp := findNetwork(c, nwT, nwBy) if !errRsp.isOK() { return nil, errRsp } var list []*endpointResource - for _, ep := range nw.Endpoints() { - epr := buildEndpointResource(ep) - list = append(list, epr) + + // If query parameter is specified, return a filtered collection + if queryByName { + if ep, errRsp := findEndpoint(c, nwT, name, nwBy, byName); errRsp.isOK() { + list = append(list, buildEndpointResource(ep)) + } + } else if queryByPid { + // Return all the prefix-matching networks + l := func(ep libnetwork.Endpoint) bool { + if strings.HasPrefix(ep.ID(), shortID) { + list = append(list, buildEndpointResource(ep)) + } + return false + } + nw.WalkEndpoints(l) + } else { + for _, ep := range nw.Endpoints() { + epr := buildEndpointResource(ep) + list = append(list, epr) + } } return list, &successResponse @@ -336,11 +384,6 @@ func procJoinEndpoint(c libnetwork.NetworkController, vars map[string]string, bo return nil, &responseStatus{Status: "Invalid body: " + err.Error(), StatusCode: http.StatusBadRequest} } - cid := vars[urlCnID] - if ej.ContainerID != cid { - return "", &mismatchResponse - } - nwT, nwBy := detectNetworkTarget(vars) epT, epBy := detectEndpointTarget(vars) @@ -434,7 +477,7 @@ func findNetwork(c libnetwork.NetworkController, s string, by int) (libnetwork.N panic(fmt.Sprintf("unexpected selector for network search: %d", by)) } if err != nil { - if err == libnetwork.ErrNoSuchNetwork { + if _, ok := err.(libnetwork.ErrNoSuchNetwork); ok { return nil, &responseStatus{Status: "Resource not found: Network", StatusCode: http.StatusNotFound} } return nil, &responseStatus{Status: err.Error(), StatusCode: http.StatusBadRequest} @@ -460,7 +503,7 @@ func findEndpoint(c libnetwork.NetworkController, ns, es string, nwBy, epBy int) panic(fmt.Sprintf("unexpected selector for endpoint search: %d", epBy)) } if err != nil { - if err == libnetwork.ErrNoSuchEndpoint { + if _, ok := err.(libnetwork.ErrNoSuchEndpoint); ok { return nil, &responseStatus{Status: "Resource not found: Endpoint", StatusCode: http.StatusNotFound} } return nil, &responseStatus{Status: err.Error(), StatusCode: http.StatusBadRequest} @@ -469,9 +512,26 @@ func findEndpoint(c libnetwork.NetworkController, ns, es string, nwBy, epBy int) } func convertNetworkError(err error) *responseStatus { - // No real libnetwork error => http error code conversion for now. - // Will came in later when new interface for libnetwork error is vailable - return &responseStatus{Status: err.Error(), StatusCode: http.StatusBadRequest} + var code int + switch err.(type) { + case types.BadRequestError: + code = http.StatusBadRequest + case types.ForbiddenError: + code = http.StatusForbidden + case types.NotFoundError: + code = http.StatusNotFound + case types.TimeoutError: + code = http.StatusRequestTimeout + case types.NotImplementedError: + code = http.StatusNotImplemented + case types.NoServiceError: + code = http.StatusServiceUnavailable + case types.InternalError: + code = http.StatusInternalServerError + default: + code = http.StatusInternalServerError + } + return &responseStatus{Status: err.Error(), StatusCode: code} } func writeJSON(w http.ResponseWriter, code int, v interface{}) error { diff --git a/vendor/src/github.com/docker/libnetwork/api/api_test.go b/vendor/src/github.com/docker/libnetwork/api/api_test.go index 5065379ccf..7fbbee504a 100644 --- a/vendor/src/github.com/docker/libnetwork/api/api_test.go +++ b/vendor/src/github.com/docker/libnetwork/api/api_test.go @@ -16,6 +16,7 @@ import ( "github.com/docker/libnetwork/netlabel" "github.com/docker/libnetwork/netutils" "github.com/docker/libnetwork/options" + "github.com/docker/libnetwork/types" ) const ( @@ -111,7 +112,7 @@ func TestJoinOptionParser(t *testing.T) { } func TestJson(t *testing.T) { - nc := networkCreate{Name: "mynet", NetworkType: bridgeNetType} + nc := networkCreate{NetworkType: bridgeNetType} b, err := json.Marshal(nc) if err != nil { t.Fatal(err) @@ -123,26 +124,10 @@ func TestJson(t *testing.T) { t.Fatal(err) } - if nc.Name != ncp.Name || nc.NetworkType != ncp.NetworkType { + if nc.NetworkType != ncp.NetworkType { t.Fatalf("Incorrect networkCreate after json encoding/deconding: %v", ncp) } - ec := endpointCreate{Name: "mioEp", NetworkID: "0xabcde"} - b, err = json.Marshal(ec) - if err != nil { - t.Fatal(err) - } - - var ecp endpointCreate - err = json.Unmarshal(b, &ecp) - if err != nil { - t.Fatal(err) - } - - if ec.Name != ecp.Name || ec.NetworkID != ecp.NetworkID { - t.Fatalf("Incorrect endpointCreate after json encoding/deconding: %v", ecp) - } - jl := endpointJoin{ContainerID: "abcdef456789"} b, err = json.Marshal(jl) if err != nil { @@ -156,7 +141,7 @@ func TestJson(t *testing.T) { } if jl.ContainerID != jld.ContainerID { - t.Fatalf("Incorrect endpointJoin after json encoding/deconding: %v", ecp) + t.Fatalf("Incorrect endpointJoin after json encoding/deconding: %v", jld) } } @@ -177,68 +162,55 @@ func TestCreateDeleteNetwork(t *testing.T) { t.Fatal(err) } - goodVars := map[string]string{urlNwName: "myNet"} - _, errRsp := procCreateNetwork(c, goodVars, badBody) - if errRsp == &createdResponse { - t.Fatalf("Expected to fail but succeeded") - } - - incompleteBody, err := json.Marshal(networkCreate{Name: "myNet"}) - if err != nil { - t.Fatal(err) - } - - _, errRsp = procCreateNetwork(c, goodVars, incompleteBody) + vars := make(map[string]string) + _, errRsp := procCreateNetwork(c, nil, badBody) if errRsp == &createdResponse { t.Fatalf("Expected to fail but succeeded") } if errRsp.StatusCode != http.StatusBadRequest { - t.Fatalf("Expected StatusBadRequest status code, got: %v", errRsp.StatusCode) + t.Fatalf("Expected StatusBadRequest status code, got: %v", errRsp) + } + + incompleteBody, err := json.Marshal(networkCreate{}) + if err != nil { + t.Fatal(err) + } + + _, errRsp = procCreateNetwork(c, vars, incompleteBody) + if errRsp == &createdResponse { + t.Fatalf("Expected to fail but succeeded") + } + if errRsp.StatusCode != http.StatusBadRequest { + t.Fatalf("Expected StatusBadRequest status code, got: %v", errRsp) } ops := make(map[string]interface{}) ops[netlabel.GenericData] = options.Generic{} - nc := networkCreate{Name: "myNet", NetworkType: bridgeNetType, Options: ops} + nc := networkCreate{Name: "network_1", NetworkType: bridgeNetType, Options: ops} goodBody, err := json.Marshal(nc) if err != nil { t.Fatal(err) } - badVars := map[string]string{urlNwName: ""} - _, errRsp = procCreateNetwork(c, badVars, goodBody) - if errRsp == &createdResponse { - t.Fatalf("Expected to fail but succeeded") - } - if errRsp.StatusCode != http.StatusBadRequest { - t.Fatalf("Expected StatusBadRequest status code, got: %v", errRsp.StatusCode) - } - - badVars[urlNwName] = "badNetworkName" - _, errRsp = procCreateNetwork(c, badVars, goodBody) - if errRsp == &createdResponse { - t.Fatalf("Expected to fail but succeeded") - } - if errRsp.StatusCode != http.StatusBadRequest { - t.Fatalf("Expected StatusBadRequest status code, got: %v", errRsp.StatusCode) - } - - _, errRsp = procCreateNetwork(c, goodVars, goodBody) + _, errRsp = procCreateNetwork(c, vars, goodBody) if errRsp != &createdResponse { t.Fatalf("Unexepected failure: %v", errRsp) } - _, errRsp = procDeleteNetwork(c, badVars, nil) + vars[urlNwName] = "" + _, errRsp = procDeleteNetwork(c, vars, nil) if errRsp == &successResponse { t.Fatalf("Expected to fail but succeeded") } - badVars[urlNwName] = "" - _, errRsp = procDeleteNetwork(c, badVars, nil) + vars[urlNwName] = "abc" + _, errRsp = procDeleteNetwork(c, vars, nil) if errRsp == &successResponse { t.Fatalf("Expected to fail but succeeded") } - _, errRsp = procDeleteNetwork(c, goodVars, nil) + vars[urlNwName] = "network_1" + _, errRsp = procDeleteNetwork(c, vars, nil) if errRsp != &successResponse { t.Fatalf("Unexepected failure: %v", errRsp) } @@ -262,7 +234,7 @@ func TestGetNetworksAndEndpoints(t *testing.T) { t.Fatal(err) } - vars := map[string]string{urlNwName: "sh"} + vars := make(map[string]string) inid, errRsp := procCreateNetwork(c, vars, body) if errRsp != &createdResponse { t.Fatalf("Unexepected failure: %v", errRsp) @@ -273,29 +245,29 @@ func TestGetNetworksAndEndpoints(t *testing.T) { } ec1 := endpointCreate{ - Name: "ep1", - NetworkID: string(nid), - ExposedPorts: []netutils.TransportPort{ - netutils.TransportPort{Proto: netutils.TCP, Port: uint16(5000)}, - netutils.TransportPort{Proto: netutils.UDP, Port: uint16(400)}, - netutils.TransportPort{Proto: netutils.TCP, Port: uint16(600)}, + Name: "ep1", + ExposedPorts: []types.TransportPort{ + types.TransportPort{Proto: types.TCP, Port: uint16(5000)}, + types.TransportPort{Proto: types.UDP, Port: uint16(400)}, + types.TransportPort{Proto: types.TCP, Port: uint16(600)}, }, - PortMapping: []netutils.PortBinding{ - netutils.PortBinding{Proto: netutils.TCP, Port: uint16(230), HostPort: uint16(23000)}, - netutils.PortBinding{Proto: netutils.UDP, Port: uint16(200), HostPort: uint16(22000)}, - netutils.PortBinding{Proto: netutils.TCP, Port: uint16(120), HostPort: uint16(12000)}, + PortMapping: []types.PortBinding{ + types.PortBinding{Proto: types.TCP, Port: uint16(230), HostPort: uint16(23000)}, + types.PortBinding{Proto: types.UDP, Port: uint16(200), HostPort: uint16(22000)}, + types.PortBinding{Proto: types.TCP, Port: uint16(120), HostPort: uint16(12000)}, }, } b1, err := json.Marshal(ec1) if err != nil { t.Fatal(err) } - ec2 := endpointCreate{Name: "ep2", NetworkID: nid} + ec2 := endpointCreate{Name: "ep2"} b2, err := json.Marshal(ec2) if err != nil { t.Fatal(err) } + vars[urlNwName] = "sh" vars[urlEpName] = "ep1" ieid1, errRsp := procCreateEndpoint(c, vars, b1) if errRsp != &createdResponse { @@ -471,6 +443,7 @@ func TestGetNetworksAndEndpoints(t *testing.T) { if errRsp != &successResponse { t.Fatalf("Unexepected failure: %v", errRsp) } + delete(vars, urlEpName) iepList, errRsp = procGetEndpoints(c, vars, nil) if errRsp != &successResponse { t.Fatalf("Unexepected failure: %v", errRsp) @@ -509,6 +482,43 @@ func TestGetNetworksAndEndpoints(t *testing.T) { } } +func TestDetectGetNetworksInvalidQueryComposition(t *testing.T) { + c, err := libnetwork.New() + if err != nil { + t.Fatal(err) + } + + vars := map[string]string{urlNwName: "x", urlNwPID: "y"} + _, errRsp := procGetNetworks(c, vars, nil) + if errRsp.StatusCode != http.StatusBadRequest { + t.Fatalf("Expected %d. Got: %v", http.StatusBadRequest, errRsp) + } +} + +func TestDetectGetEndpointsInvalidQueryComposition(t *testing.T) { + defer netutils.SetupTestNetNS(t)() + + c, err := libnetwork.New() + if err != nil { + t.Fatal(err) + } + err = c.ConfigureNetworkDriver(bridgeNetType, nil) + if err != nil { + t.Fatal(err) + } + + _, err = c.NewNetwork(bridgeNetType, "network", nil) + if err != nil { + t.Fatal(err) + } + + vars := map[string]string{urlNwName: "network", urlEpName: "x", urlEpPID: "y"} + _, errRsp := procGetEndpoints(c, vars, nil) + if errRsp.StatusCode != http.StatusBadRequest { + t.Fatalf("Expected %d. Got: %v", http.StatusBadRequest, errRsp) + } +} + func TestFindNetworkUtil(t *testing.T) { defer netutils.SetupTestNetNS(t)() @@ -603,85 +613,46 @@ func TestCreateDeleteEndpoints(t *testing.T) { t.Fatal(err) } - vars := map[string]string{urlNwName: "firstNet"} + vars := make(map[string]string) i, errRsp := procCreateNetwork(c, vars, body) if errRsp != &createdResponse { t.Fatalf("Unexepected failure: %v", errRsp) } nid := i2s(i) - vbad, err := json.Marshal("bad endppint create data") + vbad, err := json.Marshal("bad endppoint create data") if err != nil { t.Fatal(err) } - vars[urlEpName] = "ep1" + vars[urlNwName] = "firstNet" _, errRsp = procCreateEndpoint(c, vars, vbad) if errRsp == &createdResponse { t.Fatalf("Expected to fail but succeeded") } - bad, err := json.Marshal(endpointCreate{Name: "ep1", NetworkID: "123456"}) - if err != nil { - t.Fatal(err) - } - _, errRsp = procCreateEndpoint(c, vars, bad) - if errRsp == &createdResponse { - t.Fatalf("Expected to fail but succeeded") - } - - soso, err := json.Marshal(endpointCreate{Name: "ep11", NetworkID: nid}) - if err != nil { - t.Fatal(err) - } - _, errRsp = procCreateEndpoint(c, vars, soso) - if errRsp != &mismatchResponse { - t.Fatalf("Expected to fail with \"mismatchResponse\", but got: %v", errRsp) - } - - bla, err := json.Marshal(endpointCreate{Name: "", NetworkID: nid}) - if err != nil { - t.Fatal(err) - } - vars[urlNwName] = "firstNet" - vars[urlEpName] = "" - _, errRsp = procCreateEndpoint(c, vars, bla) - if errRsp == &createdResponse { - t.Fatalf("Expected to fail but succeeded: %v", errRsp) - } - - b, err := json.Marshal(endpointCreate{Name: "firstEp", NetworkID: nid}) + b, err := json.Marshal(endpointCreate{Name: ""}) if err != nil { t.Fatal(err) } vars[urlNwName] = "secondNet" - vars[urlEpName] = "firstEp" _, errRsp = procCreateEndpoint(c, vars, b) if errRsp == &createdResponse { t.Fatalf("Expected to fail but succeeded") } vars[urlNwName] = "firstNet" - vars[urlEpName] = "ep1" - _, errRsp = procCreateEndpoint(c, vars, b) - if errRsp != &mismatchResponse { - t.Fatalf("Expected to fail with \"mismatchResponse\", but got: %v", errRsp) - } - - vars = make(map[string]string) _, errRsp = procCreateEndpoint(c, vars, b) if errRsp == &successResponse { t.Fatalf("Expected failure but succeeded: %v", errRsp) } - vars[urlNwName] = "firstNet" - _, errRsp = procCreateEndpoint(c, vars, b) - if errRsp == &successResponse { - t.Fatalf("Expected failure but succeeded: %v", errRsp) + b, err = json.Marshal(endpointCreate{Name: "firstEp"}) + if err != nil { + t.Fatal(err) } - vars[urlEpName] = "firstEp" i, errRsp = procCreateEndpoint(c, vars, b) if errRsp != &createdResponse { t.Fatalf("Unexepected failure: %v", errRsp) @@ -713,8 +684,8 @@ func TestCreateDeleteEndpoints(t *testing.T) { t.Fatalf("Unexepected failure: %v", errRsp) } - if ep0 != ep1 || ep0 != ep2 || ep0 != ep3 { - t.Fatalf("Diffenrent queries returned different endpoints") + if ep0.ID() != ep1.ID() || ep0.ID() != ep2.ID() || ep0.ID() != ep3.ID() { + t.Fatalf("Diffenrent queries returned different endpoints: \nep0: %v\nep1: %v\nep2: %v\nep3: %v", ep0, ep1, ep2, ep3) } vars = make(map[string]string) @@ -766,18 +737,17 @@ func TestJoinLeave(t *testing.T) { if err != nil { t.Fatal(err) } - vars := map[string]string{urlNwName: "network"} - i, errRsp := procCreateNetwork(c, vars, nb) + vars := make(map[string]string) + _, errRsp := procCreateNetwork(c, vars, nb) if errRsp != &createdResponse { t.Fatalf("Unexepected failure: %v", errRsp) } - nid := i2s(i) - vars[urlEpName] = "epoint" - eb, err := json.Marshal(endpointCreate{Name: "epoint", NetworkID: nid}) + eb, err := json.Marshal(endpointCreate{Name: "endpoint"}) if err != nil { t.Fatal(err) } + vars[urlNwName] = "network" _, errRsp = procCreateEndpoint(c, vars, eb) if errRsp != &createdResponse { t.Fatalf("Unexepected failure: %v", errRsp) @@ -792,6 +762,7 @@ func TestJoinLeave(t *testing.T) { t.Fatalf("Expected failure, got: %v", errRsp) } + vars[urlEpName] = "endpoint" bad, err := json.Marshal(endpointJoin{}) if err != nil { t.Fatal(err) @@ -811,44 +782,30 @@ func TestJoinLeave(t *testing.T) { vars = make(map[string]string) vars[urlNwName] = "" vars[urlEpName] = "" - vars[urlCnID] = cid - _, errRsp = procJoinEndpoint(c, vars, jlb) - if errRsp == &successResponse { - t.Fatalf("Expected failure, got: %v", errRsp) - } - - vars[urlNwName] = "network1" - vars[urlEpName] = "" _, errRsp = procJoinEndpoint(c, vars, jlb) if errRsp == &successResponse { t.Fatalf("Expected failure, got: %v", errRsp) } vars[urlNwName] = "network" - vars[urlEpName] = "endpoint" + vars[urlEpName] = "" _, errRsp = procJoinEndpoint(c, vars, jlb) if errRsp == &successResponse { t.Fatalf("Expected failure, got: %v", errRsp) } vars[urlEpName] = "epoint" - delete(vars, urlCnID) _, errRsp = procJoinEndpoint(c, vars, jlb) if errRsp == &successResponse { t.Fatalf("Expected failure, got: %v", errRsp) } - vars[urlCnID] = "who?" - _, errRsp = procJoinEndpoint(c, vars, jlb) - if errRsp == &successResponse { - t.Fatalf("Expected failure, got: %v", errRsp) - } - - vars[urlCnID] = cid + vars[urlEpName] = "endpoint" cdi, errRsp := procJoinEndpoint(c, vars, jlb) if errRsp != &successResponse { - t.Fatalf("Unexpected failure, got: %v", errRsp) + t.Fatalf("Expected failure, got: %v", errRsp) } + cd := i2c(cdi) if cd.SandboxKey == "" { t.Fatalf("Empty sandbox key") @@ -897,6 +854,7 @@ func TestJoinLeave(t *testing.T) { } delete(vars, urlCnID) + vars[urlEpName] = "endpoint" _, errRsp = procLeaveEndpoint(c, vars, jlb) if errRsp == &successResponse { t.Fatalf("Expected failure, got: %v", errRsp) @@ -1178,7 +1136,7 @@ func TestHttpHandlerUninit(t *testing.T) { } rsp := newWriter() - req, err := http.NewRequest("GET", "/networks", nil) + req, err := http.NewRequest("GET", "/v1.19/networks", nil) if err != nil { t.Fatal(err) } @@ -1193,15 +1151,24 @@ func TestHttpHandlerUninit(t *testing.T) { handleRequest(rsp, req) if rsp.statusCode != http.StatusOK { - t.Fatalf("Unexpectded failure: (%d): %s", rsp.statusCode, rsp.body) + t.Fatalf("Expected (%d). Got: (%d): %s", http.StatusOK, rsp.statusCode, rsp.body) } - n, err := c.NewNetwork(bridgeNetType, "onenet", nil) + var list []*networkResource + err = json.Unmarshal(rsp.body, &list) + if err != nil { + t.Fatal(err) + } + if len(list) != 0 { + t.Fatalf("Expected empty list. Got %v", list) + } + + n, err := c.NewNetwork(bridgeNetType, "didietro", nil) if err != nil { t.Fatal(err) } nwr := buildNetworkResource(n) - expected, err := json.Marshal([]networkResource{*nwr}) + expected, err := json.Marshal([]*networkResource{nwr}) if err != nil { t.Fatal(err) } @@ -1229,7 +1196,7 @@ func TestHttpHandlerBadBody(t *testing.T) { } handleRequest := NewHTTPHandler(c) - req, err := http.NewRequest("POST", "/networks/name/zero-network", &localReader{beBad: true}) + req, err := http.NewRequest("POST", "/v1.19/networks", &localReader{beBad: true}) if err != nil { t.Fatal(err) } @@ -1240,7 +1207,7 @@ func TestHttpHandlerBadBody(t *testing.T) { body := []byte{} lr := newLocalReader(body) - req, err = http.NewRequest("POST", "/networks/name/zero-network", lr) + req, err = http.NewRequest("POST", "/v1.19/networks", lr) if err != nil { t.Fatal(err) } @@ -1250,7 +1217,7 @@ func TestHttpHandlerBadBody(t *testing.T) { } } -func TestHttpHandlerGood(t *testing.T) { +func TestEndToEnd(t *testing.T) { defer netutils.SetupTestNetNS(t)() rsp := newWriter() @@ -1261,14 +1228,14 @@ func TestHttpHandlerGood(t *testing.T) { } handleRequest := NewHTTPHandler(c) - nc := networkCreate{Name: "zero-network", NetworkType: bridgeNetType} + // Create network + nc := networkCreate{Name: "network-fiftyfive", NetworkType: bridgeNetType} body, err := json.Marshal(nc) if err != nil { t.Fatal(err) } - lr := newLocalReader(body) - req, err := http.NewRequest("POST", "/networks/name/zero-network", lr) + req, err := http.NewRequest("POST", "/v1.19/networks", lr) if err != nil { t.Fatal(err) } @@ -1280,13 +1247,102 @@ func TestHttpHandlerGood(t *testing.T) { t.Fatalf("Empty response body") } - var id string - err = json.Unmarshal(rsp.body, &id) + var nid string + err = json.Unmarshal(rsp.body, &nid) if err != nil { t.Fatal(err) } - req, err = http.NewRequest("GET", "/networks/id/"+id, nil) + // 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= when only network exist.") + } + + // Query network by name + req, err = http.NewRequest("GET", "/v1.19/networks?name=culo", nil) + if err != nil { + t.Fatal(err) + } + handleRequest(rsp, req) + if rsp.statusCode != http.StatusOK { + t.Fatalf("Expected StatusOK. Got (%d): %s", rsp.statusCode, rsp.body) + } + + var list []*networkResource + err = json.Unmarshal(rsp.body, &list) + if err != nil { + t.Fatal(err) + } + if len(list) != 0 { + t.Fatalf("Expected empty list. Got %v", list) + } + + req, err = http.NewRequest("GET", "/v1.19/networks?name=network-fiftyfive", nil) + if err != nil { + t.Fatal(err) + } + handleRequest(rsp, req) + if rsp.statusCode != http.StatusOK { + t.Fatalf("Unexpectded failure: (%d): %s", rsp.statusCode, rsp.body) + } + + err = json.Unmarshal(rsp.body, &list) + if err != nil { + t.Fatal(err) + } + if len(list) == 0 { + t.Fatalf("Expected non empty list") + } + if list[0].Name != "network-fiftyfive" || nid != list[0].ID { + t.Fatalf("Incongruent resource found: %v", list[0]) + } + + // Query network by partial id + chars := []byte(nid) + partial := string(chars[0 : len(chars)/2]) + req, err = http.NewRequest("GET", "/v1.19/networks?partial-id="+partial, nil) + if err != nil { + t.Fatal(err) + } + handleRequest(rsp, req) + if rsp.statusCode != http.StatusOK { + t.Fatalf("Unexpectded failure: (%d): %s", rsp.statusCode, rsp.body) + } + + err = json.Unmarshal(rsp.body, &list) + if err != nil { + t.Fatal(err) + } + if len(list) == 0 { + t.Fatalf("Expected non empty list") + } + if list[0].Name != "network-fiftyfive" || nid != list[0].ID { + t.Fatalf("Incongruent resource found: %v", list[0]) + } + + // Get network by id + req, err = http.NewRequest("GET", "/v1.19/networks/"+nid, nil) if err != nil { t.Fatal(err) } @@ -1300,7 +1356,211 @@ func TestHttpHandlerGood(t *testing.T) { if err != nil { t.Fatal(err) } - if nwr.Name != "zero-network" || id != nwr.ID { - t.Fatalf("Incongruent resource found") + if nwr.Name != "network-fiftyfive" || nid != nwr.ID { + t.Fatalf("Incongruent resource found: %v", nwr) + } + + // Create endpoint + eb, err := json.Marshal(endpointCreate{Name: "ep-TwentyTwo"}) + if err != nil { + t.Fatal(err) + } + + lr = newLocalReader(eb) + req, err = http.NewRequest("POST", "/v1.19/networks/"+nid+"/endpoints", lr) + if err != nil { + t.Fatal(err) + } + handleRequest(rsp, req) + if rsp.statusCode != http.StatusCreated { + t.Fatalf("Unexpectded status code. Expected (%d). Got (%d): %s.", http.StatusCreated, rsp.statusCode, string(rsp.body)) + } + if len(rsp.body) == 0 { + t.Fatalf("Empty response body") + } + + var eid string + err = json.Unmarshal(rsp.body, &eid) + if err != nil { + t.Fatal(err) + } + + // Query endpoint(s) + req, err = http.NewRequest("GET", "/v1.19/networks/"+nid+"/endpoints", nil) + if err != nil { + t.Fatal(err) + } + handleRequest(rsp, req) + if rsp.statusCode != http.StatusOK { + t.Fatalf("Expected StatusOK. Got (%d): %s", rsp.statusCode, rsp.body) + } + + req, err = http.NewRequest("GET", "/v1.19/networks/"+nid+"/endpoints?name=bla", nil) + if err != nil { + t.Fatal(err) + } + handleRequest(rsp, req) + if rsp.statusCode != http.StatusOK { + t.Fatalf("Unexpectded failure: (%d): %s", rsp.statusCode, rsp.body) + } + var epList []*endpointResource + err = json.Unmarshal(rsp.body, &epList) + if err != nil { + t.Fatal(err) + } + if len(epList) != 0 { + t.Fatalf("Expected empty list. Got %v", epList) + } + + // Query endpoint by name + req, err = http.NewRequest("GET", "/v1.19/networks/"+nid+"/endpoints?name=ep-TwentyTwo", nil) + if err != nil { + t.Fatal(err) + } + handleRequest(rsp, req) + if rsp.statusCode != http.StatusOK { + t.Fatalf("Unexpectded failure: (%d): %s", rsp.statusCode, rsp.body) + } + + err = json.Unmarshal(rsp.body, &epList) + if err != nil { + t.Fatal(err) + } + if len(epList) == 0 { + t.Fatalf("Empty response body") + } + if epList[0].Name != "ep-TwentyTwo" || eid != epList[0].ID { + t.Fatalf("Incongruent resource found: %v", epList[0]) + } + + // Query endpoint by partial id + chars = []byte(eid) + partial = string(chars[0 : len(chars)/2]) + req, err = http.NewRequest("GET", "/v1.19/networks/"+nid+"/endpoints?partial-id="+partial, nil) + if err != nil { + t.Fatal(err) + } + handleRequest(rsp, req) + if rsp.statusCode != http.StatusOK { + t.Fatalf("Unexpectded failure: (%d): %s", rsp.statusCode, rsp.body) + } + + err = json.Unmarshal(rsp.body, &epList) + if err != nil { + t.Fatal(err) + } + if len(epList) == 0 { + t.Fatalf("Empty response body") + } + if epList[0].Name != "ep-TwentyTwo" || eid != epList[0].ID { + t.Fatalf("Incongruent resource found: %v", epList[0]) + } + + // Get endpoint by id + req, err = http.NewRequest("GET", "/v1.19/networks/"+nid+"/endpoints/"+eid, nil) + if err != nil { + t.Fatal(err) + } + handleRequest(rsp, req) + if rsp.statusCode != http.StatusOK { + t.Fatalf("Unexpectded failure: (%d): %s", rsp.statusCode, rsp.body) + } + + var epr endpointResource + err = json.Unmarshal(rsp.body, &epr) + if err != nil { + t.Fatal(err) + } + if epr.Name != "ep-TwentyTwo" || epr.ID != eid { + t.Fatalf("Incongruent resource found: %v", epr) + } +} + +type bre struct{} + +func (b *bre) Error() string { + return "I am a bad request error" +} +func (b *bre) BadRequest() {} + +type nfe struct{} + +func (n *nfe) Error() string { + return "I am a not found error" +} +func (n *nfe) NotFound() {} + +type forb struct{} + +func (f *forb) Error() string { + return "I am a bad request error" +} +func (f *forb) Forbidden() {} + +type notimpl struct{} + +func (nip *notimpl) Error() string { + return "I am a not implemented error" +} +func (nip *notimpl) NotImplemented() {} + +type inter struct{} + +func (it *inter) Error() string { + return "I am a internal error" +} +func (it *inter) Internal() {} + +type tout struct{} + +func (to *tout) Error() string { + return "I am a timeout error" +} +func (to *tout) Timeout() {} + +type noserv struct{} + +func (nos *noserv) Error() string { + return "I am a no service error" +} +func (nos *noserv) NoService() {} + +type notclassified struct{} + +func (noc *notclassified) Error() string { + return "I am a non classified error" +} + +func TestErrorConversion(t *testing.T) { + if convertNetworkError(new(bre)).StatusCode != http.StatusBadRequest { + t.Fatalf("Failed to recognize BadRequest error") + } + + if convertNetworkError(new(nfe)).StatusCode != http.StatusNotFound { + t.Fatalf("Failed to recognize NotFound error") + } + + if convertNetworkError(new(forb)).StatusCode != http.StatusForbidden { + t.Fatalf("Failed to recognize Forbidden error") + } + + if convertNetworkError(new(notimpl)).StatusCode != http.StatusNotImplemented { + t.Fatalf("Failed to recognize NotImplemented error") + } + + if convertNetworkError(new(inter)).StatusCode != http.StatusInternalServerError { + t.Fatalf("Failed to recognize Internal error") + } + + if convertNetworkError(new(tout)).StatusCode != http.StatusRequestTimeout { + t.Fatalf("Failed to recognize Timeout error") + } + + if convertNetworkError(new(noserv)).StatusCode != http.StatusServiceUnavailable { + t.Fatalf("Failed to recognize No Service error") + } + + if convertNetworkError(new(notclassified)).StatusCode != http.StatusInternalServerError { + t.Fatalf("Failed to recognize not classified error as Internal error") } } diff --git a/vendor/src/github.com/docker/libnetwork/api/types.go b/vendor/src/github.com/docker/libnetwork/api/types.go index 1a0ac85562..2490a84fe4 100644 --- a/vendor/src/github.com/docker/libnetwork/api/types.go +++ b/vendor/src/github.com/docker/libnetwork/api/types.go @@ -1,6 +1,6 @@ package api -import "github.com/docker/libnetwork/netutils" +import "github.com/docker/libnetwork/types" /*********** Resources @@ -35,9 +35,8 @@ type networkCreate struct { // endpointCreate represents the body of the "create endpoint" http request message type endpointCreate struct { Name string - NetworkID string - ExposedPorts []netutils.TransportPort - PortMapping []netutils.PortBinding + ExposedPorts []types.TransportPort + PortMapping []types.PortBinding } // endpointJoin represents the expected body of the "join endpoint" or "leave endpoint" http request messages diff --git a/vendor/src/github.com/docker/libnetwork/client/client.go b/vendor/src/github.com/docker/libnetwork/client/client.go index 64c6f7da53..4bc86da4be 100644 --- a/vendor/src/github.com/docker/libnetwork/client/client.go +++ b/vendor/src/github.com/docker/libnetwork/client/client.go @@ -49,6 +49,12 @@ func (cli *NetworkCli) getMethod(args ...string) (func(string, ...string) error, // Cmd is borrowed from Docker UI and acts as the entry point for network UI commands. // network UI commands are designed to be invoked from multiple parent chains func (cli *NetworkCli) Cmd(chain string, args ...string) error { + if len(args) > 2 { + method, exists := cli.getMethod(args[:3]...) + if exists { + return method(chain+" "+args[0]+" "+args[1], args[3:]...) + } + } if len(args) > 1 { method, exists := cli.getMethod(args[:2]...) if exists { diff --git a/vendor/src/github.com/docker/libnetwork/client/client_experimental_test.go b/vendor/src/github.com/docker/libnetwork/client/client_experimental_test.go new file mode 100644 index 0000000000..9592b3ca77 --- /dev/null +++ b/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()) + } +} +*/ diff --git a/vendor/src/github.com/docker/libnetwork/client/client_test.go b/vendor/src/github.com/docker/libnetwork/client/client_test.go index fbb5ba240a..3b2f3a8eb9 100644 --- a/vendor/src/github.com/docker/libnetwork/client/client_test.go +++ b/vendor/src/github.com/docker/libnetwork/client/client_test.go @@ -2,7 +2,11 @@ package client import ( "bytes" + "encoding/json" + "fmt" "io" + "os" + "strings" "testing" _ "github.com/docker/libnetwork/netutils" @@ -15,12 +19,82 @@ type nopCloser struct { func (nopCloser) Close() error { return nil } +func TestMain(m *testing.M) { + setupMockHTTPCallback() + os.Exit(m.Run()) +} + +var callbackFunc func(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, int, error) +var mockNwJSON, mockNwListJSON, mockServiceJSON, mockServiceListJSON []byte +var mockNwName = "test" +var mockNwID = "2a3456789" +var mockServiceName = "testSrv" +var mockServiceID = "2a3456789" +var mockContainerID = "2a3456789" + +func setupMockHTTPCallback() { + var list []networkResource + nw := networkResource{Name: mockNwName, ID: mockNwID} + mockNwJSON, _ = json.Marshal(nw) + list = append(list, nw) + mockNwListJSON, _ = json.Marshal(list) + + var srvList []endpointResource + ep := endpointResource{Name: mockServiceName, ID: mockServiceID, Network: mockNwName} + mockServiceJSON, _ = json.Marshal(ep) + srvList = append(srvList, ep) + mockServiceListJSON, _ = json.Marshal(srvList) + + callbackFunc = func(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, int, error) { + var rsp string + switch method { + case "GET": + if strings.Contains(path, fmt.Sprintf("networks?name=%s", mockNwName)) { + rsp = string(mockNwListJSON) + } else if strings.Contains(path, "networks?name=") { + rsp = "[]" + } else if strings.Contains(path, fmt.Sprintf("networks?partial-id=%s", mockNwID)) { + rsp = string(mockNwListJSON) + } else if strings.Contains(path, "networks?partial-id=") { + rsp = "[]" + } else if strings.HasSuffix(path, "networks") { + rsp = string(mockNwListJSON) + } else if strings.HasSuffix(path, "networks/"+mockNwID) { + rsp = string(mockNwJSON) + } else if strings.Contains(path, fmt.Sprintf("endpoints?name=%s", mockServiceName)) { + rsp = string(mockServiceListJSON) + } else if strings.Contains(path, "endpoints?name=") { + rsp = "[]" + } else if strings.Contains(path, fmt.Sprintf("endpoints?partial-id=%s", mockServiceID)) { + rsp = string(mockServiceListJSON) + } else if strings.Contains(path, "endpoints?partial-id=") { + rsp = "[]" + } else if strings.HasSuffix(path, "endpoints") { + rsp = string(mockServiceListJSON) + } else if strings.HasSuffix(path, "endpoints/"+mockServiceID) { + rsp = string(mockServiceJSON) + } + case "POST": + var data []byte + if strings.HasSuffix(path, "networks") { + data, _ = json.Marshal(mockNwID) + } else if strings.HasSuffix(path, "endpoints") { + data, _ = json.Marshal(mockServiceID) + } else if strings.HasSuffix(path, "containers") { + data, _ = json.Marshal(mockContainerID) + } + rsp = string(data) + case "PUT": + case "DELETE": + rsp = "" + } + return nopCloser{bytes.NewBufferString(rsp)}, 200, nil + } +} + func TestClientDummyCommand(t *testing.T) { var out, errOut bytes.Buffer - cFunc := func(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, int, error) { - return nopCloser{bytes.NewBufferString("")}, 200, nil - } - cli := NewNetworkCli(&out, &errOut, cFunc) + cli := NewNetworkCli(&out, &errOut, callbackFunc) err := cli.Cmd("docker", "dummy") if err == nil { @@ -30,10 +104,7 @@ func TestClientDummyCommand(t *testing.T) { func TestClientNetworkInvalidCommand(t *testing.T) { var out, errOut bytes.Buffer - cFunc := func(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, int, error) { - return nopCloser{bytes.NewBufferString("")}, 200, nil - } - cli := NewNetworkCli(&out, &errOut, cFunc) + cli := NewNetworkCli(&out, &errOut, callbackFunc) err := cli.Cmd("docker", "network", "invalid") if err == nil { @@ -43,12 +114,9 @@ func TestClientNetworkInvalidCommand(t *testing.T) { func TestClientNetworkCreate(t *testing.T) { var out, errOut bytes.Buffer - cFunc := func(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, int, error) { - return nopCloser{bytes.NewBufferString("")}, 200, nil - } - cli := NewNetworkCli(&out, &errOut, cFunc) + cli := NewNetworkCli(&out, &errOut, callbackFunc) - err := cli.Cmd("docker", "network", "create", "test") + err := cli.Cmd("docker", "network", "create", mockNwName) if err != nil { t.Fatal(err.Error()) } @@ -56,17 +124,14 @@ func TestClientNetworkCreate(t *testing.T) { func TestClientNetworkCreateWithDriver(t *testing.T) { var out, errOut bytes.Buffer - cFunc := func(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, int, error) { - return nopCloser{bytes.NewBufferString("")}, 200, nil - } - cli := NewNetworkCli(&out, &errOut, cFunc) + cli := NewNetworkCli(&out, &errOut, callbackFunc) - err := cli.Cmd("docker", "network", "create", "-f=dummy", "test") + err := cli.Cmd("docker", "network", "create", "-f=dummy", mockNwName) if err == nil { t.Fatalf("Passing incorrect flags to the create command must fail") } - err = cli.Cmd("docker", "network", "create", "-d=dummy", "test") + err = cli.Cmd("docker", "network", "create", "-d=dummy", mockNwName) if err != nil { t.Fatalf(err.Error()) } @@ -74,12 +139,9 @@ func TestClientNetworkCreateWithDriver(t *testing.T) { func TestClientNetworkRm(t *testing.T) { var out, errOut bytes.Buffer - cFunc := func(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, int, error) { - return nopCloser{bytes.NewBufferString("")}, 200, nil - } - cli := NewNetworkCli(&out, &errOut, cFunc) + cli := NewNetworkCli(&out, &errOut, callbackFunc) - err := cli.Cmd("docker", "network", "rm", "test") + err := cli.Cmd("docker", "network", "rm", mockNwName) if err != nil { t.Fatal(err.Error()) } @@ -87,47 +149,43 @@ func TestClientNetworkRm(t *testing.T) { func TestClientNetworkLs(t *testing.T) { var out, errOut bytes.Buffer - networks := "db,web,test" - cFunc := func(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, int, error) { - return nopCloser{bytes.NewBufferString(networks)}, 200, nil - } - cli := NewNetworkCli(&out, &errOut, cFunc) + cli := NewNetworkCli(&out, &errOut, callbackFunc) err := cli.Cmd("docker", "network", "ls") if err != nil { t.Fatal(err.Error()) } - if out.String() != networks { - t.Fatal("Network List command fail to return the intended list") - } } func TestClientNetworkInfo(t *testing.T) { var out, errOut bytes.Buffer - info := "dummy info" - cFunc := func(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, int, error) { - return nopCloser{bytes.NewBufferString(info)}, 200, nil - } - cli := NewNetworkCli(&out, &errOut, cFunc) + cli := NewNetworkCli(&out, &errOut, callbackFunc) - err := cli.Cmd("docker", "network", "info", "test") + err := cli.Cmd("docker", "network", "info", mockNwName) if err != nil { t.Fatal(err.Error()) } - if out.String() != info { - t.Fatal("Network List command fail to return the intended list") +} + +func TestClientNetworkInfoById(t *testing.T) { + var out, errOut bytes.Buffer + cli := NewNetworkCli(&out, &errOut, callbackFunc) + + err := cli.Cmd("docker", "network", "info", mockNwID) + if err != nil { + t.Fatal(err.Error()) } } // Docker Flag processing in flag.go uses os.Exit() frequently, even for --help // TODO : Handle the --help test-case in the IT when CLI is available /* -func TestClientNetworkCreateHelp(t *testing.T) { +func TestClientNetworkServiceCreateHelp(t *testing.T) { var out, errOut bytes.Buffer cFunc := func(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, int, error) { return nil, 0, nil } - cli := NewNetworkCli(&out, &errOut, cFunc) + cli := NewNetworkCli(&out, &errOut, callbackFunc) err := cli.Cmd("docker", "network", "create", "--help") if err != nil { @@ -139,12 +197,12 @@ func TestClientNetworkCreateHelp(t *testing.T) { // Docker flag processing in flag.go uses os.Exit(1) for incorrect parameter case. // TODO : Handle the missing argument case in the IT when CLI is available /* -func TestClientNetworkCreateMissingArgument(t *testing.T) { +func TestClientNetworkServiceCreateMissingArgument(t *testing.T) { var out, errOut bytes.Buffer cFunc := func(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, int, error) { return nil, 0, nil } - cli := NewNetworkCli(&out, &errOut, cFunc) + cli := NewNetworkCli(&out, &errOut, callbackFunc) err := cli.Cmd("docker", "network", "create") if err != nil { diff --git a/vendor/src/github.com/docker/libnetwork/client/network.go b/vendor/src/github.com/docker/libnetwork/client/network.go index d9effab8c4..4e0232941c 100644 --- a/vendor/src/github.com/docker/libnetwork/client/network.go +++ b/vendor/src/github.com/docker/libnetwork/client/network.go @@ -2,10 +2,13 @@ package client import ( "bytes" + "encoding/json" "fmt" - "io" + "net/http" + "text/tabwriter" flag "github.com/docker/docker/pkg/mflag" + "github.com/docker/docker/pkg/stringid" ) const ( @@ -33,7 +36,7 @@ func (cli *NetworkCli) CmdNetwork(chain string, args ...string) error { err := cmd.ParseFlags(args, true) if err == nil { cmd.Usage() - return fmt.Errorf("Invalid command : %v", args) + return fmt.Errorf("invalid command : %v", args) } return err } @@ -53,31 +56,33 @@ func (cli *NetworkCli) CmdNetworkCreate(chain string, args ...string) error { nc := networkCreate{Name: cmd.Arg(0), NetworkType: *flDriver} - obj, _, err := readBody(cli.call("POST", "/networks/name/"+cmd.Arg(0), nc, nil)) + obj, _, err := readBody(cli.call("POST", "/networks", nc, nil)) if err != nil { - fmt.Fprintf(cli.err, "%s", err.Error()) return err } - if _, err := io.Copy(cli.out, bytes.NewReader(obj)); err != nil { + var replyID string + err = json.Unmarshal(obj, &replyID) + if err != nil { return err } + fmt.Fprintf(cli.out, "%s\n", replyID) return nil } // CmdNetworkRm handles Network Delete UI func (cli *NetworkCli) CmdNetworkRm(chain string, args ...string) error { - cmd := cli.Subcmd(chain, "rm", "NETWORK-NAME", "Deletes a network", false) + cmd := cli.Subcmd(chain, "rm", "NETWORK", "Deletes a network", false) cmd.Require(flag.Min, 1) err := cmd.ParseFlags(args, true) if err != nil { return err } - obj, _, err := readBody(cli.call("DELETE", "/networks/name/"+cmd.Arg(0), nil, nil)) + id, err := lookupNetworkID(cli, cmd.Arg(0)) if err != nil { - fmt.Fprintf(cli.err, "%s", err.Error()) return err } - if _, err := io.Copy(cli.out, bytes.NewReader(obj)); err != nil { + _, _, err = readBody(cli.call("DELETE", "/networks/"+id, nil, nil)) + if err != nil { return err } return nil @@ -86,45 +91,149 @@ func (cli *NetworkCli) CmdNetworkRm(chain string, args ...string) error { // CmdNetworkLs handles Network List UI func (cli *NetworkCli) CmdNetworkLs(chain string, args ...string) error { cmd := cli.Subcmd(chain, "ls", "", "Lists all the networks created by the user", false) + quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only display numeric IDs") + noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Do not truncate the output") + nLatest := cmd.Bool([]string{"l", "-latest"}, false, "Show the latest network created") + last := cmd.Int([]string{"n"}, -1, "Show n last created networks") err := cmd.ParseFlags(args, true) if err != nil { return err } obj, _, err := readBody(cli.call("GET", "/networks", nil, nil)) if err != nil { - fmt.Fprintf(cli.err, "%s", err.Error()) return err } - if _, err := io.Copy(cli.out, bytes.NewReader(obj)); err != nil { + if *last == -1 && *nLatest { + *last = 1 + } + + var networkResources []networkResource + err = json.Unmarshal(obj, &networkResources) + if err != nil { return err } + + wr := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0) + + // unless quiet (-q) is specified, print field titles + if !*quiet { + fmt.Fprintln(wr, "NETWORK ID\tNAME\tTYPE") + } + + for _, networkResource := range networkResources { + ID := networkResource.ID + netName := networkResource.Name + if !*noTrunc { + ID = stringid.TruncateID(ID) + } + if *quiet { + fmt.Fprintln(wr, ID) + continue + } + netType := networkResource.Type + fmt.Fprintf(wr, "%s\t%s\t%s\t", + ID, + netName, + netType) + fmt.Fprint(wr, "\n") + } + wr.Flush() return nil } // CmdNetworkInfo handles Network Info UI func (cli *NetworkCli) CmdNetworkInfo(chain string, args ...string) error { - cmd := cli.Subcmd(chain, "info", "NETWORK-NAME", "Displays detailed information on a network", false) + cmd := cli.Subcmd(chain, "info", "NETWORK", "Displays detailed information on a network", false) cmd.Require(flag.Min, 1) err := cmd.ParseFlags(args, true) if err != nil { return err } - obj, _, err := readBody(cli.call("GET", "/networks/name/"+cmd.Arg(0), nil, nil)) + + id, err := lookupNetworkID(cli, cmd.Arg(0)) if err != nil { - fmt.Fprintf(cli.err, "%s", err.Error()) return err } - if _, err := io.Copy(cli.out, bytes.NewReader(obj)); err != nil { + + obj, _, err := readBody(cli.call("GET", "/networks/"+id, nil, nil)) + if err != nil { return err } + networkResource := &networkResource{} + if err := json.NewDecoder(bytes.NewReader(obj)).Decode(networkResource); err != nil { + return err + } + fmt.Fprintf(cli.out, "Network Id: %s\n", networkResource.ID) + fmt.Fprintf(cli.out, "Name: %s\n", networkResource.Name) + fmt.Fprintf(cli.out, "Type: %s\n", networkResource.Type) + if networkResource.Endpoints != nil { + for _, endpointResource := range networkResource.Endpoints { + fmt.Fprintf(cli.out, " Service Id: %s\n", endpointResource.ID) + fmt.Fprintf(cli.out, "\tName: %s\n", endpointResource.Name) + } + } + return nil } +// Helper function to predict if a string is a name or id or partial-id +// This provides a best-effort mechanism to identify a id with the help of GET Filter APIs +// Being a UI, its most likely that name will be used by the user, which is used to lookup +// the corresponding ID. If ID is not found, this function will assume that the passed string +// is an ID by itself. + +func lookupNetworkID(cli *NetworkCli, nameID string) (string, error) { + obj, statusCode, err := readBody(cli.call("GET", "/networks?name="+nameID, nil, nil)) + if err != nil { + return "", err + } + + if statusCode != http.StatusOK { + return "", fmt.Errorf("name query failed for %s due to : statuscode(%d) %v", nameID, statusCode, string(obj)) + } + + var list []*networkResource + err = json.Unmarshal(obj, &list) + if err != nil { + return "", err + } + if len(list) > 0 { + // name query filter will always return a single-element collection + return list[0].ID, nil + } + + // Check for Partial-id + obj, statusCode, err = readBody(cli.call("GET", "/networks?partial-id="+nameID, nil, nil)) + if err != nil { + return "", err + } + + if statusCode != http.StatusOK { + return "", fmt.Errorf("partial-id match query failed for %s due to : statuscode(%d) %v", nameID, statusCode, string(obj)) + } + + err = json.Unmarshal(obj, &list) + if err != nil { + return "", err + } + if len(list) == 0 { + return "", fmt.Errorf("resource not found %s", nameID) + } + if len(list) > 1 { + return "", fmt.Errorf("multiple Networks matching the partial identifier (%s). Please use full identifier", nameID) + } + return list[0].ID, nil +} + func networkUsage(chain string) string { help := "Commands:\n" for _, cmd := range networkCommands { - help += fmt.Sprintf(" %-10.10s%s\n", cmd.name, cmd.description) + help += fmt.Sprintf(" %-25.25s%s\n", cmd.name, cmd.description) + } + + for _, cmd := range serviceCommands { + help += fmt.Sprintf(" %-25.25s%s\n", "service "+cmd.name, cmd.description) } help += fmt.Sprintf("\nRun '%s network COMMAND --help' for more information on a command.", chain) diff --git a/vendor/src/github.com/docker/libnetwork/client/service.go b/vendor/src/github.com/docker/libnetwork/client/service.go new file mode 100644 index 0000000000..afdbb7f84b --- /dev/null +++ b/vendor/src/github.com/docker/libnetwork/client/service.go @@ -0,0 +1,7 @@ +// +build !experimental + +package client + +var ( + serviceCommands = []command{} +) diff --git a/vendor/src/github.com/docker/libnetwork/client/service_experimental.go b/vendor/src/github.com/docker/libnetwork/client/service_experimental.go new file mode 100644 index 0000000000..02555fc197 --- /dev/null +++ b/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 +} diff --git a/vendor/src/github.com/docker/libnetwork/client/types.go b/vendor/src/github.com/docker/libnetwork/client/types.go index 27d17b9506..972ed435e8 100644 --- a/vendor/src/github.com/docker/libnetwork/client/types.go +++ b/vendor/src/github.com/docker/libnetwork/client/types.go @@ -1,6 +1,6 @@ package client -import "github.com/docker/libnetwork/sandbox" +import "github.com/docker/libnetwork/types" /*********** Resources @@ -19,7 +19,6 @@ type endpointResource struct { Name string ID string Network string - Info sandbox.Info } /*********** @@ -32,3 +31,38 @@ type networkCreate struct { NetworkType string Options map[string]interface{} } + +// endpointCreate represents the body of the "create endpoint" http request message +type endpointCreate struct { + Name string + NetworkID string + ExposedPorts []types.TransportPort + PortMapping []types.PortBinding +} + +// endpointJoin represents the expected body of the "join endpoint" or "leave endpoint" http request messages +type endpointJoin struct { + ContainerID string + HostName string + DomainName string + HostsPath string + ResolvConfPath string + DNS []string + ExtraHosts []endpointExtraHost + ParentUpdates []endpointParentUpdate + UseDefaultSandbox bool +} + +// EndpointExtraHost represents the extra host object +type endpointExtraHost struct { + Name string + Address string +} + +// EndpointParentUpdate is the object carrying the information about the +// endpoint parent that needs to be updated +type endpointParentUpdate struct { + EndpointID string + Name string + Address string +} diff --git a/vendor/src/github.com/docker/libnetwork/cmd/dnet/dnet.go b/vendor/src/github.com/docker/libnetwork/cmd/dnet/dnet.go index 547ec312e6..8c599249a1 100644 --- a/vendor/src/github.com/docker/libnetwork/cmd/dnet/dnet.go +++ b/vendor/src/github.com/docker/libnetwork/cmd/dnet/dnet.go @@ -113,10 +113,8 @@ func (d *dnetConnection) dnetDaemon() error { } httpHandler := api.NewHTTPHandler(controller) r := mux.NewRouter().StrictSlash(false) - post := r.PathPrefix("/networks").Subrouter() - post.Methods("GET").HandlerFunc(httpHandler) - post.Methods("PUT", "POST").HandlerFunc(httpHandler) - post.Methods("DELETE").HandlerFunc(httpHandler) + post := r.PathPrefix("/{.*}/networks").Subrouter() + post.Methods("GET", "PUT", "POST", "DELETE").HandlerFunc(httpHandler) return http.ListenAndServe(d.addr, r) } @@ -143,7 +141,7 @@ func (d *dnetConnection) httpCall(method, path string, data interface{}, headers return nil, -1, err } - req, err := http.NewRequest(method, fmt.Sprintf("%s", path), in) + req, err := http.NewRequest(method, fmt.Sprintf("/dnet%s", path), in) if err != nil { return nil, -1, err } @@ -160,7 +158,7 @@ func (d *dnetConnection) httpCall(method, path string, data interface{}, headers statusCode = resp.StatusCode } if err != nil { - return nil, statusCode, fmt.Errorf("An error occurred trying to connect: %v", err) + return nil, statusCode, fmt.Errorf("error when trying to connect: %v", err) } if statusCode < 200 || statusCode >= 400 { @@ -168,7 +166,7 @@ func (d *dnetConnection) httpCall(method, path string, data interface{}, headers if err != nil { return nil, statusCode, err } - return nil, statusCode, fmt.Errorf("Error response from daemon: %s", bytes.TrimSpace(body)) + return nil, statusCode, fmt.Errorf("error : %s", bytes.TrimSpace(body)) } return resp.Body, statusCode, nil diff --git a/vendor/src/github.com/docker/libnetwork/cmd/dnet/flags.go b/vendor/src/github.com/docker/libnetwork/cmd/dnet/flags.go index 468f18dc09..2e77e1873b 100644 --- a/vendor/src/github.com/docker/libnetwork/cmd/dnet/flags.go +++ b/vendor/src/github.com/docker/libnetwork/cmd/dnet/flags.go @@ -16,7 +16,7 @@ type byName []command var ( flDaemon = flag.Bool([]string{"d", "-daemon"}, false, "Enable daemon mode") - flHost = flag.String([]string{"H", "-Host"}, "", "Daemon socket to connect to") + flHost = flag.String([]string{"H", "-host"}, "", "Daemon socket to connect to") flLogLevel = flag.String([]string{"l", "-log-level"}, "info", "Set the logging level") flDebug = flag.Bool([]string{"D", "-debug"}, false, "Enable debug mode") flHelp = flag.Bool([]string{"h", "-help"}, false, "Print usage") diff --git a/vendor/src/github.com/docker/libnetwork/cmd/readme_test/readme.go b/vendor/src/github.com/docker/libnetwork/cmd/readme_test/readme.go index ce4d8fedf8..a15fda0c34 100644 --- a/vendor/src/github.com/docker/libnetwork/cmd/readme_test/readme.go +++ b/vendor/src/github.com/docker/libnetwork/cmd/readme_test/readme.go @@ -5,8 +5,8 @@ import ( "github.com/docker/libnetwork" "github.com/docker/libnetwork/netlabel" - "github.com/docker/libnetwork/netutils" "github.com/docker/libnetwork/options" + "github.com/docker/libnetwork/types" ) func main() { @@ -58,7 +58,7 @@ func main() { epInfo, err := ep.DriverInfo() mapData, ok := epInfo[netlabel.PortMap] if ok { - portMapping, ok := mapData.([]netutils.PortBinding) + portMapping, ok := mapData.([]types.PortBinding) if ok { fmt.Printf("Current port mapping for endpoint %s: %v", ep.Name(), portMapping) } diff --git a/vendor/src/github.com/docker/libnetwork/controller.go b/vendor/src/github.com/docker/libnetwork/controller.go index a64d6e526b..442473eb20 100644 --- a/vendor/src/github.com/docker/libnetwork/controller.go +++ b/vendor/src/github.com/docker/libnetwork/controller.go @@ -134,7 +134,7 @@ func (c *controller) RegisterDriver(networkType string, driver driverapi.Driver) // are network specific and modeled in a generic way. func (c *controller) NewNetwork(networkType, name string, options ...NetworkOption) (Network, error) { if name == "" { - return nil, ErrInvalidName + return nil, ErrInvalidName(name) } // Check if a driver for the specified network type is available c.Lock() @@ -203,7 +203,7 @@ func (c *controller) WalkNetworks(walker NetworkWalker) { func (c *controller) NetworkByName(name string) (Network, error) { if name == "" { - return nil, ErrInvalidName + return nil, ErrInvalidName(name) } var n Network @@ -218,7 +218,7 @@ func (c *controller) NetworkByName(name string) (Network, error) { c.WalkNetworks(s) if n == nil { - return nil, ErrNoSuchNetwork + return nil, ErrNoSuchNetwork(name) } return n, nil @@ -226,14 +226,14 @@ func (c *controller) NetworkByName(name string) (Network, error) { func (c *controller) NetworkByID(id string) (Network, error) { if id == "" { - return nil, ErrInvalidID + return nil, ErrInvalidID(id) } c.Lock() defer c.Unlock() if n, ok := c.networks[types.UUID(id)]; ok { return n, nil } - return nil, ErrNoSuchNetwork + return nil, ErrNoSuchNetwork(id) } func (c *controller) sandboxAdd(key string, create bool) (sandbox.Sandbox, error) { @@ -286,13 +286,16 @@ func (c *controller) loadDriver(networkType string) (driverapi.Driver, error) { // As per the design, this Get call will result in remote driver discovery if there is a corresponding plugin available. _, err := plugins.Get(networkType, driverapi.NetworkPluginEndpointType) if err != nil { + if err == plugins.ErrNotFound { + return nil, types.NotFoundErrorf(err.Error()) + } return nil, err } c.Lock() defer c.Unlock() d, ok := c.drivers[networkType] if !ok { - return nil, ErrInvalidNetworkDriver + return nil, ErrInvalidNetworkDriver(networkType) } return d, nil } diff --git a/vendor/src/github.com/docker/libnetwork/docs/design.md b/vendor/src/github.com/docker/libnetwork/docs/design.md index 33dcc3d651..b3112da0fc 100644 --- a/vendor/src/github.com/docker/libnetwork/docs/design.md +++ b/vendor/src/github.com/docker/libnetwork/docs/design.md @@ -6,7 +6,7 @@ This document describes how libnetwork has been designed in order to acheive thi Requirements for individual releases can be found on the [Project Page](https://github.com/docker/libnetwork/wiki) Many of the design decisions are inspired by the learnings from the Docker networking design as of Docker v1.6. -Please refer to this [Docker v1.6 Design](https://github.com/docker/libnetwork/blob/docs/legacy.md) document for more information on networking design as of Docker v1.6. +Please refer to this [Docker v1.6 Design](legacy.md) document for more information on networking design as of Docker v1.6. ## Goal diff --git a/vendor/src/github.com/docker/libnetwork/driverapi/driverapi.go b/vendor/src/github.com/docker/libnetwork/driverapi/driverapi.go index 35467dafda..9fb41ff7b6 100644 --- a/vendor/src/github.com/docker/libnetwork/driverapi/driverapi.go +++ b/vendor/src/github.com/docker/libnetwork/driverapi/driverapi.go @@ -1,24 +1,11 @@ package driverapi import ( - "errors" - "fmt" "net" "github.com/docker/libnetwork/types" ) -var ( - // ErrEndpointExists is returned if more than one endpoint is added to the network - ErrEndpointExists = errors.New("Endpoint already exists (Only one endpoint allowed)") - // ErrNoNetwork is returned if no network with the specified id exists - ErrNoNetwork = errors.New("No network exists") - // ErrNoEndpoint is returned if no endpoint with the specified id exists - ErrNoEndpoint = errors.New("No endpoint exists") - // ErrNotImplemented is returned when a Driver has not implemented an API yet - ErrNotImplemented = errors.New("The API is not implemented yet") -) - // NetworkPluginEndpointType represents the Endpoint Type used by Plugin system const NetworkPluginEndpointType = "NetworkDriver" @@ -96,8 +83,8 @@ type InterfaceInfo interface { // InterfaceNameInfo provides a go interface for the drivers to assign names // to interfaces. type InterfaceNameInfo interface { - // SetNames method assigns the srcName and dstName for the interface. - SetNames(srcName, dstName string) error + // SetNames method assigns the srcName and dstPrefix for the interface. + SetNames(srcName, dstPrefix string) error // ID returns the numerical id that was assigned to the interface by the driver // CreateEndpoint. @@ -124,14 +111,6 @@ type JoinInfo interface { SetResolvConfPath(string) error } -// ErrActiveRegistration represents an error when a driver is registered to a networkType that is previously registered -type ErrActiveRegistration string - -// Error interface for ErrActiveRegistration -func (ar ErrActiveRegistration) Error() string { - return fmt.Sprintf("Driver already registered for type %q", string(ar)) -} - // DriverCallback provides a Callback interface for Drivers into LibNetwork type DriverCallback interface { // RegisterDriver provides a way for Remote drivers to dynamically register new NetworkType and associate with a driver instance diff --git a/vendor/src/github.com/docker/libnetwork/driverapi/errors.go b/vendor/src/github.com/docker/libnetwork/driverapi/errors.go new file mode 100644 index 0000000000..041ef41506 --- /dev/null +++ b/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() {} diff --git a/vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go b/vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go index 8e52188e00..b1cfe74492 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go @@ -21,7 +21,7 @@ const ( networkType = "bridge" vethPrefix = "veth" vethLen = 7 - containerVeth = "eth0" + containerVethPrefix = "eth" maxAllocatePortAttempts = 10 ifaceID = 1 ) @@ -57,8 +57,8 @@ type NetworkConfiguration struct { // EndpointConfiguration represents the user specified configuration for the sandbox endpoint type EndpointConfiguration struct { MacAddress net.HardwareAddr - PortBindings []netutils.PortBinding - ExposedPorts []netutils.TransportPort + PortBindings []types.PortBinding + ExposedPorts []types.TransportPort } // ContainerConfiguration represents the user specified configuration for a container @@ -73,7 +73,7 @@ type bridgeEndpoint struct { macAddress net.HardwareAddr config *EndpointConfiguration // User specified parameters containerConfig *ContainerConfiguration - portMapping []netutils.PortBinding // Operation port bindings + portMapping []types.PortBinding // Operation port bindings } type bridgeNetwork struct { @@ -109,7 +109,7 @@ func Init(dc driverapi.DriverCallback) error { // Whatever can be assessed a priori before attempting any programming. func (c *NetworkConfiguration) Validate() error { if c.Mtu < 0 { - return ErrInvalidMtu + return ErrInvalidMtu(c.Mtu) } // If bridge v4 subnet is specified @@ -118,19 +118,19 @@ func (c *NetworkConfiguration) Validate() error { if c.FixedCIDR != nil { // Check Network address if !c.AddressIPv4.Contains(c.FixedCIDR.IP) { - return ErrInvalidContainerSubnet + return &ErrInvalidContainerSubnet{} } // Check it is effectively a subset brNetLen, _ := c.AddressIPv4.Mask.Size() cnNetLen, _ := c.FixedCIDR.Mask.Size() if brNetLen > cnNetLen { - return ErrInvalidContainerSubnet + return &ErrInvalidContainerSubnet{} } } // If default gw is specified, it must be part of bridge subnet if c.DefaultGatewayIPv4 != nil { if !c.AddressIPv4.Contains(c.DefaultGatewayIPv4) { - return ErrInvalidGateway + return &ErrInvalidGateway{} } } } @@ -138,7 +138,7 @@ func (c *NetworkConfiguration) Validate() error { // If default v6 gw is specified, FixedCIDRv6 must be specified and gw must belong to FixedCIDRv6 subnet if c.EnableIPv6 && c.DefaultGatewayIPv6 != nil { if c.FixedCIDRv6 == nil || !c.FixedCIDRv6.Contains(c.DefaultGatewayIPv6) { - return ErrInvalidGateway + return &ErrInvalidGateway{} } } @@ -167,7 +167,7 @@ func (d *driver) Config(option map[string]interface{}) error { defer d.Unlock() if d.config != nil { - return ErrConfigExists + return &ErrConfigExists{} } genericData, ok := option[netlabel.GenericData] @@ -182,7 +182,7 @@ func (d *driver) Config(option map[string]interface{}) error { case *Configuration: config = opt default: - return ErrInvalidDriverConfig + return &ErrInvalidDriverConfig{} } d.config = config @@ -220,7 +220,7 @@ func parseNetworkOptions(option options.Generic) (*NetworkConfiguration, error) case *NetworkConfiguration: config = opt default: - return nil, ErrInvalidNetworkConfig + return nil, &ErrInvalidNetworkConfig{} } if err := config.Validate(); err != nil { @@ -247,7 +247,7 @@ func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) err // Sanity checks if d.network != nil { d.Unlock() - return ErrNetworkExists + return &ErrNetworkExists{} } // Create and set network handler in driver @@ -361,7 +361,7 @@ func (d *driver) DeleteNetwork(nid types.UUID) error { // Sanity check if n == nil { - err = driverapi.ErrNoNetwork + err = driverapi.ErrNoNetwork(nid) return err } @@ -397,7 +397,7 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn config := n.config d.Unlock() if n == nil { - return driverapi.ErrNoNetwork + return driverapi.ErrNoNetwork(nid) } // Sanity check @@ -416,7 +416,7 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn // Endpoint with that id exists either on desired or other sandbox if ep != nil { - return driverapi.ErrEndpointExists + return driverapi.ErrEndpointExists(eid) } // Try to convert the options to endpoint configuration @@ -545,7 +545,7 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn // Create the sandbox side pipe interface intf := &sandbox.Interface{} intf.SrcName = name2 - intf.DstName = containerVeth + intf.DstName = containerVethPrefix intf.Address = ipv4Addr if config.EnableIPv6 { @@ -578,7 +578,7 @@ func (d *driver) DeleteEndpoint(nid, eid types.UUID) error { config := n.config d.Unlock() if n == nil { - return driverapi.ErrNoNetwork + return driverapi.ErrNoNetwork(nid) } // Sanity Check @@ -648,7 +648,7 @@ func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{}, n := d.network d.Unlock() if n == nil { - return nil, driverapi.ErrNoNetwork + return nil, driverapi.ErrNoNetwork(nid) } // Sanity check @@ -665,14 +665,14 @@ func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{}, return nil, err } if ep == nil { - return nil, driverapi.ErrNoEndpoint + return nil, driverapi.ErrNoEndpoint(eid) } m := make(map[string]interface{}) if ep.portMapping != nil { // Return a copy of the operational data - pmc := make([]netutils.PortBinding, 0, len(ep.portMapping)) + pmc := make([]types.PortBinding, 0, len(ep.portMapping)) for _, pm := range ep.portMapping { pmc = append(pmc, pm.GetCopy()) } @@ -856,23 +856,23 @@ func parseEndpointOptions(epOptions map[string]interface{}) (*EndpointConfigurat if mac, ok := opt.(net.HardwareAddr); ok { ec.MacAddress = mac } else { - return nil, ErrInvalidEndpointConfig + return nil, &ErrInvalidEndpointConfig{} } } if opt, ok := epOptions[netlabel.PortMap]; ok { - if bs, ok := opt.([]netutils.PortBinding); ok { + if bs, ok := opt.([]types.PortBinding); ok { ec.PortBindings = bs } else { - return nil, ErrInvalidEndpointConfig + return nil, &ErrInvalidEndpointConfig{} } } if opt, ok := epOptions[netlabel.ExposedPorts]; ok { - if ports, ok := opt.([]netutils.TransportPort); ok { + if ports, ok := opt.([]types.TransportPort); ok { ec.ExposedPorts = ports } else { - return nil, ErrInvalidEndpointConfig + return nil, &ErrInvalidEndpointConfig{} } } @@ -924,5 +924,5 @@ func generateIfaceName() (string, error) { return "", err } } - return "", ErrIfaceName + return "", &ErrIfaceName{} } diff --git a/vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge_test.go b/vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge_test.go index d11ea8104f..f8967555ec 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge_test.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge_test.go @@ -11,6 +11,7 @@ import ( "github.com/docker/libnetwork/iptables" "github.com/docker/libnetwork/netlabel" "github.com/docker/libnetwork/netutils" + "github.com/docker/libnetwork/types" "github.com/vishvananda/netlink" ) @@ -202,7 +203,7 @@ func testQueryEndpointInfo(t *testing.T, ulPxyEnabled bool) { if !ok { t.Fatalf("Endpoint operational data does not contain port mapping data") } - pm, ok := pmd.([]netutils.PortBinding) + pm, ok := pmd.([]types.PortBinding) if !ok { t.Fatalf("Unexpected format for port mapping in endpoint operational data") } @@ -261,19 +262,19 @@ func TestCreateLinkWithOptions(t *testing.T) { } } -func getExposedPorts() []netutils.TransportPort { - return []netutils.TransportPort{ - netutils.TransportPort{Proto: netutils.TCP, Port: uint16(5000)}, - netutils.TransportPort{Proto: netutils.UDP, Port: uint16(400)}, - netutils.TransportPort{Proto: netutils.TCP, Port: uint16(600)}, +func getExposedPorts() []types.TransportPort { + return []types.TransportPort{ + types.TransportPort{Proto: types.TCP, Port: uint16(5000)}, + types.TransportPort{Proto: types.UDP, Port: uint16(400)}, + types.TransportPort{Proto: types.TCP, Port: uint16(600)}, } } -func getPortMapping() []netutils.PortBinding { - return []netutils.PortBinding{ - netutils.PortBinding{Proto: netutils.TCP, Port: uint16(230), HostPort: uint16(23000)}, - netutils.PortBinding{Proto: netutils.UDP, Port: uint16(200), HostPort: uint16(22000)}, - netutils.PortBinding{Proto: netutils.TCP, Port: uint16(120), HostPort: uint16(12000)}, +func getPortMapping() []types.PortBinding { + return []types.PortBinding{ + types.PortBinding{Proto: types.TCP, Port: uint16(230), HostPort: uint16(23000)}, + types.PortBinding{Proto: types.UDP, Port: uint16(200), HostPort: uint16(22000)}, + types.PortBinding{Proto: types.TCP, Port: uint16(120), HostPort: uint16(12000)}, } } diff --git a/vendor/src/github.com/docker/libnetwork/drivers/bridge/error.go b/vendor/src/github.com/docker/libnetwork/drivers/bridge/error.go deleted file mode 100644 index 5f149c46d9..0000000000 --- a/vendor/src/github.com/docker/libnetwork/drivers/bridge/error.go +++ /dev/null @@ -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)) -} diff --git a/vendor/src/github.com/docker/libnetwork/drivers/bridge/errors.go b/vendor/src/github.com/docker/libnetwork/drivers/bridge/errors.go new file mode 100644 index 0000000000..d22912c5c7 --- /dev/null +++ b/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() {} diff --git a/vendor/src/github.com/docker/libnetwork/drivers/bridge/link.go b/vendor/src/github.com/docker/libnetwork/drivers/bridge/link.go index 05a99dc0e4..4e4444e074 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/bridge/link.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/bridge/link.go @@ -6,13 +6,13 @@ import ( log "github.com/Sirupsen/logrus" "github.com/docker/libnetwork/iptables" - "github.com/docker/libnetwork/netutils" + "github.com/docker/libnetwork/types" ) type link struct { parentIP string childIP string - ports []netutils.TransportPort + ports []types.TransportPort bridge string } @@ -20,7 +20,7 @@ func (l *link) String() string { return fmt.Sprintf("%s <-> %s [%v] on %s", l.parentIP, l.childIP, l.ports, l.bridge) } -func newLink(parentIP, childIP string, ports []netutils.TransportPort, bridge string) *link { +func newLink(parentIP, childIP string, ports []types.TransportPort, bridge string) *link { return &link{ childIP: childIP, parentIP: parentIP, @@ -45,7 +45,7 @@ func (l *link) Disable() { // that returns typed errors } -func linkContainers(action, parentIP, childIP string, ports []netutils.TransportPort, bridge string, +func linkContainers(action, parentIP, childIP string, ports []types.TransportPort, bridge string, ignoreErrors bool) error { var nfAction iptables.Action @@ -57,7 +57,7 @@ func linkContainers(action, parentIP, childIP string, ports []netutils.Transport case "-D": nfAction = iptables.Delete default: - return invalidIPTablesCfgError(action) + return InvalidIPTablesCfgError(action) } ip1 := net.ParseIP(parentIP) diff --git a/vendor/src/github.com/docker/libnetwork/drivers/bridge/link_test.go b/vendor/src/github.com/docker/libnetwork/drivers/bridge/link_test.go index c021fd63c7..fc4a6251f3 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/bridge/link_test.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/bridge/link_test.go @@ -3,14 +3,14 @@ package bridge import ( "testing" - "github.com/docker/libnetwork/netutils" + "github.com/docker/libnetwork/types" ) -func getPorts() []netutils.TransportPort { - return []netutils.TransportPort{ - netutils.TransportPort{Proto: netutils.TCP, Port: uint16(5000)}, - netutils.TransportPort{Proto: netutils.UDP, Port: uint16(400)}, - netutils.TransportPort{Proto: netutils.TCP, Port: uint16(600)}, +func getPorts() []types.TransportPort { + return []types.TransportPort{ + types.TransportPort{Proto: types.TCP, Port: uint16(5000)}, + types.TransportPort{Proto: types.UDP, Port: uint16(400)}, + types.TransportPort{Proto: types.TCP, Port: uint16(600)}, } } diff --git a/vendor/src/github.com/docker/libnetwork/drivers/bridge/network_test.go b/vendor/src/github.com/docker/libnetwork/drivers/bridge/network_test.go index abadc07e92..20afea90ad 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/bridge/network_test.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/bridge/network_test.go @@ -125,8 +125,8 @@ func TestLinkCreateTwo(t *testing.T) { te2 := &testEndpoint{ifaces: []*testInterface{}} err = d.CreateEndpoint("dummy", "ep", te2, nil) if err != nil { - if err != driverapi.ErrEndpointExists { - t.Fatalf("Failed with a wrong error :%s", err.Error()) + if _, ok := err.(driverapi.ErrEndpointExists); !ok { + t.Fatalf("Failed with a wrong error: %s", err.Error()) } } else { t.Fatalf("Expected to fail while trying to add same endpoint twice") diff --git a/vendor/src/github.com/docker/libnetwork/drivers/bridge/port_mapping.go b/vendor/src/github.com/docker/libnetwork/drivers/bridge/port_mapping.go index aec4283c01..52d036241c 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/bridge/port_mapping.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/bridge/port_mapping.go @@ -7,15 +7,15 @@ import ( "net" "github.com/Sirupsen/logrus" - "github.com/docker/libnetwork/netutils" "github.com/docker/libnetwork/sandbox" + "github.com/docker/libnetwork/types" ) var ( defaultBindingIP = net.IPv4(0, 0, 0, 0) ) -func allocatePorts(epConfig *EndpointConfiguration, intf *sandbox.Interface, reqDefBindIP net.IP, ulPxyEnabled bool) ([]netutils.PortBinding, error) { +func allocatePorts(epConfig *EndpointConfiguration, intf *sandbox.Interface, reqDefBindIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) { if epConfig == nil || epConfig.PortBindings == nil { return nil, nil } @@ -28,8 +28,8 @@ func allocatePorts(epConfig *EndpointConfiguration, intf *sandbox.Interface, req return allocatePortsInternal(epConfig.PortBindings, intf.Address.IP, defHostIP, ulPxyEnabled) } -func allocatePortsInternal(bindings []netutils.PortBinding, containerIP, defHostIP net.IP, ulPxyEnabled bool) ([]netutils.PortBinding, error) { - bs := make([]netutils.PortBinding, 0, len(bindings)) +func allocatePortsInternal(bindings []types.PortBinding, containerIP, defHostIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) { + bs := make([]types.PortBinding, 0, len(bindings)) for _, c := range bindings { b := c.GetCopy() if err := allocatePort(&b, containerIP, defHostIP, ulPxyEnabled); err != nil { @@ -44,7 +44,7 @@ func allocatePortsInternal(bindings []netutils.PortBinding, containerIP, defHost return bs, nil } -func allocatePort(bnd *netutils.PortBinding, containerIP, defHostIP net.IP, ulPxyEnabled bool) error { +func allocatePort(bnd *types.PortBinding, containerIP, defHostIP net.IP, ulPxyEnabled bool) error { var ( host net.Addr err error @@ -98,7 +98,7 @@ func releasePorts(ep *bridgeEndpoint) error { return releasePortsInternal(ep.portMapping) } -func releasePortsInternal(bindings []netutils.PortBinding) error { +func releasePortsInternal(bindings []types.PortBinding) error { var errorBuf bytes.Buffer // Attempt to release all port bindings, do not stop on failure @@ -114,7 +114,7 @@ func releasePortsInternal(bindings []netutils.PortBinding) error { return nil } -func releasePort(bnd netutils.PortBinding) error { +func releasePort(bnd types.PortBinding) error { // Construct the host side transport address host, err := bnd.HostAddr() if err != nil { diff --git a/vendor/src/github.com/docker/libnetwork/drivers/bridge/port_mapping_test.go b/vendor/src/github.com/docker/libnetwork/drivers/bridge/port_mapping_test.go index 410827d1a3..5eb16b6de8 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/bridge/port_mapping_test.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/bridge/port_mapping_test.go @@ -7,6 +7,7 @@ import ( "github.com/docker/docker/pkg/reexec" "github.com/docker/libnetwork/netlabel" "github.com/docker/libnetwork/netutils" + "github.com/docker/libnetwork/types" ) func TestMain(m *testing.M) { @@ -20,9 +21,9 @@ func TestPortMappingConfig(t *testing.T) { defer netutils.SetupTestNetNS(t)() d := newDriver() - binding1 := netutils.PortBinding{Proto: netutils.UDP, Port: uint16(400), HostPort: uint16(54000)} - binding2 := netutils.PortBinding{Proto: netutils.TCP, Port: uint16(500), HostPort: uint16(65000)} - portBindings := []netutils.PortBinding{binding1, binding2} + binding1 := types.PortBinding{Proto: types.UDP, Port: uint16(400), HostPort: uint16(54000)} + binding2 := types.PortBinding{Proto: types.TCP, Port: uint16(500), HostPort: uint16(65000)} + portBindings := []types.PortBinding{binding1, binding2} epOptions := make(map[string]interface{}) epOptions[netlabel.PortMap] = portBindings diff --git a/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_fixedcidrv4.go b/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_fixedcidrv4.go index af6aecc7aa..7657aa330c 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_fixedcidrv4.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_fixedcidrv4.go @@ -1,6 +1,8 @@ package bridge -import log "github.com/Sirupsen/logrus" +import ( + log "github.com/Sirupsen/logrus" +) func setupFixedCIDRv4(config *NetworkConfiguration, i *bridgeInterface) error { addrv4, _, err := i.addresses() @@ -10,7 +12,7 @@ func setupFixedCIDRv4(config *NetworkConfiguration, i *bridgeInterface) error { log.Debugf("Using IPv4 subnet: %v", config.FixedCIDR) if err := ipAllocator.RegisterSubnet(addrv4.IPNet, config.FixedCIDR); err != nil { - return &FixedCIDRv4Error{subnet: config.FixedCIDR, net: addrv4.IPNet, err: err} + return &FixedCIDRv4Error{Subnet: config.FixedCIDR, Net: addrv4.IPNet, Err: err} } return nil diff --git a/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_fixedcidrv6.go b/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_fixedcidrv6.go index ce1718a30e..ade465a1cb 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_fixedcidrv6.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_fixedcidrv6.go @@ -1,11 +1,13 @@ package bridge -import log "github.com/Sirupsen/logrus" +import ( + log "github.com/Sirupsen/logrus" +) func setupFixedCIDRv6(config *NetworkConfiguration, i *bridgeInterface) error { log.Debugf("Using IPv6 subnet: %v", config.FixedCIDRv6) if err := ipAllocator.RegisterSubnet(config.FixedCIDRv6, config.FixedCIDRv6); err != nil { - return &FixedCIDRv6Error{net: config.FixedCIDRv6, err: err} + return &FixedCIDRv6Error{Net: config.FixedCIDRv6, Err: err} } return nil diff --git a/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ip_forwarding.go b/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ip_forwarding.go index 85fddbca16..1bc3416ca2 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ip_forwarding.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ip_forwarding.go @@ -13,7 +13,7 @@ const ( func setupIPForwarding(config *Configuration) error { // Sanity Check if config.EnableIPForwarding == false { - return ErrIPFwdCfg + return &ErrIPFwdCfg{} } // Enable IPv4 forwarding diff --git a/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ip_forwarding_test.go b/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ip_forwarding_test.go index a555a39323..7c4cfea279 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ip_forwarding_test.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ip_forwarding_test.go @@ -47,7 +47,7 @@ func TestUnexpectedSetupIPForwarding(t *testing.T) { t.Fatal("Setup IP forwarding was expected to fail") } - if err != ErrIPFwdCfg { + if _, ok := err.(*ErrIPFwdCfg); !ok { t.Fatalf("Setup IP forwarding failed with unexpected error: %v", err) } } diff --git a/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ip_tables.go b/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ip_tables.go index e74ded7421..3d4619769a 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ip_tables.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ip_tables.go @@ -16,7 +16,7 @@ const ( func setupIPTables(config *NetworkConfiguration, i *bridgeInterface) error { // Sanity check. if config.EnableIPTables == false { - return ipTableCfgError(config.BridgeName) + return IPTableCfgError(config.BridgeName) } hairpinMode := !config.EnableUserlandProxy diff --git a/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ipv4.go b/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ipv4.go index 7a775a376d..a0059c8543 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ipv4.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ipv4.go @@ -71,7 +71,7 @@ func setupBridgeIPv4(config *NetworkConfiguration, i *bridgeInterface) error { log.Debugf("Creating bridge interface %q with network %s", config.BridgeName, bridgeIPv4) if err := netlink.AddrAdd(i.Link, &netlink.Addr{IPNet: bridgeIPv4}); err != nil { - return &IPv4AddrAddError{ip: bridgeIPv4, err: err} + return &IPv4AddrAddError{IP: bridgeIPv4, Err: err} } // Store bridge network and default gateway @@ -114,7 +114,7 @@ func electBridgeIPv4(config *NetworkConfiguration) (*net.IPNet, error) { func setupGatewayIPv4(config *NetworkConfiguration, i *bridgeInterface) error { if !i.bridgeIPv4.Contains(config.DefaultGatewayIPv4) { - return ErrInvalidGateway + return &ErrInvalidGateway{} } if _, err := ipAllocator.RequestIP(i.bridgeIPv4, config.DefaultGatewayIPv4); err != nil { return err diff --git a/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ipv6.go b/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ipv6.go index 81cbda1b88..264e5b2a23 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ipv6.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ipv6.go @@ -37,7 +37,7 @@ func setupBridgeIPv6(config *NetworkConfiguration, i *bridgeInterface) error { // Add the default link local ipv6 address if it doesn't exist if !findIPv6Address(netlink.Addr{IPNet: bridgeIPv6}, addrsv6) { if err := netlink.AddrAdd(i.Link, &netlink.Addr{IPNet: bridgeIPv6}); err != nil { - return &IPv6AddrAddError{ip: bridgeIPv6, err: err} + return &IPv6AddrAddError{IP: bridgeIPv6, Err: err} } } @@ -50,10 +50,10 @@ func setupBridgeIPv6(config *NetworkConfiguration, i *bridgeInterface) error { func setupGatewayIPv6(config *NetworkConfiguration, i *bridgeInterface) error { if config.FixedCIDRv6 == nil { - return ErrInvalidContainerSubnet + return &ErrInvalidContainerSubnet{} } if !config.FixedCIDRv6.Contains(config.DefaultGatewayIPv6) { - return ErrInvalidGateway + return &ErrInvalidGateway{} } if _, err := ipAllocator.RequestIP(config.FixedCIDRv6, config.DefaultGatewayIPv6); err != nil { return err diff --git a/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_verify.go b/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_verify.go index 9954ca8594..46d025d1b8 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_verify.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_verify.go @@ -1,6 +1,8 @@ package bridge -import "github.com/vishvananda/netlink" +import ( + "github.com/vishvananda/netlink" +) func setupVerifyAndReconcile(config *NetworkConfiguration, i *bridgeInterface) error { // Fetch a single IPv4 and a slice of IPv6 addresses from the bridge. @@ -11,12 +13,12 @@ func setupVerifyAndReconcile(config *NetworkConfiguration, i *bridgeInterface) e // Verify that the bridge does have an IPv4 address. if addrv4.IPNet == nil { - return ErrNoIPAddr + return &ErrNoIPAddr{} } // Verify that the bridge IPv4 address matches the requested configuration. if config.AddressIPv4 != nil && !addrv4.IP.Equal(config.AddressIPv4.IP) { - return &IPv4AddrNoMatchError{ip: addrv4.IP, cfgIP: config.AddressIPv4.IP} + return &IPv4AddrNoMatchError{IP: addrv4.IP, CfgIP: config.AddressIPv4.IP} } // Verify that one of the bridge IPv6 addresses matches the requested diff --git a/vendor/src/github.com/docker/libnetwork/drivers/remote/driver.go b/vendor/src/github.com/docker/libnetwork/drivers/remote/driver.go index 0159fb40bf..ffeb720ca7 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/remote/driver.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/remote/driver.go @@ -1,7 +1,8 @@ package remote import ( - "errors" + "fmt" + "net" log "github.com/Sirupsen/logrus" "github.com/docker/docker/pkg/plugins" @@ -9,59 +10,202 @@ import ( "github.com/docker/libnetwork/types" ) -var errNoCallback = errors.New("No Callback handler registered with Driver") - type driver struct { endpoint *plugins.Client networkType string } -// Init does the necessary work to register remote drivers +func newDriver(name string, client *plugins.Client) driverapi.Driver { + return &driver{networkType: name, endpoint: client} +} + +// Init makes sure a remote driver is registered when a network driver +// plugin is activated. func Init(dc driverapi.DriverCallback) error { plugins.Handle(driverapi.NetworkPluginEndpointType, func(name string, client *plugins.Client) { - - // TODO : Handhake with the Remote Plugin goes here - - newDriver := &driver{networkType: name, endpoint: client} - if err := dc.RegisterDriver(name, newDriver); err != nil { - log.Errorf("Error registering Driver for %s due to %v", name, err) + if err := dc.RegisterDriver(name, newDriver(name, client)); err != nil { + log.Errorf("error registering driver for %s due to %v", name, err) } }) return nil } +// Config is not implemented for remote drivers, since it is assumed +// to be supplied to the remote process out-of-band (e.g., as command +// line arguments). func (d *driver) Config(option map[string]interface{}) error { - return driverapi.ErrNotImplemented + return &driverapi.ErrNotImplemented{} } -func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) error { - 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, options map[string]interface{}) error { + create := &createNetworkRequest{ + NetworkID: string(id), + Options: options, + } + return d.call("CreateNetwork", create, &createNetworkResponse{}) } func (d *driver) DeleteNetwork(nid types.UUID) error { - return driverapi.ErrNotImplemented + delete := &deleteNetworkRequest{NetworkID: string(nid)} + return d.call("DeleteNetwork", delete, &deleteNetworkResponse{}) } func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error { - return driverapi.ErrNotImplemented + if epInfo == nil { + return fmt.Errorf("must not be called with nil EndpointInfo") + } + + reqIfaces := make([]*endpointInterface, len(epInfo.Interfaces())) + for i, iface := range epInfo.Interfaces() { + addr4 := iface.Address() + addr6 := iface.AddressIPv6() + reqIfaces[i] = &endpointInterface{ + ID: iface.ID(), + Address: addr4.String(), + AddressIPv6: addr6.String(), + MacAddress: iface.MacAddress().String(), + } + } + create := &createEndpointRequest{ + NetworkID: string(nid), + EndpointID: string(eid), + Interfaces: reqIfaces, + Options: epOptions, + } + var res createEndpointResponse + if err := d.call("CreateEndpoint", create, &res); err != nil { + return err + } + + ifaces, err := res.parseInterfaces() + if err != nil { + return err + } + if len(reqIfaces) > 0 && len(ifaces) > 0 { + // We're not supposed to add interfaces if there already are + // some. Attempt to roll back + return errorWithRollback("driver attempted to add more interfaces", d.DeleteEndpoint(nid, eid)) + } + for _, iface := range ifaces { + var addr4, addr6 net.IPNet + if iface.Address != nil { + addr4 = *(iface.Address) + } + if iface.AddressIPv6 != nil { + addr6 = *(iface.AddressIPv6) + } + if err := epInfo.AddInterface(iface.ID, iface.MacAddress, addr4, addr6); err != nil { + return errorWithRollback(fmt.Sprintf("failed to AddInterface %v: %s", iface, err), d.DeleteEndpoint(nid, eid)) + } + } + return nil +} + +func errorWithRollback(msg string, err error) error { + rollback := "rolled back" + if err != nil { + rollback = "failed to roll back: " + err.Error() + } + return fmt.Errorf("%s; %s", msg, rollback) } func (d *driver) DeleteEndpoint(nid, eid types.UUID) error { - return driverapi.ErrNotImplemented + delete := &deleteEndpointRequest{ + NetworkID: string(nid), + EndpointID: string(eid), + } + return d.call("DeleteEndpoint", delete, &deleteEndpointResponse{}) } func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{}, error) { - return nil, driverapi.ErrNotImplemented + info := &endpointInfoRequest{ + NetworkID: string(nid), + EndpointID: string(eid), + } + var res endpointInfoResponse + if err := d.call("EndpointOperInfo", info, &res); err != nil { + return nil, err + } + return res.Value, nil } // Join method is invoked when a Sandbox is attached to an endpoint. func (d *driver) Join(nid, eid types.UUID, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error { - return driverapi.ErrNotImplemented + join := &joinRequest{ + NetworkID: string(nid), + EndpointID: string(eid), + SandboxKey: sboxKey, + Options: options, + } + var ( + res joinResponse + err error + ) + if err = d.call("Join", join, &res); err != nil { + return err + } + + // Expect each interface ID given by CreateEndpoint to have an + // entry at that index in the names supplied here. In other words, + // if you supply 0..n interfaces with IDs 0..n above, you should + // supply the names in the same order. + ifaceNames := res.InterfaceNames + for _, iface := range jinfo.InterfaceNames() { + i := iface.ID() + if i >= len(ifaceNames) || i < 0 { + return fmt.Errorf("no correlating interface %d in supplied interface names", i) + } + supplied := ifaceNames[i] + if err := iface.SetNames(supplied.SrcName, supplied.DstName); err != nil { + return errorWithRollback(fmt.Sprintf("failed to set interface name: %s", err), d.Leave(nid, eid)) + } + } + + var addr net.IP + if res.Gateway != "" { + if addr = net.ParseIP(res.Gateway); addr == nil { + return fmt.Errorf(`unable to parse Gateway "%s"`, res.Gateway) + } + if jinfo.SetGateway(addr) != nil { + return errorWithRollback(fmt.Sprintf("failed to set gateway: %v", addr), d.Leave(nid, eid)) + } + } + if res.GatewayIPv6 != "" { + if addr = net.ParseIP(res.GatewayIPv6); addr == nil { + return fmt.Errorf(`unable to parse GatewayIPv6 "%s"`, res.GatewayIPv6) + } + if jinfo.SetGatewayIPv6(addr) != nil { + return errorWithRollback(fmt.Sprintf("failed to set gateway IPv6: %v", addr), d.Leave(nid, eid)) + } + } + if jinfo.SetHostsPath(res.HostsPath) != nil { + return errorWithRollback(fmt.Sprintf("failed to set hosts path: %s", res.HostsPath), d.Leave(nid, eid)) + } + if jinfo.SetResolvConfPath(res.ResolvConfPath) != nil { + return errorWithRollback(fmt.Sprintf("failed to set resolv.conf path: %s", res.ResolvConfPath), d.Leave(nid, eid)) + } + return nil } // Leave method is invoked when a Sandbox detaches from an endpoint. func (d *driver) Leave(nid, eid types.UUID) error { - return driverapi.ErrNotImplemented + leave := &leaveRequest{ + NetworkID: string(nid), + EndpointID: string(eid), + } + return d.call("Leave", leave, &leaveResponse{}) } func (d *driver) Type() string { diff --git a/vendor/src/github.com/docker/libnetwork/drivers/remote/driver_test.go b/vendor/src/github.com/docker/libnetwork/drivers/remote/driver_test.go new file mode 100644 index 0000000000..a9fb8b4c16 --- /dev/null +++ b/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") + } +} diff --git a/vendor/src/github.com/docker/libnetwork/drivers/remote/messages.go b/vendor/src/github.com/docker/libnetwork/drivers/remote/messages.go new file mode 100644 index 0000000000..8e03a16daf --- /dev/null +++ b/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 +} diff --git a/vendor/src/github.com/docker/libnetwork/endpoint.go b/vendor/src/github.com/docker/libnetwork/endpoint.go index f6f18a9360..9b832358e8 100644 --- a/vendor/src/github.com/docker/libnetwork/endpoint.go +++ b/vendor/src/github.com/docker/libnetwork/endpoint.go @@ -12,7 +12,6 @@ import ( "github.com/docker/docker/pkg/ioutils" "github.com/docker/libnetwork/etchosts" "github.com/docker/libnetwork/netlabel" - "github.com/docker/libnetwork/netutils" "github.com/docker/libnetwork/resolvconf" "github.com/docker/libnetwork/sandbox" "github.com/docker/libnetwork/types" @@ -106,7 +105,7 @@ type endpoint struct { iFaces []*endpointInterface joinInfo *endpointJoinInfo container *containerInfo - exposedPorts []netutils.TransportPort + exposedPorts []types.TransportPort generic map[string]interface{} joinLeaveDone chan struct{} sync.Mutex @@ -217,7 +216,7 @@ func (ep *endpoint) Join(containerID string, options ...EndpointOption) (*Contai ep.Lock() if ep.container != nil { ep.Unlock() - return nil, ErrInvalidJoin + return nil, ErrInvalidJoin{} } ep.container = &containerInfo{ @@ -292,7 +291,7 @@ func (ep *endpoint) Join(containerID string, options ...EndpointOption) (*Contai for _, i := range ifaces { iface := &sandbox.Interface{ SrcName: i.srcName, - DstName: i.dstName, + DstName: i.dstPrefix, Address: &i.addr, } if i.addrv6.IP.To16() != nil { @@ -335,7 +334,7 @@ func (ep *endpoint) Leave(containerID string, options ...EndpointOption) error { if container == nil || container.id == "" || containerID == "" || container.id != containerID { if container == nil { - err = ErrNoContainer + err = ErrNoContainer{} } else { err = InvalidContainerIDError(containerID) } @@ -413,7 +412,7 @@ func (ep *endpoint) buildHostsFiles() error { ep.Unlock() if container == nil { - return ErrNoContainer + return ErrNoContainer{} } if container.config.hostsPath == "" { @@ -463,7 +462,7 @@ func (ep *endpoint) updateParentHosts() error { ep.Unlock() if container == nil { - return ErrNoContainer + return ErrNoContainer{} } for _, update := range container.config.parentUpdates { @@ -496,7 +495,7 @@ func (ep *endpoint) updateDNS(resolvConf []byte) error { ep.Unlock() if container == nil { - return ErrNoContainer + return ErrNoContainer{} } oldHash := []byte{} @@ -574,7 +573,7 @@ func (ep *endpoint) setupDNS() error { ep.Unlock() if container == nil { - return ErrNoContainer + return ErrNoContainer{} } if container.config.resolvConfPath == "" { @@ -697,10 +696,10 @@ func JoinOptionUseDefaultSandbox() EndpointOption { // CreateOptionExposedPorts function returns an option setter for the container exposed // ports option to be passed to network.CreateEndpoint() method. -func CreateOptionExposedPorts(exposedPorts []netutils.TransportPort) EndpointOption { +func CreateOptionExposedPorts(exposedPorts []types.TransportPort) EndpointOption { return func(ep *endpoint) { // Defensive copy - eps := make([]netutils.TransportPort, len(exposedPorts)) + eps := make([]types.TransportPort, len(exposedPorts)) copy(eps, exposedPorts) // Store endpoint label and in generic because driver needs it ep.exposedPorts = eps @@ -710,10 +709,10 @@ func CreateOptionExposedPorts(exposedPorts []netutils.TransportPort) EndpointOpt // CreateOptionPortMapping function returns an option setter for the mapping // ports option to be passed to network.CreateEndpoint() method. -func CreateOptionPortMapping(portBindings []netutils.PortBinding) EndpointOption { +func CreateOptionPortMapping(portBindings []types.PortBinding) EndpointOption { return func(ep *endpoint) { // Store a copy of the bindings as generic data to pass to the driver - pbs := make([]netutils.PortBinding, len(portBindings)) + pbs := make([]types.PortBinding, len(portBindings)) copy(pbs, portBindings) ep.generic[netlabel.PortMap] = pbs } diff --git a/vendor/src/github.com/docker/libnetwork/endpoint_info.go b/vendor/src/github.com/docker/libnetwork/endpoint_info.go index 5383412c0e..f04521595a 100644 --- a/vendor/src/github.com/docker/libnetwork/endpoint_info.go +++ b/vendor/src/github.com/docker/libnetwork/endpoint_info.go @@ -4,7 +4,7 @@ import ( "net" "github.com/docker/libnetwork/driverapi" - "github.com/docker/libnetwork/netutils" + "github.com/docker/libnetwork/types" ) // EndpointInfo provides an interface to retrieve network resources bound to the endpoint. @@ -40,12 +40,12 @@ type InterfaceInfo interface { } type endpointInterface struct { - id int - mac net.HardwareAddr - addr net.IPNet - addrv6 net.IPNet - srcName string - dstName string + id int + mac net.HardwareAddr + addr net.IPNet + addrv6 net.IPNet + srcName string + dstPrefix string } type endpointJoinInfo struct { @@ -105,10 +105,10 @@ func (ep *endpoint) AddInterface(id int, mac net.HardwareAddr, ipv4 net.IPNet, i iface := &endpointInterface{ id: id, - addr: *netutils.GetIPNetCopy(&ipv4), - addrv6: *netutils.GetIPNetCopy(&ipv6), + addr: *types.GetIPNetCopy(&ipv4), + addrv6: *types.GetIPNetCopy(&ipv6), } - iface.mac = netutils.GetMacCopy(mac) + iface.mac = types.GetMacCopy(mac) ep.iFaces = append(ep.iFaces, iface) return nil @@ -119,20 +119,20 @@ func (i *endpointInterface) ID() int { } func (i *endpointInterface) MacAddress() net.HardwareAddr { - return netutils.GetMacCopy(i.mac) + return types.GetMacCopy(i.mac) } func (i *endpointInterface) Address() net.IPNet { - return (*netutils.GetIPNetCopy(&i.addr)) + return (*types.GetIPNetCopy(&i.addr)) } func (i *endpointInterface) AddressIPv6() net.IPNet { - return (*netutils.GetIPNetCopy(&i.addrv6)) + return (*types.GetIPNetCopy(&i.addrv6)) } -func (i *endpointInterface) SetNames(srcName string, dstName string) error { +func (i *endpointInterface) SetNames(srcName string, dstPrefix string) error { i.srcName = srcName - i.dstName = dstName + i.dstPrefix = dstPrefix return nil } @@ -168,7 +168,7 @@ func (ep *endpoint) Gateway() net.IP { return net.IP{} } - return netutils.GetIPCopy(ep.joinInfo.gw) + return types.GetIPCopy(ep.joinInfo.gw) } func (ep *endpoint) GatewayIPv6() net.IP { @@ -179,14 +179,14 @@ func (ep *endpoint) GatewayIPv6() net.IP { return net.IP{} } - return netutils.GetIPCopy(ep.joinInfo.gw6) + return types.GetIPCopy(ep.joinInfo.gw6) } func (ep *endpoint) SetGateway(gw net.IP) error { ep.Lock() defer ep.Unlock() - ep.joinInfo.gw = netutils.GetIPCopy(gw) + ep.joinInfo.gw = types.GetIPCopy(gw) return nil } @@ -194,7 +194,7 @@ func (ep *endpoint) SetGatewayIPv6(gw6 net.IP) error { ep.Lock() defer ep.Unlock() - ep.joinInfo.gw6 = netutils.GetIPCopy(gw6) + ep.joinInfo.gw6 = types.GetIPCopy(gw6) return nil } diff --git a/vendor/src/github.com/docker/libnetwork/error.go b/vendor/src/github.com/docker/libnetwork/error.go index 088bfbc826..a1cd01d678 100644 --- a/vendor/src/github.com/docker/libnetwork/error.go +++ b/vendor/src/github.com/docker/libnetwork/error.go @@ -1,34 +1,83 @@ package libnetwork import ( - "errors" "fmt" ) -var ( - // ErrNoSuchNetwork is returned when a network query finds no result - ErrNoSuchNetwork = errors.New("network not found") - // ErrNoSuchEndpoint is returned when a endpoint query finds no result - ErrNoSuchEndpoint = errors.New("endpoint not found") - // ErrNilNetworkDriver is returned if a nil network driver - // is passed to NewNetwork api. - ErrNilNetworkDriver = errors.New("nil NetworkDriver instance") - // ErrInvalidNetworkDriver is returned if an invalid driver - // instance is passed. - ErrInvalidNetworkDriver = errors.New("invalid driver bound to network") - // ErrInvalidJoin is returned if a join is attempted on an endpoint - // which already has a container joined. - ErrInvalidJoin = errors.New("a container has already joined the endpoint") - // ErrNoContainer is returned when the endpoint has no container - // attached to it. - ErrNoContainer = errors.New("no container attached to the endpoint") - // ErrInvalidID is returned when a query-by-id method is being invoked - // with an empty id parameter - ErrInvalidID = errors.New("invalid ID") - // ErrInvalidName is returned when a query-by-name or resource create method is - // invoked with an empty name parameter - ErrInvalidName = errors.New("invalid Name") -) +// ErrNoSuchNetwork is returned when a network query finds no result +type ErrNoSuchNetwork string + +func (nsn ErrNoSuchNetwork) Error() string { + return fmt.Sprintf("network %s not found", string(nsn)) +} + +// BadRequest denotes the type of this error +func (nsn ErrNoSuchNetwork) BadRequest() {} + +// ErrNoSuchEndpoint is returned when a endpoint query finds no result +type ErrNoSuchEndpoint string + +func (nse ErrNoSuchEndpoint) Error() string { + return fmt.Sprintf("endpoint %s not found", string(nse)) +} + +// BadRequest denotes the type of this error +func (nse ErrNoSuchEndpoint) BadRequest() {} + +// ErrInvalidNetworkDriver is returned if an invalid driver +// name is passed. +type ErrInvalidNetworkDriver string + +func (ind ErrInvalidNetworkDriver) Error() string { + return fmt.Sprintf("invalid driver bound to network: %s", string(ind)) +} + +// BadRequest denotes the type of this error +func (ind ErrInvalidNetworkDriver) BadRequest() {} + +// ErrInvalidJoin is returned if a join is attempted on an endpoint +// which already has a container joined. +type ErrInvalidJoin struct{} + +func (ij ErrInvalidJoin) Error() string { + return "a container has already joined the endpoint" +} + +// BadRequest denotes the type of this error +func (ij ErrInvalidJoin) BadRequest() {} + +// ErrNoContainer is returned when the endpoint has no container +// attached to it. +type ErrNoContainer struct{} + +func (nc ErrNoContainer) Error() string { + return "a container has already joined the endpoint" +} + +// Maskable denotes the type of this error +func (nc ErrNoContainer) Maskable() {} + +// ErrInvalidID is returned when a query-by-id method is being invoked +// with an empty id parameter +type ErrInvalidID string + +func (ii ErrInvalidID) Error() string { + return fmt.Sprintf("invalid id: %s", string(ii)) +} + +// BadRequest denotes the type of this error +func (ii ErrInvalidID) BadRequest() {} + +// ErrInvalidName is returned when a query-by-name or resource create method is +// invoked with an empty name parameter +type ErrInvalidName string + +func (in ErrInvalidName) Error() string { + return fmt.Sprintf("invalid name: %s", string(in)) +} + +// BadRequest denotes the type of this error +func (in ErrInvalidName) BadRequest() {} // NetworkTypeError type is returned when the network type string is not // known to libnetwork. @@ -38,13 +87,19 @@ func (nt NetworkTypeError) Error() string { return fmt.Sprintf("unknown driver %q", string(nt)) } +// NotFound denotes the type of this error +func (nt NetworkTypeError) NotFound() {} + // NetworkNameError is returned when a network with the same name already exists. type NetworkNameError string -func (name NetworkNameError) Error() string { - return fmt.Sprintf("network with name %s already exists", string(name)) +func (nnr NetworkNameError) Error() string { + return fmt.Sprintf("network with name %s already exists", string(nnr)) } +// Forbidden denotes the type of this error +func (nnr NetworkNameError) Forbidden() {} + // UnknownNetworkError is returned when libnetwork could not find in it's database // a network with the same name and id. type UnknownNetworkError struct { @@ -56,6 +111,9 @@ func (une *UnknownNetworkError) Error() string { return fmt.Sprintf("unknown network %s id %s", une.name, une.id) } +// NotFound denotes the type of this error +func (une *UnknownNetworkError) NotFound() {} + // ActiveEndpointsError is returned when a network is deleted which has active // endpoints in it. type ActiveEndpointsError struct { @@ -67,6 +125,9 @@ func (aee *ActiveEndpointsError) Error() string { return fmt.Sprintf("network with name %s id %s has active endpoints", aee.name, aee.id) } +// Forbidden denotes the type of this error +func (aee *ActiveEndpointsError) Forbidden() {} + // UnknownEndpointError is returned when libnetwork could not find in it's database // an endpoint with the same name and id. type UnknownEndpointError struct { @@ -78,6 +139,9 @@ func (uee *UnknownEndpointError) Error() string { return fmt.Sprintf("unknown endpoint %s id %s", uee.name, uee.id) } +// NotFound denotes the type of this error +func (uee *UnknownEndpointError) NotFound() {} + // ActiveContainerError is returned when an endpoint is deleted which has active // containers attached to it. type ActiveContainerError struct { @@ -89,6 +153,9 @@ func (ace *ActiveContainerError) Error() string { return fmt.Sprintf("endpoint with name %s id %s has active containers", ace.name, ace.id) } +// Forbidden denotes the type of this error +func (ace *ActiveContainerError) Forbidden() {} + // InvalidContainerIDError is returned when an invalid container id is passed // in Join/Leave type InvalidContainerIDError string @@ -96,3 +163,6 @@ type InvalidContainerIDError string func (id InvalidContainerIDError) Error() string { return fmt.Sprintf("invalid container id %s", string(id)) } + +// BadRequest denotes the type of this error +func (id InvalidContainerIDError) BadRequest() {} diff --git a/vendor/src/github.com/docker/libnetwork/errors_test.go b/vendor/src/github.com/docker/libnetwork/errors_test.go new file mode 100644 index 0000000000..29bf668689 --- /dev/null +++ b/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) + } + } + +} diff --git a/vendor/src/github.com/docker/libnetwork/iptables/iptables_test.go b/vendor/src/github.com/docker/libnetwork/iptables/iptables_test.go index 4035b58723..afb3587f1f 100644 --- a/vendor/src/github.com/docker/libnetwork/iptables/iptables_test.go +++ b/vendor/src/github.com/docker/libnetwork/iptables/iptables_test.go @@ -11,7 +11,7 @@ import ( _ "github.com/docker/libnetwork/netutils" ) -const chainName = "DOCKER-TEST" +const chainName = "DOCKEREST" var natChain *Chain var filterChain *Chain diff --git a/vendor/src/github.com/docker/libnetwork/libnetwork_test.go b/vendor/src/github.com/docker/libnetwork/libnetwork_test.go index 879c0f146e..981128cdc6 100644 --- a/vendor/src/github.com/docker/libnetwork/libnetwork_test.go +++ b/vendor/src/github.com/docker/libnetwork/libnetwork_test.go @@ -22,6 +22,8 @@ import ( "github.com/docker/libnetwork/netlabel" "github.com/docker/libnetwork/netutils" "github.com/docker/libnetwork/options" + "github.com/docker/libnetwork/types" + "github.com/vishvananda/netlink" "github.com/vishvananda/netns" ) @@ -65,11 +67,11 @@ func getEmptyGenericOption() map[string]interface{} { return genericOption } -func getPortMapping() []netutils.PortBinding { - return []netutils.PortBinding{ - netutils.PortBinding{Proto: netutils.TCP, Port: uint16(230), HostPort: uint16(23000)}, - netutils.PortBinding{Proto: netutils.UDP, Port: uint16(200), HostPort: uint16(22000)}, - netutils.PortBinding{Proto: netutils.TCP, Port: uint16(120), HostPort: uint16(12000)}, +func getPortMapping() []types.PortBinding { + return []types.PortBinding{ + types.PortBinding{Proto: types.TCP, Port: uint16(230), HostPort: uint16(23000)}, + types.PortBinding{Proto: types.UDP, Port: uint16(200), HostPort: uint16(22000)}, + types.PortBinding{Proto: types.TCP, Port: uint16(120), HostPort: uint16(12000)}, } } @@ -245,7 +247,7 @@ func TestBridge(t *testing.T) { if !ok { t.Fatalf("Could not find expected info in endpoint data") } - pm, ok := pmd.([]netutils.PortBinding) + pm, ok := pmd.([]types.PortBinding) if !ok { t.Fatalf("Unexpected format for port mapping in endpoint operational data") } @@ -289,7 +291,7 @@ func TestNilRemoteDriver(t *testing.T) { t.Fatal("Expected to fail. But instead succeeded") } - if err != plugins.ErrNotFound { + if _, ok := err.(types.NotFoundError); !ok { t.Fatalf("Did not fail with expected error. Actual error: %v", err) } } @@ -337,8 +339,9 @@ func TestNetworkName(t *testing.T) { if err == nil { t.Fatal("Expected to fail. But instead succeeded") } - if err != libnetwork.ErrInvalidName { - t.Fatal("Expected to fail with ErrInvalidName error") + + if _, ok := err.(libnetwork.ErrInvalidName); !ok { + t.Fatalf("Expected to fail with ErrInvalidName error. Got %v", err) } networkName := "testnetwork" @@ -474,8 +477,8 @@ func TestUnknownEndpoint(t *testing.T) { if err == nil { t.Fatal("Expected to fail. But instead succeeded") } - if err != libnetwork.ErrInvalidName { - t.Fatal("Expected to fail with ErrInvalidName error") + if _, ok := err.(libnetwork.ErrInvalidName); !ok { + t.Fatalf("Expected to fail with ErrInvalidName error. Actual error: %v", err) } ep, err := network.CreateEndpoint("testep") @@ -612,15 +615,15 @@ func TestControllerQuery(t *testing.T) { if err == nil { t.Fatalf("NetworkByName() succeeded with invalid target name") } - if err != libnetwork.ErrInvalidName { - t.Fatalf("NetworkByName() failed with unexpected error: %v", err) + if _, ok := err.(libnetwork.ErrInvalidName); !ok { + t.Fatalf("Expected NetworkByName() to fail with ErrInvalidName error. Got: %v", err) } _, err = controller.NetworkByID("") if err == nil { t.Fatalf("NetworkByID() succeeded with invalid target id") } - if err != libnetwork.ErrInvalidID { + if _, ok := err.(libnetwork.ErrInvalidID); !ok { t.Fatalf("NetworkByID() failed with unexpected error: %v", err) } @@ -628,7 +631,7 @@ func TestControllerQuery(t *testing.T) { if err == nil { t.Fatalf("Unexpected success for NetworkByID(): %v", g) } - if err != libnetwork.ErrNoSuchNetwork { + if _, ok := err.(libnetwork.ErrNoSuchNetwork); !ok { t.Fatalf("NetworkByID() failed with unexpected error: %v", err) } @@ -694,15 +697,15 @@ func TestNetworkQuery(t *testing.T) { if err == nil { t.Fatalf("EndpointByName() succeeded with invalid target name") } - if err != libnetwork.ErrInvalidName { - t.Fatalf("EndpointByName() failed with unexpected error: %v", err) + if _, ok := err.(libnetwork.ErrInvalidName); !ok { + t.Fatalf("Expected EndpointByName() to fail with ErrInvalidName error. Got: %v", err) } e, err = net1.EndpointByName("IamNotAnEndpoint") if err == nil { t.Fatalf("EndpointByName() succeeded with unknown target name") } - if err != libnetwork.ErrNoSuchEndpoint { + if _, ok := err.(libnetwork.ErrNoSuchEndpoint); !ok { t.Fatal(err) } if e != nil { @@ -721,13 +724,42 @@ func TestNetworkQuery(t *testing.T) { if err == nil { t.Fatalf("EndpointByID() succeeded with invalid target id") } - if err != libnetwork.ErrInvalidID { + if _, ok := err.(libnetwork.ErrInvalidID); !ok { t.Fatalf("EndpointByID() failed with unexpected error: %v", err) } } const containerID = "valid_container" +func checkSandbox(t *testing.T, info libnetwork.EndpointInfo) { + origns, err := netns.Get() + if err != nil { + t.Fatalf("Could not get the current netns: %v", err) + } + defer origns.Close() + + key := info.SandboxKey() + f, err := os.OpenFile(key, os.O_RDONLY, 0) + if err != nil { + t.Fatalf("Failed to open network namespace path %q: %v", key, err) + } + defer f.Close() + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + nsFD := f.Fd() + if err = netns.Set(netns.NsHandle(nsFD)); err != nil { + t.Fatalf("Setting to the namespace pointed to by the sandbox %s failed: %v", key, err) + } + defer netns.Set(origns) + + _, err = netlink.LinkByName("eth0") + if err != nil { + t.Fatalf("Could not find the interface eth0 inside the sandbox: %v", err) + } +} + func TestEndpointJoin(t *testing.T) { if !netutils.IsRunningInContainer() { defer netutils.SetupTestNetNS(t)() @@ -784,6 +816,8 @@ func TestEndpointJoin(t *testing.T) { if info.SandboxKey() == "" { t.Fatalf("Expected an non-empty sandbox key for a joined endpoint. Instead found a empty sandbox key") } + + checkSandbox(t, info) } func TestEndpointJoinInvalidContainerId(t *testing.T) { @@ -890,7 +924,7 @@ func TestEndpointMultipleJoins(t *testing.T) { t.Fatal("Expected to fail multiple joins for the same endpoint") } - if err != libnetwork.ErrInvalidJoin { + if _, ok := err.(libnetwork.ErrInvalidJoin); !ok { t.Fatalf("Failed for unexpected reason: %v", err) } } @@ -916,7 +950,7 @@ func TestEndpointInvalidLeave(t *testing.T) { } if _, ok := err.(libnetwork.InvalidContainerIDError); !ok { - if err != libnetwork.ErrNoContainer { + if _, ok := err.(libnetwork.ErrNoContainer); !ok { t.Fatalf("Failed for unexpected reason: %v", err) } } @@ -1275,6 +1309,10 @@ func TestValidRemoteDriver(t *testing.T) { w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") fmt.Fprintf(w, `{"Implements": ["%s"]}`, driverapi.NetworkPluginEndpointType) }) + mux.HandleFunc(fmt.Sprintf("/%s.CreateNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json") + fmt.Fprintf(w, "null") + }) if err := os.MkdirAll("/usr/share/docker/plugins", 0755); err != nil { t.Fatal(err) @@ -1296,7 +1334,7 @@ func TestValidRemoteDriver(t *testing.T) { _, err = controller.NewNetwork("valid-network-driver", "dummy", libnetwork.NetworkOptionGeneric(getEmptyGenericOption())) - if err != nil && err != driverapi.ErrNotImplemented { + if err != nil { t.Fatal(err) } } @@ -1370,8 +1408,10 @@ func parallelJoin(t *testing.T, ep libnetwork.Endpoint, thrNumber int) { _, err := ep.Join("racing_container") runtime.LockOSThread() if err != nil { - if err != libnetwork.ErrNoContainer && err != libnetwork.ErrInvalidJoin { - t.Fatal(err) + if _, ok := err.(libnetwork.ErrNoContainer); !ok { + if _, ok := err.(libnetwork.ErrInvalidJoin); !ok { + t.Fatal(err) + } } debugf("JE%d(%v).", thrNumber, err) } @@ -1383,8 +1423,10 @@ func parallelLeave(t *testing.T, ep libnetwork.Endpoint, thrNumber int) { err := ep.Leave("racing_container") runtime.LockOSThread() if err != nil { - if err != libnetwork.ErrNoContainer && err != libnetwork.ErrInvalidJoin { - t.Fatal(err) + if _, ok := err.(libnetwork.ErrNoContainer); !ok { + if _, ok := err.(libnetwork.ErrInvalidJoin); !ok { + t.Fatal(err) + } } debugf("LE%d(%v).", thrNumber, err) } diff --git a/vendor/src/github.com/docker/libnetwork/netutils/utils.go b/vendor/src/github.com/docker/libnetwork/netutils/utils.go index 0c3706d3e4..98da12e981 100644 --- a/vendor/src/github.com/docker/libnetwork/netutils/utils.go +++ b/vendor/src/github.com/docker/libnetwork/netutils/utils.go @@ -3,14 +3,12 @@ package netutils import ( - "bytes" "crypto/rand" "encoding/hex" "errors" "fmt" "io" "net" - "strings" "github.com/vishvananda/netlink" ) @@ -26,144 +24,6 @@ var ( networkGetRoutesFct = netlink.RouteList ) -// ErrInvalidProtocolBinding is returned when the port binding protocol is not valid. -type ErrInvalidProtocolBinding string - -func (ipb ErrInvalidProtocolBinding) Error() string { - return fmt.Sprintf("invalid transport protocol: %s", string(ipb)) -} - -// TransportPort represent a local Layer 4 endpoint -type TransportPort struct { - Proto Protocol - Port uint16 -} - -// GetCopy returns a copy of this TransportPort structure instance -func (t *TransportPort) GetCopy() TransportPort { - return TransportPort{Proto: t.Proto, Port: t.Port} -} - -// PortBinding represent a port binding between the container an the host -type PortBinding struct { - Proto Protocol - IP net.IP - Port uint16 - HostIP net.IP - HostPort uint16 -} - -// HostAddr returns the host side transport address -func (p PortBinding) HostAddr() (net.Addr, error) { - switch p.Proto { - case UDP: - return &net.UDPAddr{IP: p.HostIP, Port: int(p.HostPort)}, nil - case TCP: - return &net.TCPAddr{IP: p.HostIP, Port: int(p.HostPort)}, nil - default: - return nil, ErrInvalidProtocolBinding(p.Proto.String()) - } -} - -// ContainerAddr returns the container side transport address -func (p PortBinding) ContainerAddr() (net.Addr, error) { - switch p.Proto { - case UDP: - return &net.UDPAddr{IP: p.IP, Port: int(p.Port)}, nil - case TCP: - return &net.TCPAddr{IP: p.IP, Port: int(p.Port)}, nil - default: - return nil, ErrInvalidProtocolBinding(p.Proto.String()) - } -} - -// GetCopy returns a copy of this PortBinding structure instance -func (p *PortBinding) GetCopy() PortBinding { - return PortBinding{ - Proto: p.Proto, - IP: GetIPCopy(p.IP), - Port: p.Port, - HostIP: GetIPCopy(p.HostIP), - HostPort: p.HostPort, - } -} - -// Equal checks if this instance of PortBinding is equal to the passed one -func (p *PortBinding) Equal(o *PortBinding) bool { - if p == o { - return true - } - - if o == nil { - return false - } - - if p.Proto != o.Proto || p.Port != o.Port || p.HostPort != o.HostPort { - return false - } - - if p.IP != nil { - if !p.IP.Equal(o.IP) { - return false - } - } else { - if o.IP != nil { - return false - } - } - - if p.HostIP != nil { - if !p.HostIP.Equal(o.HostIP) { - return false - } - } else { - if o.HostIP != nil { - return false - } - } - - return true -} - -const ( - // ICMP is for the ICMP ip protocol - ICMP = 1 - // TCP is for the TCP ip protocol - TCP = 6 - // UDP is for the UDP ip protocol - UDP = 17 -) - -// Protocol represents a IP protocol number -type Protocol uint8 - -func (p Protocol) String() string { - switch p { - case ICMP: - return "icmp" - case TCP: - return "tcp" - case UDP: - return "udp" - default: - return fmt.Sprintf("%d", p) - } -} - -// ParseProtocol returns the respective Protocol type for the passed string -func ParseProtocol(s string) Protocol { - switch strings.ToLower(s) { - case "icmp": - return ICMP - case "udp": - return UDP - case "tcp": - return TCP - default: - return 0 - } -} - // CheckNameserverOverlaps checks whether the passed network overlaps with any of the nameservers func CheckNameserverOverlaps(nameservers []string, toCheck *net.IPNet) error { if len(nameservers) > 0 { @@ -287,38 +147,3 @@ func GenerateRandomName(prefix string, size int) (string, error) { } return prefix + hex.EncodeToString(id)[:size], nil } - -// GetMacCopy returns a copy of the passed MAC address -func GetMacCopy(from net.HardwareAddr) net.HardwareAddr { - to := make(net.HardwareAddr, len(from)) - copy(to, from) - return to -} - -// GetIPCopy returns a copy of the passed IP address -func GetIPCopy(from net.IP) net.IP { - to := make(net.IP, len(from)) - copy(to, from) - return to -} - -// GetIPNetCopy returns a copy of the passed IP Network -func GetIPNetCopy(from *net.IPNet) *net.IPNet { - if from == nil { - return nil - } - bm := make(net.IPMask, len(from.Mask)) - copy(bm, from.Mask) - return &net.IPNet{IP: GetIPCopy(from.IP), Mask: bm} -} - -// CompareIPNet returns equal if the two IP Networks are equal -func CompareIPNet(a, b *net.IPNet) bool { - if a == b { - return true - } - if a == nil || b == nil { - return false - } - return a.IP.Equal(b.IP) && bytes.Equal(a.Mask, b.Mask) -} diff --git a/vendor/src/github.com/docker/libnetwork/netutils/utils_test.go b/vendor/src/github.com/docker/libnetwork/netutils/utils_test.go index 4ef8d48040..78de626e7f 100644 --- a/vendor/src/github.com/docker/libnetwork/netutils/utils_test.go +++ b/vendor/src/github.com/docker/libnetwork/netutils/utils_test.go @@ -209,135 +209,3 @@ func TestUtilGenerateRandomMAC(t *testing.T) { t.Fatalf("mac1 %s should not equal mac2 %s", mac1, mac2) } } - -func TestCompareIPNet(t *testing.T) { - if CompareIPNet(nil, nil) == false { - t.Fatalf("Failed to detect two nil net.IPNets are equal") - } - - _, net1, _ := net.ParseCIDR("192.168.30.22/24") - if CompareIPNet(net1, net1) == false { - t.Fatalf("Failed to detect same net.IPNet pointers equality") - } - - _, net2, _ := net.ParseCIDR("192.168.30.22/24") - if CompareIPNet(net1, net2) == false { - t.Fatalf("Failed to detect same net.IPNet object equality") - } - - _, net3, _ := net.ParseCIDR("192.168.30.33/24") - if CompareIPNet(net1, net3) == false { - t.Fatalf("Failed to detect semantically equivalent net.IPNets") - } - - _, net3, _ = net.ParseCIDR("192.168.31.33/24") - if CompareIPNet(net2, net3) == true { - t.Fatalf("Failed to detect different net.IPNets") - } -} - -func TestIPCopyFunctions(t *testing.T) { - ip := net.ParseIP("172.28.30.134") - cp := GetIPCopy(ip) - - if !ip.Equal(cp) { - t.Fatalf("Failed to return a copy of net.IP") - } - - if &ip == &cp { - t.Fatalf("Failed to return a true copy of net.IP") - } -} - -func TestNetIPCopyFunctions(t *testing.T) { - _, net, _ := net.ParseCIDR("192.168.30.23/24") - cp := GetIPNetCopy(net) - - if CompareIPNet(net, cp) == false { - t.Fatalf("Failed to return a copy of net.IPNet") - } - - if net == cp { - t.Fatalf("Failed to return a true copy of net.IPNet") - } -} - -func TestPortBindingEqual(t *testing.T) { - pb1 := &PortBinding{ - Proto: TCP, - IP: net.ParseIP("172.17.0.1"), - Port: 80, - HostIP: net.ParseIP("192.168.100.1"), - HostPort: 8080, - } - - pb2 := &PortBinding{ - Proto: UDP, - IP: net.ParseIP("172.17.0.1"), - Port: 22, - HostIP: net.ParseIP("192.168.100.1"), - HostPort: 2222, - } - if !pb1.Equal(pb1) { - t.Fatalf("PortBinding.Equal() returned false negative") - } - - if pb1.Equal(nil) { - t.Fatalf("PortBinding.Equal() returned false negative") - } - - if pb1.Equal(pb2) { - t.Fatalf("PortBinding.Equal() returned false positive") - } - - if pb1.Equal(pb2) != pb2.Equal(pb1) { - t.Fatalf("PortBinding.Equal() failed commutative check") - } -} - -func TestPortBindingGetCopy(t *testing.T) { - pb := &PortBinding{ - Proto: TCP, - IP: net.ParseIP("172.17.0.1"), - Port: 80, - HostIP: net.ParseIP("192.168.100.1"), - HostPort: 8080, - } - cp := pb.GetCopy() - - if !pb.Equal(&cp) { - t.Fatalf("Failed to return a copy of PortBinding") - } - - if pb == &cp { - t.Fatalf("Failed to return a true copy of PortBinding") - } -} - -func TestPortBindingContainerAddr(t *testing.T) { - pb := PortBinding{ - Proto: TCP, - IP: net.ParseIP("172.17.0.1"), - Port: 80, - HostIP: net.ParseIP("192.168.100.1"), - HostPort: 8080, - } - - container, err := pb.ContainerAddr() - - if err != nil { - t.Fatal(err) - } - - switch netAddr := container.(type) { - case *net.TCPAddr: - if !pb.IP.Equal(netAddr.IP) { - t.Fatalf("PortBinding.ContainerAddr() Failed to return a ContainerAddr") - } - if int(pb.Port) != netAddr.Port { - t.Fatalf("PortBinding.ContainerAddr() Failed to return a ContainerAddr") - } - case *net.UDPAddr: - t.Fatalf("PortBinding.ContainerAddr() Failed to check correct proto") - } -} diff --git a/vendor/src/github.com/docker/libnetwork/network.go b/vendor/src/github.com/docker/libnetwork/network.go index e2955c8d65..36938a5458 100644 --- a/vendor/src/github.com/docker/libnetwork/network.go +++ b/vendor/src/github.com/docker/libnetwork/network.go @@ -133,7 +133,7 @@ func (n *network) Delete() error { func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoint, error) { if name == "" { - return nil, ErrInvalidName + return nil, ErrInvalidName(name) } ep := &endpoint{name: name, iFaces: []*endpointInterface{}, generic: make(map[string]interface{})} ep.id = types.UUID(stringid.GenerateRandomID()) @@ -173,7 +173,7 @@ func (n *network) WalkEndpoints(walker EndpointWalker) { func (n *network) EndpointByName(name string) (Endpoint, error) { if name == "" { - return nil, ErrInvalidName + return nil, ErrInvalidName(name) } var e Endpoint @@ -188,7 +188,7 @@ func (n *network) EndpointByName(name string) (Endpoint, error) { n.WalkEndpoints(s) if e == nil { - return nil, ErrNoSuchEndpoint + return nil, ErrNoSuchEndpoint(name) } return e, nil @@ -196,12 +196,12 @@ func (n *network) EndpointByName(name string) (Endpoint, error) { func (n *network) EndpointByID(id string) (Endpoint, error) { if id == "" { - return nil, ErrInvalidID + return nil, ErrInvalidID(id) } n.Lock() defer n.Unlock() if e, ok := n.endpoints[types.UUID(id)]; ok { return e, nil } - return nil, ErrNoSuchEndpoint + return nil, ErrNoSuchEndpoint(id) } diff --git a/vendor/src/github.com/docker/libnetwork/portmapper/mapper.go b/vendor/src/github.com/docker/libnetwork/portmapper/mapper.go index afaa036b8f..ac32f66ef1 100644 --- a/vendor/src/github.com/docker/libnetwork/portmapper/mapper.go +++ b/vendor/src/github.com/docker/libnetwork/portmapper/mapper.go @@ -84,6 +84,8 @@ func (pm *PortMapper) Map(container net.Addr, hostIP net.IP, hostPort int, usePr if useProxy { m.userlandProxy = newProxy(proto, hostIP, allocatedHostPort, container.(*net.TCPAddr).IP, container.(*net.TCPAddr).Port) + } else { + m.userlandProxy = newDummyProxy(proto, hostIP, allocatedHostPort) } case *net.UDPAddr: proto = "udp" @@ -99,6 +101,8 @@ func (pm *PortMapper) Map(container net.Addr, hostIP net.IP, hostPort int, usePr if useProxy { m.userlandProxy = newProxy(proto, hostIP, allocatedHostPort, container.(*net.UDPAddr).IP, container.(*net.UDPAddr).Port) + } else { + m.userlandProxy = newDummyProxy(proto, hostIP, allocatedHostPort) } default: return nil, ErrUnknownBackendAddressType @@ -123,9 +127,7 @@ func (pm *PortMapper) Map(container net.Addr, hostIP net.IP, hostPort int, usePr cleanup := func() error { // need to undo the iptables rules before we return - if m.userlandProxy != nil { - m.userlandProxy.Stop() - } + m.userlandProxy.Stop() pm.forward(iptables.Delete, m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort) if err := pm.Allocator.ReleasePort(hostIP, m.proto, allocatedHostPort); err != nil { return err @@ -134,13 +136,11 @@ func (pm *PortMapper) Map(container net.Addr, hostIP net.IP, hostPort int, usePr return nil } - if m.userlandProxy != nil { - if err := m.userlandProxy.Start(); err != nil { - if err := cleanup(); err != nil { - return nil, fmt.Errorf("Error during port allocation cleanup: %v", err) - } - return nil, err + if err := m.userlandProxy.Start(); err != nil { + if err := cleanup(); err != nil { + return nil, fmt.Errorf("Error during port allocation cleanup: %v", err) } + return nil, err } pm.currentMappings[key] = m diff --git a/vendor/src/github.com/docker/libnetwork/portmapper/mapper_test.go b/vendor/src/github.com/docker/libnetwork/portmapper/mapper_test.go index c704bad6e7..635723de8c 100644 --- a/vendor/src/github.com/docker/libnetwork/portmapper/mapper_test.go +++ b/vendor/src/github.com/docker/libnetwork/portmapper/mapper_test.go @@ -2,20 +2,16 @@ package portmapper import ( "net" - "os" + "strings" "testing" - "time" - "github.com/docker/docker/pkg/reexec" "github.com/docker/libnetwork/iptables" - "github.com/docker/libnetwork/netutils" + _ "github.com/docker/libnetwork/netutils" ) -func TestMain(m *testing.M) { - if reexec.Init() { - return - } - os.Exit(m.Run()) +func init() { + // override this func to mock out the proxy server + newProxy = newMockProxyCommand } func TestSetIptablesChain(t *testing.T) { @@ -37,7 +33,6 @@ func TestSetIptablesChain(t *testing.T) { } func TestMapTCPPorts(t *testing.T) { - defer netutils.SetupTestNetNS(t)() pm := New() dstIP1 := net.ParseIP("192.168.0.1") dstIP2 := net.ParseIP("192.168.0.2") @@ -117,7 +112,6 @@ func TestGetUDPIPAndPort(t *testing.T) { } func TestMapUDPPorts(t *testing.T) { - defer netutils.SetupTestNetNS(t)() pm := New() dstIP1 := net.ParseIP("192.168.0.1") dstIP2 := net.ParseIP("192.168.0.2") @@ -164,11 +158,6 @@ func TestMapUDPPorts(t *testing.T) { } func TestMapAllPortsSingleInterface(t *testing.T) { - newProxy = newMockProxyCommand - defer func() { - newProxy = newProxyCommand - }() - defer netutils.SetupTestNetNS(t)() pm := New() dstIP1 := net.ParseIP("0.0.0.0") srcAddr1 := &net.TCPAddr{Port: 1080, IP: net.ParseIP("172.16.0.1")} @@ -177,6 +166,12 @@ func TestMapAllPortsSingleInterface(t *testing.T) { var host net.Addr var err error + defer func() { + for _, val := range hosts { + pm.Unmap(val) + } + }() + for i := 0; i < 10; i++ { start, end := pm.Allocator.Begin, pm.Allocator.End for i := start; i < end; i++ { @@ -201,27 +196,76 @@ func TestMapAllPortsSingleInterface(t *testing.T) { } } -func TestExecProxy(t *testing.T) { - defer netutils.SetupTestNetNS(t)() - args := []string{ - userlandProxyCommandName, - "-proto", "tcp", - "-host-ip", "0.0.0.0", - "-host-port", "9999", - "-container-ip", "172.168.1.1", - "-container-port", "8888", - } - os.Args = args - doneChan := make(chan bool) - go func() { - execProxy() - doneChan <- true - }() +func TestMapTCPDummyListen(t *testing.T) { + pm := New() + dstIP := net.ParseIP("0.0.0.0") + dstAddr := &net.TCPAddr{IP: dstIP, Port: 80} - select { - case <-doneChan: - t.Fatal("execProxy is not supposed to exit") - case <-time.After(3 * time.Second): - return + // 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()) + } + + 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) + } } } diff --git a/vendor/src/github.com/docker/libnetwork/portmapper/proxy.go b/vendor/src/github.com/docker/libnetwork/portmapper/proxy.go index 5cbb4dc2a8..530703b259 100644 --- a/vendor/src/github.com/docker/libnetwork/portmapper/proxy.go +++ b/vendor/src/github.com/docker/libnetwork/portmapper/proxy.go @@ -3,6 +3,7 @@ package portmapper import ( "flag" "fmt" + "io" "io/ioutil" "log" "net" @@ -159,3 +160,50 @@ func (p *proxyCommand) Stop() error { } return nil } + +// dummyProxy just listen on some port, it is needed to prevent accidental +// port allocations on bound port, because without userland proxy we using +// iptables rules and not net.Listen +type dummyProxy struct { + listener io.Closer + addr net.Addr +} + +func newDummyProxy(proto string, hostIP net.IP, hostPort int) userlandProxy { + switch proto { + case "tcp": + addr := &net.TCPAddr{IP: hostIP, Port: hostPort} + return &dummyProxy{addr: addr} + case "udp": + addr := &net.UDPAddr{IP: hostIP, Port: hostPort} + return &dummyProxy{addr: addr} + } + return nil +} + +func (p *dummyProxy) Start() error { + switch addr := p.addr.(type) { + case *net.TCPAddr: + l, err := net.ListenTCP("tcp", addr) + if err != nil { + return err + } + p.listener = l + case *net.UDPAddr: + l, err := net.ListenUDP("udp", addr) + if err != nil { + return err + } + p.listener = l + default: + return fmt.Errorf("Unknown addr type: %T", p.addr) + } + return nil +} + +func (p *dummyProxy) Stop() error { + if p.listener != nil { + return p.listener.Close() + } + return nil +} diff --git a/vendor/src/github.com/docker/libnetwork/sandbox/namespace_linux.go b/vendor/src/github.com/docker/libnetwork/sandbox/namespace_linux.go index b4221f4f07..17881f1404 100644 --- a/vendor/src/github.com/docker/libnetwork/sandbox/namespace_linux.go +++ b/vendor/src/github.com/docker/libnetwork/sandbox/namespace_linux.go @@ -20,8 +20,10 @@ var once sync.Once // interface. It represents a linux network namespace, and moves an interface // into it when called on method AddInterface or sets the gateway etc. type networkNamespace struct { - path string - sinfo *Info + path string + sinfo *Info + nextIfIndex int + sync.Mutex } func createBasePath() { @@ -167,6 +169,11 @@ func (n *networkNamespace) RemoveInterface(i *Interface) error { } func (n *networkNamespace) AddInterface(i *Interface) error { + n.Lock() + i.DstName = fmt.Sprintf("%s%d", i.DstName, n.nextIfIndex) + n.nextIfIndex++ + n.Unlock() + runtime.LockOSThread() defer runtime.UnlockOSThread() @@ -214,7 +221,10 @@ func (n *networkNamespace) AddInterface(i *Interface) error { return err } + n.Lock() n.sinfo.Interfaces = append(n.sinfo.Interfaces, i) + n.Unlock() + return nil } diff --git a/vendor/src/github.com/docker/libnetwork/sandbox/sandbox.go b/vendor/src/github.com/docker/libnetwork/sandbox/sandbox.go index b535f6e430..9e104cabdc 100644 --- a/vendor/src/github.com/docker/libnetwork/sandbox/sandbox.go +++ b/vendor/src/github.com/docker/libnetwork/sandbox/sandbox.go @@ -3,7 +3,7 @@ package sandbox import ( "net" - "github.com/docker/libnetwork/netutils" + "github.com/docker/libnetwork/types" ) // Sandbox represents a network sandbox, identified by a specific key. It @@ -20,7 +20,9 @@ type Sandbox interface { // Add an existing Interface to this sandbox. The operation will rename // from the Interface SrcName to DstName as it moves, and reconfigure the - // interface according to the specified settings. + // interface according to the specified settings. The caller is expected + // to only provide a prefix for DstName. The AddInterface api will auto-generate + // an appropriate suffix for the DstName to disambiguate. AddInterface(*Interface) error // Remove an interface from the sandbox by renamin to original name @@ -62,7 +64,9 @@ type Interface struct { SrcName string // The name that will be assigned to the interface once moves inside a - // network namespace. + // network namespace. When the caller passes in a DstName, it is only + // expected to pass a prefix. The name will modified with an appropriately + // auto-generated suffix. DstName string // IPv4 address for the interface. @@ -77,8 +81,8 @@ func (i *Interface) GetCopy() *Interface { return &Interface{ SrcName: i.SrcName, DstName: i.DstName, - Address: netutils.GetIPNetCopy(i.Address), - AddressIPv6: netutils.GetIPNetCopy(i.AddressIPv6), + Address: types.GetIPNetCopy(i.Address), + AddressIPv6: types.GetIPNetCopy(i.AddressIPv6), } } @@ -96,11 +100,11 @@ func (i *Interface) Equal(o *Interface) bool { return false } - if !netutils.CompareIPNet(i.Address, o.Address) { + if !types.CompareIPNet(i.Address, o.Address) { return false } - if !netutils.CompareIPNet(i.AddressIPv6, o.AddressIPv6) { + if !types.CompareIPNet(i.AddressIPv6, o.AddressIPv6) { return false } @@ -113,8 +117,8 @@ func (s *Info) GetCopy() *Info { for i, iface := range s.Interfaces { list[i] = iface.GetCopy() } - gw := netutils.GetIPCopy(s.Gateway) - gw6 := netutils.GetIPCopy(s.GatewayIPv6) + gw := types.GetIPCopy(s.Gateway) + gw6 := types.GetIPCopy(s.GatewayIPv6) return &Info{Interfaces: list, Gateway: gw, GatewayIPv6: gw6} } diff --git a/vendor/src/github.com/docker/libnetwork/sandbox/sandbox_linux_test.go b/vendor/src/github.com/docker/libnetwork/sandbox/sandbox_linux_test.go index 06e98c7846..d4af061f91 100644 --- a/vendor/src/github.com/docker/libnetwork/sandbox/sandbox_linux_test.go +++ b/vendor/src/github.com/docker/libnetwork/sandbox/sandbox_linux_test.go @@ -15,6 +15,8 @@ import ( const ( vethName1 = "wierdlongname1" vethName2 = "wierdlongname2" + vethName3 = "wierdlongname3" + vethName4 = "wierdlongname4" sboxIfaceName = "containername" ) @@ -36,33 +38,59 @@ func newInfo(t *testing.T) (*Info, error) { veth := &netlink.Veth{ LinkAttrs: netlink.LinkAttrs{Name: vethName1, TxQLen: 0}, PeerName: vethName2} - err := netlink.LinkAdd(veth) - if err != nil { + if err := netlink.LinkAdd(veth); err != nil { return nil, err } // Store the sandbox side pipe interface // This is needed for cleanup on DeleteEndpoint() - intf := &Interface{} - intf.SrcName = vethName2 - intf.DstName = sboxIfaceName + intf1 := &Interface{} + intf1.SrcName = vethName2 + intf1.DstName = sboxIfaceName ip4, addr, err := net.ParseCIDR("192.168.1.100/24") if err != nil { return nil, err } - intf.Address = addr - intf.Address.IP = ip4 + intf1.Address = addr + intf1.Address.IP = ip4 // ip6, addrv6, err := net.ParseCIDR("2001:DB8::ABCD/48") ip6, addrv6, err := net.ParseCIDR("fe80::2/64") if err != nil { return nil, err } - intf.AddressIPv6 = addrv6 - intf.AddressIPv6.IP = ip6 + intf1.AddressIPv6 = addrv6 + intf1.AddressIPv6.IP = ip6 - sinfo := &Info{Interfaces: []*Interface{intf}} + 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 + + // ip6, addrv6, err := net.ParseCIDR("2001:DB8::ABCD/48") + ip6, addrv6, err = net.ParseCIDR("fe80::3/64") + if err != nil { + return nil, err + } + intf2.AddressIPv6 = addrv6 + intf2.AddressIPv6.IP = ip6 + + sinfo := &Info{Interfaces: []*Interface{intf1, intf2}} sinfo.Gateway = net.ParseIP("192.168.1.1") // sinfo.GatewayIPv6 = net.ParseIP("2001:DB8::1") sinfo.GatewayIPv6 = net.ParseIP("fe80::1") @@ -97,7 +125,13 @@ func verifySandbox(t *testing.T, s Sandbox) { } defer netns.Set(origns) - _, err = netlink.LinkByName(sboxIfaceName) + _, err = netlink.LinkByName(sboxIfaceName + "0") + if err != nil { + t.Fatalf("Could not find the interface %s inside the sandbox: %v", sboxIfaceName, + err) + } + + _, err = netlink.LinkByName(sboxIfaceName + "1") if err != nil { t.Fatalf("Could not find the interface %s inside the sandbox: %v", sboxIfaceName, err) diff --git a/vendor/src/github.com/docker/libnetwork/types/types.go b/vendor/src/github.com/docker/libnetwork/types/types.go index 363d4ab73c..3b83485f75 100644 --- a/vendor/src/github.com/docker/libnetwork/types/types.go +++ b/vendor/src/github.com/docker/libnetwork/types/types.go @@ -1,5 +1,345 @@ // Package types contains types that are common across libnetwork project package types +import ( + "bytes" + "fmt" + "net" + "strings" +) + // UUID represents a globally unique ID of various resources like network and endpoint type UUID string + +// TransportPort represent a local Layer 4 endpoint +type TransportPort struct { + Proto Protocol + Port uint16 +} + +// GetCopy returns a copy of this TransportPort structure instance +func (t *TransportPort) GetCopy() TransportPort { + return TransportPort{Proto: t.Proto, Port: t.Port} +} + +// PortBinding represent a port binding between the container an the host +type PortBinding struct { + Proto Protocol + IP net.IP + Port uint16 + HostIP net.IP + HostPort uint16 +} + +// HostAddr returns the host side transport address +func (p PortBinding) HostAddr() (net.Addr, error) { + switch p.Proto { + case UDP: + return &net.UDPAddr{IP: p.HostIP, Port: int(p.HostPort)}, nil + case TCP: + return &net.TCPAddr{IP: p.HostIP, Port: int(p.HostPort)}, nil + default: + return nil, ErrInvalidProtocolBinding(p.Proto.String()) + } +} + +// ContainerAddr returns the container side transport address +func (p PortBinding) ContainerAddr() (net.Addr, error) { + switch p.Proto { + case UDP: + return &net.UDPAddr{IP: p.IP, Port: int(p.Port)}, nil + case TCP: + return &net.TCPAddr{IP: p.IP, Port: int(p.Port)}, nil + default: + return nil, ErrInvalidProtocolBinding(p.Proto.String()) + } +} + +// GetCopy returns a copy of this PortBinding structure instance +func (p *PortBinding) GetCopy() PortBinding { + return PortBinding{ + Proto: p.Proto, + IP: GetIPCopy(p.IP), + Port: p.Port, + HostIP: GetIPCopy(p.HostIP), + HostPort: p.HostPort, + } +} + +// Equal checks if this instance of PortBinding is equal to the passed one +func (p *PortBinding) Equal(o *PortBinding) bool { + if p == o { + return true + } + + if o == nil { + return false + } + + if p.Proto != o.Proto || p.Port != o.Port || p.HostPort != o.HostPort { + return false + } + + if p.IP != nil { + if !p.IP.Equal(o.IP) { + return false + } + } else { + if o.IP != nil { + return false + } + } + + if p.HostIP != nil { + if !p.HostIP.Equal(o.HostIP) { + return false + } + } else { + if o.HostIP != nil { + return false + } + } + + return true +} + +// ErrInvalidProtocolBinding is returned when the port binding protocol is not valid. +type ErrInvalidProtocolBinding string + +func (ipb ErrInvalidProtocolBinding) Error() string { + return fmt.Sprintf("invalid transport protocol: %s", string(ipb)) +} + +const ( + // ICMP is for the ICMP ip protocol + ICMP = 1 + // TCP is for the TCP ip protocol + TCP = 6 + // UDP is for the UDP ip protocol + UDP = 17 +) + +// Protocol represents a IP protocol number +type Protocol uint8 + +func (p Protocol) String() string { + switch p { + case ICMP: + return "icmp" + case TCP: + return "tcp" + case UDP: + return "udp" + default: + return fmt.Sprintf("%d", p) + } +} + +// ParseProtocol returns the respective Protocol type for the passed string +func ParseProtocol(s string) Protocol { + switch strings.ToLower(s) { + case "icmp": + return ICMP + case "udp": + return UDP + case "tcp": + return TCP + default: + return 0 + } +} + +// GetMacCopy returns a copy of the passed MAC address +func GetMacCopy(from net.HardwareAddr) net.HardwareAddr { + to := make(net.HardwareAddr, len(from)) + copy(to, from) + return to +} + +// GetIPCopy returns a copy of the passed IP address +func GetIPCopy(from net.IP) net.IP { + to := make(net.IP, len(from)) + copy(to, from) + return to +} + +// GetIPNetCopy returns a copy of the passed IP Network +func GetIPNetCopy(from *net.IPNet) *net.IPNet { + if from == nil { + return nil + } + bm := make(net.IPMask, len(from.Mask)) + copy(bm, from.Mask) + return &net.IPNet{IP: GetIPCopy(from.IP), Mask: bm} +} + +// CompareIPNet returns equal if the two IP Networks are equal +func CompareIPNet(a, b *net.IPNet) bool { + if a == b { + return true + } + if a == nil || b == nil { + return false + } + return a.IP.Equal(b.IP) && bytes.Equal(a.Mask, b.Mask) +} + +/****************************** + * Well-known Error Interfaces + ******************************/ + +// MaskableError is an interface for errors which can be ignored by caller +type MaskableError interface { + // Maskable makes implementer into MaskableError type + Maskable() +} + +// BadRequestError is an interface for errors originated by a bad request +type BadRequestError interface { + // BadRequest makes implementer into BadRequestError type + BadRequest() +} + +// NotFoundError is an interface for errors raised because a needed resource is not available +type NotFoundError interface { + // NotFound makes implementer into NotFoundError type + NotFound() +} + +// ForbiddenError is an interface for errors which denote an valid request that cannot be honored +type ForbiddenError interface { + // Forbidden makes implementer into ForbiddenError type + Forbidden() +} + +// NoServiceError is an interface for errors returned when the required service is not available +type NoServiceError interface { + // NoService makes implementer into NoServiceError type + NoService() +} + +// TimeoutError is an interface for errors raised because of timeout +type TimeoutError interface { + // Timeout makes implementer into TimeoutError type + Timeout() +} + +// NotImplementedError is an interface for errors raised because of requested functionality is not yet implemented +type NotImplementedError interface { + // NotImplemented makes implementer into NotImplementedError type + NotImplemented() +} + +// InternalError is an interface for errors raised because of an internal error +type InternalError interface { + // Internal makes implementer into InternalError type + Internal() +} + +/****************************** + * Weel-known Error Formatters + ******************************/ + +// BadRequestErrorf creates an instance of BadRequestError +func BadRequestErrorf(format string, params ...interface{}) error { + return badRequest(fmt.Sprintf(format, params...)) +} + +// NotFoundErrorf creates an instance of NotFoundError +func NotFoundErrorf(format string, params ...interface{}) error { + return notFound(fmt.Sprintf(format, params...)) +} + +// ForbiddenErrorf creates an instance of ForbiddenError +func ForbiddenErrorf(format string, params ...interface{}) error { + return forbidden(fmt.Sprintf(format, params...)) +} + +// NoServiceErrorf creates an instance of NoServiceError +func NoServiceErrorf(format string, params ...interface{}) error { + return noService(fmt.Sprintf(format, params...)) +} + +// NotImplementedErrorf creates an instance of NotImplementedError +func NotImplementedErrorf(format string, params ...interface{}) error { + return notImpl(fmt.Sprintf(format, params...)) +} + +// TimeoutErrorf creates an instance of TimeoutError +func TimeoutErrorf(format string, params ...interface{}) error { + return timeout(fmt.Sprintf(format, params...)) +} + +// InternalErrorf creates an instance of InternalError +func InternalErrorf(format string, params ...interface{}) error { + return internal(fmt.Sprintf(format, params...)) +} + +// InternalMaskableErrorf creates an instance of InternalError and MaskableError +func InternalMaskableErrorf(format string, params ...interface{}) error { + return maskInternal(fmt.Sprintf(format, params...)) +} + +/*********************** + * Internal Error Types + ***********************/ +type badRequest string + +func (br badRequest) Error() string { + return string(br) +} +func (br badRequest) BadRequest() {} + +type maskBadRequest string + +type notFound string + +func (nf notFound) Error() string { + return string(nf) +} +func (nf notFound) NotFound() {} + +type forbidden string + +func (frb forbidden) Error() string { + return string(frb) +} +func (frb forbidden) Forbidden() {} + +type noService string + +func (ns noService) Error() string { + return string(ns) +} +func (ns noService) NoService() {} + +type maskNoService string + +type timeout string + +func (to timeout) Error() string { + return string(to) +} +func (to timeout) Timeout() {} + +type notImpl string + +func (ni notImpl) Error() string { + return string(ni) +} +func (ni notImpl) NotImplemented() {} + +type internal string + +func (nt internal) Error() string { + return string(nt) +} +func (nt internal) Internal() {} + +type maskInternal string + +func (mnt maskInternal) Error() string { + return string(mnt) +} +func (mnt maskInternal) Internal() {} +func (mnt maskInternal) Maskable() {} diff --git a/vendor/src/github.com/docker/libnetwork/types/types_test.go b/vendor/src/github.com/docker/libnetwork/types/types_test.go new file mode 100644 index 0000000000..9e96ea858d --- /dev/null +++ b/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) + } +}