diff --git a/libnetwork/api/api.go b/libnetwork/api/api.go index 0eebf4d197..9f2a4c28d5 100644 --- a/libnetwork/api/api.go +++ b/libnetwork/api/api.go @@ -17,8 +17,17 @@ var ( ) const ( - urlNwName = "name" - urlNwID = "id" + // Resource name regex + regex = "[a-zA-Z_0-9-]+" + // Router URL variable definition + nwName = "{" + urlNwName + ":" + regex + "}" + nwID = "{" + urlNwID + ":" + regex + "}" + epName = "{" + urlEpName + ":" + regex + "}" + epID = "{" + urlEpID + ":" + regex + "}" + cnID = "{" + urlCnID + ":" + regex + "}" + // Internal URL variable name, they can be anything + urlNwName = "network-name" + urlNwID = "network-id" urlEpName = "endpoint-name" urlEpID = "endpoint-id" urlCnID = "container-id" @@ -59,42 +68,38 @@ 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", nil, procGetNetworks}, + {"/networks/" + nwID, nil, procGetNetwork}, + {"/networks/" + nwID + "/endpoints", []string{"name", epName}, 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 +213,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 +232,19 @@ 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) + + // If query parameter is specified, return a filtered collection + if name, queryByName := vars[urlNwName]; queryByName { + nw, errRsp := findNetwork(c, name, byName) + if errRsp.isOK() { + list = append(list, buildNetworkResource(nw)) + } + } else { + for _, nw := range c.Networks() { + list = append(list, buildNetworkResource(nw)) + } } + return list, &successResponse } @@ -250,21 +259,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 +273,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 +294,25 @@ 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) - - 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 epT, queryByName := vars[urlEpName]; queryByName { + ep, errRsp := findEndpoint(c, nwT, epT, nwBy, byName) + if errRsp.isOK() { + list = append(list, buildEndpointResource(ep)) + } + } else { + for _, ep := range nw.Endpoints() { + epr := buildEndpointResource(ep) + list = append(list, epr) + } } return list, &successResponse @@ -336,11 +344,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) diff --git a/libnetwork/api/api_test.go b/libnetwork/api/api_test.go index 069afb7c21..aad71f1a73 100644 --- a/libnetwork/api/api_test.go +++ b/libnetwork/api/api_test.go @@ -112,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) @@ -124,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 { @@ -157,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) } } @@ -178,18 +162,18 @@ func TestCreateDeleteNetwork(t *testing.T) { t.Fatal(err) } - goodVars := map[string]string{urlNwName: "myNet"} - _, errRsp := procCreateNetwork(c, goodVars, badBody) + vars := make(map[string]string) + _, errRsp := procCreateNetwork(c, nil, badBody) if errRsp == &createdResponse { t.Fatalf("Expected to fail but succeeded") } - incompleteBody, err := json.Marshal(networkCreate{Name: "myNet"}) + incompleteBody, err := json.Marshal(networkCreate{}) if err != nil { t.Fatal(err) } - _, errRsp = procCreateNetwork(c, goodVars, incompleteBody) + _, errRsp = procCreateNetwork(c, vars, incompleteBody) if errRsp == &createdResponse { t.Fatalf("Expected to fail but succeeded") } @@ -199,47 +183,31 @@ func TestCreateDeleteNetwork(t *testing.T) { 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) } @@ -263,7 +231,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) @@ -274,8 +242,7 @@ func TestGetNetworksAndEndpoints(t *testing.T) { } ec1 := endpointCreate{ - Name: "ep1", - NetworkID: string(nid), + Name: "ep1", ExposedPorts: []types.TransportPort{ types.TransportPort{Proto: types.TCP, Port: uint16(5000)}, types.TransportPort{Proto: types.UDP, Port: uint16(400)}, @@ -291,12 +258,13 @@ func TestGetNetworksAndEndpoints(t *testing.T) { 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 { @@ -472,6 +440,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) @@ -604,85 +573,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) @@ -714,8 +644,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) @@ -767,18 +697,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) @@ -793,6 +722,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) @@ -812,44 +742,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") @@ -898,6 +814,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) @@ -1194,15 +1111,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) } @@ -1230,7 +1156,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", "/networks", &localReader{beBad: true}) if err != nil { t.Fatal(err) } @@ -1241,7 +1167,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", "/networks", lr) if err != nil { t.Fatal(err) } @@ -1251,7 +1177,7 @@ func TestHttpHandlerBadBody(t *testing.T) { } } -func TestHttpHandlerGood(t *testing.T) { +func TestEndToEnd(t *testing.T) { defer netutils.SetupTestNetNS(t)() rsp := newWriter() @@ -1262,14 +1188,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", "/networks", lr) if err != nil { t.Fatal(err) } @@ -1281,13 +1207,79 @@ 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", "/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", "/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", "/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", "/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]) + } + + // Get network by id + req, err = http.NewRequest("GET", "/networks/"+nid, nil) if err != nil { t.Fatal(err) } @@ -1301,7 +1293,99 @@ 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", "/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", "/networks/"+nid+"/endpoints", nil) + if err != nil { + t.Fatal(err) + } + handleRequest(rsp, req) + if rsp.statusCode != http.StatusNotFound { + t.Fatalf("Expected StatusNotFound. Got (%d): %s", rsp.statusCode, rsp.body) + } + + req, err = http.NewRequest("GET", "/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", "/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]) + } + + // Get endpoint by id + req, err = http.NewRequest("GET", "/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) } } diff --git a/libnetwork/api/types.go b/libnetwork/api/types.go index 842bc22aef..2490a84fe4 100644 --- a/libnetwork/api/types.go +++ b/libnetwork/api/types.go @@ -35,7 +35,6 @@ type networkCreate struct { // endpointCreate represents the body of the "create endpoint" http request message type endpointCreate struct { Name string - NetworkID string ExposedPorts []types.TransportPort PortMapping []types.PortBinding } diff --git a/libnetwork/client/network.go b/libnetwork/client/network.go index d9effab8c4..3da71fe54e 100644 --- a/libnetwork/client/network.go +++ b/libnetwork/client/network.go @@ -53,7 +53,7 @@ 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 diff --git a/libnetwork/cmd/dnet/dnet.go b/libnetwork/cmd/dnet/dnet.go index 547ec312e6..c34c38c442 100644 --- a/libnetwork/cmd/dnet/dnet.go +++ b/libnetwork/cmd/dnet/dnet.go @@ -114,9 +114,7 @@ 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.Methods("GET", "PUT", "POST", "DELETE").HandlerFunc(httpHandler) return http.ListenAndServe(d.addr, r) } diff --git a/libnetwork/cmd/dnet/flags.go b/libnetwork/cmd/dnet/flags.go index 468f18dc09..2e77e1873b 100644 --- a/libnetwork/cmd/dnet/flags.go +++ b/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")