This version brings in upto-date important bug-fixes from libnetwork
Signed-off-by: Madhu Venugopal <madhu@docker.com>
| ... | ... |
@@ -30,8 +30,8 @@ import ( |
| 30 | 30 |
"github.com/docker/libcontainer/devices" |
| 31 | 31 |
"github.com/docker/libnetwork" |
| 32 | 32 |
"github.com/docker/libnetwork/netlabel" |
| 33 |
- "github.com/docker/libnetwork/netutils" |
|
| 34 | 33 |
"github.com/docker/libnetwork/options" |
| 34 |
+ "github.com/docker/libnetwork/types" |
|
| 35 | 35 |
) |
| 36 | 36 |
|
| 37 | 37 |
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 |
| 502 | 502 |
return networkSettings, nil |
| 503 | 503 |
} |
| 504 | 504 |
|
| 505 |
- if portMapping, ok := mapData.([]netutils.PortBinding); ok {
|
|
| 505 |
+ if portMapping, ok := mapData.([]types.PortBinding); ok {
|
|
| 506 | 506 |
networkSettings.Ports = nat.PortMap{}
|
| 507 | 507 |
for _, pp := range portMapping {
|
| 508 | 508 |
natPort := nat.NewPort(pp.Proto.String(), strconv.Itoa(int(pp.Port))) |
| ... | ... |
@@ -641,8 +641,8 @@ func (container *Container) buildCreateEndpointOptions() ([]libnetwork.EndpointO |
| 641 | 641 |
var ( |
| 642 | 642 |
portSpecs = make(nat.PortSet) |
| 643 | 643 |
bindings = make(nat.PortMap) |
| 644 |
- pbList []netutils.PortBinding |
|
| 645 |
- exposeList []netutils.TransportPort |
|
| 644 |
+ pbList []types.PortBinding |
|
| 645 |
+ exposeList []types.TransportPort |
|
| 646 | 646 |
createOptions []libnetwork.EndpointOption |
| 647 | 647 |
) |
| 648 | 648 |
|
| ... | ... |
@@ -682,12 +682,12 @@ func (container *Container) buildCreateEndpointOptions() ([]libnetwork.EndpointO |
| 682 | 682 |
} |
| 683 | 683 |
nat.SortPortMap(ports, bindings) |
| 684 | 684 |
for _, port := range ports {
|
| 685 |
- expose := netutils.TransportPort{}
|
|
| 686 |
- expose.Proto = netutils.ParseProtocol(port.Proto()) |
|
| 685 |
+ expose := types.TransportPort{}
|
|
| 686 |
+ expose.Proto = types.ParseProtocol(port.Proto()) |
|
| 687 | 687 |
expose.Port = uint16(port.Int()) |
| 688 | 688 |
exposeList = append(exposeList, expose) |
| 689 | 689 |
|
| 690 |
- pb := netutils.PortBinding{Port: expose.Port, Proto: expose.Proto}
|
|
| 690 |
+ pb := types.PortBinding{Port: expose.Port, Proto: expose.Proto}
|
|
| 691 | 691 |
binding := bindings[port] |
| 692 | 692 |
for i := 0; i < len(binding); i++ {
|
| 693 | 693 |
pbCopy := pb.GetCopy() |
| ... | ... |
@@ -55,7 +55,7 @@ clone hg code.google.com/p/go.net 84a4013f96e0 |
| 55 | 55 |
clone hg code.google.com/p/gosqlite 74691fb6f837 |
| 56 | 56 |
|
| 57 | 57 |
#get libnetwork packages |
| 58 |
-clone git github.com/docker/libnetwork b39597744b0978fe4aeb9f3a099ba42f7b6c4a1f |
|
| 58 |
+clone git github.com/docker/libnetwork 67438080724b17b641b411322822c00d0d3c3201 |
|
| 59 | 59 |
clone git github.com/vishvananda/netns 008d17ae001344769b031375bdb38a86219154c6 |
| 60 | 60 |
clone git github.com/vishvananda/netlink 8eb64238879fed52fd51c5b30ad20b928fb4c36c |
| 61 | 61 |
|
| ... | ... |
@@ -5,8 +5,10 @@ import ( |
| 5 | 5 |
"fmt" |
| 6 | 6 |
"io/ioutil" |
| 7 | 7 |
"net/http" |
| 8 |
+ "strings" |
|
| 8 | 9 |
|
| 9 | 10 |
"github.com/docker/libnetwork" |
| 11 |
+ "github.com/docker/libnetwork/types" |
|
| 10 | 12 |
"github.com/gorilla/mux" |
| 11 | 13 |
) |
| 12 | 14 |
|
| ... | ... |
@@ -14,13 +16,28 @@ var ( |
| 14 | 14 |
successResponse = responseStatus{Status: "Success", StatusCode: http.StatusOK}
|
| 15 | 15 |
createdResponse = responseStatus{Status: "Created", StatusCode: http.StatusCreated}
|
| 16 | 16 |
mismatchResponse = responseStatus{Status: "Body/URI parameter mismatch", StatusCode: http.StatusBadRequest}
|
| 17 |
+ badQueryresponse = responseStatus{Status: "Unsupported query", StatusCode: http.StatusBadRequest}
|
|
| 17 | 18 |
) |
| 18 | 19 |
|
| 19 | 20 |
const ( |
| 20 |
- urlNwName = "name" |
|
| 21 |
- urlNwID = "id" |
|
| 21 |
+ // Resource name regex |
|
| 22 |
+ regex = "[a-zA-Z_0-9-]+" |
|
| 23 |
+ // Router URL variable definition |
|
| 24 |
+ nwName = "{" + urlNwName + ":" + regex + "}"
|
|
| 25 |
+ nwID = "{" + urlNwID + ":" + regex + "}"
|
|
| 26 |
+ nwPID = "{" + urlNwPID + ":" + regex + "}"
|
|
| 27 |
+ epName = "{" + urlEpName + ":" + regex + "}"
|
|
| 28 |
+ epID = "{" + urlEpID + ":" + regex + "}"
|
|
| 29 |
+ epPID = "{" + urlEpPID + ":" + regex + "}"
|
|
| 30 |
+ cnID = "{" + urlCnID + ":" + regex + "}"
|
|
| 31 |
+ |
|
| 32 |
+ // Internal URL variable name, they can be anything |
|
| 33 |
+ urlNwName = "network-name" |
|
| 34 |
+ urlNwID = "network-id" |
|
| 35 |
+ urlNwPID = "network-partial-id" |
|
| 22 | 36 |
urlEpName = "endpoint-name" |
| 23 | 37 |
urlEpID = "endpoint-id" |
| 38 |
+ urlEpPID = "endpoint-partial-id" |
|
| 24 | 39 |
urlCnID = "container-id" |
| 25 | 40 |
) |
| 26 | 41 |
|
| ... | ... |
@@ -59,42 +76,41 @@ func (h *httpHandler) handleRequest(w http.ResponseWriter, req *http.Request) {
|
| 59 | 59 |
} |
| 60 | 60 |
|
| 61 | 61 |
func (h *httpHandler) initRouter() {
|
| 62 |
- m := map[string]map[string]processor{
|
|
| 62 |
+ m := map[string][]struct {
|
|
| 63 |
+ url string |
|
| 64 |
+ qrs []string |
|
| 65 |
+ fct processor |
|
| 66 |
+ }{
|
|
| 63 | 67 |
"GET": {
|
| 64 |
- "/networks": procGetNetworks, |
|
| 65 |
- "/networks/name/{" + urlNwName + ":.*}": procGetNetwork,
|
|
| 66 |
- "/networks/id/{" + urlNwID + ":.*}": procGetNetwork,
|
|
| 67 |
- "/networks/name/{" + urlNwName + ":.*}/endpoints/": procGetEndpoints,
|
|
| 68 |
- "/networks/id/{" + urlNwID + ":.*}/endpoints/": procGetEndpoints,
|
|
| 69 |
- "/networks/name/{" + urlNwName + ":.*}/endpoints/name/{" + urlEpName + ":.*}": procGetEndpoint,
|
|
| 70 |
- "/networks/id/{" + urlNwID + ":.*}/endpoints/name/{" + urlEpName + ":.*}": procGetEndpoint,
|
|
| 71 |
- "/networks/name/{" + urlNwName + ":.*}/endpoints/id/{" + urlEpID + ":.*}": procGetEndpoint,
|
|
| 72 |
- "/networks/id/{" + urlNwID + ":.*}/endpoints/id/{" + urlEpID + ":.*}": procGetEndpoint,
|
|
| 68 |
+ // Order matters |
|
| 69 |
+ {"/networks", []string{"name", nwName}, procGetNetworks},
|
|
| 70 |
+ {"/networks", []string{"partial-id", nwPID}, procGetNetworks},
|
|
| 71 |
+ {"/networks", nil, procGetNetworks},
|
|
| 72 |
+ {"/networks/" + nwID, nil, procGetNetwork},
|
|
| 73 |
+ {"/networks/" + nwID + "/endpoints", []string{"name", epName}, procGetEndpoints},
|
|
| 74 |
+ {"/networks/" + nwID + "/endpoints", []string{"partial-id", epPID}, procGetEndpoints},
|
|
| 75 |
+ {"/networks/" + nwID + "/endpoints", nil, procGetEndpoints},
|
|
| 76 |
+ {"/networks/" + nwID + "/endpoints/" + epID, nil, procGetEndpoint},
|
|
| 73 | 77 |
}, |
| 74 | 78 |
"POST": {
|
| 75 |
- "/networks/name/{" + urlNwName + ":.*}": procCreateNetwork,
|
|
| 76 |
- "/networks/name/{" + urlNwName + ":.*}/endpoint/name/{" + urlEpName + ":.*}": procCreateEndpoint,
|
|
| 77 |
- "/networks/name/{" + urlNwName + ":.*}/endpoint/name/{" + urlEpName + ":.*}/container/{" + urlCnID + ":.*}": procJoinEndpoint,
|
|
| 79 |
+ {"/networks", nil, procCreateNetwork},
|
|
| 80 |
+ {"/networks/" + nwID + "/endpoints", nil, procCreateEndpoint},
|
|
| 81 |
+ {"/networks/" + nwID + "/endpoints/" + epID + "/containers", nil, procJoinEndpoint},
|
|
| 78 | 82 |
}, |
| 79 | 83 |
"DELETE": {
|
| 80 |
- "/networks/name/{" + urlNwName + ":.*}": procDeleteNetwork,
|
|
| 81 |
- "/networks/id/{" + urlNwID + ":.*}": procDeleteNetwork,
|
|
| 82 |
- "/networks/name/{" + urlNwName + ":.*}/endpoints/name/{" + urlEpName + ":.*}": procDeleteEndpoint,
|
|
| 83 |
- "/networks/name/{" + urlNwName + ":.*}/endpoints/id/{" + urlEpID + ":.*}": procDeleteEndpoint,
|
|
| 84 |
- "/networks/id/{" + urlNwID + ":.*}/endpoints/name/{" + urlEpName + ":.*}": procDeleteEndpoint,
|
|
| 85 |
- "/networks/id/{" + urlNwID + ":.*}/endpoints/id/{" + urlEpID + ":.*}": procDeleteEndpoint,
|
|
| 86 |
- "/networks/name/{" + urlNwName + ":.*}/endpoint/name/{" + urlEpName + ":.*}/container/{" + urlCnID + ":.*}": procLeaveEndpoint,
|
|
| 87 |
- "/networks/name/{" + urlNwName + ":.*}/endpoint/id/{" + urlEpID + ":.*}/container/{" + urlCnID + ":.*}": procLeaveEndpoint,
|
|
| 88 |
- "/networks/id/{" + urlNwID + ":.*}/endpoint/name/{" + urlEpName + ":.*}/container/{" + urlCnID + ":.*}": procLeaveEndpoint,
|
|
| 89 |
- "/networks/id/{" + urlNwID + ":.*}/endpoint/id/{" + urlEpID + ":.*}/container/{" + urlCnID + ":.*}": procLeaveEndpoint,
|
|
| 84 |
+ {"/networks/" + nwID, nil, procDeleteNetwork},
|
|
| 85 |
+ {"/networks/" + nwID + "/endpoints/" + epID, nil, procDeleteEndpoint},
|
|
| 86 |
+ {"/networks/id/" + nwID + "/endpoints/" + epID + "/containers/" + cnID, nil, procLeaveEndpoint},
|
|
| 90 | 87 |
}, |
| 91 | 88 |
} |
| 92 | 89 |
|
| 93 | 90 |
h.r = mux.NewRouter() |
| 94 | 91 |
for method, routes := range m {
|
| 95 |
- for route, fct := range routes {
|
|
| 96 |
- f := makeHandler(h.c, fct) |
|
| 97 |
- h.r.Path(route).Methods(method).HandlerFunc(f) |
|
| 92 |
+ for _, route := range routes {
|
|
| 93 |
+ r := h.r.Path("/{.*}" + route.url).Methods(method).HandlerFunc(makeHandler(h.c, route.fct))
|
|
| 94 |
+ if route.qrs != nil {
|
|
| 95 |
+ r.Queries(route.qrs...) |
|
| 96 |
+ } |
|
| 98 | 97 |
} |
| 99 | 98 |
} |
| 100 | 99 |
} |
| ... | ... |
@@ -208,12 +224,7 @@ func procCreateNetwork(c libnetwork.NetworkController, vars map[string]string, b |
| 208 | 208 |
return "", &responseStatus{Status: "Invalid body: " + err.Error(), StatusCode: http.StatusBadRequest}
|
| 209 | 209 |
} |
| 210 | 210 |
|
| 211 |
- name := vars[urlNwName] |
|
| 212 |
- if name != create.Name {
|
|
| 213 |
- return "", &mismatchResponse |
|
| 214 |
- } |
|
| 215 |
- |
|
| 216 |
- nw, err := c.NewNetwork(create.NetworkType, name, nil) |
|
| 211 |
+ nw, err := c.NewNetwork(create.NetworkType, create.Name, nil) |
|
| 217 | 212 |
if err != nil {
|
| 218 | 213 |
return "", convertNetworkError(err) |
| 219 | 214 |
} |
| ... | ... |
@@ -232,10 +243,33 @@ func procGetNetwork(c libnetwork.NetworkController, vars map[string]string, body |
| 232 | 232 |
|
| 233 | 233 |
func procGetNetworks(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
|
| 234 | 234 |
var list []*networkResource |
| 235 |
- for _, nw := range c.Networks() {
|
|
| 236 |
- nwr := buildNetworkResource(nw) |
|
| 237 |
- list = append(list, nwr) |
|
| 235 |
+ |
|
| 236 |
+ // Look for query filters and validate |
|
| 237 |
+ name, queryByName := vars[urlNwName] |
|
| 238 |
+ shortID, queryByPid := vars[urlNwPID] |
|
| 239 |
+ if queryByName && queryByPid {
|
|
| 240 |
+ return nil, &badQueryresponse |
|
| 241 |
+ } |
|
| 242 |
+ |
|
| 243 |
+ if queryByName {
|
|
| 244 |
+ if nw, errRsp := findNetwork(c, name, byName); errRsp.isOK() {
|
|
| 245 |
+ list = append(list, buildNetworkResource(nw)) |
|
| 246 |
+ } |
|
| 247 |
+ } else if queryByPid {
|
|
| 248 |
+ // Return all the prefix-matching networks |
|
| 249 |
+ l := func(nw libnetwork.Network) bool {
|
|
| 250 |
+ if strings.HasPrefix(nw.ID(), shortID) {
|
|
| 251 |
+ list = append(list, buildNetworkResource(nw)) |
|
| 252 |
+ } |
|
| 253 |
+ return false |
|
| 254 |
+ } |
|
| 255 |
+ c.WalkNetworks(l) |
|
| 256 |
+ } else {
|
|
| 257 |
+ for _, nw := range c.Networks() {
|
|
| 258 |
+ list = append(list, buildNetworkResource(nw)) |
|
| 259 |
+ } |
|
| 238 | 260 |
} |
| 261 |
+ |
|
| 239 | 262 |
return list, &successResponse |
| 240 | 263 |
} |
| 241 | 264 |
|
| ... | ... |
@@ -250,21 +284,12 @@ func procCreateEndpoint(c libnetwork.NetworkController, vars map[string]string, |
| 250 | 250 |
return "", &responseStatus{Status: "Invalid body: " + err.Error(), StatusCode: http.StatusBadRequest}
|
| 251 | 251 |
} |
| 252 | 252 |
|
| 253 |
- epn := vars[urlEpName] |
|
| 254 |
- if ec.Name != epn {
|
|
| 255 |
- return "", &mismatchResponse |
|
| 256 |
- } |
|
| 257 |
- |
|
| 258 | 253 |
nwT, nwBy := detectNetworkTarget(vars) |
| 259 | 254 |
n, errRsp := findNetwork(c, nwT, nwBy) |
| 260 | 255 |
if !errRsp.isOK() {
|
| 261 | 256 |
return "", errRsp |
| 262 | 257 |
} |
| 263 | 258 |
|
| 264 |
- if ec.NetworkID != n.ID() {
|
|
| 265 |
- return "", &mismatchResponse |
|
| 266 |
- } |
|
| 267 |
- |
|
| 268 | 259 |
var setFctList []libnetwork.EndpointOption |
| 269 | 260 |
if ec.ExposedPorts != nil {
|
| 270 | 261 |
setFctList = append(setFctList, libnetwork.CreateOptionExposedPorts(ec.ExposedPorts)) |
| ... | ... |
@@ -273,7 +298,7 @@ func procCreateEndpoint(c libnetwork.NetworkController, vars map[string]string, |
| 273 | 273 |
setFctList = append(setFctList, libnetwork.CreateOptionPortMapping(ec.PortMapping)) |
| 274 | 274 |
} |
| 275 | 275 |
|
| 276 |
- ep, err := n.CreateEndpoint(epn, setFctList...) |
|
| 276 |
+ ep, err := n.CreateEndpoint(ec.Name, setFctList...) |
|
| 277 | 277 |
if err != nil {
|
| 278 | 278 |
return "", convertNetworkError(err) |
| 279 | 279 |
} |
| ... | ... |
@@ -294,17 +319,40 @@ func procGetEndpoint(c libnetwork.NetworkController, vars map[string]string, bod |
| 294 | 294 |
} |
| 295 | 295 |
|
| 296 | 296 |
func procGetEndpoints(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
|
| 297 |
- target, by := detectNetworkTarget(vars) |
|
| 297 |
+ // Look for query filters and validate |
|
| 298 |
+ name, queryByName := vars[urlEpName] |
|
| 299 |
+ shortID, queryByPid := vars[urlEpPID] |
|
| 300 |
+ if queryByName && queryByPid {
|
|
| 301 |
+ return nil, &badQueryresponse |
|
| 302 |
+ } |
|
| 298 | 303 |
|
| 299 |
- nw, errRsp := findNetwork(c, target, by) |
|
| 304 |
+ nwT, nwBy := detectNetworkTarget(vars) |
|
| 305 |
+ nw, errRsp := findNetwork(c, nwT, nwBy) |
|
| 300 | 306 |
if !errRsp.isOK() {
|
| 301 | 307 |
return nil, errRsp |
| 302 | 308 |
} |
| 303 | 309 |
|
| 304 | 310 |
var list []*endpointResource |
| 305 |
- for _, ep := range nw.Endpoints() {
|
|
| 306 |
- epr := buildEndpointResource(ep) |
|
| 307 |
- list = append(list, epr) |
|
| 311 |
+ |
|
| 312 |
+ // If query parameter is specified, return a filtered collection |
|
| 313 |
+ if queryByName {
|
|
| 314 |
+ if ep, errRsp := findEndpoint(c, nwT, name, nwBy, byName); errRsp.isOK() {
|
|
| 315 |
+ list = append(list, buildEndpointResource(ep)) |
|
| 316 |
+ } |
|
| 317 |
+ } else if queryByPid {
|
|
| 318 |
+ // Return all the prefix-matching networks |
|
| 319 |
+ l := func(ep libnetwork.Endpoint) bool {
|
|
| 320 |
+ if strings.HasPrefix(ep.ID(), shortID) {
|
|
| 321 |
+ list = append(list, buildEndpointResource(ep)) |
|
| 322 |
+ } |
|
| 323 |
+ return false |
|
| 324 |
+ } |
|
| 325 |
+ nw.WalkEndpoints(l) |
|
| 326 |
+ } else {
|
|
| 327 |
+ for _, ep := range nw.Endpoints() {
|
|
| 328 |
+ epr := buildEndpointResource(ep) |
|
| 329 |
+ list = append(list, epr) |
|
| 330 |
+ } |
|
| 308 | 331 |
} |
| 309 | 332 |
|
| 310 | 333 |
return list, &successResponse |
| ... | ... |
@@ -336,11 +384,6 @@ func procJoinEndpoint(c libnetwork.NetworkController, vars map[string]string, bo |
| 336 | 336 |
return nil, &responseStatus{Status: "Invalid body: " + err.Error(), StatusCode: http.StatusBadRequest}
|
| 337 | 337 |
} |
| 338 | 338 |
|
| 339 |
- cid := vars[urlCnID] |
|
| 340 |
- if ej.ContainerID != cid {
|
|
| 341 |
- return "", &mismatchResponse |
|
| 342 |
- } |
|
| 343 |
- |
|
| 344 | 339 |
nwT, nwBy := detectNetworkTarget(vars) |
| 345 | 340 |
epT, epBy := detectEndpointTarget(vars) |
| 346 | 341 |
|
| ... | ... |
@@ -434,7 +477,7 @@ func findNetwork(c libnetwork.NetworkController, s string, by int) (libnetwork.N |
| 434 | 434 |
panic(fmt.Sprintf("unexpected selector for network search: %d", by))
|
| 435 | 435 |
} |
| 436 | 436 |
if err != nil {
|
| 437 |
- if err == libnetwork.ErrNoSuchNetwork {
|
|
| 437 |
+ if _, ok := err.(libnetwork.ErrNoSuchNetwork); ok {
|
|
| 438 | 438 |
return nil, &responseStatus{Status: "Resource not found: Network", StatusCode: http.StatusNotFound}
|
| 439 | 439 |
} |
| 440 | 440 |
return nil, &responseStatus{Status: err.Error(), StatusCode: http.StatusBadRequest}
|
| ... | ... |
@@ -460,7 +503,7 @@ func findEndpoint(c libnetwork.NetworkController, ns, es string, nwBy, epBy int) |
| 460 | 460 |
panic(fmt.Sprintf("unexpected selector for endpoint search: %d", epBy))
|
| 461 | 461 |
} |
| 462 | 462 |
if err != nil {
|
| 463 |
- if err == libnetwork.ErrNoSuchEndpoint {
|
|
| 463 |
+ if _, ok := err.(libnetwork.ErrNoSuchEndpoint); ok {
|
|
| 464 | 464 |
return nil, &responseStatus{Status: "Resource not found: Endpoint", StatusCode: http.StatusNotFound}
|
| 465 | 465 |
} |
| 466 | 466 |
return nil, &responseStatus{Status: err.Error(), StatusCode: http.StatusBadRequest}
|
| ... | ... |
@@ -469,9 +512,26 @@ func findEndpoint(c libnetwork.NetworkController, ns, es string, nwBy, epBy int) |
| 469 | 469 |
} |
| 470 | 470 |
|
| 471 | 471 |
func convertNetworkError(err error) *responseStatus {
|
| 472 |
- // No real libnetwork error => http error code conversion for now. |
|
| 473 |
- // Will came in later when new interface for libnetwork error is vailable |
|
| 474 |
- return &responseStatus{Status: err.Error(), StatusCode: http.StatusBadRequest}
|
|
| 472 |
+ var code int |
|
| 473 |
+ switch err.(type) {
|
|
| 474 |
+ case types.BadRequestError: |
|
| 475 |
+ code = http.StatusBadRequest |
|
| 476 |
+ case types.ForbiddenError: |
|
| 477 |
+ code = http.StatusForbidden |
|
| 478 |
+ case types.NotFoundError: |
|
| 479 |
+ code = http.StatusNotFound |
|
| 480 |
+ case types.TimeoutError: |
|
| 481 |
+ code = http.StatusRequestTimeout |
|
| 482 |
+ case types.NotImplementedError: |
|
| 483 |
+ code = http.StatusNotImplemented |
|
| 484 |
+ case types.NoServiceError: |
|
| 485 |
+ code = http.StatusServiceUnavailable |
|
| 486 |
+ case types.InternalError: |
|
| 487 |
+ code = http.StatusInternalServerError |
|
| 488 |
+ default: |
|
| 489 |
+ code = http.StatusInternalServerError |
|
| 490 |
+ } |
|
| 491 |
+ return &responseStatus{Status: err.Error(), StatusCode: code}
|
|
| 475 | 492 |
} |
| 476 | 493 |
|
| 477 | 494 |
func writeJSON(w http.ResponseWriter, code int, v interface{}) error {
|
| ... | ... |
@@ -16,6 +16,7 @@ import ( |
| 16 | 16 |
"github.com/docker/libnetwork/netlabel" |
| 17 | 17 |
"github.com/docker/libnetwork/netutils" |
| 18 | 18 |
"github.com/docker/libnetwork/options" |
| 19 |
+ "github.com/docker/libnetwork/types" |
|
| 19 | 20 |
) |
| 20 | 21 |
|
| 21 | 22 |
const ( |
| ... | ... |
@@ -111,7 +112,7 @@ func TestJoinOptionParser(t *testing.T) {
|
| 111 | 111 |
} |
| 112 | 112 |
|
| 113 | 113 |
func TestJson(t *testing.T) {
|
| 114 |
- nc := networkCreate{Name: "mynet", NetworkType: bridgeNetType}
|
|
| 114 |
+ nc := networkCreate{NetworkType: bridgeNetType}
|
|
| 115 | 115 |
b, err := json.Marshal(nc) |
| 116 | 116 |
if err != nil {
|
| 117 | 117 |
t.Fatal(err) |
| ... | ... |
@@ -123,26 +124,10 @@ func TestJson(t *testing.T) {
|
| 123 | 123 |
t.Fatal(err) |
| 124 | 124 |
} |
| 125 | 125 |
|
| 126 |
- if nc.Name != ncp.Name || nc.NetworkType != ncp.NetworkType {
|
|
| 126 |
+ if nc.NetworkType != ncp.NetworkType {
|
|
| 127 | 127 |
t.Fatalf("Incorrect networkCreate after json encoding/deconding: %v", ncp)
|
| 128 | 128 |
} |
| 129 | 129 |
|
| 130 |
- ec := endpointCreate{Name: "mioEp", NetworkID: "0xabcde"}
|
|
| 131 |
- b, err = json.Marshal(ec) |
|
| 132 |
- if err != nil {
|
|
| 133 |
- t.Fatal(err) |
|
| 134 |
- } |
|
| 135 |
- |
|
| 136 |
- var ecp endpointCreate |
|
| 137 |
- err = json.Unmarshal(b, &ecp) |
|
| 138 |
- if err != nil {
|
|
| 139 |
- t.Fatal(err) |
|
| 140 |
- } |
|
| 141 |
- |
|
| 142 |
- if ec.Name != ecp.Name || ec.NetworkID != ecp.NetworkID {
|
|
| 143 |
- t.Fatalf("Incorrect endpointCreate after json encoding/deconding: %v", ecp)
|
|
| 144 |
- } |
|
| 145 |
- |
|
| 146 | 130 |
jl := endpointJoin{ContainerID: "abcdef456789"}
|
| 147 | 131 |
b, err = json.Marshal(jl) |
| 148 | 132 |
if err != nil {
|
| ... | ... |
@@ -156,7 +141,7 @@ func TestJson(t *testing.T) {
|
| 156 | 156 |
} |
| 157 | 157 |
|
| 158 | 158 |
if jl.ContainerID != jld.ContainerID {
|
| 159 |
- t.Fatalf("Incorrect endpointJoin after json encoding/deconding: %v", ecp)
|
|
| 159 |
+ t.Fatalf("Incorrect endpointJoin after json encoding/deconding: %v", jld)
|
|
| 160 | 160 |
} |
| 161 | 161 |
} |
| 162 | 162 |
|
| ... | ... |
@@ -177,68 +162,55 @@ func TestCreateDeleteNetwork(t *testing.T) {
|
| 177 | 177 |
t.Fatal(err) |
| 178 | 178 |
} |
| 179 | 179 |
|
| 180 |
- goodVars := map[string]string{urlNwName: "myNet"}
|
|
| 181 |
- _, errRsp := procCreateNetwork(c, goodVars, badBody) |
|
| 180 |
+ vars := make(map[string]string) |
|
| 181 |
+ _, errRsp := procCreateNetwork(c, nil, badBody) |
|
| 182 | 182 |
if errRsp == &createdResponse {
|
| 183 | 183 |
t.Fatalf("Expected to fail but succeeded")
|
| 184 | 184 |
} |
| 185 |
+ if errRsp.StatusCode != http.StatusBadRequest {
|
|
| 186 |
+ t.Fatalf("Expected StatusBadRequest status code, got: %v", errRsp)
|
|
| 187 |
+ } |
|
| 185 | 188 |
|
| 186 |
- incompleteBody, err := json.Marshal(networkCreate{Name: "myNet"})
|
|
| 189 |
+ incompleteBody, err := json.Marshal(networkCreate{})
|
|
| 187 | 190 |
if err != nil {
|
| 188 | 191 |
t.Fatal(err) |
| 189 | 192 |
} |
| 190 | 193 |
|
| 191 |
- _, errRsp = procCreateNetwork(c, goodVars, incompleteBody) |
|
| 194 |
+ _, errRsp = procCreateNetwork(c, vars, incompleteBody) |
|
| 192 | 195 |
if errRsp == &createdResponse {
|
| 193 | 196 |
t.Fatalf("Expected to fail but succeeded")
|
| 194 | 197 |
} |
| 195 | 198 |
if errRsp.StatusCode != http.StatusBadRequest {
|
| 196 |
- t.Fatalf("Expected StatusBadRequest status code, got: %v", errRsp.StatusCode)
|
|
| 199 |
+ t.Fatalf("Expected StatusBadRequest status code, got: %v", errRsp)
|
|
| 197 | 200 |
} |
| 198 | 201 |
|
| 199 | 202 |
ops := make(map[string]interface{})
|
| 200 | 203 |
ops[netlabel.GenericData] = options.Generic{}
|
| 201 |
- nc := networkCreate{Name: "myNet", NetworkType: bridgeNetType, Options: ops}
|
|
| 204 |
+ nc := networkCreate{Name: "network_1", NetworkType: bridgeNetType, Options: ops}
|
|
| 202 | 205 |
goodBody, err := json.Marshal(nc) |
| 203 | 206 |
if err != nil {
|
| 204 | 207 |
t.Fatal(err) |
| 205 | 208 |
} |
| 206 | 209 |
|
| 207 |
- badVars := map[string]string{urlNwName: ""}
|
|
| 208 |
- _, errRsp = procCreateNetwork(c, badVars, goodBody) |
|
| 209 |
- if errRsp == &createdResponse {
|
|
| 210 |
- t.Fatalf("Expected to fail but succeeded")
|
|
| 211 |
- } |
|
| 212 |
- if errRsp.StatusCode != http.StatusBadRequest {
|
|
| 213 |
- t.Fatalf("Expected StatusBadRequest status code, got: %v", errRsp.StatusCode)
|
|
| 214 |
- } |
|
| 215 |
- |
|
| 216 |
- badVars[urlNwName] = "badNetworkName" |
|
| 217 |
- _, errRsp = procCreateNetwork(c, badVars, goodBody) |
|
| 218 |
- if errRsp == &createdResponse {
|
|
| 219 |
- t.Fatalf("Expected to fail but succeeded")
|
|
| 220 |
- } |
|
| 221 |
- if errRsp.StatusCode != http.StatusBadRequest {
|
|
| 222 |
- t.Fatalf("Expected StatusBadRequest status code, got: %v", errRsp.StatusCode)
|
|
| 223 |
- } |
|
| 224 |
- |
|
| 225 |
- _, errRsp = procCreateNetwork(c, goodVars, goodBody) |
|
| 210 |
+ _, errRsp = procCreateNetwork(c, vars, goodBody) |
|
| 226 | 211 |
if errRsp != &createdResponse {
|
| 227 | 212 |
t.Fatalf("Unexepected failure: %v", errRsp)
|
| 228 | 213 |
} |
| 229 | 214 |
|
| 230 |
- _, errRsp = procDeleteNetwork(c, badVars, nil) |
|
| 215 |
+ vars[urlNwName] = "" |
|
| 216 |
+ _, errRsp = procDeleteNetwork(c, vars, nil) |
|
| 231 | 217 |
if errRsp == &successResponse {
|
| 232 | 218 |
t.Fatalf("Expected to fail but succeeded")
|
| 233 | 219 |
} |
| 234 | 220 |
|
| 235 |
- badVars[urlNwName] = "" |
|
| 236 |
- _, errRsp = procDeleteNetwork(c, badVars, nil) |
|
| 221 |
+ vars[urlNwName] = "abc" |
|
| 222 |
+ _, errRsp = procDeleteNetwork(c, vars, nil) |
|
| 237 | 223 |
if errRsp == &successResponse {
|
| 238 | 224 |
t.Fatalf("Expected to fail but succeeded")
|
| 239 | 225 |
} |
| 240 | 226 |
|
| 241 |
- _, errRsp = procDeleteNetwork(c, goodVars, nil) |
|
| 227 |
+ vars[urlNwName] = "network_1" |
|
| 228 |
+ _, errRsp = procDeleteNetwork(c, vars, nil) |
|
| 242 | 229 |
if errRsp != &successResponse {
|
| 243 | 230 |
t.Fatalf("Unexepected failure: %v", errRsp)
|
| 244 | 231 |
} |
| ... | ... |
@@ -262,7 +234,7 @@ func TestGetNetworksAndEndpoints(t *testing.T) {
|
| 262 | 262 |
t.Fatal(err) |
| 263 | 263 |
} |
| 264 | 264 |
|
| 265 |
- vars := map[string]string{urlNwName: "sh"}
|
|
| 265 |
+ vars := make(map[string]string) |
|
| 266 | 266 |
inid, errRsp := procCreateNetwork(c, vars, body) |
| 267 | 267 |
if errRsp != &createdResponse {
|
| 268 | 268 |
t.Fatalf("Unexepected failure: %v", errRsp)
|
| ... | ... |
@@ -273,29 +245,29 @@ func TestGetNetworksAndEndpoints(t *testing.T) {
|
| 273 | 273 |
} |
| 274 | 274 |
|
| 275 | 275 |
ec1 := endpointCreate{
|
| 276 |
- Name: "ep1", |
|
| 277 |
- NetworkID: string(nid), |
|
| 278 |
- ExposedPorts: []netutils.TransportPort{
|
|
| 279 |
- netutils.TransportPort{Proto: netutils.TCP, Port: uint16(5000)},
|
|
| 280 |
- netutils.TransportPort{Proto: netutils.UDP, Port: uint16(400)},
|
|
| 281 |
- netutils.TransportPort{Proto: netutils.TCP, Port: uint16(600)},
|
|
| 276 |
+ Name: "ep1", |
|
| 277 |
+ ExposedPorts: []types.TransportPort{
|
|
| 278 |
+ types.TransportPort{Proto: types.TCP, Port: uint16(5000)},
|
|
| 279 |
+ types.TransportPort{Proto: types.UDP, Port: uint16(400)},
|
|
| 280 |
+ types.TransportPort{Proto: types.TCP, Port: uint16(600)},
|
|
| 282 | 281 |
}, |
| 283 |
- PortMapping: []netutils.PortBinding{
|
|
| 284 |
- netutils.PortBinding{Proto: netutils.TCP, Port: uint16(230), HostPort: uint16(23000)},
|
|
| 285 |
- netutils.PortBinding{Proto: netutils.UDP, Port: uint16(200), HostPort: uint16(22000)},
|
|
| 286 |
- netutils.PortBinding{Proto: netutils.TCP, Port: uint16(120), HostPort: uint16(12000)},
|
|
| 282 |
+ PortMapping: []types.PortBinding{
|
|
| 283 |
+ types.PortBinding{Proto: types.TCP, Port: uint16(230), HostPort: uint16(23000)},
|
|
| 284 |
+ types.PortBinding{Proto: types.UDP, Port: uint16(200), HostPort: uint16(22000)},
|
|
| 285 |
+ types.PortBinding{Proto: types.TCP, Port: uint16(120), HostPort: uint16(12000)},
|
|
| 287 | 286 |
}, |
| 288 | 287 |
} |
| 289 | 288 |
b1, err := json.Marshal(ec1) |
| 290 | 289 |
if err != nil {
|
| 291 | 290 |
t.Fatal(err) |
| 292 | 291 |
} |
| 293 |
- ec2 := endpointCreate{Name: "ep2", NetworkID: nid}
|
|
| 292 |
+ ec2 := endpointCreate{Name: "ep2"}
|
|
| 294 | 293 |
b2, err := json.Marshal(ec2) |
| 295 | 294 |
if err != nil {
|
| 296 | 295 |
t.Fatal(err) |
| 297 | 296 |
} |
| 298 | 297 |
|
| 298 |
+ vars[urlNwName] = "sh" |
|
| 299 | 299 |
vars[urlEpName] = "ep1" |
| 300 | 300 |
ieid1, errRsp := procCreateEndpoint(c, vars, b1) |
| 301 | 301 |
if errRsp != &createdResponse {
|
| ... | ... |
@@ -471,6 +443,7 @@ func TestGetNetworksAndEndpoints(t *testing.T) {
|
| 471 | 471 |
if errRsp != &successResponse {
|
| 472 | 472 |
t.Fatalf("Unexepected failure: %v", errRsp)
|
| 473 | 473 |
} |
| 474 |
+ delete(vars, urlEpName) |
|
| 474 | 475 |
iepList, errRsp = procGetEndpoints(c, vars, nil) |
| 475 | 476 |
if errRsp != &successResponse {
|
| 476 | 477 |
t.Fatalf("Unexepected failure: %v", errRsp)
|
| ... | ... |
@@ -509,6 +482,43 @@ func TestGetNetworksAndEndpoints(t *testing.T) {
|
| 509 | 509 |
} |
| 510 | 510 |
} |
| 511 | 511 |
|
| 512 |
+func TestDetectGetNetworksInvalidQueryComposition(t *testing.T) {
|
|
| 513 |
+ c, err := libnetwork.New() |
|
| 514 |
+ if err != nil {
|
|
| 515 |
+ t.Fatal(err) |
|
| 516 |
+ } |
|
| 517 |
+ |
|
| 518 |
+ vars := map[string]string{urlNwName: "x", urlNwPID: "y"}
|
|
| 519 |
+ _, errRsp := procGetNetworks(c, vars, nil) |
|
| 520 |
+ if errRsp.StatusCode != http.StatusBadRequest {
|
|
| 521 |
+ t.Fatalf("Expected %d. Got: %v", http.StatusBadRequest, errRsp)
|
|
| 522 |
+ } |
|
| 523 |
+} |
|
| 524 |
+ |
|
| 525 |
+func TestDetectGetEndpointsInvalidQueryComposition(t *testing.T) {
|
|
| 526 |
+ defer netutils.SetupTestNetNS(t)() |
|
| 527 |
+ |
|
| 528 |
+ c, err := libnetwork.New() |
|
| 529 |
+ if err != nil {
|
|
| 530 |
+ t.Fatal(err) |
|
| 531 |
+ } |
|
| 532 |
+ err = c.ConfigureNetworkDriver(bridgeNetType, nil) |
|
| 533 |
+ if err != nil {
|
|
| 534 |
+ t.Fatal(err) |
|
| 535 |
+ } |
|
| 536 |
+ |
|
| 537 |
+ _, err = c.NewNetwork(bridgeNetType, "network", nil) |
|
| 538 |
+ if err != nil {
|
|
| 539 |
+ t.Fatal(err) |
|
| 540 |
+ } |
|
| 541 |
+ |
|
| 542 |
+ vars := map[string]string{urlNwName: "network", urlEpName: "x", urlEpPID: "y"}
|
|
| 543 |
+ _, errRsp := procGetEndpoints(c, vars, nil) |
|
| 544 |
+ if errRsp.StatusCode != http.StatusBadRequest {
|
|
| 545 |
+ t.Fatalf("Expected %d. Got: %v", http.StatusBadRequest, errRsp)
|
|
| 546 |
+ } |
|
| 547 |
+} |
|
| 548 |
+ |
|
| 512 | 549 |
func TestFindNetworkUtil(t *testing.T) {
|
| 513 | 550 |
defer netutils.SetupTestNetNS(t)() |
| 514 | 551 |
|
| ... | ... |
@@ -603,85 +613,46 @@ func TestCreateDeleteEndpoints(t *testing.T) {
|
| 603 | 603 |
t.Fatal(err) |
| 604 | 604 |
} |
| 605 | 605 |
|
| 606 |
- vars := map[string]string{urlNwName: "firstNet"}
|
|
| 606 |
+ vars := make(map[string]string) |
|
| 607 | 607 |
i, errRsp := procCreateNetwork(c, vars, body) |
| 608 | 608 |
if errRsp != &createdResponse {
|
| 609 | 609 |
t.Fatalf("Unexepected failure: %v", errRsp)
|
| 610 | 610 |
} |
| 611 | 611 |
nid := i2s(i) |
| 612 | 612 |
|
| 613 |
- vbad, err := json.Marshal("bad endppint create data")
|
|
| 613 |
+ vbad, err := json.Marshal("bad endppoint create data")
|
|
| 614 | 614 |
if err != nil {
|
| 615 | 615 |
t.Fatal(err) |
| 616 | 616 |
} |
| 617 | 617 |
|
| 618 |
- vars[urlEpName] = "ep1" |
|
| 618 |
+ vars[urlNwName] = "firstNet" |
|
| 619 | 619 |
_, errRsp = procCreateEndpoint(c, vars, vbad) |
| 620 | 620 |
if errRsp == &createdResponse {
|
| 621 | 621 |
t.Fatalf("Expected to fail but succeeded")
|
| 622 | 622 |
} |
| 623 | 623 |
|
| 624 |
- bad, err := json.Marshal(endpointCreate{Name: "ep1", NetworkID: "123456"})
|
|
| 625 |
- if err != nil {
|
|
| 626 |
- t.Fatal(err) |
|
| 627 |
- } |
|
| 628 |
- _, errRsp = procCreateEndpoint(c, vars, bad) |
|
| 629 |
- if errRsp == &createdResponse {
|
|
| 630 |
- t.Fatalf("Expected to fail but succeeded")
|
|
| 631 |
- } |
|
| 632 |
- |
|
| 633 |
- soso, err := json.Marshal(endpointCreate{Name: "ep11", NetworkID: nid})
|
|
| 634 |
- if err != nil {
|
|
| 635 |
- t.Fatal(err) |
|
| 636 |
- } |
|
| 637 |
- _, errRsp = procCreateEndpoint(c, vars, soso) |
|
| 638 |
- if errRsp != &mismatchResponse {
|
|
| 639 |
- t.Fatalf("Expected to fail with \"mismatchResponse\", but got: %v", errRsp)
|
|
| 640 |
- } |
|
| 641 |
- |
|
| 642 |
- bla, err := json.Marshal(endpointCreate{Name: "", NetworkID: nid})
|
|
| 643 |
- if err != nil {
|
|
| 644 |
- t.Fatal(err) |
|
| 645 |
- } |
|
| 646 |
- vars[urlNwName] = "firstNet" |
|
| 647 |
- vars[urlEpName] = "" |
|
| 648 |
- _, errRsp = procCreateEndpoint(c, vars, bla) |
|
| 649 |
- if errRsp == &createdResponse {
|
|
| 650 |
- t.Fatalf("Expected to fail but succeeded: %v", errRsp)
|
|
| 651 |
- } |
|
| 652 |
- |
|
| 653 |
- b, err := json.Marshal(endpointCreate{Name: "firstEp", NetworkID: nid})
|
|
| 624 |
+ b, err := json.Marshal(endpointCreate{Name: ""})
|
|
| 654 | 625 |
if err != nil {
|
| 655 | 626 |
t.Fatal(err) |
| 656 | 627 |
} |
| 657 | 628 |
|
| 658 | 629 |
vars[urlNwName] = "secondNet" |
| 659 |
- vars[urlEpName] = "firstEp" |
|
| 660 | 630 |
_, errRsp = procCreateEndpoint(c, vars, b) |
| 661 | 631 |
if errRsp == &createdResponse {
|
| 662 | 632 |
t.Fatalf("Expected to fail but succeeded")
|
| 663 | 633 |
} |
| 664 | 634 |
|
| 665 | 635 |
vars[urlNwName] = "firstNet" |
| 666 |
- vars[urlEpName] = "ep1" |
|
| 667 |
- _, errRsp = procCreateEndpoint(c, vars, b) |
|
| 668 |
- if errRsp != &mismatchResponse {
|
|
| 669 |
- t.Fatalf("Expected to fail with \"mismatchResponse\", but got: %v", errRsp)
|
|
| 670 |
- } |
|
| 671 |
- |
|
| 672 |
- vars = make(map[string]string) |
|
| 673 | 636 |
_, errRsp = procCreateEndpoint(c, vars, b) |
| 674 | 637 |
if errRsp == &successResponse {
|
| 675 | 638 |
t.Fatalf("Expected failure but succeeded: %v", errRsp)
|
| 676 | 639 |
} |
| 677 | 640 |
|
| 678 |
- vars[urlNwName] = "firstNet" |
|
| 679 |
- _, errRsp = procCreateEndpoint(c, vars, b) |
|
| 680 |
- if errRsp == &successResponse {
|
|
| 681 |
- t.Fatalf("Expected failure but succeeded: %v", errRsp)
|
|
| 641 |
+ b, err = json.Marshal(endpointCreate{Name: "firstEp"})
|
|
| 642 |
+ if err != nil {
|
|
| 643 |
+ t.Fatal(err) |
|
| 682 | 644 |
} |
| 683 | 645 |
|
| 684 |
- vars[urlEpName] = "firstEp" |
|
| 685 | 646 |
i, errRsp = procCreateEndpoint(c, vars, b) |
| 686 | 647 |
if errRsp != &createdResponse {
|
| 687 | 648 |
t.Fatalf("Unexepected failure: %v", errRsp)
|
| ... | ... |
@@ -713,8 +684,8 @@ func TestCreateDeleteEndpoints(t *testing.T) {
|
| 713 | 713 |
t.Fatalf("Unexepected failure: %v", errRsp)
|
| 714 | 714 |
} |
| 715 | 715 |
|
| 716 |
- if ep0 != ep1 || ep0 != ep2 || ep0 != ep3 {
|
|
| 717 |
- t.Fatalf("Diffenrent queries returned different endpoints")
|
|
| 716 |
+ if ep0.ID() != ep1.ID() || ep0.ID() != ep2.ID() || ep0.ID() != ep3.ID() {
|
|
| 717 |
+ t.Fatalf("Diffenrent queries returned different endpoints: \nep0: %v\nep1: %v\nep2: %v\nep3: %v", ep0, ep1, ep2, ep3)
|
|
| 718 | 718 |
} |
| 719 | 719 |
|
| 720 | 720 |
vars = make(map[string]string) |
| ... | ... |
@@ -766,18 +737,17 @@ func TestJoinLeave(t *testing.T) {
|
| 766 | 766 |
if err != nil {
|
| 767 | 767 |
t.Fatal(err) |
| 768 | 768 |
} |
| 769 |
- vars := map[string]string{urlNwName: "network"}
|
|
| 770 |
- i, errRsp := procCreateNetwork(c, vars, nb) |
|
| 769 |
+ vars := make(map[string]string) |
|
| 770 |
+ _, errRsp := procCreateNetwork(c, vars, nb) |
|
| 771 | 771 |
if errRsp != &createdResponse {
|
| 772 | 772 |
t.Fatalf("Unexepected failure: %v", errRsp)
|
| 773 | 773 |
} |
| 774 |
- nid := i2s(i) |
|
| 775 | 774 |
|
| 776 |
- vars[urlEpName] = "epoint" |
|
| 777 |
- eb, err := json.Marshal(endpointCreate{Name: "epoint", NetworkID: nid})
|
|
| 775 |
+ eb, err := json.Marshal(endpointCreate{Name: "endpoint"})
|
|
| 778 | 776 |
if err != nil {
|
| 779 | 777 |
t.Fatal(err) |
| 780 | 778 |
} |
| 779 |
+ vars[urlNwName] = "network" |
|
| 781 | 780 |
_, errRsp = procCreateEndpoint(c, vars, eb) |
| 782 | 781 |
if errRsp != &createdResponse {
|
| 783 | 782 |
t.Fatalf("Unexepected failure: %v", errRsp)
|
| ... | ... |
@@ -792,6 +762,7 @@ func TestJoinLeave(t *testing.T) {
|
| 792 | 792 |
t.Fatalf("Expected failure, got: %v", errRsp)
|
| 793 | 793 |
} |
| 794 | 794 |
|
| 795 |
+ vars[urlEpName] = "endpoint" |
|
| 795 | 796 |
bad, err := json.Marshal(endpointJoin{})
|
| 796 | 797 |
if err != nil {
|
| 797 | 798 |
t.Fatal(err) |
| ... | ... |
@@ -811,44 +782,30 @@ func TestJoinLeave(t *testing.T) {
|
| 811 | 811 |
vars = make(map[string]string) |
| 812 | 812 |
vars[urlNwName] = "" |
| 813 | 813 |
vars[urlEpName] = "" |
| 814 |
- vars[urlCnID] = cid |
|
| 815 |
- _, errRsp = procJoinEndpoint(c, vars, jlb) |
|
| 816 |
- if errRsp == &successResponse {
|
|
| 817 |
- t.Fatalf("Expected failure, got: %v", errRsp)
|
|
| 818 |
- } |
|
| 819 |
- |
|
| 820 |
- vars[urlNwName] = "network1" |
|
| 821 |
- vars[urlEpName] = "" |
|
| 822 | 814 |
_, errRsp = procJoinEndpoint(c, vars, jlb) |
| 823 | 815 |
if errRsp == &successResponse {
|
| 824 | 816 |
t.Fatalf("Expected failure, got: %v", errRsp)
|
| 825 | 817 |
} |
| 826 | 818 |
|
| 827 | 819 |
vars[urlNwName] = "network" |
| 828 |
- vars[urlEpName] = "endpoint" |
|
| 820 |
+ vars[urlEpName] = "" |
|
| 829 | 821 |
_, errRsp = procJoinEndpoint(c, vars, jlb) |
| 830 | 822 |
if errRsp == &successResponse {
|
| 831 | 823 |
t.Fatalf("Expected failure, got: %v", errRsp)
|
| 832 | 824 |
} |
| 833 | 825 |
|
| 834 | 826 |
vars[urlEpName] = "epoint" |
| 835 |
- delete(vars, urlCnID) |
|
| 836 | 827 |
_, errRsp = procJoinEndpoint(c, vars, jlb) |
| 837 | 828 |
if errRsp == &successResponse {
|
| 838 | 829 |
t.Fatalf("Expected failure, got: %v", errRsp)
|
| 839 | 830 |
} |
| 840 | 831 |
|
| 841 |
- vars[urlCnID] = "who?" |
|
| 842 |
- _, errRsp = procJoinEndpoint(c, vars, jlb) |
|
| 843 |
- if errRsp == &successResponse {
|
|
| 844 |
- t.Fatalf("Expected failure, got: %v", errRsp)
|
|
| 845 |
- } |
|
| 846 |
- |
|
| 847 |
- vars[urlCnID] = cid |
|
| 832 |
+ vars[urlEpName] = "endpoint" |
|
| 848 | 833 |
cdi, errRsp := procJoinEndpoint(c, vars, jlb) |
| 849 | 834 |
if errRsp != &successResponse {
|
| 850 |
- t.Fatalf("Unexpected failure, got: %v", errRsp)
|
|
| 835 |
+ t.Fatalf("Expected failure, got: %v", errRsp)
|
|
| 851 | 836 |
} |
| 837 |
+ |
|
| 852 | 838 |
cd := i2c(cdi) |
| 853 | 839 |
if cd.SandboxKey == "" {
|
| 854 | 840 |
t.Fatalf("Empty sandbox key")
|
| ... | ... |
@@ -897,6 +854,7 @@ func TestJoinLeave(t *testing.T) {
|
| 897 | 897 |
} |
| 898 | 898 |
|
| 899 | 899 |
delete(vars, urlCnID) |
| 900 |
+ vars[urlEpName] = "endpoint" |
|
| 900 | 901 |
_, errRsp = procLeaveEndpoint(c, vars, jlb) |
| 901 | 902 |
if errRsp == &successResponse {
|
| 902 | 903 |
t.Fatalf("Expected failure, got: %v", errRsp)
|
| ... | ... |
@@ -1178,7 +1136,7 @@ func TestHttpHandlerUninit(t *testing.T) {
|
| 1178 | 1178 |
} |
| 1179 | 1179 |
|
| 1180 | 1180 |
rsp := newWriter() |
| 1181 |
- req, err := http.NewRequest("GET", "/networks", nil)
|
|
| 1181 |
+ req, err := http.NewRequest("GET", "/v1.19/networks", nil)
|
|
| 1182 | 1182 |
if err != nil {
|
| 1183 | 1183 |
t.Fatal(err) |
| 1184 | 1184 |
} |
| ... | ... |
@@ -1193,15 +1151,24 @@ func TestHttpHandlerUninit(t *testing.T) {
|
| 1193 | 1193 |
|
| 1194 | 1194 |
handleRequest(rsp, req) |
| 1195 | 1195 |
if rsp.statusCode != http.StatusOK {
|
| 1196 |
- t.Fatalf("Unexpectded failure: (%d): %s", rsp.statusCode, rsp.body)
|
|
| 1196 |
+ t.Fatalf("Expected (%d). Got: (%d): %s", http.StatusOK, rsp.statusCode, rsp.body)
|
|
| 1197 | 1197 |
} |
| 1198 | 1198 |
|
| 1199 |
- n, err := c.NewNetwork(bridgeNetType, "onenet", nil) |
|
| 1199 |
+ var list []*networkResource |
|
| 1200 |
+ err = json.Unmarshal(rsp.body, &list) |
|
| 1201 |
+ if err != nil {
|
|
| 1202 |
+ t.Fatal(err) |
|
| 1203 |
+ } |
|
| 1204 |
+ if len(list) != 0 {
|
|
| 1205 |
+ t.Fatalf("Expected empty list. Got %v", list)
|
|
| 1206 |
+ } |
|
| 1207 |
+ |
|
| 1208 |
+ n, err := c.NewNetwork(bridgeNetType, "didietro", nil) |
|
| 1200 | 1209 |
if err != nil {
|
| 1201 | 1210 |
t.Fatal(err) |
| 1202 | 1211 |
} |
| 1203 | 1212 |
nwr := buildNetworkResource(n) |
| 1204 |
- expected, err := json.Marshal([]networkResource{*nwr})
|
|
| 1213 |
+ expected, err := json.Marshal([]*networkResource{nwr})
|
|
| 1205 | 1214 |
if err != nil {
|
| 1206 | 1215 |
t.Fatal(err) |
| 1207 | 1216 |
} |
| ... | ... |
@@ -1229,7 +1196,7 @@ func TestHttpHandlerBadBody(t *testing.T) {
|
| 1229 | 1229 |
} |
| 1230 | 1230 |
handleRequest := NewHTTPHandler(c) |
| 1231 | 1231 |
|
| 1232 |
- req, err := http.NewRequest("POST", "/networks/name/zero-network", &localReader{beBad: true})
|
|
| 1232 |
+ req, err := http.NewRequest("POST", "/v1.19/networks", &localReader{beBad: true})
|
|
| 1233 | 1233 |
if err != nil {
|
| 1234 | 1234 |
t.Fatal(err) |
| 1235 | 1235 |
} |
| ... | ... |
@@ -1240,7 +1207,7 @@ func TestHttpHandlerBadBody(t *testing.T) {
|
| 1240 | 1240 |
|
| 1241 | 1241 |
body := []byte{}
|
| 1242 | 1242 |
lr := newLocalReader(body) |
| 1243 |
- req, err = http.NewRequest("POST", "/networks/name/zero-network", lr)
|
|
| 1243 |
+ req, err = http.NewRequest("POST", "/v1.19/networks", lr)
|
|
| 1244 | 1244 |
if err != nil {
|
| 1245 | 1245 |
t.Fatal(err) |
| 1246 | 1246 |
} |
| ... | ... |
@@ -1250,7 +1217,7 @@ func TestHttpHandlerBadBody(t *testing.T) {
|
| 1250 | 1250 |
} |
| 1251 | 1251 |
} |
| 1252 | 1252 |
|
| 1253 |
-func TestHttpHandlerGood(t *testing.T) {
|
|
| 1253 |
+func TestEndToEnd(t *testing.T) {
|
|
| 1254 | 1254 |
defer netutils.SetupTestNetNS(t)() |
| 1255 | 1255 |
|
| 1256 | 1256 |
rsp := newWriter() |
| ... | ... |
@@ -1261,14 +1228,14 @@ func TestHttpHandlerGood(t *testing.T) {
|
| 1261 | 1261 |
} |
| 1262 | 1262 |
handleRequest := NewHTTPHandler(c) |
| 1263 | 1263 |
|
| 1264 |
- nc := networkCreate{Name: "zero-network", NetworkType: bridgeNetType}
|
|
| 1264 |
+ // Create network |
|
| 1265 |
+ nc := networkCreate{Name: "network-fiftyfive", NetworkType: bridgeNetType}
|
|
| 1265 | 1266 |
body, err := json.Marshal(nc) |
| 1266 | 1267 |
if err != nil {
|
| 1267 | 1268 |
t.Fatal(err) |
| 1268 | 1269 |
} |
| 1269 |
- |
|
| 1270 | 1270 |
lr := newLocalReader(body) |
| 1271 |
- req, err := http.NewRequest("POST", "/networks/name/zero-network", lr)
|
|
| 1271 |
+ req, err := http.NewRequest("POST", "/v1.19/networks", lr)
|
|
| 1272 | 1272 |
if err != nil {
|
| 1273 | 1273 |
t.Fatal(err) |
| 1274 | 1274 |
} |
| ... | ... |
@@ -1280,13 +1247,102 @@ func TestHttpHandlerGood(t *testing.T) {
|
| 1280 | 1280 |
t.Fatalf("Empty response body")
|
| 1281 | 1281 |
} |
| 1282 | 1282 |
|
| 1283 |
- var id string |
|
| 1284 |
- err = json.Unmarshal(rsp.body, &id) |
|
| 1283 |
+ var nid string |
|
| 1284 |
+ err = json.Unmarshal(rsp.body, &nid) |
|
| 1285 |
+ if err != nil {
|
|
| 1286 |
+ t.Fatal(err) |
|
| 1287 |
+ } |
|
| 1288 |
+ |
|
| 1289 |
+ // Query networks collection |
|
| 1290 |
+ req, err = http.NewRequest("GET", "/v1.19/networks", nil)
|
|
| 1291 |
+ if err != nil {
|
|
| 1292 |
+ t.Fatal(err) |
|
| 1293 |
+ } |
|
| 1294 |
+ handleRequest(rsp, req) |
|
| 1295 |
+ if rsp.statusCode != http.StatusOK {
|
|
| 1296 |
+ t.Fatalf("Expected StatusOK. Got (%d): %s", rsp.statusCode, rsp.body)
|
|
| 1297 |
+ } |
|
| 1298 |
+ |
|
| 1299 |
+ b0 := make([]byte, len(rsp.body)) |
|
| 1300 |
+ copy(b0, rsp.body) |
|
| 1301 |
+ |
|
| 1302 |
+ req, err = http.NewRequest("GET", "/v1.19/networks?name=network-fiftyfive", nil)
|
|
| 1303 |
+ if err != nil {
|
|
| 1304 |
+ t.Fatal(err) |
|
| 1305 |
+ } |
|
| 1306 |
+ handleRequest(rsp, req) |
|
| 1307 |
+ if rsp.statusCode != http.StatusOK {
|
|
| 1308 |
+ t.Fatalf("Expected StatusOK. Got (%d): %s", rsp.statusCode, rsp.body)
|
|
| 1309 |
+ } |
|
| 1310 |
+ |
|
| 1311 |
+ if !bytes.Equal(b0, rsp.body) {
|
|
| 1312 |
+ t.Fatalf("Expected same body from GET /networks and GET /networks?name=<nw> when only network <nw> exist.")
|
|
| 1313 |
+ } |
|
| 1314 |
+ |
|
| 1315 |
+ // Query network by name |
|
| 1316 |
+ req, err = http.NewRequest("GET", "/v1.19/networks?name=culo", nil)
|
|
| 1317 |
+ if err != nil {
|
|
| 1318 |
+ t.Fatal(err) |
|
| 1319 |
+ } |
|
| 1320 |
+ handleRequest(rsp, req) |
|
| 1321 |
+ if rsp.statusCode != http.StatusOK {
|
|
| 1322 |
+ t.Fatalf("Expected StatusOK. Got (%d): %s", rsp.statusCode, rsp.body)
|
|
| 1323 |
+ } |
|
| 1324 |
+ |
|
| 1325 |
+ var list []*networkResource |
|
| 1326 |
+ err = json.Unmarshal(rsp.body, &list) |
|
| 1327 |
+ if err != nil {
|
|
| 1328 |
+ t.Fatal(err) |
|
| 1329 |
+ } |
|
| 1330 |
+ if len(list) != 0 {
|
|
| 1331 |
+ t.Fatalf("Expected empty list. Got %v", list)
|
|
| 1332 |
+ } |
|
| 1333 |
+ |
|
| 1334 |
+ req, err = http.NewRequest("GET", "/v1.19/networks?name=network-fiftyfive", nil)
|
|
| 1335 |
+ if err != nil {
|
|
| 1336 |
+ t.Fatal(err) |
|
| 1337 |
+ } |
|
| 1338 |
+ handleRequest(rsp, req) |
|
| 1339 |
+ if rsp.statusCode != http.StatusOK {
|
|
| 1340 |
+ t.Fatalf("Unexpectded failure: (%d): %s", rsp.statusCode, rsp.body)
|
|
| 1341 |
+ } |
|
| 1342 |
+ |
|
| 1343 |
+ err = json.Unmarshal(rsp.body, &list) |
|
| 1285 | 1344 |
if err != nil {
|
| 1286 | 1345 |
t.Fatal(err) |
| 1287 | 1346 |
} |
| 1347 |
+ if len(list) == 0 {
|
|
| 1348 |
+ t.Fatalf("Expected non empty list")
|
|
| 1349 |
+ } |
|
| 1350 |
+ if list[0].Name != "network-fiftyfive" || nid != list[0].ID {
|
|
| 1351 |
+ t.Fatalf("Incongruent resource found: %v", list[0])
|
|
| 1352 |
+ } |
|
| 1288 | 1353 |
|
| 1289 |
- req, err = http.NewRequest("GET", "/networks/id/"+id, nil)
|
|
| 1354 |
+ // Query network by partial id |
|
| 1355 |
+ chars := []byte(nid) |
|
| 1356 |
+ partial := string(chars[0 : len(chars)/2]) |
|
| 1357 |
+ req, err = http.NewRequest("GET", "/v1.19/networks?partial-id="+partial, nil)
|
|
| 1358 |
+ if err != nil {
|
|
| 1359 |
+ t.Fatal(err) |
|
| 1360 |
+ } |
|
| 1361 |
+ handleRequest(rsp, req) |
|
| 1362 |
+ if rsp.statusCode != http.StatusOK {
|
|
| 1363 |
+ t.Fatalf("Unexpectded failure: (%d): %s", rsp.statusCode, rsp.body)
|
|
| 1364 |
+ } |
|
| 1365 |
+ |
|
| 1366 |
+ err = json.Unmarshal(rsp.body, &list) |
|
| 1367 |
+ if err != nil {
|
|
| 1368 |
+ t.Fatal(err) |
|
| 1369 |
+ } |
|
| 1370 |
+ if len(list) == 0 {
|
|
| 1371 |
+ t.Fatalf("Expected non empty list")
|
|
| 1372 |
+ } |
|
| 1373 |
+ if list[0].Name != "network-fiftyfive" || nid != list[0].ID {
|
|
| 1374 |
+ t.Fatalf("Incongruent resource found: %v", list[0])
|
|
| 1375 |
+ } |
|
| 1376 |
+ |
|
| 1377 |
+ // Get network by id |
|
| 1378 |
+ req, err = http.NewRequest("GET", "/v1.19/networks/"+nid, nil)
|
|
| 1290 | 1379 |
if err != nil {
|
| 1291 | 1380 |
t.Fatal(err) |
| 1292 | 1381 |
} |
| ... | ... |
@@ -1300,7 +1356,211 @@ func TestHttpHandlerGood(t *testing.T) {
|
| 1300 | 1300 |
if err != nil {
|
| 1301 | 1301 |
t.Fatal(err) |
| 1302 | 1302 |
} |
| 1303 |
- if nwr.Name != "zero-network" || id != nwr.ID {
|
|
| 1304 |
- t.Fatalf("Incongruent resource found")
|
|
| 1303 |
+ if nwr.Name != "network-fiftyfive" || nid != nwr.ID {
|
|
| 1304 |
+ t.Fatalf("Incongruent resource found: %v", nwr)
|
|
| 1305 |
+ } |
|
| 1306 |
+ |
|
| 1307 |
+ // Create endpoint |
|
| 1308 |
+ eb, err := json.Marshal(endpointCreate{Name: "ep-TwentyTwo"})
|
|
| 1309 |
+ if err != nil {
|
|
| 1310 |
+ t.Fatal(err) |
|
| 1311 |
+ } |
|
| 1312 |
+ |
|
| 1313 |
+ lr = newLocalReader(eb) |
|
| 1314 |
+ req, err = http.NewRequest("POST", "/v1.19/networks/"+nid+"/endpoints", lr)
|
|
| 1315 |
+ if err != nil {
|
|
| 1316 |
+ t.Fatal(err) |
|
| 1317 |
+ } |
|
| 1318 |
+ handleRequest(rsp, req) |
|
| 1319 |
+ if rsp.statusCode != http.StatusCreated {
|
|
| 1320 |
+ t.Fatalf("Unexpectded status code. Expected (%d). Got (%d): %s.", http.StatusCreated, rsp.statusCode, string(rsp.body))
|
|
| 1321 |
+ } |
|
| 1322 |
+ if len(rsp.body) == 0 {
|
|
| 1323 |
+ t.Fatalf("Empty response body")
|
|
| 1324 |
+ } |
|
| 1325 |
+ |
|
| 1326 |
+ var eid string |
|
| 1327 |
+ err = json.Unmarshal(rsp.body, &eid) |
|
| 1328 |
+ if err != nil {
|
|
| 1329 |
+ t.Fatal(err) |
|
| 1330 |
+ } |
|
| 1331 |
+ |
|
| 1332 |
+ // Query endpoint(s) |
|
| 1333 |
+ req, err = http.NewRequest("GET", "/v1.19/networks/"+nid+"/endpoints", nil)
|
|
| 1334 |
+ if err != nil {
|
|
| 1335 |
+ t.Fatal(err) |
|
| 1336 |
+ } |
|
| 1337 |
+ handleRequest(rsp, req) |
|
| 1338 |
+ if rsp.statusCode != http.StatusOK {
|
|
| 1339 |
+ t.Fatalf("Expected StatusOK. Got (%d): %s", rsp.statusCode, rsp.body)
|
|
| 1340 |
+ } |
|
| 1341 |
+ |
|
| 1342 |
+ req, err = http.NewRequest("GET", "/v1.19/networks/"+nid+"/endpoints?name=bla", nil)
|
|
| 1343 |
+ if err != nil {
|
|
| 1344 |
+ t.Fatal(err) |
|
| 1345 |
+ } |
|
| 1346 |
+ handleRequest(rsp, req) |
|
| 1347 |
+ if rsp.statusCode != http.StatusOK {
|
|
| 1348 |
+ t.Fatalf("Unexpectded failure: (%d): %s", rsp.statusCode, rsp.body)
|
|
| 1349 |
+ } |
|
| 1350 |
+ var epList []*endpointResource |
|
| 1351 |
+ err = json.Unmarshal(rsp.body, &epList) |
|
| 1352 |
+ if err != nil {
|
|
| 1353 |
+ t.Fatal(err) |
|
| 1354 |
+ } |
|
| 1355 |
+ if len(epList) != 0 {
|
|
| 1356 |
+ t.Fatalf("Expected empty list. Got %v", epList)
|
|
| 1357 |
+ } |
|
| 1358 |
+ |
|
| 1359 |
+ // Query endpoint by name |
|
| 1360 |
+ req, err = http.NewRequest("GET", "/v1.19/networks/"+nid+"/endpoints?name=ep-TwentyTwo", nil)
|
|
| 1361 |
+ if err != nil {
|
|
| 1362 |
+ t.Fatal(err) |
|
| 1363 |
+ } |
|
| 1364 |
+ handleRequest(rsp, req) |
|
| 1365 |
+ if rsp.statusCode != http.StatusOK {
|
|
| 1366 |
+ t.Fatalf("Unexpectded failure: (%d): %s", rsp.statusCode, rsp.body)
|
|
| 1367 |
+ } |
|
| 1368 |
+ |
|
| 1369 |
+ err = json.Unmarshal(rsp.body, &epList) |
|
| 1370 |
+ if err != nil {
|
|
| 1371 |
+ t.Fatal(err) |
|
| 1372 |
+ } |
|
| 1373 |
+ if len(epList) == 0 {
|
|
| 1374 |
+ t.Fatalf("Empty response body")
|
|
| 1375 |
+ } |
|
| 1376 |
+ if epList[0].Name != "ep-TwentyTwo" || eid != epList[0].ID {
|
|
| 1377 |
+ t.Fatalf("Incongruent resource found: %v", epList[0])
|
|
| 1378 |
+ } |
|
| 1379 |
+ |
|
| 1380 |
+ // Query endpoint by partial id |
|
| 1381 |
+ chars = []byte(eid) |
|
| 1382 |
+ partial = string(chars[0 : len(chars)/2]) |
|
| 1383 |
+ req, err = http.NewRequest("GET", "/v1.19/networks/"+nid+"/endpoints?partial-id="+partial, nil)
|
|
| 1384 |
+ if err != nil {
|
|
| 1385 |
+ t.Fatal(err) |
|
| 1386 |
+ } |
|
| 1387 |
+ handleRequest(rsp, req) |
|
| 1388 |
+ if rsp.statusCode != http.StatusOK {
|
|
| 1389 |
+ t.Fatalf("Unexpectded failure: (%d): %s", rsp.statusCode, rsp.body)
|
|
| 1390 |
+ } |
|
| 1391 |
+ |
|
| 1392 |
+ err = json.Unmarshal(rsp.body, &epList) |
|
| 1393 |
+ if err != nil {
|
|
| 1394 |
+ t.Fatal(err) |
|
| 1395 |
+ } |
|
| 1396 |
+ if len(epList) == 0 {
|
|
| 1397 |
+ t.Fatalf("Empty response body")
|
|
| 1398 |
+ } |
|
| 1399 |
+ if epList[0].Name != "ep-TwentyTwo" || eid != epList[0].ID {
|
|
| 1400 |
+ t.Fatalf("Incongruent resource found: %v", epList[0])
|
|
| 1401 |
+ } |
|
| 1402 |
+ |
|
| 1403 |
+ // Get endpoint by id |
|
| 1404 |
+ req, err = http.NewRequest("GET", "/v1.19/networks/"+nid+"/endpoints/"+eid, nil)
|
|
| 1405 |
+ if err != nil {
|
|
| 1406 |
+ t.Fatal(err) |
|
| 1407 |
+ } |
|
| 1408 |
+ handleRequest(rsp, req) |
|
| 1409 |
+ if rsp.statusCode != http.StatusOK {
|
|
| 1410 |
+ t.Fatalf("Unexpectded failure: (%d): %s", rsp.statusCode, rsp.body)
|
|
| 1411 |
+ } |
|
| 1412 |
+ |
|
| 1413 |
+ var epr endpointResource |
|
| 1414 |
+ err = json.Unmarshal(rsp.body, &epr) |
|
| 1415 |
+ if err != nil {
|
|
| 1416 |
+ t.Fatal(err) |
|
| 1417 |
+ } |
|
| 1418 |
+ if epr.Name != "ep-TwentyTwo" || epr.ID != eid {
|
|
| 1419 |
+ t.Fatalf("Incongruent resource found: %v", epr)
|
|
| 1420 |
+ } |
|
| 1421 |
+} |
|
| 1422 |
+ |
|
| 1423 |
+type bre struct{}
|
|
| 1424 |
+ |
|
| 1425 |
+func (b *bre) Error() string {
|
|
| 1426 |
+ return "I am a bad request error" |
|
| 1427 |
+} |
|
| 1428 |
+func (b *bre) BadRequest() {}
|
|
| 1429 |
+ |
|
| 1430 |
+type nfe struct{}
|
|
| 1431 |
+ |
|
| 1432 |
+func (n *nfe) Error() string {
|
|
| 1433 |
+ return "I am a not found error" |
|
| 1434 |
+} |
|
| 1435 |
+func (n *nfe) NotFound() {}
|
|
| 1436 |
+ |
|
| 1437 |
+type forb struct{}
|
|
| 1438 |
+ |
|
| 1439 |
+func (f *forb) Error() string {
|
|
| 1440 |
+ return "I am a bad request error" |
|
| 1441 |
+} |
|
| 1442 |
+func (f *forb) Forbidden() {}
|
|
| 1443 |
+ |
|
| 1444 |
+type notimpl struct{}
|
|
| 1445 |
+ |
|
| 1446 |
+func (nip *notimpl) Error() string {
|
|
| 1447 |
+ return "I am a not implemented error" |
|
| 1448 |
+} |
|
| 1449 |
+func (nip *notimpl) NotImplemented() {}
|
|
| 1450 |
+ |
|
| 1451 |
+type inter struct{}
|
|
| 1452 |
+ |
|
| 1453 |
+func (it *inter) Error() string {
|
|
| 1454 |
+ return "I am a internal error" |
|
| 1455 |
+} |
|
| 1456 |
+func (it *inter) Internal() {}
|
|
| 1457 |
+ |
|
| 1458 |
+type tout struct{}
|
|
| 1459 |
+ |
|
| 1460 |
+func (to *tout) Error() string {
|
|
| 1461 |
+ return "I am a timeout error" |
|
| 1462 |
+} |
|
| 1463 |
+func (to *tout) Timeout() {}
|
|
| 1464 |
+ |
|
| 1465 |
+type noserv struct{}
|
|
| 1466 |
+ |
|
| 1467 |
+func (nos *noserv) Error() string {
|
|
| 1468 |
+ return "I am a no service error" |
|
| 1469 |
+} |
|
| 1470 |
+func (nos *noserv) NoService() {}
|
|
| 1471 |
+ |
|
| 1472 |
+type notclassified struct{}
|
|
| 1473 |
+ |
|
| 1474 |
+func (noc *notclassified) Error() string {
|
|
| 1475 |
+ return "I am a non classified error" |
|
| 1476 |
+} |
|
| 1477 |
+ |
|
| 1478 |
+func TestErrorConversion(t *testing.T) {
|
|
| 1479 |
+ if convertNetworkError(new(bre)).StatusCode != http.StatusBadRequest {
|
|
| 1480 |
+ t.Fatalf("Failed to recognize BadRequest error")
|
|
| 1481 |
+ } |
|
| 1482 |
+ |
|
| 1483 |
+ if convertNetworkError(new(nfe)).StatusCode != http.StatusNotFound {
|
|
| 1484 |
+ t.Fatalf("Failed to recognize NotFound error")
|
|
| 1485 |
+ } |
|
| 1486 |
+ |
|
| 1487 |
+ if convertNetworkError(new(forb)).StatusCode != http.StatusForbidden {
|
|
| 1488 |
+ t.Fatalf("Failed to recognize Forbidden error")
|
|
| 1489 |
+ } |
|
| 1490 |
+ |
|
| 1491 |
+ if convertNetworkError(new(notimpl)).StatusCode != http.StatusNotImplemented {
|
|
| 1492 |
+ t.Fatalf("Failed to recognize NotImplemented error")
|
|
| 1493 |
+ } |
|
| 1494 |
+ |
|
| 1495 |
+ if convertNetworkError(new(inter)).StatusCode != http.StatusInternalServerError {
|
|
| 1496 |
+ t.Fatalf("Failed to recognize Internal error")
|
|
| 1497 |
+ } |
|
| 1498 |
+ |
|
| 1499 |
+ if convertNetworkError(new(tout)).StatusCode != http.StatusRequestTimeout {
|
|
| 1500 |
+ t.Fatalf("Failed to recognize Timeout error")
|
|
| 1501 |
+ } |
|
| 1502 |
+ |
|
| 1503 |
+ if convertNetworkError(new(noserv)).StatusCode != http.StatusServiceUnavailable {
|
|
| 1504 |
+ t.Fatalf("Failed to recognize No Service error")
|
|
| 1505 |
+ } |
|
| 1506 |
+ |
|
| 1507 |
+ if convertNetworkError(new(notclassified)).StatusCode != http.StatusInternalServerError {
|
|
| 1508 |
+ t.Fatalf("Failed to recognize not classified error as Internal error")
|
|
| 1305 | 1509 |
} |
| 1306 | 1510 |
} |
| ... | ... |
@@ -1,6 +1,6 @@ |
| 1 | 1 |
package api |
| 2 | 2 |
|
| 3 |
-import "github.com/docker/libnetwork/netutils" |
|
| 3 |
+import "github.com/docker/libnetwork/types" |
|
| 4 | 4 |
|
| 5 | 5 |
/*********** |
| 6 | 6 |
Resources |
| ... | ... |
@@ -35,9 +35,8 @@ type networkCreate struct {
|
| 35 | 35 |
// endpointCreate represents the body of the "create endpoint" http request message |
| 36 | 36 |
type endpointCreate struct {
|
| 37 | 37 |
Name string |
| 38 |
- NetworkID string |
|
| 39 |
- ExposedPorts []netutils.TransportPort |
|
| 40 |
- PortMapping []netutils.PortBinding |
|
| 38 |
+ ExposedPorts []types.TransportPort |
|
| 39 |
+ PortMapping []types.PortBinding |
|
| 41 | 40 |
} |
| 42 | 41 |
|
| 43 | 42 |
// endpointJoin represents the expected body of the "join endpoint" or "leave endpoint" http request messages |
| ... | ... |
@@ -49,6 +49,12 @@ func (cli *NetworkCli) getMethod(args ...string) (func(string, ...string) error, |
| 49 | 49 |
// Cmd is borrowed from Docker UI and acts as the entry point for network UI commands. |
| 50 | 50 |
// network UI commands are designed to be invoked from multiple parent chains |
| 51 | 51 |
func (cli *NetworkCli) Cmd(chain string, args ...string) error {
|
| 52 |
+ if len(args) > 2 {
|
|
| 53 |
+ method, exists := cli.getMethod(args[:3]...) |
|
| 54 |
+ if exists {
|
|
| 55 |
+ return method(chain+" "+args[0]+" "+args[1], args[3:]...) |
|
| 56 |
+ } |
|
| 57 |
+ } |
|
| 52 | 58 |
if len(args) > 1 {
|
| 53 | 59 |
method, exists := cli.getMethod(args[:2]...) |
| 54 | 60 |
if exists {
|
| 55 | 61 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,124 @@ |
| 0 |
+// +build experimental |
|
| 1 |
+ |
|
| 2 |
+package client |
|
| 3 |
+ |
|
| 4 |
+import ( |
|
| 5 |
+ "bytes" |
|
| 6 |
+ "testing" |
|
| 7 |
+ |
|
| 8 |
+ _ "github.com/docker/libnetwork/netutils" |
|
| 9 |
+) |
|
| 10 |
+ |
|
| 11 |
+func TestClientNetworkServiceInvalidCommand(t *testing.T) {
|
|
| 12 |
+ var out, errOut bytes.Buffer |
|
| 13 |
+ cli := NewNetworkCli(&out, &errOut, callbackFunc) |
|
| 14 |
+ |
|
| 15 |
+ err := cli.Cmd("docker", "network", "service", "invalid")
|
|
| 16 |
+ if err == nil {
|
|
| 17 |
+ t.Fatalf("Passing invalid commands must fail")
|
|
| 18 |
+ } |
|
| 19 |
+} |
|
| 20 |
+ |
|
| 21 |
+func TestClientNetworkServiceCreate(t *testing.T) {
|
|
| 22 |
+ var out, errOut bytes.Buffer |
|
| 23 |
+ cli := NewNetworkCli(&out, &errOut, callbackFunc) |
|
| 24 |
+ |
|
| 25 |
+ err := cli.Cmd("docker", "network", "service", "create", mockServiceName, mockNwName)
|
|
| 26 |
+ if err != nil {
|
|
| 27 |
+ t.Fatal(err.Error()) |
|
| 28 |
+ } |
|
| 29 |
+} |
|
| 30 |
+ |
|
| 31 |
+func TestClientNetworkServiceRm(t *testing.T) {
|
|
| 32 |
+ var out, errOut bytes.Buffer |
|
| 33 |
+ cli := NewNetworkCli(&out, &errOut, callbackFunc) |
|
| 34 |
+ |
|
| 35 |
+ err := cli.Cmd("docker", "network", "service", "rm", mockServiceName, mockNwName)
|
|
| 36 |
+ if err != nil {
|
|
| 37 |
+ t.Fatal(err.Error()) |
|
| 38 |
+ } |
|
| 39 |
+} |
|
| 40 |
+ |
|
| 41 |
+func TestClientNetworkServiceLs(t *testing.T) {
|
|
| 42 |
+ var out, errOut bytes.Buffer |
|
| 43 |
+ cli := NewNetworkCli(&out, &errOut, callbackFunc) |
|
| 44 |
+ |
|
| 45 |
+ err := cli.Cmd("docker", "network", "service", "ls", mockNwName)
|
|
| 46 |
+ if err != nil {
|
|
| 47 |
+ t.Fatal(err.Error()) |
|
| 48 |
+ } |
|
| 49 |
+} |
|
| 50 |
+ |
|
| 51 |
+func TestClientNetworkServiceInfo(t *testing.T) {
|
|
| 52 |
+ var out, errOut bytes.Buffer |
|
| 53 |
+ cli := NewNetworkCli(&out, &errOut, callbackFunc) |
|
| 54 |
+ |
|
| 55 |
+ err := cli.Cmd("docker", "network", "service", "info", mockServiceName, mockNwName)
|
|
| 56 |
+ if err != nil {
|
|
| 57 |
+ t.Fatal(err.Error()) |
|
| 58 |
+ } |
|
| 59 |
+} |
|
| 60 |
+ |
|
| 61 |
+func TestClientNetworkServiceInfoById(t *testing.T) {
|
|
| 62 |
+ var out, errOut bytes.Buffer |
|
| 63 |
+ cli := NewNetworkCli(&out, &errOut, callbackFunc) |
|
| 64 |
+ |
|
| 65 |
+ err := cli.Cmd("docker", "network", "service", "info", mockServiceID, mockNwID)
|
|
| 66 |
+ if err != nil {
|
|
| 67 |
+ t.Fatal(err.Error()) |
|
| 68 |
+ } |
|
| 69 |
+} |
|
| 70 |
+ |
|
| 71 |
+func TestClientNetworkServiceJoin(t *testing.T) {
|
|
| 72 |
+ var out, errOut bytes.Buffer |
|
| 73 |
+ cli := NewNetworkCli(&out, &errOut, callbackFunc) |
|
| 74 |
+ |
|
| 75 |
+ err := cli.Cmd("docker", "network", "service", "join", mockContainerID, mockServiceName, mockNwName)
|
|
| 76 |
+ if err != nil {
|
|
| 77 |
+ t.Fatal(err.Error()) |
|
| 78 |
+ } |
|
| 79 |
+} |
|
| 80 |
+ |
|
| 81 |
+func TestClientNetworkServiceLeave(t *testing.T) {
|
|
| 82 |
+ var out, errOut bytes.Buffer |
|
| 83 |
+ cli := NewNetworkCli(&out, &errOut, callbackFunc) |
|
| 84 |
+ |
|
| 85 |
+ err := cli.Cmd("docker", "network", "service", "leave", mockContainerID, mockServiceName, mockNwName)
|
|
| 86 |
+ if err != nil {
|
|
| 87 |
+ t.Fatal(err.Error()) |
|
| 88 |
+ } |
|
| 89 |
+} |
|
| 90 |
+ |
|
| 91 |
+// Docker Flag processing in flag.go uses os.Exit() frequently, even for --help |
|
| 92 |
+// TODO : Handle the --help test-case in the IT when CLI is available |
|
| 93 |
+/* |
|
| 94 |
+func TestClientNetworkServiceCreateHelp(t *testing.T) {
|
|
| 95 |
+ var out, errOut bytes.Buffer |
|
| 96 |
+ cFunc := func(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, int, error) {
|
|
| 97 |
+ return nil, 0, nil |
|
| 98 |
+ } |
|
| 99 |
+ cli := NewNetworkCli(&out, &errOut, callbackFunc) |
|
| 100 |
+ |
|
| 101 |
+ err := cli.Cmd("docker", "network", "create", "--help")
|
|
| 102 |
+ if err != nil {
|
|
| 103 |
+ t.Fatalf(err.Error()) |
|
| 104 |
+ } |
|
| 105 |
+} |
|
| 106 |
+*/ |
|
| 107 |
+ |
|
| 108 |
+// Docker flag processing in flag.go uses os.Exit(1) for incorrect parameter case. |
|
| 109 |
+// TODO : Handle the missing argument case in the IT when CLI is available |
|
| 110 |
+/* |
|
| 111 |
+func TestClientNetworkServiceCreateMissingArgument(t *testing.T) {
|
|
| 112 |
+ var out, errOut bytes.Buffer |
|
| 113 |
+ cFunc := func(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, int, error) {
|
|
| 114 |
+ return nil, 0, nil |
|
| 115 |
+ } |
|
| 116 |
+ cli := NewNetworkCli(&out, &errOut, callbackFunc) |
|
| 117 |
+ |
|
| 118 |
+ err := cli.Cmd("docker", "network", "create")
|
|
| 119 |
+ if err != nil {
|
|
| 120 |
+ t.Fatal(err.Error()) |
|
| 121 |
+ } |
|
| 122 |
+} |
|
| 123 |
+*/ |
| ... | ... |
@@ -2,7 +2,11 @@ package client |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 | 4 |
"bytes" |
| 5 |
+ "encoding/json" |
|
| 6 |
+ "fmt" |
|
| 5 | 7 |
"io" |
| 8 |
+ "os" |
|
| 9 |
+ "strings" |
|
| 6 | 10 |
"testing" |
| 7 | 11 |
|
| 8 | 12 |
_ "github.com/docker/libnetwork/netutils" |
| ... | ... |
@@ -15,12 +19,82 @@ type nopCloser struct {
|
| 15 | 15 |
|
| 16 | 16 |
func (nopCloser) Close() error { return nil }
|
| 17 | 17 |
|
| 18 |
+func TestMain(m *testing.M) {
|
|
| 19 |
+ setupMockHTTPCallback() |
|
| 20 |
+ os.Exit(m.Run()) |
|
| 21 |
+} |
|
| 22 |
+ |
|
| 23 |
+var callbackFunc func(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, int, error)
|
|
| 24 |
+var mockNwJSON, mockNwListJSON, mockServiceJSON, mockServiceListJSON []byte |
|
| 25 |
+var mockNwName = "test" |
|
| 26 |
+var mockNwID = "2a3456789" |
|
| 27 |
+var mockServiceName = "testSrv" |
|
| 28 |
+var mockServiceID = "2a3456789" |
|
| 29 |
+var mockContainerID = "2a3456789" |
|
| 30 |
+ |
|
| 31 |
+func setupMockHTTPCallback() {
|
|
| 32 |
+ var list []networkResource |
|
| 33 |
+ nw := networkResource{Name: mockNwName, ID: mockNwID}
|
|
| 34 |
+ mockNwJSON, _ = json.Marshal(nw) |
|
| 35 |
+ list = append(list, nw) |
|
| 36 |
+ mockNwListJSON, _ = json.Marshal(list) |
|
| 37 |
+ |
|
| 38 |
+ var srvList []endpointResource |
|
| 39 |
+ ep := endpointResource{Name: mockServiceName, ID: mockServiceID, Network: mockNwName}
|
|
| 40 |
+ mockServiceJSON, _ = json.Marshal(ep) |
|
| 41 |
+ srvList = append(srvList, ep) |
|
| 42 |
+ mockServiceListJSON, _ = json.Marshal(srvList) |
|
| 43 |
+ |
|
| 44 |
+ callbackFunc = func(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, int, error) {
|
|
| 45 |
+ var rsp string |
|
| 46 |
+ switch method {
|
|
| 47 |
+ case "GET": |
|
| 48 |
+ if strings.Contains(path, fmt.Sprintf("networks?name=%s", mockNwName)) {
|
|
| 49 |
+ rsp = string(mockNwListJSON) |
|
| 50 |
+ } else if strings.Contains(path, "networks?name=") {
|
|
| 51 |
+ rsp = "[]" |
|
| 52 |
+ } else if strings.Contains(path, fmt.Sprintf("networks?partial-id=%s", mockNwID)) {
|
|
| 53 |
+ rsp = string(mockNwListJSON) |
|
| 54 |
+ } else if strings.Contains(path, "networks?partial-id=") {
|
|
| 55 |
+ rsp = "[]" |
|
| 56 |
+ } else if strings.HasSuffix(path, "networks") {
|
|
| 57 |
+ rsp = string(mockNwListJSON) |
|
| 58 |
+ } else if strings.HasSuffix(path, "networks/"+mockNwID) {
|
|
| 59 |
+ rsp = string(mockNwJSON) |
|
| 60 |
+ } else if strings.Contains(path, fmt.Sprintf("endpoints?name=%s", mockServiceName)) {
|
|
| 61 |
+ rsp = string(mockServiceListJSON) |
|
| 62 |
+ } else if strings.Contains(path, "endpoints?name=") {
|
|
| 63 |
+ rsp = "[]" |
|
| 64 |
+ } else if strings.Contains(path, fmt.Sprintf("endpoints?partial-id=%s", mockServiceID)) {
|
|
| 65 |
+ rsp = string(mockServiceListJSON) |
|
| 66 |
+ } else if strings.Contains(path, "endpoints?partial-id=") {
|
|
| 67 |
+ rsp = "[]" |
|
| 68 |
+ } else if strings.HasSuffix(path, "endpoints") {
|
|
| 69 |
+ rsp = string(mockServiceListJSON) |
|
| 70 |
+ } else if strings.HasSuffix(path, "endpoints/"+mockServiceID) {
|
|
| 71 |
+ rsp = string(mockServiceJSON) |
|
| 72 |
+ } |
|
| 73 |
+ case "POST": |
|
| 74 |
+ var data []byte |
|
| 75 |
+ if strings.HasSuffix(path, "networks") {
|
|
| 76 |
+ data, _ = json.Marshal(mockNwID) |
|
| 77 |
+ } else if strings.HasSuffix(path, "endpoints") {
|
|
| 78 |
+ data, _ = json.Marshal(mockServiceID) |
|
| 79 |
+ } else if strings.HasSuffix(path, "containers") {
|
|
| 80 |
+ data, _ = json.Marshal(mockContainerID) |
|
| 81 |
+ } |
|
| 82 |
+ rsp = string(data) |
|
| 83 |
+ case "PUT": |
|
| 84 |
+ case "DELETE": |
|
| 85 |
+ rsp = "" |
|
| 86 |
+ } |
|
| 87 |
+ return nopCloser{bytes.NewBufferString(rsp)}, 200, nil
|
|
| 88 |
+ } |
|
| 89 |
+} |
|
| 90 |
+ |
|
| 18 | 91 |
func TestClientDummyCommand(t *testing.T) {
|
| 19 | 92 |
var out, errOut bytes.Buffer |
| 20 |
- cFunc := func(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, int, error) {
|
|
| 21 |
- return nopCloser{bytes.NewBufferString("")}, 200, nil
|
|
| 22 |
- } |
|
| 23 |
- cli := NewNetworkCli(&out, &errOut, cFunc) |
|
| 93 |
+ cli := NewNetworkCli(&out, &errOut, callbackFunc) |
|
| 24 | 94 |
|
| 25 | 95 |
err := cli.Cmd("docker", "dummy")
|
| 26 | 96 |
if err == nil {
|
| ... | ... |
@@ -30,10 +104,7 @@ func TestClientDummyCommand(t *testing.T) {
|
| 30 | 30 |
|
| 31 | 31 |
func TestClientNetworkInvalidCommand(t *testing.T) {
|
| 32 | 32 |
var out, errOut bytes.Buffer |
| 33 |
- cFunc := func(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, int, error) {
|
|
| 34 |
- return nopCloser{bytes.NewBufferString("")}, 200, nil
|
|
| 35 |
- } |
|
| 36 |
- cli := NewNetworkCli(&out, &errOut, cFunc) |
|
| 33 |
+ cli := NewNetworkCli(&out, &errOut, callbackFunc) |
|
| 37 | 34 |
|
| 38 | 35 |
err := cli.Cmd("docker", "network", "invalid")
|
| 39 | 36 |
if err == nil {
|
| ... | ... |
@@ -43,12 +114,9 @@ func TestClientNetworkInvalidCommand(t *testing.T) {
|
| 43 | 43 |
|
| 44 | 44 |
func TestClientNetworkCreate(t *testing.T) {
|
| 45 | 45 |
var out, errOut bytes.Buffer |
| 46 |
- cFunc := func(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, int, error) {
|
|
| 47 |
- return nopCloser{bytes.NewBufferString("")}, 200, nil
|
|
| 48 |
- } |
|
| 49 |
- cli := NewNetworkCli(&out, &errOut, cFunc) |
|
| 46 |
+ cli := NewNetworkCli(&out, &errOut, callbackFunc) |
|
| 50 | 47 |
|
| 51 |
- err := cli.Cmd("docker", "network", "create", "test")
|
|
| 48 |
+ err := cli.Cmd("docker", "network", "create", mockNwName)
|
|
| 52 | 49 |
if err != nil {
|
| 53 | 50 |
t.Fatal(err.Error()) |
| 54 | 51 |
} |
| ... | ... |
@@ -56,17 +124,14 @@ func TestClientNetworkCreate(t *testing.T) {
|
| 56 | 56 |
|
| 57 | 57 |
func TestClientNetworkCreateWithDriver(t *testing.T) {
|
| 58 | 58 |
var out, errOut bytes.Buffer |
| 59 |
- cFunc := func(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, int, error) {
|
|
| 60 |
- return nopCloser{bytes.NewBufferString("")}, 200, nil
|
|
| 61 |
- } |
|
| 62 |
- cli := NewNetworkCli(&out, &errOut, cFunc) |
|
| 59 |
+ cli := NewNetworkCli(&out, &errOut, callbackFunc) |
|
| 63 | 60 |
|
| 64 |
- err := cli.Cmd("docker", "network", "create", "-f=dummy", "test")
|
|
| 61 |
+ err := cli.Cmd("docker", "network", "create", "-f=dummy", mockNwName)
|
|
| 65 | 62 |
if err == nil {
|
| 66 | 63 |
t.Fatalf("Passing incorrect flags to the create command must fail")
|
| 67 | 64 |
} |
| 68 | 65 |
|
| 69 |
- err = cli.Cmd("docker", "network", "create", "-d=dummy", "test")
|
|
| 66 |
+ err = cli.Cmd("docker", "network", "create", "-d=dummy", mockNwName)
|
|
| 70 | 67 |
if err != nil {
|
| 71 | 68 |
t.Fatalf(err.Error()) |
| 72 | 69 |
} |
| ... | ... |
@@ -74,12 +139,9 @@ func TestClientNetworkCreateWithDriver(t *testing.T) {
|
| 74 | 74 |
|
| 75 | 75 |
func TestClientNetworkRm(t *testing.T) {
|
| 76 | 76 |
var out, errOut bytes.Buffer |
| 77 |
- cFunc := func(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, int, error) {
|
|
| 78 |
- return nopCloser{bytes.NewBufferString("")}, 200, nil
|
|
| 79 |
- } |
|
| 80 |
- cli := NewNetworkCli(&out, &errOut, cFunc) |
|
| 77 |
+ cli := NewNetworkCli(&out, &errOut, callbackFunc) |
|
| 81 | 78 |
|
| 82 |
- err := cli.Cmd("docker", "network", "rm", "test")
|
|
| 79 |
+ err := cli.Cmd("docker", "network", "rm", mockNwName)
|
|
| 83 | 80 |
if err != nil {
|
| 84 | 81 |
t.Fatal(err.Error()) |
| 85 | 82 |
} |
| ... | ... |
@@ -87,47 +149,43 @@ func TestClientNetworkRm(t *testing.T) {
|
| 87 | 87 |
|
| 88 | 88 |
func TestClientNetworkLs(t *testing.T) {
|
| 89 | 89 |
var out, errOut bytes.Buffer |
| 90 |
- networks := "db,web,test" |
|
| 91 |
- cFunc := func(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, int, error) {
|
|
| 92 |
- return nopCloser{bytes.NewBufferString(networks)}, 200, nil
|
|
| 93 |
- } |
|
| 94 |
- cli := NewNetworkCli(&out, &errOut, cFunc) |
|
| 90 |
+ cli := NewNetworkCli(&out, &errOut, callbackFunc) |
|
| 95 | 91 |
|
| 96 | 92 |
err := cli.Cmd("docker", "network", "ls")
|
| 97 | 93 |
if err != nil {
|
| 98 | 94 |
t.Fatal(err.Error()) |
| 99 | 95 |
} |
| 100 |
- if out.String() != networks {
|
|
| 101 |
- t.Fatal("Network List command fail to return the intended list")
|
|
| 102 |
- } |
|
| 103 | 96 |
} |
| 104 | 97 |
|
| 105 | 98 |
func TestClientNetworkInfo(t *testing.T) {
|
| 106 | 99 |
var out, errOut bytes.Buffer |
| 107 |
- info := "dummy info" |
|
| 108 |
- cFunc := func(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, int, error) {
|
|
| 109 |
- return nopCloser{bytes.NewBufferString(info)}, 200, nil
|
|
| 110 |
- } |
|
| 111 |
- cli := NewNetworkCli(&out, &errOut, cFunc) |
|
| 100 |
+ cli := NewNetworkCli(&out, &errOut, callbackFunc) |
|
| 112 | 101 |
|
| 113 |
- err := cli.Cmd("docker", "network", "info", "test")
|
|
| 102 |
+ err := cli.Cmd("docker", "network", "info", mockNwName)
|
|
| 114 | 103 |
if err != nil {
|
| 115 | 104 |
t.Fatal(err.Error()) |
| 116 | 105 |
} |
| 117 |
- if out.String() != info {
|
|
| 118 |
- t.Fatal("Network List command fail to return the intended list")
|
|
| 106 |
+} |
|
| 107 |
+ |
|
| 108 |
+func TestClientNetworkInfoById(t *testing.T) {
|
|
| 109 |
+ var out, errOut bytes.Buffer |
|
| 110 |
+ cli := NewNetworkCli(&out, &errOut, callbackFunc) |
|
| 111 |
+ |
|
| 112 |
+ err := cli.Cmd("docker", "network", "info", mockNwID)
|
|
| 113 |
+ if err != nil {
|
|
| 114 |
+ t.Fatal(err.Error()) |
|
| 119 | 115 |
} |
| 120 | 116 |
} |
| 121 | 117 |
|
| 122 | 118 |
// Docker Flag processing in flag.go uses os.Exit() frequently, even for --help |
| 123 | 119 |
// TODO : Handle the --help test-case in the IT when CLI is available |
| 124 | 120 |
/* |
| 125 |
-func TestClientNetworkCreateHelp(t *testing.T) {
|
|
| 121 |
+func TestClientNetworkServiceCreateHelp(t *testing.T) {
|
|
| 126 | 122 |
var out, errOut bytes.Buffer |
| 127 | 123 |
cFunc := func(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, int, error) {
|
| 128 | 124 |
return nil, 0, nil |
| 129 | 125 |
} |
| 130 |
- cli := NewNetworkCli(&out, &errOut, cFunc) |
|
| 126 |
+ cli := NewNetworkCli(&out, &errOut, callbackFunc) |
|
| 131 | 127 |
|
| 132 | 128 |
err := cli.Cmd("docker", "network", "create", "--help")
|
| 133 | 129 |
if err != nil {
|
| ... | ... |
@@ -139,12 +197,12 @@ func TestClientNetworkCreateHelp(t *testing.T) {
|
| 139 | 139 |
// Docker flag processing in flag.go uses os.Exit(1) for incorrect parameter case. |
| 140 | 140 |
// TODO : Handle the missing argument case in the IT when CLI is available |
| 141 | 141 |
/* |
| 142 |
-func TestClientNetworkCreateMissingArgument(t *testing.T) {
|
|
| 142 |
+func TestClientNetworkServiceCreateMissingArgument(t *testing.T) {
|
|
| 143 | 143 |
var out, errOut bytes.Buffer |
| 144 | 144 |
cFunc := func(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, int, error) {
|
| 145 | 145 |
return nil, 0, nil |
| 146 | 146 |
} |
| 147 |
- cli := NewNetworkCli(&out, &errOut, cFunc) |
|
| 147 |
+ cli := NewNetworkCli(&out, &errOut, callbackFunc) |
|
| 148 | 148 |
|
| 149 | 149 |
err := cli.Cmd("docker", "network", "create")
|
| 150 | 150 |
if err != nil {
|
| ... | ... |
@@ -2,10 +2,13 @@ package client |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 | 4 |
"bytes" |
| 5 |
+ "encoding/json" |
|
| 5 | 6 |
"fmt" |
| 6 |
- "io" |
|
| 7 |
+ "net/http" |
|
| 8 |
+ "text/tabwriter" |
|
| 7 | 9 |
|
| 8 | 10 |
flag "github.com/docker/docker/pkg/mflag" |
| 11 |
+ "github.com/docker/docker/pkg/stringid" |
|
| 9 | 12 |
) |
| 10 | 13 |
|
| 11 | 14 |
const ( |
| ... | ... |
@@ -33,7 +36,7 @@ func (cli *NetworkCli) CmdNetwork(chain string, args ...string) error {
|
| 33 | 33 |
err := cmd.ParseFlags(args, true) |
| 34 | 34 |
if err == nil {
|
| 35 | 35 |
cmd.Usage() |
| 36 |
- return fmt.Errorf("Invalid command : %v", args)
|
|
| 36 |
+ return fmt.Errorf("invalid command : %v", args)
|
|
| 37 | 37 |
} |
| 38 | 38 |
return err |
| 39 | 39 |
} |
| ... | ... |
@@ -53,31 +56,33 @@ func (cli *NetworkCli) CmdNetworkCreate(chain string, args ...string) error {
|
| 53 | 53 |
|
| 54 | 54 |
nc := networkCreate{Name: cmd.Arg(0), NetworkType: *flDriver}
|
| 55 | 55 |
|
| 56 |
- obj, _, err := readBody(cli.call("POST", "/networks/name/"+cmd.Arg(0), nc, nil))
|
|
| 56 |
+ obj, _, err := readBody(cli.call("POST", "/networks", nc, nil))
|
|
| 57 | 57 |
if err != nil {
|
| 58 |
- fmt.Fprintf(cli.err, "%s", err.Error()) |
|
| 59 | 58 |
return err |
| 60 | 59 |
} |
| 61 |
- if _, err := io.Copy(cli.out, bytes.NewReader(obj)); err != nil {
|
|
| 60 |
+ var replyID string |
|
| 61 |
+ err = json.Unmarshal(obj, &replyID) |
|
| 62 |
+ if err != nil {
|
|
| 62 | 63 |
return err |
| 63 | 64 |
} |
| 65 |
+ fmt.Fprintf(cli.out, "%s\n", replyID) |
|
| 64 | 66 |
return nil |
| 65 | 67 |
} |
| 66 | 68 |
|
| 67 | 69 |
// CmdNetworkRm handles Network Delete UI |
| 68 | 70 |
func (cli *NetworkCli) CmdNetworkRm(chain string, args ...string) error {
|
| 69 |
- cmd := cli.Subcmd(chain, "rm", "NETWORK-NAME", "Deletes a network", false) |
|
| 71 |
+ cmd := cli.Subcmd(chain, "rm", "NETWORK", "Deletes a network", false) |
|
| 70 | 72 |
cmd.Require(flag.Min, 1) |
| 71 | 73 |
err := cmd.ParseFlags(args, true) |
| 72 | 74 |
if err != nil {
|
| 73 | 75 |
return err |
| 74 | 76 |
} |
| 75 |
- obj, _, err := readBody(cli.call("DELETE", "/networks/name/"+cmd.Arg(0), nil, nil))
|
|
| 77 |
+ id, err := lookupNetworkID(cli, cmd.Arg(0)) |
|
| 76 | 78 |
if err != nil {
|
| 77 |
- fmt.Fprintf(cli.err, "%s", err.Error()) |
|
| 78 | 79 |
return err |
| 79 | 80 |
} |
| 80 |
- if _, err := io.Copy(cli.out, bytes.NewReader(obj)); err != nil {
|
|
| 81 |
+ _, _, err = readBody(cli.call("DELETE", "/networks/"+id, nil, nil))
|
|
| 82 |
+ if err != nil {
|
|
| 81 | 83 |
return err |
| 82 | 84 |
} |
| 83 | 85 |
return nil |
| ... | ... |
@@ -86,45 +91,149 @@ func (cli *NetworkCli) CmdNetworkRm(chain string, args ...string) error {
|
| 86 | 86 |
// CmdNetworkLs handles Network List UI |
| 87 | 87 |
func (cli *NetworkCli) CmdNetworkLs(chain string, args ...string) error {
|
| 88 | 88 |
cmd := cli.Subcmd(chain, "ls", "", "Lists all the networks created by the user", false) |
| 89 |
+ quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only display numeric IDs")
|
|
| 90 |
+ noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Do not truncate the output")
|
|
| 91 |
+ nLatest := cmd.Bool([]string{"l", "-latest"}, false, "Show the latest network created")
|
|
| 92 |
+ last := cmd.Int([]string{"n"}, -1, "Show n last created networks")
|
|
| 89 | 93 |
err := cmd.ParseFlags(args, true) |
| 90 | 94 |
if err != nil {
|
| 91 | 95 |
return err |
| 92 | 96 |
} |
| 93 | 97 |
obj, _, err := readBody(cli.call("GET", "/networks", nil, nil))
|
| 94 | 98 |
if err != nil {
|
| 95 |
- fmt.Fprintf(cli.err, "%s", err.Error()) |
|
| 96 | 99 |
return err |
| 97 | 100 |
} |
| 98 |
- if _, err := io.Copy(cli.out, bytes.NewReader(obj)); err != nil {
|
|
| 101 |
+ if *last == -1 && *nLatest {
|
|
| 102 |
+ *last = 1 |
|
| 103 |
+ } |
|
| 104 |
+ |
|
| 105 |
+ var networkResources []networkResource |
|
| 106 |
+ err = json.Unmarshal(obj, &networkResources) |
|
| 107 |
+ if err != nil {
|
|
| 99 | 108 |
return err |
| 100 | 109 |
} |
| 110 |
+ |
|
| 111 |
+ wr := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0) |
|
| 112 |
+ |
|
| 113 |
+ // unless quiet (-q) is specified, print field titles |
|
| 114 |
+ if !*quiet {
|
|
| 115 |
+ fmt.Fprintln(wr, "NETWORK ID\tNAME\tTYPE") |
|
| 116 |
+ } |
|
| 117 |
+ |
|
| 118 |
+ for _, networkResource := range networkResources {
|
|
| 119 |
+ ID := networkResource.ID |
|
| 120 |
+ netName := networkResource.Name |
|
| 121 |
+ if !*noTrunc {
|
|
| 122 |
+ ID = stringid.TruncateID(ID) |
|
| 123 |
+ } |
|
| 124 |
+ if *quiet {
|
|
| 125 |
+ fmt.Fprintln(wr, ID) |
|
| 126 |
+ continue |
|
| 127 |
+ } |
|
| 128 |
+ netType := networkResource.Type |
|
| 129 |
+ fmt.Fprintf(wr, "%s\t%s\t%s\t", |
|
| 130 |
+ ID, |
|
| 131 |
+ netName, |
|
| 132 |
+ netType) |
|
| 133 |
+ fmt.Fprint(wr, "\n") |
|
| 134 |
+ } |
|
| 135 |
+ wr.Flush() |
|
| 101 | 136 |
return nil |
| 102 | 137 |
} |
| 103 | 138 |
|
| 104 | 139 |
// CmdNetworkInfo handles Network Info UI |
| 105 | 140 |
func (cli *NetworkCli) CmdNetworkInfo(chain string, args ...string) error {
|
| 106 |
- cmd := cli.Subcmd(chain, "info", "NETWORK-NAME", "Displays detailed information on a network", false) |
|
| 141 |
+ cmd := cli.Subcmd(chain, "info", "NETWORK", "Displays detailed information on a network", false) |
|
| 107 | 142 |
cmd.Require(flag.Min, 1) |
| 108 | 143 |
err := cmd.ParseFlags(args, true) |
| 109 | 144 |
if err != nil {
|
| 110 | 145 |
return err |
| 111 | 146 |
} |
| 112 |
- obj, _, err := readBody(cli.call("GET", "/networks/name/"+cmd.Arg(0), nil, nil))
|
|
| 147 |
+ |
|
| 148 |
+ id, err := lookupNetworkID(cli, cmd.Arg(0)) |
|
| 149 |
+ if err != nil {
|
|
| 150 |
+ return err |
|
| 151 |
+ } |
|
| 152 |
+ |
|
| 153 |
+ obj, _, err := readBody(cli.call("GET", "/networks/"+id, nil, nil))
|
|
| 113 | 154 |
if err != nil {
|
| 114 |
- fmt.Fprintf(cli.err, "%s", err.Error()) |
|
| 115 | 155 |
return err |
| 116 | 156 |
} |
| 117 |
- if _, err := io.Copy(cli.out, bytes.NewReader(obj)); err != nil {
|
|
| 157 |
+ networkResource := &networkResource{}
|
|
| 158 |
+ if err := json.NewDecoder(bytes.NewReader(obj)).Decode(networkResource); err != nil {
|
|
| 118 | 159 |
return err |
| 119 | 160 |
} |
| 161 |
+ fmt.Fprintf(cli.out, "Network Id: %s\n", networkResource.ID) |
|
| 162 |
+ fmt.Fprintf(cli.out, "Name: %s\n", networkResource.Name) |
|
| 163 |
+ fmt.Fprintf(cli.out, "Type: %s\n", networkResource.Type) |
|
| 164 |
+ if networkResource.Endpoints != nil {
|
|
| 165 |
+ for _, endpointResource := range networkResource.Endpoints {
|
|
| 166 |
+ fmt.Fprintf(cli.out, " Service Id: %s\n", endpointResource.ID) |
|
| 167 |
+ fmt.Fprintf(cli.out, "\tName: %s\n", endpointResource.Name) |
|
| 168 |
+ } |
|
| 169 |
+ } |
|
| 170 |
+ |
|
| 120 | 171 |
return nil |
| 121 | 172 |
} |
| 122 | 173 |
|
| 174 |
+// Helper function to predict if a string is a name or id or partial-id |
|
| 175 |
+// This provides a best-effort mechanism to identify a id with the help of GET Filter APIs |
|
| 176 |
+// Being a UI, its most likely that name will be used by the user, which is used to lookup |
|
| 177 |
+// the corresponding ID. If ID is not found, this function will assume that the passed string |
|
| 178 |
+// is an ID by itself. |
|
| 179 |
+ |
|
| 180 |
+func lookupNetworkID(cli *NetworkCli, nameID string) (string, error) {
|
|
| 181 |
+ obj, statusCode, err := readBody(cli.call("GET", "/networks?name="+nameID, nil, nil))
|
|
| 182 |
+ if err != nil {
|
|
| 183 |
+ return "", err |
|
| 184 |
+ } |
|
| 185 |
+ |
|
| 186 |
+ if statusCode != http.StatusOK {
|
|
| 187 |
+ return "", fmt.Errorf("name query failed for %s due to : statuscode(%d) %v", nameID, statusCode, string(obj))
|
|
| 188 |
+ } |
|
| 189 |
+ |
|
| 190 |
+ var list []*networkResource |
|
| 191 |
+ err = json.Unmarshal(obj, &list) |
|
| 192 |
+ if err != nil {
|
|
| 193 |
+ return "", err |
|
| 194 |
+ } |
|
| 195 |
+ if len(list) > 0 {
|
|
| 196 |
+ // name query filter will always return a single-element collection |
|
| 197 |
+ return list[0].ID, nil |
|
| 198 |
+ } |
|
| 199 |
+ |
|
| 200 |
+ // Check for Partial-id |
|
| 201 |
+ obj, statusCode, err = readBody(cli.call("GET", "/networks?partial-id="+nameID, nil, nil))
|
|
| 202 |
+ if err != nil {
|
|
| 203 |
+ return "", err |
|
| 204 |
+ } |
|
| 205 |
+ |
|
| 206 |
+ if statusCode != http.StatusOK {
|
|
| 207 |
+ return "", fmt.Errorf("partial-id match query failed for %s due to : statuscode(%d) %v", nameID, statusCode, string(obj))
|
|
| 208 |
+ } |
|
| 209 |
+ |
|
| 210 |
+ err = json.Unmarshal(obj, &list) |
|
| 211 |
+ if err != nil {
|
|
| 212 |
+ return "", err |
|
| 213 |
+ } |
|
| 214 |
+ if len(list) == 0 {
|
|
| 215 |
+ return "", fmt.Errorf("resource not found %s", nameID)
|
|
| 216 |
+ } |
|
| 217 |
+ if len(list) > 1 {
|
|
| 218 |
+ return "", fmt.Errorf("multiple Networks matching the partial identifier (%s). Please use full identifier", nameID)
|
|
| 219 |
+ } |
|
| 220 |
+ return list[0].ID, nil |
|
| 221 |
+} |
|
| 222 |
+ |
|
| 123 | 223 |
func networkUsage(chain string) string {
|
| 124 | 224 |
help := "Commands:\n" |
| 125 | 225 |
|
| 126 | 226 |
for _, cmd := range networkCommands {
|
| 127 |
- help += fmt.Sprintf(" %-10.10s%s\n", cmd.name, cmd.description)
|
|
| 227 |
+ help += fmt.Sprintf(" %-25.25s%s\n", cmd.name, cmd.description)
|
|
| 228 |
+ } |
|
| 229 |
+ |
|
| 230 |
+ for _, cmd := range serviceCommands {
|
|
| 231 |
+ help += fmt.Sprintf(" %-25.25s%s\n", "service "+cmd.name, cmd.description)
|
|
| 128 | 232 |
} |
| 129 | 233 |
|
| 130 | 234 |
help += fmt.Sprintf("\nRun '%s network COMMAND --help' for more information on a command.", chain)
|
| 0 | 7 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,317 @@ |
| 0 |
+// +build experimental |
|
| 1 |
+ |
|
| 2 |
+package client |
|
| 3 |
+ |
|
| 4 |
+import ( |
|
| 5 |
+ "bytes" |
|
| 6 |
+ "encoding/json" |
|
| 7 |
+ "fmt" |
|
| 8 |
+ "net/http" |
|
| 9 |
+ "text/tabwriter" |
|
| 10 |
+ |
|
| 11 |
+ flag "github.com/docker/docker/pkg/mflag" |
|
| 12 |
+ "github.com/docker/docker/pkg/stringid" |
|
| 13 |
+) |
|
| 14 |
+ |
|
| 15 |
+var ( |
|
| 16 |
+ serviceCommands = []command{
|
|
| 17 |
+ {"create", "Create a service endpoint"},
|
|
| 18 |
+ {"rm", "Remove a service endpoint"},
|
|
| 19 |
+ {"join", "Join a container to a service endpoint"},
|
|
| 20 |
+ {"leave", "Leave a container from a service endpoint"},
|
|
| 21 |
+ {"ls", "Lists all service endpoints on a network"},
|
|
| 22 |
+ {"info", "Display information of a service endpoint"},
|
|
| 23 |
+ } |
|
| 24 |
+) |
|
| 25 |
+ |
|
| 26 |
+func lookupServiceID(cli *NetworkCli, networkID string, nameID string) (string, error) {
|
|
| 27 |
+ obj, statusCode, err := readBody(cli.call("GET", fmt.Sprintf("/networks/%s/endpoints?name=%s", networkID, nameID), nil, nil))
|
|
| 28 |
+ if err != nil {
|
|
| 29 |
+ return "", err |
|
| 30 |
+ } |
|
| 31 |
+ |
|
| 32 |
+ if statusCode != http.StatusOK {
|
|
| 33 |
+ return "", fmt.Errorf("name query failed for %s due to : statuscode(%d) %v", nameID, statusCode, string(obj))
|
|
| 34 |
+ } |
|
| 35 |
+ |
|
| 36 |
+ var list []*networkResource |
|
| 37 |
+ err = json.Unmarshal(obj, &list) |
|
| 38 |
+ if err != nil {
|
|
| 39 |
+ return "", err |
|
| 40 |
+ } |
|
| 41 |
+ if len(list) > 0 {
|
|
| 42 |
+ // name query filter will always return a single-element collection |
|
| 43 |
+ return list[0].ID, nil |
|
| 44 |
+ } |
|
| 45 |
+ |
|
| 46 |
+ // Check for Partial-id |
|
| 47 |
+ obj, statusCode, err = readBody(cli.call("GET", fmt.Sprintf("/networks/%s/endpoints?partial-id=%s", networkID, nameID), nil, nil))
|
|
| 48 |
+ if err != nil {
|
|
| 49 |
+ return "", err |
|
| 50 |
+ } |
|
| 51 |
+ |
|
| 52 |
+ if statusCode != http.StatusOK {
|
|
| 53 |
+ return "", fmt.Errorf("partial-id match query failed for %s due to : statuscode(%d) %v", nameID, statusCode, string(obj))
|
|
| 54 |
+ } |
|
| 55 |
+ |
|
| 56 |
+ err = json.Unmarshal(obj, &list) |
|
| 57 |
+ if err != nil {
|
|
| 58 |
+ return "", err |
|
| 59 |
+ } |
|
| 60 |
+ if len(list) == 0 {
|
|
| 61 |
+ return "", fmt.Errorf("resource not found %s", nameID)
|
|
| 62 |
+ } |
|
| 63 |
+ if len(list) > 1 {
|
|
| 64 |
+ return "", fmt.Errorf("multiple services matching the partial identifier (%s). Please use full identifier", nameID)
|
|
| 65 |
+ } |
|
| 66 |
+ return list[0].ID, nil |
|
| 67 |
+} |
|
| 68 |
+ |
|
| 69 |
+func lookupContainerID(cli *NetworkCli, nameID string) (string, error) {
|
|
| 70 |
+ // TODO : containerID to sandbox-key ? |
|
| 71 |
+ return nameID, nil |
|
| 72 |
+} |
|
| 73 |
+ |
|
| 74 |
+// CmdNetworkService handles the network service UI |
|
| 75 |
+func (cli *NetworkCli) CmdNetworkService(chain string, args ...string) error {
|
|
| 76 |
+ cmd := cli.Subcmd(chain, "service", "COMMAND [OPTIONS] [arg...]", serviceUsage(chain), false) |
|
| 77 |
+ cmd.Require(flag.Min, 1) |
|
| 78 |
+ err := cmd.ParseFlags(args, true) |
|
| 79 |
+ if err == nil {
|
|
| 80 |
+ cmd.Usage() |
|
| 81 |
+ return fmt.Errorf("Invalid command : %v", args)
|
|
| 82 |
+ } |
|
| 83 |
+ return err |
|
| 84 |
+} |
|
| 85 |
+ |
|
| 86 |
+// CmdNetworkServiceCreate handles service create UI |
|
| 87 |
+func (cli *NetworkCli) CmdNetworkServiceCreate(chain string, args ...string) error {
|
|
| 88 |
+ cmd := cli.Subcmd(chain, "create", "SERVICE NETWORK", "Creates a new service on a network", false) |
|
| 89 |
+ cmd.Require(flag.Min, 2) |
|
| 90 |
+ err := cmd.ParseFlags(args, true) |
|
| 91 |
+ if err != nil {
|
|
| 92 |
+ return err |
|
| 93 |
+ } |
|
| 94 |
+ |
|
| 95 |
+ networkID, err := lookupNetworkID(cli, cmd.Arg(1)) |
|
| 96 |
+ if err != nil {
|
|
| 97 |
+ return err |
|
| 98 |
+ } |
|
| 99 |
+ |
|
| 100 |
+ ec := endpointCreate{Name: cmd.Arg(0), NetworkID: networkID}
|
|
| 101 |
+ |
|
| 102 |
+ obj, _, err := readBody(cli.call("POST", "/networks/"+networkID+"/endpoints", ec, nil))
|
|
| 103 |
+ if err != nil {
|
|
| 104 |
+ return err |
|
| 105 |
+ } |
|
| 106 |
+ |
|
| 107 |
+ var replyID string |
|
| 108 |
+ err = json.Unmarshal(obj, &replyID) |
|
| 109 |
+ if err != nil {
|
|
| 110 |
+ return err |
|
| 111 |
+ } |
|
| 112 |
+ |
|
| 113 |
+ fmt.Fprintf(cli.out, "%s\n", replyID) |
|
| 114 |
+ return nil |
|
| 115 |
+} |
|
| 116 |
+ |
|
| 117 |
+// CmdNetworkServiceRm handles service delete UI |
|
| 118 |
+func (cli *NetworkCli) CmdNetworkServiceRm(chain string, args ...string) error {
|
|
| 119 |
+ cmd := cli.Subcmd(chain, "rm", "SERVICE NETWORK", "Deletes a service", false) |
|
| 120 |
+ cmd.Require(flag.Min, 2) |
|
| 121 |
+ err := cmd.ParseFlags(args, true) |
|
| 122 |
+ if err != nil {
|
|
| 123 |
+ return err |
|
| 124 |
+ } |
|
| 125 |
+ |
|
| 126 |
+ networkID, err := lookupNetworkID(cli, cmd.Arg(1)) |
|
| 127 |
+ if err != nil {
|
|
| 128 |
+ return err |
|
| 129 |
+ } |
|
| 130 |
+ |
|
| 131 |
+ serviceID, err := lookupServiceID(cli, networkID, cmd.Arg(0)) |
|
| 132 |
+ if err != nil {
|
|
| 133 |
+ return err |
|
| 134 |
+ } |
|
| 135 |
+ |
|
| 136 |
+ _, _, err = readBody(cli.call("DELETE", "/networks/"+networkID+"/endpoints/"+serviceID, nil, nil))
|
|
| 137 |
+ if err != nil {
|
|
| 138 |
+ return err |
|
| 139 |
+ } |
|
| 140 |
+ return nil |
|
| 141 |
+} |
|
| 142 |
+ |
|
| 143 |
+// CmdNetworkServiceLs handles service list UI |
|
| 144 |
+func (cli *NetworkCli) CmdNetworkServiceLs(chain string, args ...string) error {
|
|
| 145 |
+ cmd := cli.Subcmd(chain, "ls", "NETWORK", "Lists all the services on a network", false) |
|
| 146 |
+ quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only display numeric IDs")
|
|
| 147 |
+ noTrunc := cmd.Bool([]string{"#notrunc", "-no-trunc"}, false, "Do not truncate the output")
|
|
| 148 |
+ nLatest := cmd.Bool([]string{"l", "-latest"}, false, "Show the latest network created")
|
|
| 149 |
+ last := cmd.Int([]string{"n"}, -1, "Show n last created networks")
|
|
| 150 |
+ err := cmd.ParseFlags(args, true) |
|
| 151 |
+ if err != nil {
|
|
| 152 |
+ return err |
|
| 153 |
+ } |
|
| 154 |
+ |
|
| 155 |
+ cmd.Require(flag.Min, 1) |
|
| 156 |
+ |
|
| 157 |
+ networkID, err := lookupNetworkID(cli, cmd.Arg(0)) |
|
| 158 |
+ if err != nil {
|
|
| 159 |
+ return err |
|
| 160 |
+ } |
|
| 161 |
+ |
|
| 162 |
+ obj, _, err := readBody(cli.call("GET", "/networks/"+networkID+"/endpoints", nil, nil))
|
|
| 163 |
+ if err != nil {
|
|
| 164 |
+ fmt.Fprintf(cli.err, "%s", err.Error()) |
|
| 165 |
+ return err |
|
| 166 |
+ } |
|
| 167 |
+ if *last == -1 && *nLatest {
|
|
| 168 |
+ *last = 1 |
|
| 169 |
+ } |
|
| 170 |
+ |
|
| 171 |
+ var endpointResources []endpointResource |
|
| 172 |
+ err = json.Unmarshal(obj, &endpointResources) |
|
| 173 |
+ if err != nil {
|
|
| 174 |
+ return err |
|
| 175 |
+ } |
|
| 176 |
+ |
|
| 177 |
+ wr := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0) |
|
| 178 |
+ // unless quiet (-q) is specified, print field titles |
|
| 179 |
+ if !*quiet {
|
|
| 180 |
+ fmt.Fprintln(wr, "NETWORK SERVICE ID\tNAME\tNETWORK") |
|
| 181 |
+ } |
|
| 182 |
+ |
|
| 183 |
+ for _, networkResource := range endpointResources {
|
|
| 184 |
+ ID := networkResource.ID |
|
| 185 |
+ netName := networkResource.Name |
|
| 186 |
+ if !*noTrunc {
|
|
| 187 |
+ ID = stringid.TruncateID(ID) |
|
| 188 |
+ } |
|
| 189 |
+ if *quiet {
|
|
| 190 |
+ fmt.Fprintln(wr, ID) |
|
| 191 |
+ continue |
|
| 192 |
+ } |
|
| 193 |
+ network := networkResource.Network |
|
| 194 |
+ fmt.Fprintf(wr, "%s\t%s\t%s", |
|
| 195 |
+ ID, |
|
| 196 |
+ netName, |
|
| 197 |
+ network) |
|
| 198 |
+ fmt.Fprint(wr, "\n") |
|
| 199 |
+ } |
|
| 200 |
+ wr.Flush() |
|
| 201 |
+ |
|
| 202 |
+ return nil |
|
| 203 |
+} |
|
| 204 |
+ |
|
| 205 |
+// CmdNetworkServiceInfo handles service info UI |
|
| 206 |
+func (cli *NetworkCli) CmdNetworkServiceInfo(chain string, args ...string) error {
|
|
| 207 |
+ cmd := cli.Subcmd(chain, "info", "SERVICE NETWORK", "Displays detailed information on a service", false) |
|
| 208 |
+ cmd.Require(flag.Min, 2) |
|
| 209 |
+ err := cmd.ParseFlags(args, true) |
|
| 210 |
+ if err != nil {
|
|
| 211 |
+ return err |
|
| 212 |
+ } |
|
| 213 |
+ |
|
| 214 |
+ networkID, err := lookupNetworkID(cli, cmd.Arg(1)) |
|
| 215 |
+ if err != nil {
|
|
| 216 |
+ return err |
|
| 217 |
+ } |
|
| 218 |
+ |
|
| 219 |
+ serviceID, err := lookupServiceID(cli, networkID, cmd.Arg(0)) |
|
| 220 |
+ if err != nil {
|
|
| 221 |
+ return err |
|
| 222 |
+ } |
|
| 223 |
+ |
|
| 224 |
+ obj, _, err := readBody(cli.call("GET", "/networks/"+networkID+"/endpoints/"+serviceID, nil, nil))
|
|
| 225 |
+ if err != nil {
|
|
| 226 |
+ fmt.Fprintf(cli.err, "%s", err.Error()) |
|
| 227 |
+ return err |
|
| 228 |
+ } |
|
| 229 |
+ |
|
| 230 |
+ endpointResource := &endpointResource{}
|
|
| 231 |
+ if err := json.NewDecoder(bytes.NewReader(obj)).Decode(endpointResource); err != nil {
|
|
| 232 |
+ return err |
|
| 233 |
+ } |
|
| 234 |
+ fmt.Fprintf(cli.out, "Service Id: %s\n", endpointResource.ID) |
|
| 235 |
+ fmt.Fprintf(cli.out, "\tName: %s\n", endpointResource.Name) |
|
| 236 |
+ fmt.Fprintf(cli.out, "\tNetwork: %s\n", endpointResource.Network) |
|
| 237 |
+ |
|
| 238 |
+ return nil |
|
| 239 |
+} |
|
| 240 |
+ |
|
| 241 |
+// CmdNetworkServiceJoin handles service join UI |
|
| 242 |
+func (cli *NetworkCli) CmdNetworkServiceJoin(chain string, args ...string) error {
|
|
| 243 |
+ cmd := cli.Subcmd(chain, "join", "CONTAINER SERVICE NETWORK", "Sets a container as a service backend", false) |
|
| 244 |
+ cmd.Require(flag.Min, 3) |
|
| 245 |
+ err := cmd.ParseFlags(args, true) |
|
| 246 |
+ if err != nil {
|
|
| 247 |
+ return err |
|
| 248 |
+ } |
|
| 249 |
+ |
|
| 250 |
+ containerID, err := lookupContainerID(cli, cmd.Arg(0)) |
|
| 251 |
+ if err != nil {
|
|
| 252 |
+ return err |
|
| 253 |
+ } |
|
| 254 |
+ |
|
| 255 |
+ networkID, err := lookupNetworkID(cli, cmd.Arg(2)) |
|
| 256 |
+ if err != nil {
|
|
| 257 |
+ return err |
|
| 258 |
+ } |
|
| 259 |
+ |
|
| 260 |
+ serviceID, err := lookupServiceID(cli, networkID, cmd.Arg(1)) |
|
| 261 |
+ if err != nil {
|
|
| 262 |
+ return err |
|
| 263 |
+ } |
|
| 264 |
+ |
|
| 265 |
+ nc := endpointJoin{ContainerID: containerID}
|
|
| 266 |
+ |
|
| 267 |
+ _, _, err = readBody(cli.call("POST", "/networks/"+networkID+"/endpoints/"+serviceID+"/containers", nc, nil))
|
|
| 268 |
+ if err != nil {
|
|
| 269 |
+ fmt.Fprintf(cli.err, "%s", err.Error()) |
|
| 270 |
+ return err |
|
| 271 |
+ } |
|
| 272 |
+ return nil |
|
| 273 |
+} |
|
| 274 |
+ |
|
| 275 |
+// CmdNetworkServiceLeave handles service leave UI |
|
| 276 |
+func (cli *NetworkCli) CmdNetworkServiceLeave(chain string, args ...string) error {
|
|
| 277 |
+ cmd := cli.Subcmd(chain, "leave", "CONTAINER SERVICE NETWORK", "Removes a container from service backend", false) |
|
| 278 |
+ cmd.Require(flag.Min, 3) |
|
| 279 |
+ err := cmd.ParseFlags(args, true) |
|
| 280 |
+ if err != nil {
|
|
| 281 |
+ return err |
|
| 282 |
+ } |
|
| 283 |
+ |
|
| 284 |
+ containerID, err := lookupContainerID(cli, cmd.Arg(0)) |
|
| 285 |
+ if err != nil {
|
|
| 286 |
+ return err |
|
| 287 |
+ } |
|
| 288 |
+ |
|
| 289 |
+ networkID, err := lookupNetworkID(cli, cmd.Arg(2)) |
|
| 290 |
+ if err != nil {
|
|
| 291 |
+ return err |
|
| 292 |
+ } |
|
| 293 |
+ |
|
| 294 |
+ serviceID, err := lookupServiceID(cli, networkID, cmd.Arg(1)) |
|
| 295 |
+ if err != nil {
|
|
| 296 |
+ return err |
|
| 297 |
+ } |
|
| 298 |
+ |
|
| 299 |
+ _, _, err = readBody(cli.call("DELETE", "/networks/"+networkID+"/endpoints/"+serviceID+"/containers/"+containerID, nil, nil))
|
|
| 300 |
+ if err != nil {
|
|
| 301 |
+ fmt.Fprintf(cli.err, "%s", err.Error()) |
|
| 302 |
+ return err |
|
| 303 |
+ } |
|
| 304 |
+ return nil |
|
| 305 |
+} |
|
| 306 |
+ |
|
| 307 |
+func serviceUsage(chain string) string {
|
|
| 308 |
+ help := "Commands:\n" |
|
| 309 |
+ |
|
| 310 |
+ for _, cmd := range serviceCommands {
|
|
| 311 |
+ help += fmt.Sprintf(" %-10.10s%s\n", cmd, cmd.description)
|
|
| 312 |
+ } |
|
| 313 |
+ |
|
| 314 |
+ help += fmt.Sprintf("\nRun '%s service COMMAND --help' for more information on a command.", chain)
|
|
| 315 |
+ return help |
|
| 316 |
+} |
| ... | ... |
@@ -1,6 +1,6 @@ |
| 1 | 1 |
package client |
| 2 | 2 |
|
| 3 |
-import "github.com/docker/libnetwork/sandbox" |
|
| 3 |
+import "github.com/docker/libnetwork/types" |
|
| 4 | 4 |
|
| 5 | 5 |
/*********** |
| 6 | 6 |
Resources |
| ... | ... |
@@ -19,7 +19,6 @@ type endpointResource struct {
|
| 19 | 19 |
Name string |
| 20 | 20 |
ID string |
| 21 | 21 |
Network string |
| 22 |
- Info sandbox.Info |
|
| 23 | 22 |
} |
| 24 | 23 |
|
| 25 | 24 |
/*********** |
| ... | ... |
@@ -32,3 +31,38 @@ type networkCreate struct {
|
| 32 | 32 |
NetworkType string |
| 33 | 33 |
Options map[string]interface{}
|
| 34 | 34 |
} |
| 35 |
+ |
|
| 36 |
+// endpointCreate represents the body of the "create endpoint" http request message |
|
| 37 |
+type endpointCreate struct {
|
|
| 38 |
+ Name string |
|
| 39 |
+ NetworkID string |
|
| 40 |
+ ExposedPorts []types.TransportPort |
|
| 41 |
+ PortMapping []types.PortBinding |
|
| 42 |
+} |
|
| 43 |
+ |
|
| 44 |
+// endpointJoin represents the expected body of the "join endpoint" or "leave endpoint" http request messages |
|
| 45 |
+type endpointJoin struct {
|
|
| 46 |
+ ContainerID string |
|
| 47 |
+ HostName string |
|
| 48 |
+ DomainName string |
|
| 49 |
+ HostsPath string |
|
| 50 |
+ ResolvConfPath string |
|
| 51 |
+ DNS []string |
|
| 52 |
+ ExtraHosts []endpointExtraHost |
|
| 53 |
+ ParentUpdates []endpointParentUpdate |
|
| 54 |
+ UseDefaultSandbox bool |
|
| 55 |
+} |
|
| 56 |
+ |
|
| 57 |
+// EndpointExtraHost represents the extra host object |
|
| 58 |
+type endpointExtraHost struct {
|
|
| 59 |
+ Name string |
|
| 60 |
+ Address string |
|
| 61 |
+} |
|
| 62 |
+ |
|
| 63 |
+// EndpointParentUpdate is the object carrying the information about the |
|
| 64 |
+// endpoint parent that needs to be updated |
|
| 65 |
+type endpointParentUpdate struct {
|
|
| 66 |
+ EndpointID string |
|
| 67 |
+ Name string |
|
| 68 |
+ Address string |
|
| 69 |
+} |
| ... | ... |
@@ -113,10 +113,8 @@ func (d *dnetConnection) dnetDaemon() error {
|
| 113 | 113 |
} |
| 114 | 114 |
httpHandler := api.NewHTTPHandler(controller) |
| 115 | 115 |
r := mux.NewRouter().StrictSlash(false) |
| 116 |
- post := r.PathPrefix("/networks").Subrouter()
|
|
| 117 |
- post.Methods("GET").HandlerFunc(httpHandler)
|
|
| 118 |
- post.Methods("PUT", "POST").HandlerFunc(httpHandler)
|
|
| 119 |
- post.Methods("DELETE").HandlerFunc(httpHandler)
|
|
| 116 |
+ post := r.PathPrefix("/{.*}/networks").Subrouter()
|
|
| 117 |
+ post.Methods("GET", "PUT", "POST", "DELETE").HandlerFunc(httpHandler)
|
|
| 120 | 118 |
return http.ListenAndServe(d.addr, r) |
| 121 | 119 |
} |
| 122 | 120 |
|
| ... | ... |
@@ -143,7 +141,7 @@ func (d *dnetConnection) httpCall(method, path string, data interface{}, headers
|
| 143 | 143 |
return nil, -1, err |
| 144 | 144 |
} |
| 145 | 145 |
|
| 146 |
- req, err := http.NewRequest(method, fmt.Sprintf("%s", path), in)
|
|
| 146 |
+ req, err := http.NewRequest(method, fmt.Sprintf("/dnet%s", path), in)
|
|
| 147 | 147 |
if err != nil {
|
| 148 | 148 |
return nil, -1, err |
| 149 | 149 |
} |
| ... | ... |
@@ -160,7 +158,7 @@ func (d *dnetConnection) httpCall(method, path string, data interface{}, headers
|
| 160 | 160 |
statusCode = resp.StatusCode |
| 161 | 161 |
} |
| 162 | 162 |
if err != nil {
|
| 163 |
- return nil, statusCode, fmt.Errorf("An error occurred trying to connect: %v", err)
|
|
| 163 |
+ return nil, statusCode, fmt.Errorf("error when trying to connect: %v", err)
|
|
| 164 | 164 |
} |
| 165 | 165 |
|
| 166 | 166 |
if statusCode < 200 || statusCode >= 400 {
|
| ... | ... |
@@ -168,7 +166,7 @@ func (d *dnetConnection) httpCall(method, path string, data interface{}, headers
|
| 168 | 168 |
if err != nil {
|
| 169 | 169 |
return nil, statusCode, err |
| 170 | 170 |
} |
| 171 |
- return nil, statusCode, fmt.Errorf("Error response from daemon: %s", bytes.TrimSpace(body))
|
|
| 171 |
+ return nil, statusCode, fmt.Errorf("error : %s", bytes.TrimSpace(body))
|
|
| 172 | 172 |
} |
| 173 | 173 |
|
| 174 | 174 |
return resp.Body, statusCode, nil |
| ... | ... |
@@ -16,7 +16,7 @@ type byName []command |
| 16 | 16 |
|
| 17 | 17 |
var ( |
| 18 | 18 |
flDaemon = flag.Bool([]string{"d", "-daemon"}, false, "Enable daemon mode")
|
| 19 |
- flHost = flag.String([]string{"H", "-Host"}, "", "Daemon socket to connect to")
|
|
| 19 |
+ flHost = flag.String([]string{"H", "-host"}, "", "Daemon socket to connect to")
|
|
| 20 | 20 |
flLogLevel = flag.String([]string{"l", "-log-level"}, "info", "Set the logging level")
|
| 21 | 21 |
flDebug = flag.Bool([]string{"D", "-debug"}, false, "Enable debug mode")
|
| 22 | 22 |
flHelp = flag.Bool([]string{"h", "-help"}, false, "Print usage")
|
| ... | ... |
@@ -5,8 +5,8 @@ import ( |
| 5 | 5 |
|
| 6 | 6 |
"github.com/docker/libnetwork" |
| 7 | 7 |
"github.com/docker/libnetwork/netlabel" |
| 8 |
- "github.com/docker/libnetwork/netutils" |
|
| 9 | 8 |
"github.com/docker/libnetwork/options" |
| 9 |
+ "github.com/docker/libnetwork/types" |
|
| 10 | 10 |
) |
| 11 | 11 |
|
| 12 | 12 |
func main() {
|
| ... | ... |
@@ -58,7 +58,7 @@ func main() {
|
| 58 | 58 |
epInfo, err := ep.DriverInfo() |
| 59 | 59 |
mapData, ok := epInfo[netlabel.PortMap] |
| 60 | 60 |
if ok {
|
| 61 |
- portMapping, ok := mapData.([]netutils.PortBinding) |
|
| 61 |
+ portMapping, ok := mapData.([]types.PortBinding) |
|
| 62 | 62 |
if ok {
|
| 63 | 63 |
fmt.Printf("Current port mapping for endpoint %s: %v", ep.Name(), portMapping)
|
| 64 | 64 |
} |
| ... | ... |
@@ -134,7 +134,7 @@ func (c *controller) RegisterDriver(networkType string, driver driverapi.Driver) |
| 134 | 134 |
// are network specific and modeled in a generic way. |
| 135 | 135 |
func (c *controller) NewNetwork(networkType, name string, options ...NetworkOption) (Network, error) {
|
| 136 | 136 |
if name == "" {
|
| 137 |
- return nil, ErrInvalidName |
|
| 137 |
+ return nil, ErrInvalidName(name) |
|
| 138 | 138 |
} |
| 139 | 139 |
// Check if a driver for the specified network type is available |
| 140 | 140 |
c.Lock() |
| ... | ... |
@@ -203,7 +203,7 @@ func (c *controller) WalkNetworks(walker NetworkWalker) {
|
| 203 | 203 |
|
| 204 | 204 |
func (c *controller) NetworkByName(name string) (Network, error) {
|
| 205 | 205 |
if name == "" {
|
| 206 |
- return nil, ErrInvalidName |
|
| 206 |
+ return nil, ErrInvalidName(name) |
|
| 207 | 207 |
} |
| 208 | 208 |
var n Network |
| 209 | 209 |
|
| ... | ... |
@@ -218,7 +218,7 @@ func (c *controller) NetworkByName(name string) (Network, error) {
|
| 218 | 218 |
c.WalkNetworks(s) |
| 219 | 219 |
|
| 220 | 220 |
if n == nil {
|
| 221 |
- return nil, ErrNoSuchNetwork |
|
| 221 |
+ return nil, ErrNoSuchNetwork(name) |
|
| 222 | 222 |
} |
| 223 | 223 |
|
| 224 | 224 |
return n, nil |
| ... | ... |
@@ -226,14 +226,14 @@ func (c *controller) NetworkByName(name string) (Network, error) {
|
| 226 | 226 |
|
| 227 | 227 |
func (c *controller) NetworkByID(id string) (Network, error) {
|
| 228 | 228 |
if id == "" {
|
| 229 |
- return nil, ErrInvalidID |
|
| 229 |
+ return nil, ErrInvalidID(id) |
|
| 230 | 230 |
} |
| 231 | 231 |
c.Lock() |
| 232 | 232 |
defer c.Unlock() |
| 233 | 233 |
if n, ok := c.networks[types.UUID(id)]; ok {
|
| 234 | 234 |
return n, nil |
| 235 | 235 |
} |
| 236 |
- return nil, ErrNoSuchNetwork |
|
| 236 |
+ return nil, ErrNoSuchNetwork(id) |
|
| 237 | 237 |
} |
| 238 | 238 |
|
| 239 | 239 |
func (c *controller) sandboxAdd(key string, create bool) (sandbox.Sandbox, error) {
|
| ... | ... |
@@ -286,13 +286,16 @@ func (c *controller) loadDriver(networkType string) (driverapi.Driver, error) {
|
| 286 | 286 |
// As per the design, this Get call will result in remote driver discovery if there is a corresponding plugin available. |
| 287 | 287 |
_, err := plugins.Get(networkType, driverapi.NetworkPluginEndpointType) |
| 288 | 288 |
if err != nil {
|
| 289 |
+ if err == plugins.ErrNotFound {
|
|
| 290 |
+ return nil, types.NotFoundErrorf(err.Error()) |
|
| 291 |
+ } |
|
| 289 | 292 |
return nil, err |
| 290 | 293 |
} |
| 291 | 294 |
c.Lock() |
| 292 | 295 |
defer c.Unlock() |
| 293 | 296 |
d, ok := c.drivers[networkType] |
| 294 | 297 |
if !ok {
|
| 295 |
- return nil, ErrInvalidNetworkDriver |
|
| 298 |
+ return nil, ErrInvalidNetworkDriver(networkType) |
|
| 296 | 299 |
} |
| 297 | 300 |
return d, nil |
| 298 | 301 |
} |
| ... | ... |
@@ -6,7 +6,7 @@ This document describes how libnetwork has been designed in order to acheive thi |
| 6 | 6 |
Requirements for individual releases can be found on the [Project Page](https://github.com/docker/libnetwork/wiki) |
| 7 | 7 |
|
| 8 | 8 |
Many of the design decisions are inspired by the learnings from the Docker networking design as of Docker v1.6. |
| 9 |
-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. |
|
| 9 |
+Please refer to this [Docker v1.6 Design](legacy.md) document for more information on networking design as of Docker v1.6. |
|
| 10 | 10 |
|
| 11 | 11 |
## Goal |
| 12 | 12 |
|
| ... | ... |
@@ -1,24 +1,11 @@ |
| 1 | 1 |
package driverapi |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
- "errors" |
|
| 5 |
- "fmt" |
|
| 6 | 4 |
"net" |
| 7 | 5 |
|
| 8 | 6 |
"github.com/docker/libnetwork/types" |
| 9 | 7 |
) |
| 10 | 8 |
|
| 11 |
-var ( |
|
| 12 |
- // ErrEndpointExists is returned if more than one endpoint is added to the network |
|
| 13 |
- ErrEndpointExists = errors.New("Endpoint already exists (Only one endpoint allowed)")
|
|
| 14 |
- // ErrNoNetwork is returned if no network with the specified id exists |
|
| 15 |
- ErrNoNetwork = errors.New("No network exists")
|
|
| 16 |
- // ErrNoEndpoint is returned if no endpoint with the specified id exists |
|
| 17 |
- ErrNoEndpoint = errors.New("No endpoint exists")
|
|
| 18 |
- // ErrNotImplemented is returned when a Driver has not implemented an API yet |
|
| 19 |
- ErrNotImplemented = errors.New("The API is not implemented yet")
|
|
| 20 |
-) |
|
| 21 |
- |
|
| 22 | 9 |
// NetworkPluginEndpointType represents the Endpoint Type used by Plugin system |
| 23 | 10 |
const NetworkPluginEndpointType = "NetworkDriver" |
| 24 | 11 |
|
| ... | ... |
@@ -96,8 +83,8 @@ type InterfaceInfo interface {
|
| 96 | 96 |
// InterfaceNameInfo provides a go interface for the drivers to assign names |
| 97 | 97 |
// to interfaces. |
| 98 | 98 |
type InterfaceNameInfo interface {
|
| 99 |
- // SetNames method assigns the srcName and dstName for the interface. |
|
| 100 |
- SetNames(srcName, dstName string) error |
|
| 99 |
+ // SetNames method assigns the srcName and dstPrefix for the interface. |
|
| 100 |
+ SetNames(srcName, dstPrefix string) error |
|
| 101 | 101 |
|
| 102 | 102 |
// ID returns the numerical id that was assigned to the interface by the driver |
| 103 | 103 |
// CreateEndpoint. |
| ... | ... |
@@ -124,14 +111,6 @@ type JoinInfo interface {
|
| 124 | 124 |
SetResolvConfPath(string) error |
| 125 | 125 |
} |
| 126 | 126 |
|
| 127 |
-// ErrActiveRegistration represents an error when a driver is registered to a networkType that is previously registered |
|
| 128 |
-type ErrActiveRegistration string |
|
| 129 |
- |
|
| 130 |
-// Error interface for ErrActiveRegistration |
|
| 131 |
-func (ar ErrActiveRegistration) Error() string {
|
|
| 132 |
- return fmt.Sprintf("Driver already registered for type %q", string(ar))
|
|
| 133 |
-} |
|
| 134 |
- |
|
| 135 | 127 |
// DriverCallback provides a Callback interface for Drivers into LibNetwork |
| 136 | 128 |
type DriverCallback interface {
|
| 137 | 129 |
// RegisterDriver provides a way for Remote drivers to dynamically register new NetworkType and associate with a driver instance |
| 138 | 130 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,56 @@ |
| 0 |
+package driverapi |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "fmt" |
|
| 4 |
+) |
|
| 5 |
+ |
|
| 6 |
+// ErrNoNetwork is returned if no network with the specified id exists |
|
| 7 |
+type ErrNoNetwork string |
|
| 8 |
+ |
|
| 9 |
+func (enn ErrNoNetwork) Error() string {
|
|
| 10 |
+ return fmt.Sprintf("No network (%s) exists", string(enn))
|
|
| 11 |
+} |
|
| 12 |
+ |
|
| 13 |
+// NotFound denotes the type of this error |
|
| 14 |
+func (enn ErrNoNetwork) NotFound() {}
|
|
| 15 |
+ |
|
| 16 |
+// ErrEndpointExists is returned if more than one endpoint is added to the network |
|
| 17 |
+type ErrEndpointExists string |
|
| 18 |
+ |
|
| 19 |
+func (ee ErrEndpointExists) Error() string {
|
|
| 20 |
+ return fmt.Sprintf("Endpoint (%s) already exists (Only one endpoint allowed)", string(ee))
|
|
| 21 |
+} |
|
| 22 |
+ |
|
| 23 |
+// Forbidden denotes the type of this error |
|
| 24 |
+func (ee ErrEndpointExists) Forbidden() {}
|
|
| 25 |
+ |
|
| 26 |
+// ErrNotImplemented is returned when a Driver has not implemented an API yet |
|
| 27 |
+type ErrNotImplemented struct{}
|
|
| 28 |
+ |
|
| 29 |
+func (eni *ErrNotImplemented) Error() string {
|
|
| 30 |
+ return "The API is not implemented yet" |
|
| 31 |
+} |
|
| 32 |
+ |
|
| 33 |
+// NotImplemented denotes the type of this error |
|
| 34 |
+func (eni *ErrNotImplemented) NotImplemented() {}
|
|
| 35 |
+ |
|
| 36 |
+// ErrNoEndpoint is returned if no endpoint with the specified id exists |
|
| 37 |
+type ErrNoEndpoint string |
|
| 38 |
+ |
|
| 39 |
+func (ene ErrNoEndpoint) Error() string {
|
|
| 40 |
+ return fmt.Sprintf("No endpoint (%s) exists", string(ene))
|
|
| 41 |
+} |
|
| 42 |
+ |
|
| 43 |
+// NotFound denotes the type of this error |
|
| 44 |
+func (ene ErrNoEndpoint) NotFound() {}
|
|
| 45 |
+ |
|
| 46 |
+// ErrActiveRegistration represents an error when a driver is registered to a networkType that is previously registered |
|
| 47 |
+type ErrActiveRegistration string |
|
| 48 |
+ |
|
| 49 |
+// Error interface for ErrActiveRegistration |
|
| 50 |
+func (ar ErrActiveRegistration) Error() string {
|
|
| 51 |
+ return fmt.Sprintf("Driver already registered for type %q", string(ar))
|
|
| 52 |
+} |
|
| 53 |
+ |
|
| 54 |
+// Forbidden denotes the type of this error |
|
| 55 |
+func (ar ErrActiveRegistration) Forbidden() {}
|
| ... | ... |
@@ -21,7 +21,7 @@ const ( |
| 21 | 21 |
networkType = "bridge" |
| 22 | 22 |
vethPrefix = "veth" |
| 23 | 23 |
vethLen = 7 |
| 24 |
- containerVeth = "eth0" |
|
| 24 |
+ containerVethPrefix = "eth" |
|
| 25 | 25 |
maxAllocatePortAttempts = 10 |
| 26 | 26 |
ifaceID = 1 |
| 27 | 27 |
) |
| ... | ... |
@@ -57,8 +57,8 @@ type NetworkConfiguration struct {
|
| 57 | 57 |
// EndpointConfiguration represents the user specified configuration for the sandbox endpoint |
| 58 | 58 |
type EndpointConfiguration struct {
|
| 59 | 59 |
MacAddress net.HardwareAddr |
| 60 |
- PortBindings []netutils.PortBinding |
|
| 61 |
- ExposedPorts []netutils.TransportPort |
|
| 60 |
+ PortBindings []types.PortBinding |
|
| 61 |
+ ExposedPorts []types.TransportPort |
|
| 62 | 62 |
} |
| 63 | 63 |
|
| 64 | 64 |
// ContainerConfiguration represents the user specified configuration for a container |
| ... | ... |
@@ -73,7 +73,7 @@ type bridgeEndpoint struct {
|
| 73 | 73 |
macAddress net.HardwareAddr |
| 74 | 74 |
config *EndpointConfiguration // User specified parameters |
| 75 | 75 |
containerConfig *ContainerConfiguration |
| 76 |
- portMapping []netutils.PortBinding // Operation port bindings |
|
| 76 |
+ portMapping []types.PortBinding // Operation port bindings |
|
| 77 | 77 |
} |
| 78 | 78 |
|
| 79 | 79 |
type bridgeNetwork struct {
|
| ... | ... |
@@ -109,7 +109,7 @@ func Init(dc driverapi.DriverCallback) error {
|
| 109 | 109 |
// Whatever can be assessed a priori before attempting any programming. |
| 110 | 110 |
func (c *NetworkConfiguration) Validate() error {
|
| 111 | 111 |
if c.Mtu < 0 {
|
| 112 |
- return ErrInvalidMtu |
|
| 112 |
+ return ErrInvalidMtu(c.Mtu) |
|
| 113 | 113 |
} |
| 114 | 114 |
|
| 115 | 115 |
// If bridge v4 subnet is specified |
| ... | ... |
@@ -118,19 +118,19 @@ func (c *NetworkConfiguration) Validate() error {
|
| 118 | 118 |
if c.FixedCIDR != nil {
|
| 119 | 119 |
// Check Network address |
| 120 | 120 |
if !c.AddressIPv4.Contains(c.FixedCIDR.IP) {
|
| 121 |
- return ErrInvalidContainerSubnet |
|
| 121 |
+ return &ErrInvalidContainerSubnet{}
|
|
| 122 | 122 |
} |
| 123 | 123 |
// Check it is effectively a subset |
| 124 | 124 |
brNetLen, _ := c.AddressIPv4.Mask.Size() |
| 125 | 125 |
cnNetLen, _ := c.FixedCIDR.Mask.Size() |
| 126 | 126 |
if brNetLen > cnNetLen {
|
| 127 |
- return ErrInvalidContainerSubnet |
|
| 127 |
+ return &ErrInvalidContainerSubnet{}
|
|
| 128 | 128 |
} |
| 129 | 129 |
} |
| 130 | 130 |
// If default gw is specified, it must be part of bridge subnet |
| 131 | 131 |
if c.DefaultGatewayIPv4 != nil {
|
| 132 | 132 |
if !c.AddressIPv4.Contains(c.DefaultGatewayIPv4) {
|
| 133 |
- return ErrInvalidGateway |
|
| 133 |
+ return &ErrInvalidGateway{}
|
|
| 134 | 134 |
} |
| 135 | 135 |
} |
| 136 | 136 |
} |
| ... | ... |
@@ -138,7 +138,7 @@ func (c *NetworkConfiguration) Validate() error {
|
| 138 | 138 |
// If default v6 gw is specified, FixedCIDRv6 must be specified and gw must belong to FixedCIDRv6 subnet |
| 139 | 139 |
if c.EnableIPv6 && c.DefaultGatewayIPv6 != nil {
|
| 140 | 140 |
if c.FixedCIDRv6 == nil || !c.FixedCIDRv6.Contains(c.DefaultGatewayIPv6) {
|
| 141 |
- return ErrInvalidGateway |
|
| 141 |
+ return &ErrInvalidGateway{}
|
|
| 142 | 142 |
} |
| 143 | 143 |
} |
| 144 | 144 |
|
| ... | ... |
@@ -167,7 +167,7 @@ func (d *driver) Config(option map[string]interface{}) error {
|
| 167 | 167 |
defer d.Unlock() |
| 168 | 168 |
|
| 169 | 169 |
if d.config != nil {
|
| 170 |
- return ErrConfigExists |
|
| 170 |
+ return &ErrConfigExists{}
|
|
| 171 | 171 |
} |
| 172 | 172 |
|
| 173 | 173 |
genericData, ok := option[netlabel.GenericData] |
| ... | ... |
@@ -182,7 +182,7 @@ func (d *driver) Config(option map[string]interface{}) error {
|
| 182 | 182 |
case *Configuration: |
| 183 | 183 |
config = opt |
| 184 | 184 |
default: |
| 185 |
- return ErrInvalidDriverConfig |
|
| 185 |
+ return &ErrInvalidDriverConfig{}
|
|
| 186 | 186 |
} |
| 187 | 187 |
|
| 188 | 188 |
d.config = config |
| ... | ... |
@@ -220,7 +220,7 @@ func parseNetworkOptions(option options.Generic) (*NetworkConfiguration, error) |
| 220 | 220 |
case *NetworkConfiguration: |
| 221 | 221 |
config = opt |
| 222 | 222 |
default: |
| 223 |
- return nil, ErrInvalidNetworkConfig |
|
| 223 |
+ return nil, &ErrInvalidNetworkConfig{}
|
|
| 224 | 224 |
} |
| 225 | 225 |
|
| 226 | 226 |
if err := config.Validate(); err != nil {
|
| ... | ... |
@@ -247,7 +247,7 @@ func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) err
|
| 247 | 247 |
// Sanity checks |
| 248 | 248 |
if d.network != nil {
|
| 249 | 249 |
d.Unlock() |
| 250 |
- return ErrNetworkExists |
|
| 250 |
+ return &ErrNetworkExists{}
|
|
| 251 | 251 |
} |
| 252 | 252 |
|
| 253 | 253 |
// Create and set network handler in driver |
| ... | ... |
@@ -361,7 +361,7 @@ func (d *driver) DeleteNetwork(nid types.UUID) error {
|
| 361 | 361 |
|
| 362 | 362 |
// Sanity check |
| 363 | 363 |
if n == nil {
|
| 364 |
- err = driverapi.ErrNoNetwork |
|
| 364 |
+ err = driverapi.ErrNoNetwork(nid) |
|
| 365 | 365 |
return err |
| 366 | 366 |
} |
| 367 | 367 |
|
| ... | ... |
@@ -397,7 +397,7 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn |
| 397 | 397 |
config := n.config |
| 398 | 398 |
d.Unlock() |
| 399 | 399 |
if n == nil {
|
| 400 |
- return driverapi.ErrNoNetwork |
|
| 400 |
+ return driverapi.ErrNoNetwork(nid) |
|
| 401 | 401 |
} |
| 402 | 402 |
|
| 403 | 403 |
// Sanity check |
| ... | ... |
@@ -416,7 +416,7 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn |
| 416 | 416 |
|
| 417 | 417 |
// Endpoint with that id exists either on desired or other sandbox |
| 418 | 418 |
if ep != nil {
|
| 419 |
- return driverapi.ErrEndpointExists |
|
| 419 |
+ return driverapi.ErrEndpointExists(eid) |
|
| 420 | 420 |
} |
| 421 | 421 |
|
| 422 | 422 |
// Try to convert the options to endpoint configuration |
| ... | ... |
@@ -545,7 +545,7 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn |
| 545 | 545 |
// Create the sandbox side pipe interface |
| 546 | 546 |
intf := &sandbox.Interface{}
|
| 547 | 547 |
intf.SrcName = name2 |
| 548 |
- intf.DstName = containerVeth |
|
| 548 |
+ intf.DstName = containerVethPrefix |
|
| 549 | 549 |
intf.Address = ipv4Addr |
| 550 | 550 |
|
| 551 | 551 |
if config.EnableIPv6 {
|
| ... | ... |
@@ -578,7 +578,7 @@ func (d *driver) DeleteEndpoint(nid, eid types.UUID) error {
|
| 578 | 578 |
config := n.config |
| 579 | 579 |
d.Unlock() |
| 580 | 580 |
if n == nil {
|
| 581 |
- return driverapi.ErrNoNetwork |
|
| 581 |
+ return driverapi.ErrNoNetwork(nid) |
|
| 582 | 582 |
} |
| 583 | 583 |
|
| 584 | 584 |
// Sanity Check |
| ... | ... |
@@ -648,7 +648,7 @@ func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{},
|
| 648 | 648 |
n := d.network |
| 649 | 649 |
d.Unlock() |
| 650 | 650 |
if n == nil {
|
| 651 |
- return nil, driverapi.ErrNoNetwork |
|
| 651 |
+ return nil, driverapi.ErrNoNetwork(nid) |
|
| 652 | 652 |
} |
| 653 | 653 |
|
| 654 | 654 |
// Sanity check |
| ... | ... |
@@ -665,14 +665,14 @@ func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{},
|
| 665 | 665 |
return nil, err |
| 666 | 666 |
} |
| 667 | 667 |
if ep == nil {
|
| 668 |
- return nil, driverapi.ErrNoEndpoint |
|
| 668 |
+ return nil, driverapi.ErrNoEndpoint(eid) |
|
| 669 | 669 |
} |
| 670 | 670 |
|
| 671 | 671 |
m := make(map[string]interface{})
|
| 672 | 672 |
|
| 673 | 673 |
if ep.portMapping != nil {
|
| 674 | 674 |
// Return a copy of the operational data |
| 675 |
- pmc := make([]netutils.PortBinding, 0, len(ep.portMapping)) |
|
| 675 |
+ pmc := make([]types.PortBinding, 0, len(ep.portMapping)) |
|
| 676 | 676 |
for _, pm := range ep.portMapping {
|
| 677 | 677 |
pmc = append(pmc, pm.GetCopy()) |
| 678 | 678 |
} |
| ... | ... |
@@ -856,23 +856,23 @@ func parseEndpointOptions(epOptions map[string]interface{}) (*EndpointConfigurat
|
| 856 | 856 |
if mac, ok := opt.(net.HardwareAddr); ok {
|
| 857 | 857 |
ec.MacAddress = mac |
| 858 | 858 |
} else {
|
| 859 |
- return nil, ErrInvalidEndpointConfig |
|
| 859 |
+ return nil, &ErrInvalidEndpointConfig{}
|
|
| 860 | 860 |
} |
| 861 | 861 |
} |
| 862 | 862 |
|
| 863 | 863 |
if opt, ok := epOptions[netlabel.PortMap]; ok {
|
| 864 |
- if bs, ok := opt.([]netutils.PortBinding); ok {
|
|
| 864 |
+ if bs, ok := opt.([]types.PortBinding); ok {
|
|
| 865 | 865 |
ec.PortBindings = bs |
| 866 | 866 |
} else {
|
| 867 |
- return nil, ErrInvalidEndpointConfig |
|
| 867 |
+ return nil, &ErrInvalidEndpointConfig{}
|
|
| 868 | 868 |
} |
| 869 | 869 |
} |
| 870 | 870 |
|
| 871 | 871 |
if opt, ok := epOptions[netlabel.ExposedPorts]; ok {
|
| 872 |
- if ports, ok := opt.([]netutils.TransportPort); ok {
|
|
| 872 |
+ if ports, ok := opt.([]types.TransportPort); ok {
|
|
| 873 | 873 |
ec.ExposedPorts = ports |
| 874 | 874 |
} else {
|
| 875 |
- return nil, ErrInvalidEndpointConfig |
|
| 875 |
+ return nil, &ErrInvalidEndpointConfig{}
|
|
| 876 | 876 |
} |
| 877 | 877 |
} |
| 878 | 878 |
|
| ... | ... |
@@ -924,5 +924,5 @@ func generateIfaceName() (string, error) {
|
| 924 | 924 |
return "", err |
| 925 | 925 |
} |
| 926 | 926 |
} |
| 927 |
- return "", ErrIfaceName |
|
| 927 |
+ return "", &ErrIfaceName{}
|
|
| 928 | 928 |
} |
| ... | ... |
@@ -11,6 +11,7 @@ import ( |
| 11 | 11 |
"github.com/docker/libnetwork/iptables" |
| 12 | 12 |
"github.com/docker/libnetwork/netlabel" |
| 13 | 13 |
"github.com/docker/libnetwork/netutils" |
| 14 |
+ "github.com/docker/libnetwork/types" |
|
| 14 | 15 |
"github.com/vishvananda/netlink" |
| 15 | 16 |
) |
| 16 | 17 |
|
| ... | ... |
@@ -202,7 +203,7 @@ func testQueryEndpointInfo(t *testing.T, ulPxyEnabled bool) {
|
| 202 | 202 |
if !ok {
|
| 203 | 203 |
t.Fatalf("Endpoint operational data does not contain port mapping data")
|
| 204 | 204 |
} |
| 205 |
- pm, ok := pmd.([]netutils.PortBinding) |
|
| 205 |
+ pm, ok := pmd.([]types.PortBinding) |
|
| 206 | 206 |
if !ok {
|
| 207 | 207 |
t.Fatalf("Unexpected format for port mapping in endpoint operational data")
|
| 208 | 208 |
} |
| ... | ... |
@@ -261,19 +262,19 @@ func TestCreateLinkWithOptions(t *testing.T) {
|
| 261 | 261 |
} |
| 262 | 262 |
} |
| 263 | 263 |
|
| 264 |
-func getExposedPorts() []netutils.TransportPort {
|
|
| 265 |
- return []netutils.TransportPort{
|
|
| 266 |
- netutils.TransportPort{Proto: netutils.TCP, Port: uint16(5000)},
|
|
| 267 |
- netutils.TransportPort{Proto: netutils.UDP, Port: uint16(400)},
|
|
| 268 |
- netutils.TransportPort{Proto: netutils.TCP, Port: uint16(600)},
|
|
| 264 |
+func getExposedPorts() []types.TransportPort {
|
|
| 265 |
+ return []types.TransportPort{
|
|
| 266 |
+ types.TransportPort{Proto: types.TCP, Port: uint16(5000)},
|
|
| 267 |
+ types.TransportPort{Proto: types.UDP, Port: uint16(400)},
|
|
| 268 |
+ types.TransportPort{Proto: types.TCP, Port: uint16(600)},
|
|
| 269 | 269 |
} |
| 270 | 270 |
} |
| 271 | 271 |
|
| 272 |
-func getPortMapping() []netutils.PortBinding {
|
|
| 273 |
- return []netutils.PortBinding{
|
|
| 274 |
- netutils.PortBinding{Proto: netutils.TCP, Port: uint16(230), HostPort: uint16(23000)},
|
|
| 275 |
- netutils.PortBinding{Proto: netutils.UDP, Port: uint16(200), HostPort: uint16(22000)},
|
|
| 276 |
- netutils.PortBinding{Proto: netutils.TCP, Port: uint16(120), HostPort: uint16(12000)},
|
|
| 272 |
+func getPortMapping() []types.PortBinding {
|
|
| 273 |
+ return []types.PortBinding{
|
|
| 274 |
+ types.PortBinding{Proto: types.TCP, Port: uint16(230), HostPort: uint16(23000)},
|
|
| 275 |
+ types.PortBinding{Proto: types.UDP, Port: uint16(200), HostPort: uint16(22000)},
|
|
| 276 |
+ types.PortBinding{Proto: types.TCP, Port: uint16(120), HostPort: uint16(12000)},
|
|
| 277 | 277 |
} |
| 278 | 278 |
} |
| 279 | 279 |
|
| 280 | 280 |
deleted file mode 100644 |
| ... | ... |
@@ -1,201 +0,0 @@ |
| 1 |
-package bridge |
|
| 2 |
- |
|
| 3 |
-import ( |
|
| 4 |
- "errors" |
|
| 5 |
- "fmt" |
|
| 6 |
- "net" |
|
| 7 |
-) |
|
| 8 |
- |
|
| 9 |
-var ( |
|
| 10 |
- // ErrConfigExists error is returned when driver already has a config applied. |
|
| 11 |
- ErrConfigExists = errors.New("configuration already exists, bridge configuration can be applied only once")
|
|
| 12 |
- |
|
| 13 |
- // ErrInvalidDriverConfig error is returned when Bridge Driver is passed an invalid config |
|
| 14 |
- ErrInvalidDriverConfig = errors.New("Invalid configuration passed to Bridge Driver")
|
|
| 15 |
- |
|
| 16 |
- // ErrInvalidNetworkConfig error is returned when a network is created on a driver without valid config. |
|
| 17 |
- ErrInvalidNetworkConfig = errors.New("trying to create a network on a driver without valid config")
|
|
| 18 |
- |
|
| 19 |
- // ErrInvalidContainerConfig error is returned when a endpoint create is attempted with an invalid configuration. |
|
| 20 |
- ErrInvalidContainerConfig = errors.New("Error in joining a container due to invalid configuration")
|
|
| 21 |
- |
|
| 22 |
- // ErrInvalidEndpointConfig error is returned when a endpoint create is attempted with an invalid endpoint configuration. |
|
| 23 |
- ErrInvalidEndpointConfig = errors.New("trying to create an endpoint with an invalid endpoint configuration")
|
|
| 24 |
- |
|
| 25 |
- // ErrNetworkExists error is returned when a network already exists and another network is created. |
|
| 26 |
- ErrNetworkExists = errors.New("network already exists, bridge can only have one network")
|
|
| 27 |
- |
|
| 28 |
- // ErrIfaceName error is returned when a new name could not be generated. |
|
| 29 |
- ErrIfaceName = errors.New("failed to find name for new interface")
|
|
| 30 |
- |
|
| 31 |
- // ErrNoIPAddr error is returned when bridge has no IPv4 address configured. |
|
| 32 |
- ErrNoIPAddr = errors.New("bridge has no IPv4 address configured")
|
|
| 33 |
- |
|
| 34 |
- // ErrInvalidGateway is returned when the user provided default gateway (v4/v6) is not not valid. |
|
| 35 |
- ErrInvalidGateway = errors.New("default gateway ip must be part of the network")
|
|
| 36 |
- |
|
| 37 |
- // ErrInvalidContainerSubnet is returned when the container subnet (FixedCIDR) is not valid. |
|
| 38 |
- ErrInvalidContainerSubnet = errors.New("container subnet must be a subset of bridge network")
|
|
| 39 |
- |
|
| 40 |
- // ErrInvalidMtu is returned when the user provided MTU is not valid. |
|
| 41 |
- ErrInvalidMtu = errors.New("invalid MTU number")
|
|
| 42 |
- |
|
| 43 |
- // ErrIPFwdCfg is returned when ip forwarding setup is invoked when the configuration |
|
| 44 |
- // not enabled. |
|
| 45 |
- ErrIPFwdCfg = errors.New("unexpected request to enable IP Forwarding")
|
|
| 46 |
-) |
|
| 47 |
- |
|
| 48 |
-// ErrInvalidPort is returned when the container or host port specified in the port binding is not valid. |
|
| 49 |
-type ErrInvalidPort string |
|
| 50 |
- |
|
| 51 |
-func (ip ErrInvalidPort) Error() string {
|
|
| 52 |
- return fmt.Sprintf("invalid transport port: %s", string(ip))
|
|
| 53 |
-} |
|
| 54 |
- |
|
| 55 |
-// ErrUnsupportedAddressType is returned when the specified address type is not supported. |
|
| 56 |
-type ErrUnsupportedAddressType string |
|
| 57 |
- |
|
| 58 |
-func (uat ErrUnsupportedAddressType) Error() string {
|
|
| 59 |
- return fmt.Sprintf("unsupported address type: %s", string(uat))
|
|
| 60 |
-} |
|
| 61 |
- |
|
| 62 |
-// ErrInvalidAddressBinding is returned when the host address specified in the port binding is not valid. |
|
| 63 |
-type ErrInvalidAddressBinding string |
|
| 64 |
- |
|
| 65 |
-func (iab ErrInvalidAddressBinding) Error() string {
|
|
| 66 |
- return fmt.Sprintf("invalid host address in port binding: %s", string(iab))
|
|
| 67 |
-} |
|
| 68 |
- |
|
| 69 |
-// ActiveEndpointsError is returned when there are |
|
| 70 |
-// still active endpoints in the network being deleted. |
|
| 71 |
-type ActiveEndpointsError string |
|
| 72 |
- |
|
| 73 |
-func (aee ActiveEndpointsError) Error() string {
|
|
| 74 |
- return fmt.Sprintf("network %s has active endpoint", string(aee))
|
|
| 75 |
-} |
|
| 76 |
- |
|
| 77 |
-// InvalidNetworkIDError is returned when the passed |
|
| 78 |
-// network id for an existing network is not a known id. |
|
| 79 |
-type InvalidNetworkIDError string |
|
| 80 |
- |
|
| 81 |
-func (inie InvalidNetworkIDError) Error() string {
|
|
| 82 |
- return fmt.Sprintf("invalid network id %s", string(inie))
|
|
| 83 |
-} |
|
| 84 |
- |
|
| 85 |
-// InvalidEndpointIDError is returned when the passed |
|
| 86 |
-// endpoint id is not valid. |
|
| 87 |
-type InvalidEndpointIDError string |
|
| 88 |
- |
|
| 89 |
-func (ieie InvalidEndpointIDError) Error() string {
|
|
| 90 |
- return fmt.Sprintf("invalid endpoint id: %s", string(ieie))
|
|
| 91 |
-} |
|
| 92 |
- |
|
| 93 |
-// InvalidSandboxIDError is returned when the passed |
|
| 94 |
-// sandbox id valid. |
|
| 95 |
-type InvalidSandboxIDError string |
|
| 96 |
- |
|
| 97 |
-func (isie InvalidSandboxIDError) Error() string {
|
|
| 98 |
- return fmt.Sprintf("invalid sanbox id: %s", string(isie))
|
|
| 99 |
-} |
|
| 100 |
- |
|
| 101 |
-// EndpointNotFoundError is returned when the no endpoint |
|
| 102 |
-// with the passed endpoint id is found. |
|
| 103 |
-type EndpointNotFoundError string |
|
| 104 |
- |
|
| 105 |
-func (enfe EndpointNotFoundError) Error() string {
|
|
| 106 |
- return fmt.Sprintf("endpoint not found: %s", string(enfe))
|
|
| 107 |
-} |
|
| 108 |
- |
|
| 109 |
-// NonDefaultBridgeExistError is returned when a non-default |
|
| 110 |
-// bridge config is passed but it does not already exist. |
|
| 111 |
-type NonDefaultBridgeExistError string |
|
| 112 |
- |
|
| 113 |
-func (ndbee NonDefaultBridgeExistError) Error() string {
|
|
| 114 |
- return fmt.Sprintf("bridge device with non default name %s must be created manually", string(ndbee))
|
|
| 115 |
-} |
|
| 116 |
- |
|
| 117 |
-// FixedCIDRv4Error is returned when fixed-cidrv4 configuration |
|
| 118 |
-// failed. |
|
| 119 |
-type FixedCIDRv4Error struct {
|
|
| 120 |
- net *net.IPNet |
|
| 121 |
- subnet *net.IPNet |
|
| 122 |
- err error |
|
| 123 |
-} |
|
| 124 |
- |
|
| 125 |
-func (fcv4 *FixedCIDRv4Error) Error() string {
|
|
| 126 |
- return fmt.Sprintf("setup FixedCIDRv4 failed for subnet %s in %s: %v", fcv4.subnet, fcv4.net, fcv4.err)
|
|
| 127 |
-} |
|
| 128 |
- |
|
| 129 |
-// FixedCIDRv6Error is returned when fixed-cidrv6 configuration |
|
| 130 |
-// failed. |
|
| 131 |
-type FixedCIDRv6Error struct {
|
|
| 132 |
- net *net.IPNet |
|
| 133 |
- err error |
|
| 134 |
-} |
|
| 135 |
- |
|
| 136 |
-func (fcv6 *FixedCIDRv6Error) Error() string {
|
|
| 137 |
- return fmt.Sprintf("setup FixedCIDRv6 failed for subnet %s in %s: %v", fcv6.net, fcv6.net, fcv6.err)
|
|
| 138 |
-} |
|
| 139 |
- |
|
| 140 |
-type ipTableCfgError string |
|
| 141 |
- |
|
| 142 |
-func (name ipTableCfgError) Error() string {
|
|
| 143 |
- return fmt.Sprintf("unexpected request to set IP tables for interface: %s", string(name))
|
|
| 144 |
-} |
|
| 145 |
- |
|
| 146 |
-type invalidIPTablesCfgError string |
|
| 147 |
- |
|
| 148 |
-func (action invalidIPTablesCfgError) Error() string {
|
|
| 149 |
- return fmt.Sprintf("Invalid IPTables action '%s'", string(action))
|
|
| 150 |
-} |
|
| 151 |
- |
|
| 152 |
-// IPv4AddrRangeError is returned when a valid IP address range couldn't be found. |
|
| 153 |
-type IPv4AddrRangeError string |
|
| 154 |
- |
|
| 155 |
-func (name IPv4AddrRangeError) Error() string {
|
|
| 156 |
- return fmt.Sprintf("can't find an address range for interface %q", string(name))
|
|
| 157 |
-} |
|
| 158 |
- |
|
| 159 |
-// IPv4AddrAddError is returned when IPv4 address could not be added to the bridge. |
|
| 160 |
-type IPv4AddrAddError struct {
|
|
| 161 |
- ip *net.IPNet |
|
| 162 |
- err error |
|
| 163 |
-} |
|
| 164 |
- |
|
| 165 |
-func (ipv4 *IPv4AddrAddError) Error() string {
|
|
| 166 |
- return fmt.Sprintf("failed to add IPv4 address %s to bridge: %v", ipv4.ip, ipv4.err)
|
|
| 167 |
-} |
|
| 168 |
- |
|
| 169 |
-// IPv6AddrAddError is returned when IPv6 address could not be added to the bridge. |
|
| 170 |
-type IPv6AddrAddError struct {
|
|
| 171 |
- ip *net.IPNet |
|
| 172 |
- err error |
|
| 173 |
-} |
|
| 174 |
- |
|
| 175 |
-func (ipv6 *IPv6AddrAddError) Error() string {
|
|
| 176 |
- return fmt.Sprintf("failed to add IPv6 address %s to bridge: %v", ipv6.ip, ipv6.err)
|
|
| 177 |
-} |
|
| 178 |
- |
|
| 179 |
-// IPv4AddrNoMatchError is returned when the bridge's IPv4 address does not match configured. |
|
| 180 |
-type IPv4AddrNoMatchError struct {
|
|
| 181 |
- ip net.IP |
|
| 182 |
- cfgIP net.IP |
|
| 183 |
-} |
|
| 184 |
- |
|
| 185 |
-func (ipv4 *IPv4AddrNoMatchError) Error() string {
|
|
| 186 |
- return fmt.Sprintf("bridge IPv4 (%s) does not match requested configuration %s", ipv4.ip, ipv4.cfgIP)
|
|
| 187 |
-} |
|
| 188 |
- |
|
| 189 |
-// IPv6AddrNoMatchError is returned when the bridge's IPv6 address does not match configured. |
|
| 190 |
-type IPv6AddrNoMatchError net.IPNet |
|
| 191 |
- |
|
| 192 |
-func (ipv6 *IPv6AddrNoMatchError) Error() string {
|
|
| 193 |
- return fmt.Sprintf("bridge IPv6 addresses do not match the expected bridge configuration %s", (*net.IPNet)(ipv6).String())
|
|
| 194 |
-} |
|
| 195 |
- |
|
| 196 |
-// InvalidLinkIPAddrError is returned when a link is configured to a container with an invalid ip address |
|
| 197 |
-type InvalidLinkIPAddrError string |
|
| 198 |
- |
|
| 199 |
-func (address InvalidLinkIPAddrError) Error() string {
|
|
| 200 |
- return fmt.Sprintf("Cannot link to a container with Invalid IP Address '%s'", string(address))
|
|
| 201 |
-} |
| 202 | 1 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,341 @@ |
| 0 |
+package bridge |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "fmt" |
|
| 4 |
+ "net" |
|
| 5 |
+) |
|
| 6 |
+ |
|
| 7 |
+// ErrConfigExists error is returned when driver already has a config applied. |
|
| 8 |
+type ErrConfigExists struct{}
|
|
| 9 |
+ |
|
| 10 |
+func (ece *ErrConfigExists) Error() string {
|
|
| 11 |
+ return "configuration already exists, bridge configuration can be applied only once" |
|
| 12 |
+} |
|
| 13 |
+ |
|
| 14 |
+// Forbidden denotes the type of this error |
|
| 15 |
+func (ece *ErrConfigExists) Forbidden() {}
|
|
| 16 |
+ |
|
| 17 |
+// ErrInvalidDriverConfig error is returned when Bridge Driver is passed an invalid config |
|
| 18 |
+type ErrInvalidDriverConfig struct{}
|
|
| 19 |
+ |
|
| 20 |
+func (eidc *ErrInvalidDriverConfig) Error() string {
|
|
| 21 |
+ return "Invalid configuration passed to Bridge Driver" |
|
| 22 |
+} |
|
| 23 |
+ |
|
| 24 |
+// BadRequest denotes the type of this error |
|
| 25 |
+func (eidc *ErrInvalidDriverConfig) BadRequest() {}
|
|
| 26 |
+ |
|
| 27 |
+// ErrInvalidNetworkConfig error is returned when a network is created on a driver without valid config. |
|
| 28 |
+type ErrInvalidNetworkConfig struct{}
|
|
| 29 |
+ |
|
| 30 |
+func (einc *ErrInvalidNetworkConfig) Error() string {
|
|
| 31 |
+ return "trying to create a network on a driver without valid config" |
|
| 32 |
+} |
|
| 33 |
+ |
|
| 34 |
+// Forbidden denotes the type of this error |
|
| 35 |
+func (einc *ErrInvalidNetworkConfig) Forbidden() {}
|
|
| 36 |
+ |
|
| 37 |
+// ErrInvalidContainerConfig error is returned when a endpoint create is attempted with an invalid configuration. |
|
| 38 |
+type ErrInvalidContainerConfig struct{}
|
|
| 39 |
+ |
|
| 40 |
+func (eicc *ErrInvalidContainerConfig) Error() string {
|
|
| 41 |
+ return "Error in joining a container due to invalid configuration" |
|
| 42 |
+} |
|
| 43 |
+ |
|
| 44 |
+// BadRequest denotes the type of this error |
|
| 45 |
+func (eicc *ErrInvalidContainerConfig) BadRequest() {}
|
|
| 46 |
+ |
|
| 47 |
+// ErrInvalidEndpointConfig error is returned when a endpoint create is attempted with an invalid endpoint configuration. |
|
| 48 |
+type ErrInvalidEndpointConfig struct{}
|
|
| 49 |
+ |
|
| 50 |
+func (eiec *ErrInvalidEndpointConfig) Error() string {
|
|
| 51 |
+ return "trying to create an endpoint with an invalid endpoint configuration" |
|
| 52 |
+} |
|
| 53 |
+ |
|
| 54 |
+// BadRequest denotes the type of this error |
|
| 55 |
+func (eiec *ErrInvalidEndpointConfig) BadRequest() {}
|
|
| 56 |
+ |
|
| 57 |
+// ErrNetworkExists error is returned when a network already exists and another network is created. |
|
| 58 |
+type ErrNetworkExists struct{}
|
|
| 59 |
+ |
|
| 60 |
+func (ene *ErrNetworkExists) Error() string {
|
|
| 61 |
+ return "network already exists, bridge can only have one network" |
|
| 62 |
+} |
|
| 63 |
+ |
|
| 64 |
+// Forbidden denotes the type of this error |
|
| 65 |
+func (ene *ErrNetworkExists) Forbidden() {}
|
|
| 66 |
+ |
|
| 67 |
+// ErrIfaceName error is returned when a new name could not be generated. |
|
| 68 |
+type ErrIfaceName struct{}
|
|
| 69 |
+ |
|
| 70 |
+func (ein *ErrIfaceName) Error() string {
|
|
| 71 |
+ return "failed to find name for new interface" |
|
| 72 |
+} |
|
| 73 |
+ |
|
| 74 |
+// InternalError denotes the type of this error |
|
| 75 |
+func (ein *ErrIfaceName) InternalError() {}
|
|
| 76 |
+ |
|
| 77 |
+// ErrNoIPAddr error is returned when bridge has no IPv4 address configured. |
|
| 78 |
+type ErrNoIPAddr struct{}
|
|
| 79 |
+ |
|
| 80 |
+func (enip *ErrNoIPAddr) Error() string {
|
|
| 81 |
+ return "bridge has no IPv4 address configured" |
|
| 82 |
+} |
|
| 83 |
+ |
|
| 84 |
+// InternalError denotes the type of this error |
|
| 85 |
+func (enip *ErrNoIPAddr) InternalError() {}
|
|
| 86 |
+ |
|
| 87 |
+// ErrInvalidGateway is returned when the user provided default gateway (v4/v6) is not not valid. |
|
| 88 |
+type ErrInvalidGateway struct{}
|
|
| 89 |
+ |
|
| 90 |
+func (eig *ErrInvalidGateway) Error() string {
|
|
| 91 |
+ return "default gateway ip must be part of the network" |
|
| 92 |
+} |
|
| 93 |
+ |
|
| 94 |
+// BadRequest denotes the type of this error |
|
| 95 |
+func (eig *ErrInvalidGateway) BadRequest() {}
|
|
| 96 |
+ |
|
| 97 |
+// ErrInvalidContainerSubnet is returned when the container subnet (FixedCIDR) is not valid. |
|
| 98 |
+type ErrInvalidContainerSubnet struct{}
|
|
| 99 |
+ |
|
| 100 |
+func (eis *ErrInvalidContainerSubnet) Error() string {
|
|
| 101 |
+ return "container subnet must be a subset of bridge network" |
|
| 102 |
+} |
|
| 103 |
+ |
|
| 104 |
+// BadRequest denotes the type of this error |
|
| 105 |
+func (eis *ErrInvalidContainerSubnet) BadRequest() {}
|
|
| 106 |
+ |
|
| 107 |
+// ErrInvalidMtu is returned when the user provided MTU is not valid. |
|
| 108 |
+type ErrInvalidMtu int |
|
| 109 |
+ |
|
| 110 |
+func (eim ErrInvalidMtu) Error() string {
|
|
| 111 |
+ return fmt.Sprintf("invalid MTU number: %d", int(eim))
|
|
| 112 |
+} |
|
| 113 |
+ |
|
| 114 |
+// BadRequest denotes the type of this error |
|
| 115 |
+func (eim ErrInvalidMtu) BadRequest() {}
|
|
| 116 |
+ |
|
| 117 |
+// ErrIPFwdCfg is returned when ip forwarding setup is invoked when the configuration |
|
| 118 |
+// not enabled. |
|
| 119 |
+type ErrIPFwdCfg struct{}
|
|
| 120 |
+ |
|
| 121 |
+func (eipf *ErrIPFwdCfg) Error() string {
|
|
| 122 |
+ return "unexpected request to enable IP Forwarding" |
|
| 123 |
+} |
|
| 124 |
+ |
|
| 125 |
+// BadRequest denotes the type of this error |
|
| 126 |
+func (eipf *ErrIPFwdCfg) BadRequest() {}
|
|
| 127 |
+ |
|
| 128 |
+// ErrInvalidPort is returned when the container or host port specified in the port binding is not valid. |
|
| 129 |
+type ErrInvalidPort string |
|
| 130 |
+ |
|
| 131 |
+func (ip ErrInvalidPort) Error() string {
|
|
| 132 |
+ return fmt.Sprintf("invalid transport port: %s", string(ip))
|
|
| 133 |
+} |
|
| 134 |
+ |
|
| 135 |
+// BadRequest denotes the type of this error |
|
| 136 |
+func (ip ErrInvalidPort) BadRequest() {}
|
|
| 137 |
+ |
|
| 138 |
+// ErrUnsupportedAddressType is returned when the specified address type is not supported. |
|
| 139 |
+type ErrUnsupportedAddressType string |
|
| 140 |
+ |
|
| 141 |
+func (uat ErrUnsupportedAddressType) Error() string {
|
|
| 142 |
+ return fmt.Sprintf("unsupported address type: %s", string(uat))
|
|
| 143 |
+} |
|
| 144 |
+ |
|
| 145 |
+// BadRequest denotes the type of this error |
|
| 146 |
+func (uat ErrUnsupportedAddressType) BadRequest() {}
|
|
| 147 |
+ |
|
| 148 |
+// ErrInvalidAddressBinding is returned when the host address specified in the port binding is not valid. |
|
| 149 |
+type ErrInvalidAddressBinding string |
|
| 150 |
+ |
|
| 151 |
+func (iab ErrInvalidAddressBinding) Error() string {
|
|
| 152 |
+ return fmt.Sprintf("invalid host address in port binding: %s", string(iab))
|
|
| 153 |
+} |
|
| 154 |
+ |
|
| 155 |
+// BadRequest denotes the type of this error |
|
| 156 |
+func (iab ErrInvalidAddressBinding) BadRequest() {}
|
|
| 157 |
+ |
|
| 158 |
+// ActiveEndpointsError is returned when there are |
|
| 159 |
+// still active endpoints in the network being deleted. |
|
| 160 |
+type ActiveEndpointsError string |
|
| 161 |
+ |
|
| 162 |
+func (aee ActiveEndpointsError) Error() string {
|
|
| 163 |
+ return fmt.Sprintf("network %s has active endpoint", string(aee))
|
|
| 164 |
+} |
|
| 165 |
+ |
|
| 166 |
+// Forbidden denotes the type of this error |
|
| 167 |
+func (aee ActiveEndpointsError) Forbidden() {}
|
|
| 168 |
+ |
|
| 169 |
+// InvalidNetworkIDError is returned when the passed |
|
| 170 |
+// network id for an existing network is not a known id. |
|
| 171 |
+type InvalidNetworkIDError string |
|
| 172 |
+ |
|
| 173 |
+func (inie InvalidNetworkIDError) Error() string {
|
|
| 174 |
+ return fmt.Sprintf("invalid network id %s", string(inie))
|
|
| 175 |
+} |
|
| 176 |
+ |
|
| 177 |
+// NotFound denotes the type of this error |
|
| 178 |
+func (inie InvalidNetworkIDError) NotFound() {}
|
|
| 179 |
+ |
|
| 180 |
+// InvalidEndpointIDError is returned when the passed |
|
| 181 |
+// endpoint id is not valid. |
|
| 182 |
+type InvalidEndpointIDError string |
|
| 183 |
+ |
|
| 184 |
+func (ieie InvalidEndpointIDError) Error() string {
|
|
| 185 |
+ return fmt.Sprintf("invalid endpoint id: %s", string(ieie))
|
|
| 186 |
+} |
|
| 187 |
+ |
|
| 188 |
+// BadRequest denotes the type of this error |
|
| 189 |
+func (ieie InvalidEndpointIDError) BadRequest() {}
|
|
| 190 |
+ |
|
| 191 |
+// InvalidSandboxIDError is returned when the passed |
|
| 192 |
+// sandbox id is not valid. |
|
| 193 |
+type InvalidSandboxIDError string |
|
| 194 |
+ |
|
| 195 |
+func (isie InvalidSandboxIDError) Error() string {
|
|
| 196 |
+ return fmt.Sprintf("invalid sanbox id: %s", string(isie))
|
|
| 197 |
+} |
|
| 198 |
+ |
|
| 199 |
+// BadRequest denotes the type of this error |
|
| 200 |
+func (isie InvalidSandboxIDError) BadRequest() {}
|
|
| 201 |
+ |
|
| 202 |
+// EndpointNotFoundError is returned when the no endpoint |
|
| 203 |
+// with the passed endpoint id is found. |
|
| 204 |
+type EndpointNotFoundError string |
|
| 205 |
+ |
|
| 206 |
+func (enfe EndpointNotFoundError) Error() string {
|
|
| 207 |
+ return fmt.Sprintf("endpoint not found: %s", string(enfe))
|
|
| 208 |
+} |
|
| 209 |
+ |
|
| 210 |
+// NotFound denotes the type of this error |
|
| 211 |
+func (enfe EndpointNotFoundError) NotFound() {}
|
|
| 212 |
+ |
|
| 213 |
+// NonDefaultBridgeExistError is returned when a non-default |
|
| 214 |
+// bridge config is passed but it does not already exist. |
|
| 215 |
+type NonDefaultBridgeExistError string |
|
| 216 |
+ |
|
| 217 |
+func (ndbee NonDefaultBridgeExistError) Error() string {
|
|
| 218 |
+ return fmt.Sprintf("bridge device with non default name %s must be created manually", string(ndbee))
|
|
| 219 |
+} |
|
| 220 |
+ |
|
| 221 |
+// Forbidden denotes the type of this error |
|
| 222 |
+func (ndbee NonDefaultBridgeExistError) Forbidden() {}
|
|
| 223 |
+ |
|
| 224 |
+// FixedCIDRv4Error is returned when fixed-cidrv4 configuration |
|
| 225 |
+// failed. |
|
| 226 |
+type FixedCIDRv4Error struct {
|
|
| 227 |
+ Net *net.IPNet |
|
| 228 |
+ Subnet *net.IPNet |
|
| 229 |
+ Err error |
|
| 230 |
+} |
|
| 231 |
+ |
|
| 232 |
+func (fcv4 *FixedCIDRv4Error) Error() string {
|
|
| 233 |
+ return fmt.Sprintf("setup FixedCIDRv4 failed for subnet %s in %s: %v", fcv4.Subnet, fcv4.Net, fcv4.Err)
|
|
| 234 |
+} |
|
| 235 |
+ |
|
| 236 |
+// InternalError denotes the type of this error |
|
| 237 |
+func (fcv4 *FixedCIDRv4Error) InternalError() {}
|
|
| 238 |
+ |
|
| 239 |
+// FixedCIDRv6Error is returned when fixed-cidrv6 configuration |
|
| 240 |
+// failed. |
|
| 241 |
+type FixedCIDRv6Error struct {
|
|
| 242 |
+ Net *net.IPNet |
|
| 243 |
+ Err error |
|
| 244 |
+} |
|
| 245 |
+ |
|
| 246 |
+func (fcv6 *FixedCIDRv6Error) Error() string {
|
|
| 247 |
+ return fmt.Sprintf("setup FixedCIDRv6 failed for subnet %s in %s: %v", fcv6.Net, fcv6.Net, fcv6.Err)
|
|
| 248 |
+} |
|
| 249 |
+ |
|
| 250 |
+// InternalError denotes the type of this error |
|
| 251 |
+func (fcv6 *FixedCIDRv6Error) InternalError() {}
|
|
| 252 |
+ |
|
| 253 |
+// IPTableCfgError is returned when an unexpected ip tables configuration is entered |
|
| 254 |
+type IPTableCfgError string |
|
| 255 |
+ |
|
| 256 |
+func (name IPTableCfgError) Error() string {
|
|
| 257 |
+ return fmt.Sprintf("unexpected request to set IP tables for interface: %s", string(name))
|
|
| 258 |
+} |
|
| 259 |
+ |
|
| 260 |
+// BadRequest denotes the type of this error |
|
| 261 |
+func (name IPTableCfgError) BadRequest() {}
|
|
| 262 |
+ |
|
| 263 |
+// InvalidIPTablesCfgError is returned when an invalid ip tables configuration is entered |
|
| 264 |
+type InvalidIPTablesCfgError string |
|
| 265 |
+ |
|
| 266 |
+func (action InvalidIPTablesCfgError) Error() string {
|
|
| 267 |
+ return fmt.Sprintf("Invalid IPTables action '%s'", string(action))
|
|
| 268 |
+} |
|
| 269 |
+ |
|
| 270 |
+// BadRequest denotes the type of this error |
|
| 271 |
+func (action InvalidIPTablesCfgError) BadRequest() {}
|
|
| 272 |
+ |
|
| 273 |
+// IPv4AddrRangeError is returned when a valid IP address range couldn't be found. |
|
| 274 |
+type IPv4AddrRangeError string |
|
| 275 |
+ |
|
| 276 |
+func (name IPv4AddrRangeError) Error() string {
|
|
| 277 |
+ return fmt.Sprintf("can't find an address range for interface %q", string(name))
|
|
| 278 |
+} |
|
| 279 |
+ |
|
| 280 |
+// BadRequest denotes the type of this error |
|
| 281 |
+func (name IPv4AddrRangeError) BadRequest() {}
|
|
| 282 |
+ |
|
| 283 |
+// IPv4AddrAddError is returned when IPv4 address could not be added to the bridge. |
|
| 284 |
+type IPv4AddrAddError struct {
|
|
| 285 |
+ IP *net.IPNet |
|
| 286 |
+ Err error |
|
| 287 |
+} |
|
| 288 |
+ |
|
| 289 |
+func (ipv4 *IPv4AddrAddError) Error() string {
|
|
| 290 |
+ return fmt.Sprintf("failed to add IPv4 address %s to bridge: %v", ipv4.IP, ipv4.Err)
|
|
| 291 |
+} |
|
| 292 |
+ |
|
| 293 |
+// InternalError denotes the type of this error |
|
| 294 |
+func (ipv4 *IPv4AddrAddError) InternalError() {}
|
|
| 295 |
+ |
|
| 296 |
+// IPv6AddrAddError is returned when IPv6 address could not be added to the bridge. |
|
| 297 |
+type IPv6AddrAddError struct {
|
|
| 298 |
+ IP *net.IPNet |
|
| 299 |
+ Err error |
|
| 300 |
+} |
|
| 301 |
+ |
|
| 302 |
+func (ipv6 *IPv6AddrAddError) Error() string {
|
|
| 303 |
+ return fmt.Sprintf("failed to add IPv6 address %s to bridge: %v", ipv6.IP, ipv6.Err)
|
|
| 304 |
+} |
|
| 305 |
+ |
|
| 306 |
+// InternalError denotes the type of this error |
|
| 307 |
+func (ipv6 *IPv6AddrAddError) InternalError() {}
|
|
| 308 |
+ |
|
| 309 |
+// IPv4AddrNoMatchError is returned when the bridge's IPv4 address does not match configured. |
|
| 310 |
+type IPv4AddrNoMatchError struct {
|
|
| 311 |
+ IP net.IP |
|
| 312 |
+ CfgIP net.IP |
|
| 313 |
+} |
|
| 314 |
+ |
|
| 315 |
+func (ipv4 *IPv4AddrNoMatchError) Error() string {
|
|
| 316 |
+ return fmt.Sprintf("bridge IPv4 (%s) does not match requested configuration %s", ipv4.IP, ipv4.CfgIP)
|
|
| 317 |
+} |
|
| 318 |
+ |
|
| 319 |
+// BadRequest denotes the type of this error |
|
| 320 |
+func (ipv4 *IPv4AddrNoMatchError) BadRequest() {}
|
|
| 321 |
+ |
|
| 322 |
+// IPv6AddrNoMatchError is returned when the bridge's IPv6 address does not match configured. |
|
| 323 |
+type IPv6AddrNoMatchError net.IPNet |
|
| 324 |
+ |
|
| 325 |
+func (ipv6 *IPv6AddrNoMatchError) Error() string {
|
|
| 326 |
+ return fmt.Sprintf("bridge IPv6 addresses do not match the expected bridge configuration %s", (*net.IPNet)(ipv6).String())
|
|
| 327 |
+} |
|
| 328 |
+ |
|
| 329 |
+// BadRequest denotes the type of this error |
|
| 330 |
+func (ipv6 *IPv6AddrNoMatchError) BadRequest() {}
|
|
| 331 |
+ |
|
| 332 |
+// InvalidLinkIPAddrError is returned when a link is configured to a container with an invalid ip address |
|
| 333 |
+type InvalidLinkIPAddrError string |
|
| 334 |
+ |
|
| 335 |
+func (address InvalidLinkIPAddrError) Error() string {
|
|
| 336 |
+ return fmt.Sprintf("Cannot link to a container with Invalid IP Address '%s'", string(address))
|
|
| 337 |
+} |
|
| 338 |
+ |
|
| 339 |
+// BadRequest denotes the type of this error |
|
| 340 |
+func (address InvalidLinkIPAddrError) BadRequest() {}
|
| ... | ... |
@@ -6,13 +6,13 @@ import ( |
| 6 | 6 |
|
| 7 | 7 |
log "github.com/Sirupsen/logrus" |
| 8 | 8 |
"github.com/docker/libnetwork/iptables" |
| 9 |
- "github.com/docker/libnetwork/netutils" |
|
| 9 |
+ "github.com/docker/libnetwork/types" |
|
| 10 | 10 |
) |
| 11 | 11 |
|
| 12 | 12 |
type link struct {
|
| 13 | 13 |
parentIP string |
| 14 | 14 |
childIP string |
| 15 |
- ports []netutils.TransportPort |
|
| 15 |
+ ports []types.TransportPort |
|
| 16 | 16 |
bridge string |
| 17 | 17 |
} |
| 18 | 18 |
|
| ... | ... |
@@ -20,7 +20,7 @@ func (l *link) String() string {
|
| 20 | 20 |
return fmt.Sprintf("%s <-> %s [%v] on %s", l.parentIP, l.childIP, l.ports, l.bridge)
|
| 21 | 21 |
} |
| 22 | 22 |
|
| 23 |
-func newLink(parentIP, childIP string, ports []netutils.TransportPort, bridge string) *link {
|
|
| 23 |
+func newLink(parentIP, childIP string, ports []types.TransportPort, bridge string) *link {
|
|
| 24 | 24 |
return &link{
|
| 25 | 25 |
childIP: childIP, |
| 26 | 26 |
parentIP: parentIP, |
| ... | ... |
@@ -45,7 +45,7 @@ func (l *link) Disable() {
|
| 45 | 45 |
// that returns typed errors |
| 46 | 46 |
} |
| 47 | 47 |
|
| 48 |
-func linkContainers(action, parentIP, childIP string, ports []netutils.TransportPort, bridge string, |
|
| 48 |
+func linkContainers(action, parentIP, childIP string, ports []types.TransportPort, bridge string, |
|
| 49 | 49 |
ignoreErrors bool) error {
|
| 50 | 50 |
var nfAction iptables.Action |
| 51 | 51 |
|
| ... | ... |
@@ -57,7 +57,7 @@ func linkContainers(action, parentIP, childIP string, ports []netutils.Transport |
| 57 | 57 |
case "-D": |
| 58 | 58 |
nfAction = iptables.Delete |
| 59 | 59 |
default: |
| 60 |
- return invalidIPTablesCfgError(action) |
|
| 60 |
+ return InvalidIPTablesCfgError(action) |
|
| 61 | 61 |
} |
| 62 | 62 |
|
| 63 | 63 |
ip1 := net.ParseIP(parentIP) |
| ... | ... |
@@ -3,14 +3,14 @@ package bridge |
| 3 | 3 |
import ( |
| 4 | 4 |
"testing" |
| 5 | 5 |
|
| 6 |
- "github.com/docker/libnetwork/netutils" |
|
| 6 |
+ "github.com/docker/libnetwork/types" |
|
| 7 | 7 |
) |
| 8 | 8 |
|
| 9 |
-func getPorts() []netutils.TransportPort {
|
|
| 10 |
- return []netutils.TransportPort{
|
|
| 11 |
- netutils.TransportPort{Proto: netutils.TCP, Port: uint16(5000)},
|
|
| 12 |
- netutils.TransportPort{Proto: netutils.UDP, Port: uint16(400)},
|
|
| 13 |
- netutils.TransportPort{Proto: netutils.TCP, Port: uint16(600)},
|
|
| 9 |
+func getPorts() []types.TransportPort {
|
|
| 10 |
+ return []types.TransportPort{
|
|
| 11 |
+ types.TransportPort{Proto: types.TCP, Port: uint16(5000)},
|
|
| 12 |
+ types.TransportPort{Proto: types.UDP, Port: uint16(400)},
|
|
| 13 |
+ types.TransportPort{Proto: types.TCP, Port: uint16(600)},
|
|
| 14 | 14 |
} |
| 15 | 15 |
} |
| 16 | 16 |
|
| ... | ... |
@@ -125,8 +125,8 @@ func TestLinkCreateTwo(t *testing.T) {
|
| 125 | 125 |
te2 := &testEndpoint{ifaces: []*testInterface{}}
|
| 126 | 126 |
err = d.CreateEndpoint("dummy", "ep", te2, nil)
|
| 127 | 127 |
if err != nil {
|
| 128 |
- if err != driverapi.ErrEndpointExists {
|
|
| 129 |
- t.Fatalf("Failed with a wrong error :%s", err.Error())
|
|
| 128 |
+ if _, ok := err.(driverapi.ErrEndpointExists); !ok {
|
|
| 129 |
+ t.Fatalf("Failed with a wrong error: %s", err.Error())
|
|
| 130 | 130 |
} |
| 131 | 131 |
} else {
|
| 132 | 132 |
t.Fatalf("Expected to fail while trying to add same endpoint twice")
|
| ... | ... |
@@ -7,15 +7,15 @@ import ( |
| 7 | 7 |
"net" |
| 8 | 8 |
|
| 9 | 9 |
"github.com/Sirupsen/logrus" |
| 10 |
- "github.com/docker/libnetwork/netutils" |
|
| 11 | 10 |
"github.com/docker/libnetwork/sandbox" |
| 11 |
+ "github.com/docker/libnetwork/types" |
|
| 12 | 12 |
) |
| 13 | 13 |
|
| 14 | 14 |
var ( |
| 15 | 15 |
defaultBindingIP = net.IPv4(0, 0, 0, 0) |
| 16 | 16 |
) |
| 17 | 17 |
|
| 18 |
-func allocatePorts(epConfig *EndpointConfiguration, intf *sandbox.Interface, reqDefBindIP net.IP, ulPxyEnabled bool) ([]netutils.PortBinding, error) {
|
|
| 18 |
+func allocatePorts(epConfig *EndpointConfiguration, intf *sandbox.Interface, reqDefBindIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {
|
|
| 19 | 19 |
if epConfig == nil || epConfig.PortBindings == nil {
|
| 20 | 20 |
return nil, nil |
| 21 | 21 |
} |
| ... | ... |
@@ -28,8 +28,8 @@ func allocatePorts(epConfig *EndpointConfiguration, intf *sandbox.Interface, req |
| 28 | 28 |
return allocatePortsInternal(epConfig.PortBindings, intf.Address.IP, defHostIP, ulPxyEnabled) |
| 29 | 29 |
} |
| 30 | 30 |
|
| 31 |
-func allocatePortsInternal(bindings []netutils.PortBinding, containerIP, defHostIP net.IP, ulPxyEnabled bool) ([]netutils.PortBinding, error) {
|
|
| 32 |
- bs := make([]netutils.PortBinding, 0, len(bindings)) |
|
| 31 |
+func allocatePortsInternal(bindings []types.PortBinding, containerIP, defHostIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {
|
|
| 32 |
+ bs := make([]types.PortBinding, 0, len(bindings)) |
|
| 33 | 33 |
for _, c := range bindings {
|
| 34 | 34 |
b := c.GetCopy() |
| 35 | 35 |
if err := allocatePort(&b, containerIP, defHostIP, ulPxyEnabled); err != nil {
|
| ... | ... |
@@ -44,7 +44,7 @@ func allocatePortsInternal(bindings []netutils.PortBinding, containerIP, defHost |
| 44 | 44 |
return bs, nil |
| 45 | 45 |
} |
| 46 | 46 |
|
| 47 |
-func allocatePort(bnd *netutils.PortBinding, containerIP, defHostIP net.IP, ulPxyEnabled bool) error {
|
|
| 47 |
+func allocatePort(bnd *types.PortBinding, containerIP, defHostIP net.IP, ulPxyEnabled bool) error {
|
|
| 48 | 48 |
var ( |
| 49 | 49 |
host net.Addr |
| 50 | 50 |
err error |
| ... | ... |
@@ -98,7 +98,7 @@ func releasePorts(ep *bridgeEndpoint) error {
|
| 98 | 98 |
return releasePortsInternal(ep.portMapping) |
| 99 | 99 |
} |
| 100 | 100 |
|
| 101 |
-func releasePortsInternal(bindings []netutils.PortBinding) error {
|
|
| 101 |
+func releasePortsInternal(bindings []types.PortBinding) error {
|
|
| 102 | 102 |
var errorBuf bytes.Buffer |
| 103 | 103 |
|
| 104 | 104 |
// Attempt to release all port bindings, do not stop on failure |
| ... | ... |
@@ -114,7 +114,7 @@ func releasePortsInternal(bindings []netutils.PortBinding) error {
|
| 114 | 114 |
return nil |
| 115 | 115 |
} |
| 116 | 116 |
|
| 117 |
-func releasePort(bnd netutils.PortBinding) error {
|
|
| 117 |
+func releasePort(bnd types.PortBinding) error {
|
|
| 118 | 118 |
// Construct the host side transport address |
| 119 | 119 |
host, err := bnd.HostAddr() |
| 120 | 120 |
if err != nil {
|
| ... | ... |
@@ -7,6 +7,7 @@ import ( |
| 7 | 7 |
"github.com/docker/docker/pkg/reexec" |
| 8 | 8 |
"github.com/docker/libnetwork/netlabel" |
| 9 | 9 |
"github.com/docker/libnetwork/netutils" |
| 10 |
+ "github.com/docker/libnetwork/types" |
|
| 10 | 11 |
) |
| 11 | 12 |
|
| 12 | 13 |
func TestMain(m *testing.M) {
|
| ... | ... |
@@ -20,9 +21,9 @@ func TestPortMappingConfig(t *testing.T) {
|
| 20 | 20 |
defer netutils.SetupTestNetNS(t)() |
| 21 | 21 |
d := newDriver() |
| 22 | 22 |
|
| 23 |
- binding1 := netutils.PortBinding{Proto: netutils.UDP, Port: uint16(400), HostPort: uint16(54000)}
|
|
| 24 |
- binding2 := netutils.PortBinding{Proto: netutils.TCP, Port: uint16(500), HostPort: uint16(65000)}
|
|
| 25 |
- portBindings := []netutils.PortBinding{binding1, binding2}
|
|
| 23 |
+ binding1 := types.PortBinding{Proto: types.UDP, Port: uint16(400), HostPort: uint16(54000)}
|
|
| 24 |
+ binding2 := types.PortBinding{Proto: types.TCP, Port: uint16(500), HostPort: uint16(65000)}
|
|
| 25 |
+ portBindings := []types.PortBinding{binding1, binding2}
|
|
| 26 | 26 |
|
| 27 | 27 |
epOptions := make(map[string]interface{})
|
| 28 | 28 |
epOptions[netlabel.PortMap] = portBindings |
| ... | ... |
@@ -1,6 +1,8 @@ |
| 1 | 1 |
package bridge |
| 2 | 2 |
|
| 3 |
-import log "github.com/Sirupsen/logrus" |
|
| 3 |
+import ( |
|
| 4 |
+ log "github.com/Sirupsen/logrus" |
|
| 5 |
+) |
|
| 4 | 6 |
|
| 5 | 7 |
func setupFixedCIDRv4(config *NetworkConfiguration, i *bridgeInterface) error {
|
| 6 | 8 |
addrv4, _, err := i.addresses() |
| ... | ... |
@@ -10,7 +12,7 @@ func setupFixedCIDRv4(config *NetworkConfiguration, i *bridgeInterface) error {
|
| 10 | 10 |
|
| 11 | 11 |
log.Debugf("Using IPv4 subnet: %v", config.FixedCIDR)
|
| 12 | 12 |
if err := ipAllocator.RegisterSubnet(addrv4.IPNet, config.FixedCIDR); err != nil {
|
| 13 |
- return &FixedCIDRv4Error{subnet: config.FixedCIDR, net: addrv4.IPNet, err: err}
|
|
| 13 |
+ return &FixedCIDRv4Error{Subnet: config.FixedCIDR, Net: addrv4.IPNet, Err: err}
|
|
| 14 | 14 |
} |
| 15 | 15 |
|
| 16 | 16 |
return nil |
| ... | ... |
@@ -1,11 +1,13 @@ |
| 1 | 1 |
package bridge |
| 2 | 2 |
|
| 3 |
-import log "github.com/Sirupsen/logrus" |
|
| 3 |
+import ( |
|
| 4 |
+ log "github.com/Sirupsen/logrus" |
|
| 5 |
+) |
|
| 4 | 6 |
|
| 5 | 7 |
func setupFixedCIDRv6(config *NetworkConfiguration, i *bridgeInterface) error {
|
| 6 | 8 |
log.Debugf("Using IPv6 subnet: %v", config.FixedCIDRv6)
|
| 7 | 9 |
if err := ipAllocator.RegisterSubnet(config.FixedCIDRv6, config.FixedCIDRv6); err != nil {
|
| 8 |
- return &FixedCIDRv6Error{net: config.FixedCIDRv6, err: err}
|
|
| 10 |
+ return &FixedCIDRv6Error{Net: config.FixedCIDRv6, Err: err}
|
|
| 9 | 11 |
} |
| 10 | 12 |
|
| 11 | 13 |
return nil |
| ... | ... |
@@ -47,7 +47,7 @@ func TestUnexpectedSetupIPForwarding(t *testing.T) {
|
| 47 | 47 |
t.Fatal("Setup IP forwarding was expected to fail")
|
| 48 | 48 |
} |
| 49 | 49 |
|
| 50 |
- if err != ErrIPFwdCfg {
|
|
| 50 |
+ if _, ok := err.(*ErrIPFwdCfg); !ok {
|
|
| 51 | 51 |
t.Fatalf("Setup IP forwarding failed with unexpected error: %v", err)
|
| 52 | 52 |
} |
| 53 | 53 |
} |
| ... | ... |
@@ -16,7 +16,7 @@ const ( |
| 16 | 16 |
func setupIPTables(config *NetworkConfiguration, i *bridgeInterface) error {
|
| 17 | 17 |
// Sanity check. |
| 18 | 18 |
if config.EnableIPTables == false {
|
| 19 |
- return ipTableCfgError(config.BridgeName) |
|
| 19 |
+ return IPTableCfgError(config.BridgeName) |
|
| 20 | 20 |
} |
| 21 | 21 |
|
| 22 | 22 |
hairpinMode := !config.EnableUserlandProxy |
| ... | ... |
@@ -71,7 +71,7 @@ func setupBridgeIPv4(config *NetworkConfiguration, i *bridgeInterface) error {
|
| 71 | 71 |
|
| 72 | 72 |
log.Debugf("Creating bridge interface %q with network %s", config.BridgeName, bridgeIPv4)
|
| 73 | 73 |
if err := netlink.AddrAdd(i.Link, &netlink.Addr{IPNet: bridgeIPv4}); err != nil {
|
| 74 |
- return &IPv4AddrAddError{ip: bridgeIPv4, err: err}
|
|
| 74 |
+ return &IPv4AddrAddError{IP: bridgeIPv4, Err: err}
|
|
| 75 | 75 |
} |
| 76 | 76 |
|
| 77 | 77 |
// Store bridge network and default gateway |
| ... | ... |
@@ -114,7 +114,7 @@ func electBridgeIPv4(config *NetworkConfiguration) (*net.IPNet, error) {
|
| 114 | 114 |
|
| 115 | 115 |
func setupGatewayIPv4(config *NetworkConfiguration, i *bridgeInterface) error {
|
| 116 | 116 |
if !i.bridgeIPv4.Contains(config.DefaultGatewayIPv4) {
|
| 117 |
- return ErrInvalidGateway |
|
| 117 |
+ return &ErrInvalidGateway{}
|
|
| 118 | 118 |
} |
| 119 | 119 |
if _, err := ipAllocator.RequestIP(i.bridgeIPv4, config.DefaultGatewayIPv4); err != nil {
|
| 120 | 120 |
return err |
| ... | ... |
@@ -37,7 +37,7 @@ func setupBridgeIPv6(config *NetworkConfiguration, i *bridgeInterface) error {
|
| 37 | 37 |
// Add the default link local ipv6 address if it doesn't exist |
| 38 | 38 |
if !findIPv6Address(netlink.Addr{IPNet: bridgeIPv6}, addrsv6) {
|
| 39 | 39 |
if err := netlink.AddrAdd(i.Link, &netlink.Addr{IPNet: bridgeIPv6}); err != nil {
|
| 40 |
- return &IPv6AddrAddError{ip: bridgeIPv6, err: err}
|
|
| 40 |
+ return &IPv6AddrAddError{IP: bridgeIPv6, Err: err}
|
|
| 41 | 41 |
} |
| 42 | 42 |
} |
| 43 | 43 |
|
| ... | ... |
@@ -50,10 +50,10 @@ func setupBridgeIPv6(config *NetworkConfiguration, i *bridgeInterface) error {
|
| 50 | 50 |
|
| 51 | 51 |
func setupGatewayIPv6(config *NetworkConfiguration, i *bridgeInterface) error {
|
| 52 | 52 |
if config.FixedCIDRv6 == nil {
|
| 53 |
- return ErrInvalidContainerSubnet |
|
| 53 |
+ return &ErrInvalidContainerSubnet{}
|
|
| 54 | 54 |
} |
| 55 | 55 |
if !config.FixedCIDRv6.Contains(config.DefaultGatewayIPv6) {
|
| 56 |
- return ErrInvalidGateway |
|
| 56 |
+ return &ErrInvalidGateway{}
|
|
| 57 | 57 |
} |
| 58 | 58 |
if _, err := ipAllocator.RequestIP(config.FixedCIDRv6, config.DefaultGatewayIPv6); err != nil {
|
| 59 | 59 |
return err |
| ... | ... |
@@ -1,6 +1,8 @@ |
| 1 | 1 |
package bridge |
| 2 | 2 |
|
| 3 |
-import "github.com/vishvananda/netlink" |
|
| 3 |
+import ( |
|
| 4 |
+ "github.com/vishvananda/netlink" |
|
| 5 |
+) |
|
| 4 | 6 |
|
| 5 | 7 |
func setupVerifyAndReconcile(config *NetworkConfiguration, i *bridgeInterface) error {
|
| 6 | 8 |
// Fetch a single IPv4 and a slice of IPv6 addresses from the bridge. |
| ... | ... |
@@ -11,12 +13,12 @@ func setupVerifyAndReconcile(config *NetworkConfiguration, i *bridgeInterface) e |
| 11 | 11 |
|
| 12 | 12 |
// Verify that the bridge does have an IPv4 address. |
| 13 | 13 |
if addrv4.IPNet == nil {
|
| 14 |
- return ErrNoIPAddr |
|
| 14 |
+ return &ErrNoIPAddr{}
|
|
| 15 | 15 |
} |
| 16 | 16 |
|
| 17 | 17 |
// Verify that the bridge IPv4 address matches the requested configuration. |
| 18 | 18 |
if config.AddressIPv4 != nil && !addrv4.IP.Equal(config.AddressIPv4.IP) {
|
| 19 |
- return &IPv4AddrNoMatchError{ip: addrv4.IP, cfgIP: config.AddressIPv4.IP}
|
|
| 19 |
+ return &IPv4AddrNoMatchError{IP: addrv4.IP, CfgIP: config.AddressIPv4.IP}
|
|
| 20 | 20 |
} |
| 21 | 21 |
|
| 22 | 22 |
// Verify that one of the bridge IPv6 addresses matches the requested |
| ... | ... |
@@ -1,7 +1,8 @@ |
| 1 | 1 |
package remote |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
- "errors" |
|
| 4 |
+ "fmt" |
|
| 5 |
+ "net" |
|
| 5 | 6 |
|
| 6 | 7 |
log "github.com/Sirupsen/logrus" |
| 7 | 8 |
"github.com/docker/docker/pkg/plugins" |
| ... | ... |
@@ -9,59 +10,202 @@ import ( |
| 9 | 9 |
"github.com/docker/libnetwork/types" |
| 10 | 10 |
) |
| 11 | 11 |
|
| 12 |
-var errNoCallback = errors.New("No Callback handler registered with Driver")
|
|
| 13 |
- |
|
| 14 | 12 |
type driver struct {
|
| 15 | 13 |
endpoint *plugins.Client |
| 16 | 14 |
networkType string |
| 17 | 15 |
} |
| 18 | 16 |
|
| 19 |
-// Init does the necessary work to register remote drivers |
|
| 17 |
+func newDriver(name string, client *plugins.Client) driverapi.Driver {
|
|
| 18 |
+ return &driver{networkType: name, endpoint: client}
|
|
| 19 |
+} |
|
| 20 |
+ |
|
| 21 |
+// Init makes sure a remote driver is registered when a network driver |
|
| 22 |
+// plugin is activated. |
|
| 20 | 23 |
func Init(dc driverapi.DriverCallback) error {
|
| 21 | 24 |
plugins.Handle(driverapi.NetworkPluginEndpointType, func(name string, client *plugins.Client) {
|
| 22 |
- |
|
| 23 |
- // TODO : Handhake with the Remote Plugin goes here |
|
| 24 |
- |
|
| 25 |
- newDriver := &driver{networkType: name, endpoint: client}
|
|
| 26 |
- if err := dc.RegisterDriver(name, newDriver); err != nil {
|
|
| 27 |
- log.Errorf("Error registering Driver for %s due to %v", name, err)
|
|
| 25 |
+ if err := dc.RegisterDriver(name, newDriver(name, client)); err != nil {
|
|
| 26 |
+ log.Errorf("error registering driver for %s due to %v", name, err)
|
|
| 28 | 27 |
} |
| 29 | 28 |
}) |
| 30 | 29 |
return nil |
| 31 | 30 |
} |
| 32 | 31 |
|
| 32 |
+// Config is not implemented for remote drivers, since it is assumed |
|
| 33 |
+// to be supplied to the remote process out-of-band (e.g., as command |
|
| 34 |
+// line arguments). |
|
| 33 | 35 |
func (d *driver) Config(option map[string]interface{}) error {
|
| 34 |
- return driverapi.ErrNotImplemented |
|
| 36 |
+ return &driverapi.ErrNotImplemented{}
|
|
| 37 |
+} |
|
| 38 |
+ |
|
| 39 |
+func (d *driver) call(methodName string, arg interface{}, retVal maybeError) error {
|
|
| 40 |
+ method := driverapi.NetworkPluginEndpointType + "." + methodName |
|
| 41 |
+ err := d.endpoint.Call(method, arg, retVal) |
|
| 42 |
+ if err != nil {
|
|
| 43 |
+ return err |
|
| 44 |
+ } |
|
| 45 |
+ if e := retVal.getError(); e != "" {
|
|
| 46 |
+ return fmt.Errorf("remote: %s", e)
|
|
| 47 |
+ } |
|
| 48 |
+ return nil |
|
| 35 | 49 |
} |
| 36 | 50 |
|
| 37 |
-func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) error {
|
|
| 38 |
- return driverapi.ErrNotImplemented |
|
| 51 |
+func (d *driver) CreateNetwork(id types.UUID, options map[string]interface{}) error {
|
|
| 52 |
+ create := &createNetworkRequest{
|
|
| 53 |
+ NetworkID: string(id), |
|
| 54 |
+ Options: options, |
|
| 55 |
+ } |
|
| 56 |
+ return d.call("CreateNetwork", create, &createNetworkResponse{})
|
|
| 39 | 57 |
} |
| 40 | 58 |
|
| 41 | 59 |
func (d *driver) DeleteNetwork(nid types.UUID) error {
|
| 42 |
- return driverapi.ErrNotImplemented |
|
| 60 |
+ delete := &deleteNetworkRequest{NetworkID: string(nid)}
|
|
| 61 |
+ return d.call("DeleteNetwork", delete, &deleteNetworkResponse{})
|
|
| 43 | 62 |
} |
| 44 | 63 |
|
| 45 | 64 |
func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error {
|
| 46 |
- return driverapi.ErrNotImplemented |
|
| 65 |
+ if epInfo == nil {
|
|
| 66 |
+ return fmt.Errorf("must not be called with nil EndpointInfo")
|
|
| 67 |
+ } |
|
| 68 |
+ |
|
| 69 |
+ reqIfaces := make([]*endpointInterface, len(epInfo.Interfaces())) |
|
| 70 |
+ for i, iface := range epInfo.Interfaces() {
|
|
| 71 |
+ addr4 := iface.Address() |
|
| 72 |
+ addr6 := iface.AddressIPv6() |
|
| 73 |
+ reqIfaces[i] = &endpointInterface{
|
|
| 74 |
+ ID: iface.ID(), |
|
| 75 |
+ Address: addr4.String(), |
|
| 76 |
+ AddressIPv6: addr6.String(), |
|
| 77 |
+ MacAddress: iface.MacAddress().String(), |
|
| 78 |
+ } |
|
| 79 |
+ } |
|
| 80 |
+ create := &createEndpointRequest{
|
|
| 81 |
+ NetworkID: string(nid), |
|
| 82 |
+ EndpointID: string(eid), |
|
| 83 |
+ Interfaces: reqIfaces, |
|
| 84 |
+ Options: epOptions, |
|
| 85 |
+ } |
|
| 86 |
+ var res createEndpointResponse |
|
| 87 |
+ if err := d.call("CreateEndpoint", create, &res); err != nil {
|
|
| 88 |
+ return err |
|
| 89 |
+ } |
|
| 90 |
+ |
|
| 91 |
+ ifaces, err := res.parseInterfaces() |
|
| 92 |
+ if err != nil {
|
|
| 93 |
+ return err |
|
| 94 |
+ } |
|
| 95 |
+ if len(reqIfaces) > 0 && len(ifaces) > 0 {
|
|
| 96 |
+ // We're not supposed to add interfaces if there already are |
|
| 97 |
+ // some. Attempt to roll back |
|
| 98 |
+ return errorWithRollback("driver attempted to add more interfaces", d.DeleteEndpoint(nid, eid))
|
|
| 99 |
+ } |
|
| 100 |
+ for _, iface := range ifaces {
|
|
| 101 |
+ var addr4, addr6 net.IPNet |
|
| 102 |
+ if iface.Address != nil {
|
|
| 103 |
+ addr4 = *(iface.Address) |
|
| 104 |
+ } |
|
| 105 |
+ if iface.AddressIPv6 != nil {
|
|
| 106 |
+ addr6 = *(iface.AddressIPv6) |
|
| 107 |
+ } |
|
| 108 |
+ if err := epInfo.AddInterface(iface.ID, iface.MacAddress, addr4, addr6); err != nil {
|
|
| 109 |
+ return errorWithRollback(fmt.Sprintf("failed to AddInterface %v: %s", iface, err), d.DeleteEndpoint(nid, eid))
|
|
| 110 |
+ } |
|
| 111 |
+ } |
|
| 112 |
+ return nil |
|
| 113 |
+} |
|
| 114 |
+ |
|
| 115 |
+func errorWithRollback(msg string, err error) error {
|
|
| 116 |
+ rollback := "rolled back" |
|
| 117 |
+ if err != nil {
|
|
| 118 |
+ rollback = "failed to roll back: " + err.Error() |
|
| 119 |
+ } |
|
| 120 |
+ return fmt.Errorf("%s; %s", msg, rollback)
|
|
| 47 | 121 |
} |
| 48 | 122 |
|
| 49 | 123 |
func (d *driver) DeleteEndpoint(nid, eid types.UUID) error {
|
| 50 |
- return driverapi.ErrNotImplemented |
|
| 124 |
+ delete := &deleteEndpointRequest{
|
|
| 125 |
+ NetworkID: string(nid), |
|
| 126 |
+ EndpointID: string(eid), |
|
| 127 |
+ } |
|
| 128 |
+ return d.call("DeleteEndpoint", delete, &deleteEndpointResponse{})
|
|
| 51 | 129 |
} |
| 52 | 130 |
|
| 53 | 131 |
func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{}, error) {
|
| 54 |
- return nil, driverapi.ErrNotImplemented |
|
| 132 |
+ info := &endpointInfoRequest{
|
|
| 133 |
+ NetworkID: string(nid), |
|
| 134 |
+ EndpointID: string(eid), |
|
| 135 |
+ } |
|
| 136 |
+ var res endpointInfoResponse |
|
| 137 |
+ if err := d.call("EndpointOperInfo", info, &res); err != nil {
|
|
| 138 |
+ return nil, err |
|
| 139 |
+ } |
|
| 140 |
+ return res.Value, nil |
|
| 55 | 141 |
} |
| 56 | 142 |
|
| 57 | 143 |
// Join method is invoked when a Sandbox is attached to an endpoint. |
| 58 | 144 |
func (d *driver) Join(nid, eid types.UUID, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
|
| 59 |
- return driverapi.ErrNotImplemented |
|
| 145 |
+ join := &joinRequest{
|
|
| 146 |
+ NetworkID: string(nid), |
|
| 147 |
+ EndpointID: string(eid), |
|
| 148 |
+ SandboxKey: sboxKey, |
|
| 149 |
+ Options: options, |
|
| 150 |
+ } |
|
| 151 |
+ var ( |
|
| 152 |
+ res joinResponse |
|
| 153 |
+ err error |
|
| 154 |
+ ) |
|
| 155 |
+ if err = d.call("Join", join, &res); err != nil {
|
|
| 156 |
+ return err |
|
| 157 |
+ } |
|
| 158 |
+ |
|
| 159 |
+ // Expect each interface ID given by CreateEndpoint to have an |
|
| 160 |
+ // entry at that index in the names supplied here. In other words, |
|
| 161 |
+ // if you supply 0..n interfaces with IDs 0..n above, you should |
|
| 162 |
+ // supply the names in the same order. |
|
| 163 |
+ ifaceNames := res.InterfaceNames |
|
| 164 |
+ for _, iface := range jinfo.InterfaceNames() {
|
|
| 165 |
+ i := iface.ID() |
|
| 166 |
+ if i >= len(ifaceNames) || i < 0 {
|
|
| 167 |
+ return fmt.Errorf("no correlating interface %d in supplied interface names", i)
|
|
| 168 |
+ } |
|
| 169 |
+ supplied := ifaceNames[i] |
|
| 170 |
+ if err := iface.SetNames(supplied.SrcName, supplied.DstName); err != nil {
|
|
| 171 |
+ return errorWithRollback(fmt.Sprintf("failed to set interface name: %s", err), d.Leave(nid, eid))
|
|
| 172 |
+ } |
|
| 173 |
+ } |
|
| 174 |
+ |
|
| 175 |
+ var addr net.IP |
|
| 176 |
+ if res.Gateway != "" {
|
|
| 177 |
+ if addr = net.ParseIP(res.Gateway); addr == nil {
|
|
| 178 |
+ return fmt.Errorf(`unable to parse Gateway "%s"`, res.Gateway) |
|
| 179 |
+ } |
|
| 180 |
+ if jinfo.SetGateway(addr) != nil {
|
|
| 181 |
+ return errorWithRollback(fmt.Sprintf("failed to set gateway: %v", addr), d.Leave(nid, eid))
|
|
| 182 |
+ } |
|
| 183 |
+ } |
|
| 184 |
+ if res.GatewayIPv6 != "" {
|
|
| 185 |
+ if addr = net.ParseIP(res.GatewayIPv6); addr == nil {
|
|
| 186 |
+ return fmt.Errorf(`unable to parse GatewayIPv6 "%s"`, res.GatewayIPv6) |
|
| 187 |
+ } |
|
| 188 |
+ if jinfo.SetGatewayIPv6(addr) != nil {
|
|
| 189 |
+ return errorWithRollback(fmt.Sprintf("failed to set gateway IPv6: %v", addr), d.Leave(nid, eid))
|
|
| 190 |
+ } |
|
| 191 |
+ } |
|
| 192 |
+ if jinfo.SetHostsPath(res.HostsPath) != nil {
|
|
| 193 |
+ return errorWithRollback(fmt.Sprintf("failed to set hosts path: %s", res.HostsPath), d.Leave(nid, eid))
|
|
| 194 |
+ } |
|
| 195 |
+ if jinfo.SetResolvConfPath(res.ResolvConfPath) != nil {
|
|
| 196 |
+ return errorWithRollback(fmt.Sprintf("failed to set resolv.conf path: %s", res.ResolvConfPath), d.Leave(nid, eid))
|
|
| 197 |
+ } |
|
| 198 |
+ return nil |
|
| 60 | 199 |
} |
| 61 | 200 |
|
| 62 | 201 |
// Leave method is invoked when a Sandbox detaches from an endpoint. |
| 63 | 202 |
func (d *driver) Leave(nid, eid types.UUID) error {
|
| 64 |
- return driverapi.ErrNotImplemented |
|
| 203 |
+ leave := &leaveRequest{
|
|
| 204 |
+ NetworkID: string(nid), |
|
| 205 |
+ EndpointID: string(eid), |
|
| 206 |
+ } |
|
| 207 |
+ return d.call("Leave", leave, &leaveResponse{})
|
|
| 65 | 208 |
} |
| 66 | 209 |
|
| 67 | 210 |
func (d *driver) Type() string {
|
| 68 | 211 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,397 @@ |
| 0 |
+package remote |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "encoding/json" |
|
| 4 |
+ "fmt" |
|
| 5 |
+ "net" |
|
| 6 |
+ "net/http" |
|
| 7 |
+ "os" |
|
| 8 |
+ "testing" |
|
| 9 |
+ |
|
| 10 |
+ "github.com/docker/docker/pkg/plugins" |
|
| 11 |
+ "github.com/docker/libnetwork/driverapi" |
|
| 12 |
+ _ "github.com/docker/libnetwork/netutils" |
|
| 13 |
+ "github.com/docker/libnetwork/types" |
|
| 14 |
+) |
|
| 15 |
+ |
|
| 16 |
+func decodeToMap(r *http.Request) (res map[string]interface{}, err error) {
|
|
| 17 |
+ err = json.NewDecoder(r.Body).Decode(&res) |
|
| 18 |
+ return |
|
| 19 |
+} |
|
| 20 |
+ |
|
| 21 |
+func handle(t *testing.T, mux *http.ServeMux, method string, h func(map[string]interface{}) interface{}) {
|
|
| 22 |
+ mux.HandleFunc(fmt.Sprintf("/%s.%s", driverapi.NetworkPluginEndpointType, method), func(w http.ResponseWriter, r *http.Request) {
|
|
| 23 |
+ ask, err := decodeToMap(r) |
|
| 24 |
+ if err != nil {
|
|
| 25 |
+ t.Fatal(err) |
|
| 26 |
+ } |
|
| 27 |
+ answer := h(ask) |
|
| 28 |
+ err = json.NewEncoder(w).Encode(&answer) |
|
| 29 |
+ if err != nil {
|
|
| 30 |
+ t.Fatal(err) |
|
| 31 |
+ } |
|
| 32 |
+ }) |
|
| 33 |
+} |
|
| 34 |
+ |
|
| 35 |
+func setupPlugin(t *testing.T, name string, mux *http.ServeMux) func() {
|
|
| 36 |
+ if err := os.MkdirAll("/usr/share/docker/plugins", 0755); err != nil {
|
|
| 37 |
+ t.Fatal(err) |
|
| 38 |
+ } |
|
| 39 |
+ |
|
| 40 |
+ listener, err := net.Listen("unix", fmt.Sprintf("/usr/share/docker/plugins/%s.sock", name))
|
|
| 41 |
+ if err != nil {
|
|
| 42 |
+ t.Fatal("Could not listen to the plugin socket")
|
|
| 43 |
+ } |
|
| 44 |
+ |
|
| 45 |
+ mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) {
|
|
| 46 |
+ fmt.Fprintf(w, `{"Implements": ["%s"]}`, driverapi.NetworkPluginEndpointType)
|
|
| 47 |
+ }) |
|
| 48 |
+ |
|
| 49 |
+ go http.Serve(listener, mux) |
|
| 50 |
+ |
|
| 51 |
+ return func() {
|
|
| 52 |
+ listener.Close() |
|
| 53 |
+ if err := os.RemoveAll("/usr/share/docker/plugins"); err != nil {
|
|
| 54 |
+ t.Fatal(err) |
|
| 55 |
+ } |
|
| 56 |
+ } |
|
| 57 |
+} |
|
| 58 |
+ |
|
| 59 |
+type testEndpoint struct {
|
|
| 60 |
+ t *testing.T |
|
| 61 |
+ id int |
|
| 62 |
+ src string |
|
| 63 |
+ dst string |
|
| 64 |
+ address string |
|
| 65 |
+ addressIPv6 string |
|
| 66 |
+ macAddress string |
|
| 67 |
+ gateway string |
|
| 68 |
+ gatewayIPv6 string |
|
| 69 |
+ resolvConfPath string |
|
| 70 |
+ hostsPath string |
|
| 71 |
+} |
|
| 72 |
+ |
|
| 73 |
+func (test *testEndpoint) Interfaces() []driverapi.InterfaceInfo {
|
|
| 74 |
+ // return an empty one so we don't trip the check for existing |
|
| 75 |
+ // interfaces; we don't care about this after that |
|
| 76 |
+ return []driverapi.InterfaceInfo{}
|
|
| 77 |
+} |
|
| 78 |
+ |
|
| 79 |
+func (test *testEndpoint) AddInterface(ID int, mac net.HardwareAddr, ipv4 net.IPNet, ipv6 net.IPNet) error {
|
|
| 80 |
+ if ID != test.id {
|
|
| 81 |
+ test.t.Fatalf("Wrong ID passed to AddInterface: %d", ID)
|
|
| 82 |
+ } |
|
| 83 |
+ ip4, net4, _ := net.ParseCIDR(test.address) |
|
| 84 |
+ ip6, net6, _ := net.ParseCIDR(test.addressIPv6) |
|
| 85 |
+ if ip4 != nil {
|
|
| 86 |
+ net4.IP = ip4 |
|
| 87 |
+ if !types.CompareIPNet(net4, &ipv4) {
|
|
| 88 |
+ test.t.Fatalf("Wrong address given %+v", ipv4)
|
|
| 89 |
+ } |
|
| 90 |
+ } |
|
| 91 |
+ if ip6 != nil {
|
|
| 92 |
+ net6.IP = ip6 |
|
| 93 |
+ if !types.CompareIPNet(net6, &ipv6) {
|
|
| 94 |
+ test.t.Fatalf("Wrong address (IPv6) given %+v", ipv6)
|
|
| 95 |
+ } |
|
| 96 |
+ } |
|
| 97 |
+ if test.macAddress != "" && mac.String() != test.macAddress {
|
|
| 98 |
+ test.t.Fatalf("Wrong MAC address given %v", mac)
|
|
| 99 |
+ } |
|
| 100 |
+ return nil |
|
| 101 |
+} |
|
| 102 |
+ |
|
| 103 |
+func (test *testEndpoint) InterfaceNames() []driverapi.InterfaceNameInfo {
|
|
| 104 |
+ return []driverapi.InterfaceNameInfo{test}
|
|
| 105 |
+} |
|
| 106 |
+ |
|
| 107 |
+func compareIPs(t *testing.T, kind string, shouldBe string, supplied net.IP) {
|
|
| 108 |
+ ip := net.ParseIP(shouldBe) |
|
| 109 |
+ if ip == nil {
|
|
| 110 |
+ t.Fatalf(`Invalid IP to test against: "%s"`, shouldBe) |
|
| 111 |
+ } |
|
| 112 |
+ if !ip.Equal(supplied) {
|
|
| 113 |
+ t.Fatalf(`%s IPs are not equal: expected "%s", got %v`, kind, shouldBe, supplied) |
|
| 114 |
+ } |
|
| 115 |
+} |
|
| 116 |
+ |
|
| 117 |
+func (test *testEndpoint) SetGateway(ipv4 net.IP) error {
|
|
| 118 |
+ compareIPs(test.t, "Gateway", test.gateway, ipv4) |
|
| 119 |
+ return nil |
|
| 120 |
+} |
|
| 121 |
+ |
|
| 122 |
+func (test *testEndpoint) SetGatewayIPv6(ipv6 net.IP) error {
|
|
| 123 |
+ compareIPs(test.t, "GatewayIPv6", test.gatewayIPv6, ipv6) |
|
| 124 |
+ return nil |
|
| 125 |
+} |
|
| 126 |
+ |
|
| 127 |
+func (test *testEndpoint) SetHostsPath(p string) error {
|
|
| 128 |
+ if p != test.hostsPath {
|
|
| 129 |
+ test.t.Fatalf(`Wrong HostsPath; expected "%s", got "%s"`, test.hostsPath, p) |
|
| 130 |
+ } |
|
| 131 |
+ return nil |
|
| 132 |
+} |
|
| 133 |
+ |
|
| 134 |
+func (test *testEndpoint) SetResolvConfPath(p string) error {
|
|
| 135 |
+ if p != test.resolvConfPath {
|
|
| 136 |
+ test.t.Fatalf(`Wrong ResolvConfPath; expected "%s", got "%s"`, test.resolvConfPath, p) |
|
| 137 |
+ } |
|
| 138 |
+ return nil |
|
| 139 |
+} |
|
| 140 |
+ |
|
| 141 |
+func (test *testEndpoint) SetNames(src string, dst string) error {
|
|
| 142 |
+ if test.src != src {
|
|
| 143 |
+ test.t.Fatalf(`Wrong SrcName; expected "%s", got "%s"`, test.src, src) |
|
| 144 |
+ } |
|
| 145 |
+ if test.dst != dst {
|
|
| 146 |
+ test.t.Fatalf(`Wrong DstName; expected "%s", got "%s"`, test.dst, dst) |
|
| 147 |
+ } |
|
| 148 |
+ return nil |
|
| 149 |
+} |
|
| 150 |
+ |
|
| 151 |
+func (test *testEndpoint) ID() int {
|
|
| 152 |
+ return test.id |
|
| 153 |
+} |
|
| 154 |
+ |
|
| 155 |
+func TestRemoteDriver(t *testing.T) {
|
|
| 156 |
+ var plugin = "test-net-driver" |
|
| 157 |
+ |
|
| 158 |
+ ep := &testEndpoint{
|
|
| 159 |
+ t: t, |
|
| 160 |
+ src: "vethsrc", |
|
| 161 |
+ dst: "vethdst", |
|
| 162 |
+ address: "192.168.5.7/16", |
|
| 163 |
+ addressIPv6: "2001:DB8::5:7/48", |
|
| 164 |
+ macAddress: "7a:56:78:34:12:da", |
|
| 165 |
+ gateway: "192.168.0.1", |
|
| 166 |
+ gatewayIPv6: "2001:DB8::1", |
|
| 167 |
+ hostsPath: "/here/comes/the/host/path", |
|
| 168 |
+ resolvConfPath: "/there/goes/the/resolv/conf", |
|
| 169 |
+ } |
|
| 170 |
+ |
|
| 171 |
+ mux := http.NewServeMux() |
|
| 172 |
+ defer setupPlugin(t, plugin, mux)() |
|
| 173 |
+ |
|
| 174 |
+ var networkID string |
|
| 175 |
+ |
|
| 176 |
+ handle(t, mux, "CreateNetwork", func(msg map[string]interface{}) interface{} {
|
|
| 177 |
+ nid := msg["NetworkID"] |
|
| 178 |
+ var ok bool |
|
| 179 |
+ if networkID, ok = nid.(string); !ok {
|
|
| 180 |
+ t.Fatal("RPC did not include network ID string")
|
|
| 181 |
+ } |
|
| 182 |
+ return map[string]interface{}{}
|
|
| 183 |
+ }) |
|
| 184 |
+ handle(t, mux, "DeleteNetwork", func(msg map[string]interface{}) interface{} {
|
|
| 185 |
+ if nid, ok := msg["NetworkID"]; !ok || nid != networkID {
|
|
| 186 |
+ t.Fatal("Network ID missing or does not match that created")
|
|
| 187 |
+ } |
|
| 188 |
+ return map[string]interface{}{}
|
|
| 189 |
+ }) |
|
| 190 |
+ handle(t, mux, "CreateEndpoint", func(msg map[string]interface{}) interface{} {
|
|
| 191 |
+ iface := map[string]interface{}{
|
|
| 192 |
+ "ID": ep.id, |
|
| 193 |
+ "Address": ep.address, |
|
| 194 |
+ "AddressIPv6": ep.addressIPv6, |
|
| 195 |
+ "MacAddress": ep.macAddress, |
|
| 196 |
+ } |
|
| 197 |
+ return map[string]interface{}{
|
|
| 198 |
+ "Interfaces": []interface{}{iface},
|
|
| 199 |
+ } |
|
| 200 |
+ }) |
|
| 201 |
+ handle(t, mux, "Join", func(msg map[string]interface{}) interface{} {
|
|
| 202 |
+ options := msg["Options"].(map[string]interface{})
|
|
| 203 |
+ foo, ok := options["foo"].(string) |
|
| 204 |
+ if !ok || foo != "fooValue" {
|
|
| 205 |
+ t.Fatalf("Did not receive expected foo string in request options: %+v", msg)
|
|
| 206 |
+ } |
|
| 207 |
+ return map[string]interface{}{
|
|
| 208 |
+ "Gateway": ep.gateway, |
|
| 209 |
+ "GatewayIPv6": ep.gatewayIPv6, |
|
| 210 |
+ "HostsPath": ep.hostsPath, |
|
| 211 |
+ "ResolvConfPath": ep.resolvConfPath, |
|
| 212 |
+ "InterfaceNames": []map[string]interface{}{
|
|
| 213 |
+ map[string]interface{}{
|
|
| 214 |
+ "SrcName": ep.src, |
|
| 215 |
+ "DstName": ep.dst, |
|
| 216 |
+ }, |
|
| 217 |
+ }, |
|
| 218 |
+ } |
|
| 219 |
+ }) |
|
| 220 |
+ handle(t, mux, "Leave", func(msg map[string]interface{}) interface{} {
|
|
| 221 |
+ return map[string]string{}
|
|
| 222 |
+ }) |
|
| 223 |
+ handle(t, mux, "DeleteEndpoint", func(msg map[string]interface{}) interface{} {
|
|
| 224 |
+ return map[string]interface{}{}
|
|
| 225 |
+ }) |
|
| 226 |
+ handle(t, mux, "EndpointOperInfo", func(msg map[string]interface{}) interface{} {
|
|
| 227 |
+ return map[string]interface{}{
|
|
| 228 |
+ "Value": map[string]string{
|
|
| 229 |
+ "Arbitrary": "key", |
|
| 230 |
+ "Value": "pairs?", |
|
| 231 |
+ }, |
|
| 232 |
+ } |
|
| 233 |
+ }) |
|
| 234 |
+ |
|
| 235 |
+ p, err := plugins.Get(plugin, driverapi.NetworkPluginEndpointType) |
|
| 236 |
+ if err != nil {
|
|
| 237 |
+ t.Fatal(err) |
|
| 238 |
+ } |
|
| 239 |
+ |
|
| 240 |
+ driver := newDriver(plugin, p.Client) |
|
| 241 |
+ if driver.Type() != plugin {
|
|
| 242 |
+ t.Fatal("Driver type does not match that given")
|
|
| 243 |
+ } |
|
| 244 |
+ |
|
| 245 |
+ netID := types.UUID("dummy-network")
|
|
| 246 |
+ err = driver.CreateNetwork(netID, map[string]interface{}{})
|
|
| 247 |
+ if err != nil {
|
|
| 248 |
+ t.Fatal(err) |
|
| 249 |
+ } |
|
| 250 |
+ |
|
| 251 |
+ endID := types.UUID("dummy-endpoint")
|
|
| 252 |
+ err = driver.CreateEndpoint(netID, endID, ep, map[string]interface{}{})
|
|
| 253 |
+ if err != nil {
|
|
| 254 |
+ t.Fatal(err) |
|
| 255 |
+ } |
|
| 256 |
+ |
|
| 257 |
+ joinOpts := map[string]interface{}{"foo": "fooValue"}
|
|
| 258 |
+ err = driver.Join(netID, endID, "sandbox-key", ep, joinOpts) |
|
| 259 |
+ if err != nil {
|
|
| 260 |
+ t.Fatal(err) |
|
| 261 |
+ } |
|
| 262 |
+ if _, err = driver.EndpointOperInfo(netID, endID); err != nil {
|
|
| 263 |
+ t.Fatal(err) |
|
| 264 |
+ } |
|
| 265 |
+ if err = driver.Leave(netID, endID); err != nil {
|
|
| 266 |
+ t.Fatal(err) |
|
| 267 |
+ } |
|
| 268 |
+ if err = driver.DeleteEndpoint(netID, endID); err != nil {
|
|
| 269 |
+ t.Fatal(err) |
|
| 270 |
+ } |
|
| 271 |
+ if err = driver.DeleteNetwork(netID); err != nil {
|
|
| 272 |
+ t.Fatal(err) |
|
| 273 |
+ } |
|
| 274 |
+} |
|
| 275 |
+ |
|
| 276 |
+type failEndpoint struct {
|
|
| 277 |
+ t *testing.T |
|
| 278 |
+} |
|
| 279 |
+ |
|
| 280 |
+func (f *failEndpoint) Interfaces() []*driverapi.InterfaceInfo {
|
|
| 281 |
+ f.t.Fatal("Unexpected call of Interfaces")
|
|
| 282 |
+ return nil |
|
| 283 |
+} |
|
| 284 |
+func (f *failEndpoint) AddInterface(int, net.HardwareAddr, net.IPNet, net.IPNet) error {
|
|
| 285 |
+ f.t.Fatal("Unexpected call of AddInterface")
|
|
| 286 |
+ return nil |
|
| 287 |
+} |
|
| 288 |
+ |
|
| 289 |
+func TestDriverError(t *testing.T) {
|
|
| 290 |
+ var plugin = "test-net-driver-error" |
|
| 291 |
+ |
|
| 292 |
+ mux := http.NewServeMux() |
|
| 293 |
+ defer setupPlugin(t, plugin, mux)() |
|
| 294 |
+ |
|
| 295 |
+ handle(t, mux, "CreateEndpoint", func(msg map[string]interface{}) interface{} {
|
|
| 296 |
+ return map[string]interface{}{
|
|
| 297 |
+ "Err": "this should get raised as an error", |
|
| 298 |
+ } |
|
| 299 |
+ }) |
|
| 300 |
+ |
|
| 301 |
+ p, err := plugins.Get(plugin, driverapi.NetworkPluginEndpointType) |
|
| 302 |
+ if err != nil {
|
|
| 303 |
+ t.Fatal(err) |
|
| 304 |
+ } |
|
| 305 |
+ |
|
| 306 |
+ driver := newDriver(plugin, p.Client) |
|
| 307 |
+ |
|
| 308 |
+ if err := driver.CreateEndpoint(types.UUID("dummy"), types.UUID("dummy"), &testEndpoint{t: t}, map[string]interface{}{}); err == nil {
|
|
| 309 |
+ t.Fatalf("Expected error from driver")
|
|
| 310 |
+ } |
|
| 311 |
+} |
|
| 312 |
+ |
|
| 313 |
+func TestMissingValues(t *testing.T) {
|
|
| 314 |
+ var plugin = "test-net-driver-missing" |
|
| 315 |
+ |
|
| 316 |
+ mux := http.NewServeMux() |
|
| 317 |
+ defer setupPlugin(t, plugin, mux)() |
|
| 318 |
+ |
|
| 319 |
+ ep := &testEndpoint{
|
|
| 320 |
+ t: t, |
|
| 321 |
+ id: 0, |
|
| 322 |
+ } |
|
| 323 |
+ |
|
| 324 |
+ handle(t, mux, "CreateEndpoint", func(msg map[string]interface{}) interface{} {
|
|
| 325 |
+ iface := map[string]interface{}{
|
|
| 326 |
+ "ID": ep.id, |
|
| 327 |
+ "Address": ep.address, |
|
| 328 |
+ "AddressIPv6": ep.addressIPv6, |
|
| 329 |
+ "MacAddress": ep.macAddress, |
|
| 330 |
+ } |
|
| 331 |
+ return map[string]interface{}{
|
|
| 332 |
+ "Interfaces": []interface{}{iface},
|
|
| 333 |
+ } |
|
| 334 |
+ }) |
|
| 335 |
+ |
|
| 336 |
+ p, err := plugins.Get(plugin, driverapi.NetworkPluginEndpointType) |
|
| 337 |
+ if err != nil {
|
|
| 338 |
+ t.Fatal(err) |
|
| 339 |
+ } |
|
| 340 |
+ driver := newDriver(plugin, p.Client) |
|
| 341 |
+ |
|
| 342 |
+ if err := driver.CreateEndpoint(types.UUID("dummy"), types.UUID("dummy"), ep, map[string]interface{}{}); err != nil {
|
|
| 343 |
+ t.Fatal(err) |
|
| 344 |
+ } |
|
| 345 |
+} |
|
| 346 |
+ |
|
| 347 |
+type rollbackEndpoint struct {
|
|
| 348 |
+} |
|
| 349 |
+ |
|
| 350 |
+func (r *rollbackEndpoint) Interfaces() []driverapi.InterfaceInfo {
|
|
| 351 |
+ return []driverapi.InterfaceInfo{}
|
|
| 352 |
+} |
|
| 353 |
+ |
|
| 354 |
+func (r *rollbackEndpoint) AddInterface(_ int, _ net.HardwareAddr, _ net.IPNet, _ net.IPNet) error {
|
|
| 355 |
+ return fmt.Errorf("fail this to trigger a rollback")
|
|
| 356 |
+} |
|
| 357 |
+ |
|
| 358 |
+func TestRollback(t *testing.T) {
|
|
| 359 |
+ var plugin = "test-net-driver-rollback" |
|
| 360 |
+ |
|
| 361 |
+ mux := http.NewServeMux() |
|
| 362 |
+ defer setupPlugin(t, plugin, mux)() |
|
| 363 |
+ |
|
| 364 |
+ rolledback := false |
|
| 365 |
+ |
|
| 366 |
+ handle(t, mux, "CreateEndpoint", func(msg map[string]interface{}) interface{} {
|
|
| 367 |
+ iface := map[string]interface{}{
|
|
| 368 |
+ "ID": 0, |
|
| 369 |
+ "Address": "192.168.4.5/16", |
|
| 370 |
+ "AddressIPv6": "", |
|
| 371 |
+ "MacAddress": "7a:12:34:56:78:90", |
|
| 372 |
+ } |
|
| 373 |
+ return map[string]interface{}{
|
|
| 374 |
+ "Interfaces": []interface{}{iface},
|
|
| 375 |
+ } |
|
| 376 |
+ }) |
|
| 377 |
+ handle(t, mux, "DeleteEndpoint", func(msg map[string]interface{}) interface{} {
|
|
| 378 |
+ rolledback = true |
|
| 379 |
+ return map[string]interface{}{}
|
|
| 380 |
+ }) |
|
| 381 |
+ |
|
| 382 |
+ p, err := plugins.Get(plugin, driverapi.NetworkPluginEndpointType) |
|
| 383 |
+ if err != nil {
|
|
| 384 |
+ t.Fatal(err) |
|
| 385 |
+ } |
|
| 386 |
+ driver := newDriver(plugin, p.Client) |
|
| 387 |
+ |
|
| 388 |
+ ep := &rollbackEndpoint{}
|
|
| 389 |
+ |
|
| 390 |
+ if err := driver.CreateEndpoint(types.UUID("dummy"), types.UUID("dummy"), ep, map[string]interface{}{}); err == nil {
|
|
| 391 |
+ t.Fatalf("Expected error from driver")
|
|
| 392 |
+ } |
|
| 393 |
+ if !rolledback {
|
|
| 394 |
+ t.Fatalf("Expected to have had DeleteEndpoint called")
|
|
| 395 |
+ } |
|
| 396 |
+} |
| 0 | 397 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,143 @@ |
| 0 |
+package remote |
|
| 1 |
+ |
|
| 2 |
+import "net" |
|
| 3 |
+ |
|
| 4 |
+type response struct {
|
|
| 5 |
+ Err string |
|
| 6 |
+} |
|
| 7 |
+ |
|
| 8 |
+type maybeError interface {
|
|
| 9 |
+ getError() string |
|
| 10 |
+} |
|
| 11 |
+ |
|
| 12 |
+func (r *response) getError() string {
|
|
| 13 |
+ return r.Err |
|
| 14 |
+} |
|
| 15 |
+ |
|
| 16 |
+type createNetworkRequest struct {
|
|
| 17 |
+ NetworkID string |
|
| 18 |
+ Options map[string]interface{}
|
|
| 19 |
+} |
|
| 20 |
+ |
|
| 21 |
+type createNetworkResponse struct {
|
|
| 22 |
+ response |
|
| 23 |
+} |
|
| 24 |
+ |
|
| 25 |
+type deleteNetworkRequest struct {
|
|
| 26 |
+ NetworkID string |
|
| 27 |
+} |
|
| 28 |
+ |
|
| 29 |
+type deleteNetworkResponse struct {
|
|
| 30 |
+ response |
|
| 31 |
+} |
|
| 32 |
+ |
|
| 33 |
+type createEndpointRequest struct {
|
|
| 34 |
+ NetworkID string |
|
| 35 |
+ EndpointID string |
|
| 36 |
+ Interfaces []*endpointInterface |
|
| 37 |
+ Options map[string]interface{}
|
|
| 38 |
+} |
|
| 39 |
+ |
|
| 40 |
+type endpointInterface struct {
|
|
| 41 |
+ ID int |
|
| 42 |
+ Address string |
|
| 43 |
+ AddressIPv6 string |
|
| 44 |
+ MacAddress string |
|
| 45 |
+} |
|
| 46 |
+ |
|
| 47 |
+type createEndpointResponse struct {
|
|
| 48 |
+ response |
|
| 49 |
+ Interfaces []*endpointInterface |
|
| 50 |
+} |
|
| 51 |
+ |
|
| 52 |
+func toAddr(ipAddr string) (*net.IPNet, error) {
|
|
| 53 |
+ ip, ipnet, err := net.ParseCIDR(ipAddr) |
|
| 54 |
+ if err != nil {
|
|
| 55 |
+ return nil, err |
|
| 56 |
+ } |
|
| 57 |
+ ipnet.IP = ip |
|
| 58 |
+ return ipnet, nil |
|
| 59 |
+} |
|
| 60 |
+ |
|
| 61 |
+type iface struct {
|
|
| 62 |
+ ID int |
|
| 63 |
+ Address *net.IPNet |
|
| 64 |
+ AddressIPv6 *net.IPNet |
|
| 65 |
+ MacAddress net.HardwareAddr |
|
| 66 |
+} |
|
| 67 |
+ |
|
| 68 |
+func (r *createEndpointResponse) parseInterfaces() ([]*iface, error) {
|
|
| 69 |
+ var ( |
|
| 70 |
+ ifaces = make([]*iface, len(r.Interfaces)) |
|
| 71 |
+ ) |
|
| 72 |
+ for i, inIf := range r.Interfaces {
|
|
| 73 |
+ var err error |
|
| 74 |
+ outIf := &iface{ID: inIf.ID}
|
|
| 75 |
+ if inIf.Address != "" {
|
|
| 76 |
+ if outIf.Address, err = toAddr(inIf.Address); err != nil {
|
|
| 77 |
+ return nil, err |
|
| 78 |
+ } |
|
| 79 |
+ } |
|
| 80 |
+ if inIf.AddressIPv6 != "" {
|
|
| 81 |
+ if outIf.AddressIPv6, err = toAddr(inIf.AddressIPv6); err != nil {
|
|
| 82 |
+ return nil, err |
|
| 83 |
+ } |
|
| 84 |
+ } |
|
| 85 |
+ if inIf.MacAddress != "" {
|
|
| 86 |
+ if outIf.MacAddress, err = net.ParseMAC(inIf.MacAddress); err != nil {
|
|
| 87 |
+ return nil, err |
|
| 88 |
+ } |
|
| 89 |
+ } |
|
| 90 |
+ ifaces[i] = outIf |
|
| 91 |
+ } |
|
| 92 |
+ return ifaces, nil |
|
| 93 |
+} |
|
| 94 |
+ |
|
| 95 |
+type deleteEndpointRequest struct {
|
|
| 96 |
+ NetworkID string |
|
| 97 |
+ EndpointID string |
|
| 98 |
+} |
|
| 99 |
+ |
|
| 100 |
+type deleteEndpointResponse struct {
|
|
| 101 |
+ response |
|
| 102 |
+} |
|
| 103 |
+ |
|
| 104 |
+type endpointInfoRequest struct {
|
|
| 105 |
+ NetworkID string |
|
| 106 |
+ EndpointID string |
|
| 107 |
+} |
|
| 108 |
+ |
|
| 109 |
+type endpointInfoResponse struct {
|
|
| 110 |
+ response |
|
| 111 |
+ Value map[string]interface{}
|
|
| 112 |
+} |
|
| 113 |
+ |
|
| 114 |
+type joinRequest struct {
|
|
| 115 |
+ NetworkID string |
|
| 116 |
+ EndpointID string |
|
| 117 |
+ SandboxKey string |
|
| 118 |
+ Options map[string]interface{}
|
|
| 119 |
+} |
|
| 120 |
+ |
|
| 121 |
+type ifaceName struct {
|
|
| 122 |
+ SrcName string |
|
| 123 |
+ DstName string |
|
| 124 |
+} |
|
| 125 |
+ |
|
| 126 |
+type joinResponse struct {
|
|
| 127 |
+ response |
|
| 128 |
+ InterfaceNames []*ifaceName |
|
| 129 |
+ Gateway string |
|
| 130 |
+ GatewayIPv6 string |
|
| 131 |
+ HostsPath string |
|
| 132 |
+ ResolvConfPath string |
|
| 133 |
+} |
|
| 134 |
+ |
|
| 135 |
+type leaveRequest struct {
|
|
| 136 |
+ NetworkID string |
|
| 137 |
+ EndpointID string |
|
| 138 |
+} |
|
| 139 |
+ |
|
| 140 |
+type leaveResponse struct {
|
|
| 141 |
+ response |
|
| 142 |
+} |
| ... | ... |
@@ -12,7 +12,6 @@ import ( |
| 12 | 12 |
"github.com/docker/docker/pkg/ioutils" |
| 13 | 13 |
"github.com/docker/libnetwork/etchosts" |
| 14 | 14 |
"github.com/docker/libnetwork/netlabel" |
| 15 |
- "github.com/docker/libnetwork/netutils" |
|
| 16 | 15 |
"github.com/docker/libnetwork/resolvconf" |
| 17 | 16 |
"github.com/docker/libnetwork/sandbox" |
| 18 | 17 |
"github.com/docker/libnetwork/types" |
| ... | ... |
@@ -106,7 +105,7 @@ type endpoint struct {
|
| 106 | 106 |
iFaces []*endpointInterface |
| 107 | 107 |
joinInfo *endpointJoinInfo |
| 108 | 108 |
container *containerInfo |
| 109 |
- exposedPorts []netutils.TransportPort |
|
| 109 |
+ exposedPorts []types.TransportPort |
|
| 110 | 110 |
generic map[string]interface{}
|
| 111 | 111 |
joinLeaveDone chan struct{}
|
| 112 | 112 |
sync.Mutex |
| ... | ... |
@@ -217,7 +216,7 @@ func (ep *endpoint) Join(containerID string, options ...EndpointOption) (*Contai |
| 217 | 217 |
ep.Lock() |
| 218 | 218 |
if ep.container != nil {
|
| 219 | 219 |
ep.Unlock() |
| 220 |
- return nil, ErrInvalidJoin |
|
| 220 |
+ return nil, ErrInvalidJoin{}
|
|
| 221 | 221 |
} |
| 222 | 222 |
|
| 223 | 223 |
ep.container = &containerInfo{
|
| ... | ... |
@@ -292,7 +291,7 @@ func (ep *endpoint) Join(containerID string, options ...EndpointOption) (*Contai |
| 292 | 292 |
for _, i := range ifaces {
|
| 293 | 293 |
iface := &sandbox.Interface{
|
| 294 | 294 |
SrcName: i.srcName, |
| 295 |
- DstName: i.dstName, |
|
| 295 |
+ DstName: i.dstPrefix, |
|
| 296 | 296 |
Address: &i.addr, |
| 297 | 297 |
} |
| 298 | 298 |
if i.addrv6.IP.To16() != nil {
|
| ... | ... |
@@ -335,7 +334,7 @@ func (ep *endpoint) Leave(containerID string, options ...EndpointOption) error {
|
| 335 | 335 |
if container == nil || container.id == "" || |
| 336 | 336 |
containerID == "" || container.id != containerID {
|
| 337 | 337 |
if container == nil {
|
| 338 |
- err = ErrNoContainer |
|
| 338 |
+ err = ErrNoContainer{}
|
|
| 339 | 339 |
} else {
|
| 340 | 340 |
err = InvalidContainerIDError(containerID) |
| 341 | 341 |
} |
| ... | ... |
@@ -413,7 +412,7 @@ func (ep *endpoint) buildHostsFiles() error {
|
| 413 | 413 |
ep.Unlock() |
| 414 | 414 |
|
| 415 | 415 |
if container == nil {
|
| 416 |
- return ErrNoContainer |
|
| 416 |
+ return ErrNoContainer{}
|
|
| 417 | 417 |
} |
| 418 | 418 |
|
| 419 | 419 |
if container.config.hostsPath == "" {
|
| ... | ... |
@@ -463,7 +462,7 @@ func (ep *endpoint) updateParentHosts() error {
|
| 463 | 463 |
ep.Unlock() |
| 464 | 464 |
|
| 465 | 465 |
if container == nil {
|
| 466 |
- return ErrNoContainer |
|
| 466 |
+ return ErrNoContainer{}
|
|
| 467 | 467 |
} |
| 468 | 468 |
|
| 469 | 469 |
for _, update := range container.config.parentUpdates {
|
| ... | ... |
@@ -496,7 +495,7 @@ func (ep *endpoint) updateDNS(resolvConf []byte) error {
|
| 496 | 496 |
ep.Unlock() |
| 497 | 497 |
|
| 498 | 498 |
if container == nil {
|
| 499 |
- return ErrNoContainer |
|
| 499 |
+ return ErrNoContainer{}
|
|
| 500 | 500 |
} |
| 501 | 501 |
|
| 502 | 502 |
oldHash := []byte{}
|
| ... | ... |
@@ -574,7 +573,7 @@ func (ep *endpoint) setupDNS() error {
|
| 574 | 574 |
ep.Unlock() |
| 575 | 575 |
|
| 576 | 576 |
if container == nil {
|
| 577 |
- return ErrNoContainer |
|
| 577 |
+ return ErrNoContainer{}
|
|
| 578 | 578 |
} |
| 579 | 579 |
|
| 580 | 580 |
if container.config.resolvConfPath == "" {
|
| ... | ... |
@@ -697,10 +696,10 @@ func JoinOptionUseDefaultSandbox() EndpointOption {
|
| 697 | 697 |
|
| 698 | 698 |
// CreateOptionExposedPorts function returns an option setter for the container exposed |
| 699 | 699 |
// ports option to be passed to network.CreateEndpoint() method. |
| 700 |
-func CreateOptionExposedPorts(exposedPorts []netutils.TransportPort) EndpointOption {
|
|
| 700 |
+func CreateOptionExposedPorts(exposedPorts []types.TransportPort) EndpointOption {
|
|
| 701 | 701 |
return func(ep *endpoint) {
|
| 702 | 702 |
// Defensive copy |
| 703 |
- eps := make([]netutils.TransportPort, len(exposedPorts)) |
|
| 703 |
+ eps := make([]types.TransportPort, len(exposedPorts)) |
|
| 704 | 704 |
copy(eps, exposedPorts) |
| 705 | 705 |
// Store endpoint label and in generic because driver needs it |
| 706 | 706 |
ep.exposedPorts = eps |
| ... | ... |
@@ -710,10 +709,10 @@ func CreateOptionExposedPorts(exposedPorts []netutils.TransportPort) EndpointOpt |
| 710 | 710 |
|
| 711 | 711 |
// CreateOptionPortMapping function returns an option setter for the mapping |
| 712 | 712 |
// ports option to be passed to network.CreateEndpoint() method. |
| 713 |
-func CreateOptionPortMapping(portBindings []netutils.PortBinding) EndpointOption {
|
|
| 713 |
+func CreateOptionPortMapping(portBindings []types.PortBinding) EndpointOption {
|
|
| 714 | 714 |
return func(ep *endpoint) {
|
| 715 | 715 |
// Store a copy of the bindings as generic data to pass to the driver |
| 716 |
- pbs := make([]netutils.PortBinding, len(portBindings)) |
|
| 716 |
+ pbs := make([]types.PortBinding, len(portBindings)) |
|
| 717 | 717 |
copy(pbs, portBindings) |
| 718 | 718 |
ep.generic[netlabel.PortMap] = pbs |
| 719 | 719 |
} |
| ... | ... |
@@ -4,7 +4,7 @@ import ( |
| 4 | 4 |
"net" |
| 5 | 5 |
|
| 6 | 6 |
"github.com/docker/libnetwork/driverapi" |
| 7 |
- "github.com/docker/libnetwork/netutils" |
|
| 7 |
+ "github.com/docker/libnetwork/types" |
|
| 8 | 8 |
) |
| 9 | 9 |
|
| 10 | 10 |
// EndpointInfo provides an interface to retrieve network resources bound to the endpoint. |
| ... | ... |
@@ -40,12 +40,12 @@ type InterfaceInfo interface {
|
| 40 | 40 |
} |
| 41 | 41 |
|
| 42 | 42 |
type endpointInterface struct {
|
| 43 |
- id int |
|
| 44 |
- mac net.HardwareAddr |
|
| 45 |
- addr net.IPNet |
|
| 46 |
- addrv6 net.IPNet |
|
| 47 |
- srcName string |
|
| 48 |
- dstName string |
|
| 43 |
+ id int |
|
| 44 |
+ mac net.HardwareAddr |
|
| 45 |
+ addr net.IPNet |
|
| 46 |
+ addrv6 net.IPNet |
|
| 47 |
+ srcName string |
|
| 48 |
+ dstPrefix string |
|
| 49 | 49 |
} |
| 50 | 50 |
|
| 51 | 51 |
type endpointJoinInfo struct {
|
| ... | ... |
@@ -105,10 +105,10 @@ func (ep *endpoint) AddInterface(id int, mac net.HardwareAddr, ipv4 net.IPNet, i |
| 105 | 105 |
|
| 106 | 106 |
iface := &endpointInterface{
|
| 107 | 107 |
id: id, |
| 108 |
- addr: *netutils.GetIPNetCopy(&ipv4), |
|
| 109 |
- addrv6: *netutils.GetIPNetCopy(&ipv6), |
|
| 108 |
+ addr: *types.GetIPNetCopy(&ipv4), |
|
| 109 |
+ addrv6: *types.GetIPNetCopy(&ipv6), |
|
| 110 | 110 |
} |
| 111 |
- iface.mac = netutils.GetMacCopy(mac) |
|
| 111 |
+ iface.mac = types.GetMacCopy(mac) |
|
| 112 | 112 |
|
| 113 | 113 |
ep.iFaces = append(ep.iFaces, iface) |
| 114 | 114 |
return nil |
| ... | ... |
@@ -119,20 +119,20 @@ func (i *endpointInterface) ID() int {
|
| 119 | 119 |
} |
| 120 | 120 |
|
| 121 | 121 |
func (i *endpointInterface) MacAddress() net.HardwareAddr {
|
| 122 |
- return netutils.GetMacCopy(i.mac) |
|
| 122 |
+ return types.GetMacCopy(i.mac) |
|
| 123 | 123 |
} |
| 124 | 124 |
|
| 125 | 125 |
func (i *endpointInterface) Address() net.IPNet {
|
| 126 |
- return (*netutils.GetIPNetCopy(&i.addr)) |
|
| 126 |
+ return (*types.GetIPNetCopy(&i.addr)) |
|
| 127 | 127 |
} |
| 128 | 128 |
|
| 129 | 129 |
func (i *endpointInterface) AddressIPv6() net.IPNet {
|
| 130 |
- return (*netutils.GetIPNetCopy(&i.addrv6)) |
|
| 130 |
+ return (*types.GetIPNetCopy(&i.addrv6)) |
|
| 131 | 131 |
} |
| 132 | 132 |
|
| 133 |
-func (i *endpointInterface) SetNames(srcName string, dstName string) error {
|
|
| 133 |
+func (i *endpointInterface) SetNames(srcName string, dstPrefix string) error {
|
|
| 134 | 134 |
i.srcName = srcName |
| 135 |
- i.dstName = dstName |
|
| 135 |
+ i.dstPrefix = dstPrefix |
|
| 136 | 136 |
return nil |
| 137 | 137 |
} |
| 138 | 138 |
|
| ... | ... |
@@ -168,7 +168,7 @@ func (ep *endpoint) Gateway() net.IP {
|
| 168 | 168 |
return net.IP{}
|
| 169 | 169 |
} |
| 170 | 170 |
|
| 171 |
- return netutils.GetIPCopy(ep.joinInfo.gw) |
|
| 171 |
+ return types.GetIPCopy(ep.joinInfo.gw) |
|
| 172 | 172 |
} |
| 173 | 173 |
|
| 174 | 174 |
func (ep *endpoint) GatewayIPv6() net.IP {
|
| ... | ... |
@@ -179,14 +179,14 @@ func (ep *endpoint) GatewayIPv6() net.IP {
|
| 179 | 179 |
return net.IP{}
|
| 180 | 180 |
} |
| 181 | 181 |
|
| 182 |
- return netutils.GetIPCopy(ep.joinInfo.gw6) |
|
| 182 |
+ return types.GetIPCopy(ep.joinInfo.gw6) |
|
| 183 | 183 |
} |
| 184 | 184 |
|
| 185 | 185 |
func (ep *endpoint) SetGateway(gw net.IP) error {
|
| 186 | 186 |
ep.Lock() |
| 187 | 187 |
defer ep.Unlock() |
| 188 | 188 |
|
| 189 |
- ep.joinInfo.gw = netutils.GetIPCopy(gw) |
|
| 189 |
+ ep.joinInfo.gw = types.GetIPCopy(gw) |
|
| 190 | 190 |
return nil |
| 191 | 191 |
} |
| 192 | 192 |
|
| ... | ... |
@@ -194,7 +194,7 @@ func (ep *endpoint) SetGatewayIPv6(gw6 net.IP) error {
|
| 194 | 194 |
ep.Lock() |
| 195 | 195 |
defer ep.Unlock() |
| 196 | 196 |
|
| 197 |
- ep.joinInfo.gw6 = netutils.GetIPCopy(gw6) |
|
| 197 |
+ ep.joinInfo.gw6 = types.GetIPCopy(gw6) |
|
| 198 | 198 |
return nil |
| 199 | 199 |
} |
| 200 | 200 |
|
| ... | ... |
@@ -1,34 +1,83 @@ |
| 1 | 1 |
package libnetwork |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
- "errors" |
|
| 5 | 4 |
"fmt" |
| 6 | 5 |
) |
| 7 | 6 |
|
| 8 |
-var ( |
|
| 9 |
- // ErrNoSuchNetwork is returned when a network query finds no result |
|
| 10 |
- ErrNoSuchNetwork = errors.New("network not found")
|
|
| 11 |
- // ErrNoSuchEndpoint is returned when a endpoint query finds no result |
|
| 12 |
- ErrNoSuchEndpoint = errors.New("endpoint not found")
|
|
| 13 |
- // ErrNilNetworkDriver is returned if a nil network driver |
|
| 14 |
- // is passed to NewNetwork api. |
|
| 15 |
- ErrNilNetworkDriver = errors.New("nil NetworkDriver instance")
|
|
| 16 |
- // ErrInvalidNetworkDriver is returned if an invalid driver |
|
| 17 |
- // instance is passed. |
|
| 18 |
- ErrInvalidNetworkDriver = errors.New("invalid driver bound to network")
|
|
| 19 |
- // ErrInvalidJoin is returned if a join is attempted on an endpoint |
|
| 20 |
- // which already has a container joined. |
|
| 21 |
- ErrInvalidJoin = errors.New("a container has already joined the endpoint")
|
|
| 22 |
- // ErrNoContainer is returned when the endpoint has no container |
|
| 23 |
- // attached to it. |
|
| 24 |
- ErrNoContainer = errors.New("no container attached to the endpoint")
|
|
| 25 |
- // ErrInvalidID is returned when a query-by-id method is being invoked |
|
| 26 |
- // with an empty id parameter |
|
| 27 |
- ErrInvalidID = errors.New("invalid ID")
|
|
| 28 |
- // ErrInvalidName is returned when a query-by-name or resource create method is |
|
| 29 |
- // invoked with an empty name parameter |
|
| 30 |
- ErrInvalidName = errors.New("invalid Name")
|
|
| 31 |
-) |
|
| 7 |
+// ErrNoSuchNetwork is returned when a network query finds no result |
|
| 8 |
+type ErrNoSuchNetwork string |
|
| 9 |
+ |
|
| 10 |
+func (nsn ErrNoSuchNetwork) Error() string {
|
|
| 11 |
+ return fmt.Sprintf("network %s not found", string(nsn))
|
|
| 12 |
+} |
|
| 13 |
+ |
|
| 14 |
+// BadRequest denotes the type of this error |
|
| 15 |
+func (nsn ErrNoSuchNetwork) BadRequest() {}
|
|
| 16 |
+ |
|
| 17 |
+// ErrNoSuchEndpoint is returned when a endpoint query finds no result |
|
| 18 |
+type ErrNoSuchEndpoint string |
|
| 19 |
+ |
|
| 20 |
+func (nse ErrNoSuchEndpoint) Error() string {
|
|
| 21 |
+ return fmt.Sprintf("endpoint %s not found", string(nse))
|
|
| 22 |
+} |
|
| 23 |
+ |
|
| 24 |
+// BadRequest denotes the type of this error |
|
| 25 |
+func (nse ErrNoSuchEndpoint) BadRequest() {}
|
|
| 26 |
+ |
|
| 27 |
+// ErrInvalidNetworkDriver is returned if an invalid driver |
|
| 28 |
+// name is passed. |
|
| 29 |
+type ErrInvalidNetworkDriver string |
|
| 30 |
+ |
|
| 31 |
+func (ind ErrInvalidNetworkDriver) Error() string {
|
|
| 32 |
+ return fmt.Sprintf("invalid driver bound to network: %s", string(ind))
|
|
| 33 |
+} |
|
| 34 |
+ |
|
| 35 |
+// BadRequest denotes the type of this error |
|
| 36 |
+func (ind ErrInvalidNetworkDriver) BadRequest() {}
|
|
| 37 |
+ |
|
| 38 |
+// ErrInvalidJoin is returned if a join is attempted on an endpoint |
|
| 39 |
+// which already has a container joined. |
|
| 40 |
+type ErrInvalidJoin struct{}
|
|
| 41 |
+ |
|
| 42 |
+func (ij ErrInvalidJoin) Error() string {
|
|
| 43 |
+ return "a container has already joined the endpoint" |
|
| 44 |
+} |
|
| 45 |
+ |
|
| 46 |
+// BadRequest denotes the type of this error |
|
| 47 |
+func (ij ErrInvalidJoin) BadRequest() {}
|
|
| 48 |
+ |
|
| 49 |
+// ErrNoContainer is returned when the endpoint has no container |
|
| 50 |
+// attached to it. |
|
| 51 |
+type ErrNoContainer struct{}
|
|
| 52 |
+ |
|
| 53 |
+func (nc ErrNoContainer) Error() string {
|
|
| 54 |
+ return "a container has already joined the endpoint" |
|
| 55 |
+} |
|
| 56 |
+ |
|
| 57 |
+// Maskable denotes the type of this error |
|
| 58 |
+func (nc ErrNoContainer) Maskable() {}
|
|
| 59 |
+ |
|
| 60 |
+// ErrInvalidID is returned when a query-by-id method is being invoked |
|
| 61 |
+// with an empty id parameter |
|
| 62 |
+type ErrInvalidID string |
|
| 63 |
+ |
|
| 64 |
+func (ii ErrInvalidID) Error() string {
|
|
| 65 |
+ return fmt.Sprintf("invalid id: %s", string(ii))
|
|
| 66 |
+} |
|
| 67 |
+ |
|
| 68 |
+// BadRequest denotes the type of this error |
|
| 69 |
+func (ii ErrInvalidID) BadRequest() {}
|
|
| 70 |
+ |
|
| 71 |
+// ErrInvalidName is returned when a query-by-name or resource create method is |
|
| 72 |
+// invoked with an empty name parameter |
|
| 73 |
+type ErrInvalidName string |
|
| 74 |
+ |
|
| 75 |
+func (in ErrInvalidName) Error() string {
|
|
| 76 |
+ return fmt.Sprintf("invalid name: %s", string(in))
|
|
| 77 |
+} |
|
| 78 |
+ |
|
| 79 |
+// BadRequest denotes the type of this error |
|
| 80 |
+func (in ErrInvalidName) BadRequest() {}
|
|
| 32 | 81 |
|
| 33 | 82 |
// NetworkTypeError type is returned when the network type string is not |
| 34 | 83 |
// known to libnetwork. |
| ... | ... |
@@ -38,13 +87,19 @@ func (nt NetworkTypeError) Error() string {
|
| 38 | 38 |
return fmt.Sprintf("unknown driver %q", string(nt))
|
| 39 | 39 |
} |
| 40 | 40 |
|
| 41 |
+// NotFound denotes the type of this error |
|
| 42 |
+func (nt NetworkTypeError) NotFound() {}
|
|
| 43 |
+ |
|
| 41 | 44 |
// NetworkNameError is returned when a network with the same name already exists. |
| 42 | 45 |
type NetworkNameError string |
| 43 | 46 |
|
| 44 |
-func (name NetworkNameError) Error() string {
|
|
| 45 |
- return fmt.Sprintf("network with name %s already exists", string(name))
|
|
| 47 |
+func (nnr NetworkNameError) Error() string {
|
|
| 48 |
+ return fmt.Sprintf("network with name %s already exists", string(nnr))
|
|
| 46 | 49 |
} |
| 47 | 50 |
|
| 51 |
+// Forbidden denotes the type of this error |
|
| 52 |
+func (nnr NetworkNameError) Forbidden() {}
|
|
| 53 |
+ |
|
| 48 | 54 |
// UnknownNetworkError is returned when libnetwork could not find in it's database |
| 49 | 55 |
// a network with the same name and id. |
| 50 | 56 |
type UnknownNetworkError struct {
|
| ... | ... |
@@ -56,6 +111,9 @@ func (une *UnknownNetworkError) Error() string {
|
| 56 | 56 |
return fmt.Sprintf("unknown network %s id %s", une.name, une.id)
|
| 57 | 57 |
} |
| 58 | 58 |
|
| 59 |
+// NotFound denotes the type of this error |
|
| 60 |
+func (une *UnknownNetworkError) NotFound() {}
|
|
| 61 |
+ |
|
| 59 | 62 |
// ActiveEndpointsError is returned when a network is deleted which has active |
| 60 | 63 |
// endpoints in it. |
| 61 | 64 |
type ActiveEndpointsError struct {
|
| ... | ... |
@@ -67,6 +125,9 @@ func (aee *ActiveEndpointsError) Error() string {
|
| 67 | 67 |
return fmt.Sprintf("network with name %s id %s has active endpoints", aee.name, aee.id)
|
| 68 | 68 |
} |
| 69 | 69 |
|
| 70 |
+// Forbidden denotes the type of this error |
|
| 71 |
+func (aee *ActiveEndpointsError) Forbidden() {}
|
|
| 72 |
+ |
|
| 70 | 73 |
// UnknownEndpointError is returned when libnetwork could not find in it's database |
| 71 | 74 |
// an endpoint with the same name and id. |
| 72 | 75 |
type UnknownEndpointError struct {
|
| ... | ... |
@@ -78,6 +139,9 @@ func (uee *UnknownEndpointError) Error() string {
|
| 78 | 78 |
return fmt.Sprintf("unknown endpoint %s id %s", uee.name, uee.id)
|
| 79 | 79 |
} |
| 80 | 80 |
|
| 81 |
+// NotFound denotes the type of this error |
|
| 82 |
+func (uee *UnknownEndpointError) NotFound() {}
|
|
| 83 |
+ |
|
| 81 | 84 |
// ActiveContainerError is returned when an endpoint is deleted which has active |
| 82 | 85 |
// containers attached to it. |
| 83 | 86 |
type ActiveContainerError struct {
|
| ... | ... |
@@ -89,6 +153,9 @@ func (ace *ActiveContainerError) Error() string {
|
| 89 | 89 |
return fmt.Sprintf("endpoint with name %s id %s has active containers", ace.name, ace.id)
|
| 90 | 90 |
} |
| 91 | 91 |
|
| 92 |
+// Forbidden denotes the type of this error |
|
| 93 |
+func (ace *ActiveContainerError) Forbidden() {}
|
|
| 94 |
+ |
|
| 92 | 95 |
// InvalidContainerIDError is returned when an invalid container id is passed |
| 93 | 96 |
// in Join/Leave |
| 94 | 97 |
type InvalidContainerIDError string |
| ... | ... |
@@ -96,3 +163,6 @@ type InvalidContainerIDError string |
| 96 | 96 |
func (id InvalidContainerIDError) Error() string {
|
| 97 | 97 |
return fmt.Sprintf("invalid container id %s", string(id))
|
| 98 | 98 |
} |
| 99 |
+ |
|
| 100 |
+// BadRequest denotes the type of this error |
|
| 101 |
+func (id InvalidContainerIDError) BadRequest() {}
|
| 99 | 102 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,51 @@ |
| 0 |
+package libnetwork |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "testing" |
|
| 4 |
+ |
|
| 5 |
+ "github.com/docker/libnetwork/types" |
|
| 6 |
+) |
|
| 7 |
+ |
|
| 8 |
+func TestErrorInterfaces(t *testing.T) {
|
|
| 9 |
+ |
|
| 10 |
+ badRequestErrorList := []error{ErrInvalidID(""), ErrInvalidName(""), ErrInvalidJoin{}, ErrInvalidNetworkDriver(""), InvalidContainerIDError(""), ErrNoSuchNetwork(""), ErrNoSuchEndpoint("")}
|
|
| 11 |
+ for _, err := range badRequestErrorList {
|
|
| 12 |
+ switch u := err.(type) {
|
|
| 13 |
+ case types.BadRequestError: |
|
| 14 |
+ return |
|
| 15 |
+ default: |
|
| 16 |
+ t.Fatalf("Failed to detect err %v is of type BadRequestError. Got type: %T", err, u)
|
|
| 17 |
+ } |
|
| 18 |
+ } |
|
| 19 |
+ |
|
| 20 |
+ maskableErrorList := []error{ErrNoContainer{}}
|
|
| 21 |
+ for _, err := range maskableErrorList {
|
|
| 22 |
+ switch u := err.(type) {
|
|
| 23 |
+ case types.MaskableError: |
|
| 24 |
+ return |
|
| 25 |
+ default: |
|
| 26 |
+ t.Fatalf("Failed to detect err %v is of type MaskableError. Got type: %T", err, u)
|
|
| 27 |
+ } |
|
| 28 |
+ } |
|
| 29 |
+ |
|
| 30 |
+ notFoundErrorList := []error{NetworkTypeError(""), &UnknownNetworkError{}, &UnknownEndpointError{}}
|
|
| 31 |
+ for _, err := range notFoundErrorList {
|
|
| 32 |
+ switch u := err.(type) {
|
|
| 33 |
+ case types.NotFoundError: |
|
| 34 |
+ return |
|
| 35 |
+ default: |
|
| 36 |
+ t.Fatalf("Failed to detect err %v is of type NotFoundError. Got type: %T", err, u)
|
|
| 37 |
+ } |
|
| 38 |
+ } |
|
| 39 |
+ |
|
| 40 |
+ forbiddenErrorList := []error{NetworkTypeError(""), &UnknownNetworkError{}, &UnknownEndpointError{}}
|
|
| 41 |
+ for _, err := range forbiddenErrorList {
|
|
| 42 |
+ switch u := err.(type) {
|
|
| 43 |
+ case types.ForbiddenError: |
|
| 44 |
+ return |
|
| 45 |
+ default: |
|
| 46 |
+ t.Fatalf("Failed to detect err %v is of type ForbiddenError. Got type: %T", err, u)
|
|
| 47 |
+ } |
|
| 48 |
+ } |
|
| 49 |
+ |
|
| 50 |
+} |
| ... | ... |
@@ -22,6 +22,8 @@ import ( |
| 22 | 22 |
"github.com/docker/libnetwork/netlabel" |
| 23 | 23 |
"github.com/docker/libnetwork/netutils" |
| 24 | 24 |
"github.com/docker/libnetwork/options" |
| 25 |
+ "github.com/docker/libnetwork/types" |
|
| 26 |
+ "github.com/vishvananda/netlink" |
|
| 25 | 27 |
"github.com/vishvananda/netns" |
| 26 | 28 |
) |
| 27 | 29 |
|
| ... | ... |
@@ -65,11 +67,11 @@ func getEmptyGenericOption() map[string]interface{} {
|
| 65 | 65 |
return genericOption |
| 66 | 66 |
} |
| 67 | 67 |
|
| 68 |
-func getPortMapping() []netutils.PortBinding {
|
|
| 69 |
- return []netutils.PortBinding{
|
|
| 70 |
- netutils.PortBinding{Proto: netutils.TCP, Port: uint16(230), HostPort: uint16(23000)},
|
|
| 71 |
- netutils.PortBinding{Proto: netutils.UDP, Port: uint16(200), HostPort: uint16(22000)},
|
|
| 72 |
- netutils.PortBinding{Proto: netutils.TCP, Port: uint16(120), HostPort: uint16(12000)},
|
|
| 68 |
+func getPortMapping() []types.PortBinding {
|
|
| 69 |
+ return []types.PortBinding{
|
|
| 70 |
+ types.PortBinding{Proto: types.TCP, Port: uint16(230), HostPort: uint16(23000)},
|
|
| 71 |
+ types.PortBinding{Proto: types.UDP, Port: uint16(200), HostPort: uint16(22000)},
|
|
| 72 |
+ types.PortBinding{Proto: types.TCP, Port: uint16(120), HostPort: uint16(12000)},
|
|
| 73 | 73 |
} |
| 74 | 74 |
} |
| 75 | 75 |
|
| ... | ... |
@@ -245,7 +247,7 @@ func TestBridge(t *testing.T) {
|
| 245 | 245 |
if !ok {
|
| 246 | 246 |
t.Fatalf("Could not find expected info in endpoint data")
|
| 247 | 247 |
} |
| 248 |
- pm, ok := pmd.([]netutils.PortBinding) |
|
| 248 |
+ pm, ok := pmd.([]types.PortBinding) |
|
| 249 | 249 |
if !ok {
|
| 250 | 250 |
t.Fatalf("Unexpected format for port mapping in endpoint operational data")
|
| 251 | 251 |
} |
| ... | ... |
@@ -289,7 +291,7 @@ func TestNilRemoteDriver(t *testing.T) {
|
| 289 | 289 |
t.Fatal("Expected to fail. But instead succeeded")
|
| 290 | 290 |
} |
| 291 | 291 |
|
| 292 |
- if err != plugins.ErrNotFound {
|
|
| 292 |
+ if _, ok := err.(types.NotFoundError); !ok {
|
|
| 293 | 293 |
t.Fatalf("Did not fail with expected error. Actual error: %v", err)
|
| 294 | 294 |
} |
| 295 | 295 |
} |
| ... | ... |
@@ -337,8 +339,9 @@ func TestNetworkName(t *testing.T) {
|
| 337 | 337 |
if err == nil {
|
| 338 | 338 |
t.Fatal("Expected to fail. But instead succeeded")
|
| 339 | 339 |
} |
| 340 |
- if err != libnetwork.ErrInvalidName {
|
|
| 341 |
- t.Fatal("Expected to fail with ErrInvalidName error")
|
|
| 340 |
+ |
|
| 341 |
+ if _, ok := err.(libnetwork.ErrInvalidName); !ok {
|
|
| 342 |
+ t.Fatalf("Expected to fail with ErrInvalidName error. Got %v", err)
|
|
| 342 | 343 |
} |
| 343 | 344 |
|
| 344 | 345 |
networkName := "testnetwork" |
| ... | ... |
@@ -474,8 +477,8 @@ func TestUnknownEndpoint(t *testing.T) {
|
| 474 | 474 |
if err == nil {
|
| 475 | 475 |
t.Fatal("Expected to fail. But instead succeeded")
|
| 476 | 476 |
} |
| 477 |
- if err != libnetwork.ErrInvalidName {
|
|
| 478 |
- t.Fatal("Expected to fail with ErrInvalidName error")
|
|
| 477 |
+ if _, ok := err.(libnetwork.ErrInvalidName); !ok {
|
|
| 478 |
+ t.Fatalf("Expected to fail with ErrInvalidName error. Actual error: %v", err)
|
|
| 479 | 479 |
} |
| 480 | 480 |
|
| 481 | 481 |
ep, err := network.CreateEndpoint("testep")
|
| ... | ... |
@@ -612,15 +615,15 @@ func TestControllerQuery(t *testing.T) {
|
| 612 | 612 |
if err == nil {
|
| 613 | 613 |
t.Fatalf("NetworkByName() succeeded with invalid target name")
|
| 614 | 614 |
} |
| 615 |
- if err != libnetwork.ErrInvalidName {
|
|
| 616 |
- t.Fatalf("NetworkByName() failed with unexpected error: %v", err)
|
|
| 615 |
+ if _, ok := err.(libnetwork.ErrInvalidName); !ok {
|
|
| 616 |
+ t.Fatalf("Expected NetworkByName() to fail with ErrInvalidName error. Got: %v", err)
|
|
| 617 | 617 |
} |
| 618 | 618 |
|
| 619 | 619 |
_, err = controller.NetworkByID("")
|
| 620 | 620 |
if err == nil {
|
| 621 | 621 |
t.Fatalf("NetworkByID() succeeded with invalid target id")
|
| 622 | 622 |
} |
| 623 |
- if err != libnetwork.ErrInvalidID {
|
|
| 623 |
+ if _, ok := err.(libnetwork.ErrInvalidID); !ok {
|
|
| 624 | 624 |
t.Fatalf("NetworkByID() failed with unexpected error: %v", err)
|
| 625 | 625 |
} |
| 626 | 626 |
|
| ... | ... |
@@ -628,7 +631,7 @@ func TestControllerQuery(t *testing.T) {
|
| 628 | 628 |
if err == nil {
|
| 629 | 629 |
t.Fatalf("Unexpected success for NetworkByID(): %v", g)
|
| 630 | 630 |
} |
| 631 |
- if err != libnetwork.ErrNoSuchNetwork {
|
|
| 631 |
+ if _, ok := err.(libnetwork.ErrNoSuchNetwork); !ok {
|
|
| 632 | 632 |
t.Fatalf("NetworkByID() failed with unexpected error: %v", err)
|
| 633 | 633 |
} |
| 634 | 634 |
|
| ... | ... |
@@ -694,15 +697,15 @@ func TestNetworkQuery(t *testing.T) {
|
| 694 | 694 |
if err == nil {
|
| 695 | 695 |
t.Fatalf("EndpointByName() succeeded with invalid target name")
|
| 696 | 696 |
} |
| 697 |
- if err != libnetwork.ErrInvalidName {
|
|
| 698 |
- t.Fatalf("EndpointByName() failed with unexpected error: %v", err)
|
|
| 697 |
+ if _, ok := err.(libnetwork.ErrInvalidName); !ok {
|
|
| 698 |
+ t.Fatalf("Expected EndpointByName() to fail with ErrInvalidName error. Got: %v", err)
|
|
| 699 | 699 |
} |
| 700 | 700 |
|
| 701 | 701 |
e, err = net1.EndpointByName("IamNotAnEndpoint")
|
| 702 | 702 |
if err == nil {
|
| 703 | 703 |
t.Fatalf("EndpointByName() succeeded with unknown target name")
|
| 704 | 704 |
} |
| 705 |
- if err != libnetwork.ErrNoSuchEndpoint {
|
|
| 705 |
+ if _, ok := err.(libnetwork.ErrNoSuchEndpoint); !ok {
|
|
| 706 | 706 |
t.Fatal(err) |
| 707 | 707 |
} |
| 708 | 708 |
if e != nil {
|
| ... | ... |
@@ -721,13 +724,42 @@ func TestNetworkQuery(t *testing.T) {
|
| 721 | 721 |
if err == nil {
|
| 722 | 722 |
t.Fatalf("EndpointByID() succeeded with invalid target id")
|
| 723 | 723 |
} |
| 724 |
- if err != libnetwork.ErrInvalidID {
|
|
| 724 |
+ if _, ok := err.(libnetwork.ErrInvalidID); !ok {
|
|
| 725 | 725 |
t.Fatalf("EndpointByID() failed with unexpected error: %v", err)
|
| 726 | 726 |
} |
| 727 | 727 |
} |
| 728 | 728 |
|
| 729 | 729 |
const containerID = "valid_container" |
| 730 | 730 |
|
| 731 |
+func checkSandbox(t *testing.T, info libnetwork.EndpointInfo) {
|
|
| 732 |
+ origns, err := netns.Get() |
|
| 733 |
+ if err != nil {
|
|
| 734 |
+ t.Fatalf("Could not get the current netns: %v", err)
|
|
| 735 |
+ } |
|
| 736 |
+ defer origns.Close() |
|
| 737 |
+ |
|
| 738 |
+ key := info.SandboxKey() |
|
| 739 |
+ f, err := os.OpenFile(key, os.O_RDONLY, 0) |
|
| 740 |
+ if err != nil {
|
|
| 741 |
+ t.Fatalf("Failed to open network namespace path %q: %v", key, err)
|
|
| 742 |
+ } |
|
| 743 |
+ defer f.Close() |
|
| 744 |
+ |
|
| 745 |
+ runtime.LockOSThread() |
|
| 746 |
+ defer runtime.UnlockOSThread() |
|
| 747 |
+ |
|
| 748 |
+ nsFD := f.Fd() |
|
| 749 |
+ if err = netns.Set(netns.NsHandle(nsFD)); err != nil {
|
|
| 750 |
+ t.Fatalf("Setting to the namespace pointed to by the sandbox %s failed: %v", key, err)
|
|
| 751 |
+ } |
|
| 752 |
+ defer netns.Set(origns) |
|
| 753 |
+ |
|
| 754 |
+ _, err = netlink.LinkByName("eth0")
|
|
| 755 |
+ if err != nil {
|
|
| 756 |
+ t.Fatalf("Could not find the interface eth0 inside the sandbox: %v", err)
|
|
| 757 |
+ } |
|
| 758 |
+} |
|
| 759 |
+ |
|
| 731 | 760 |
func TestEndpointJoin(t *testing.T) {
|
| 732 | 761 |
if !netutils.IsRunningInContainer() {
|
| 733 | 762 |
defer netutils.SetupTestNetNS(t)() |
| ... | ... |
@@ -784,6 +816,8 @@ func TestEndpointJoin(t *testing.T) {
|
| 784 | 784 |
if info.SandboxKey() == "" {
|
| 785 | 785 |
t.Fatalf("Expected an non-empty sandbox key for a joined endpoint. Instead found a empty sandbox key")
|
| 786 | 786 |
} |
| 787 |
+ |
|
| 788 |
+ checkSandbox(t, info) |
|
| 787 | 789 |
} |
| 788 | 790 |
|
| 789 | 791 |
func TestEndpointJoinInvalidContainerId(t *testing.T) {
|
| ... | ... |
@@ -890,7 +924,7 @@ func TestEndpointMultipleJoins(t *testing.T) {
|
| 890 | 890 |
t.Fatal("Expected to fail multiple joins for the same endpoint")
|
| 891 | 891 |
} |
| 892 | 892 |
|
| 893 |
- if err != libnetwork.ErrInvalidJoin {
|
|
| 893 |
+ if _, ok := err.(libnetwork.ErrInvalidJoin); !ok {
|
|
| 894 | 894 |
t.Fatalf("Failed for unexpected reason: %v", err)
|
| 895 | 895 |
} |
| 896 | 896 |
} |
| ... | ... |
@@ -916,7 +950,7 @@ func TestEndpointInvalidLeave(t *testing.T) {
|
| 916 | 916 |
} |
| 917 | 917 |
|
| 918 | 918 |
if _, ok := err.(libnetwork.InvalidContainerIDError); !ok {
|
| 919 |
- if err != libnetwork.ErrNoContainer {
|
|
| 919 |
+ if _, ok := err.(libnetwork.ErrNoContainer); !ok {
|
|
| 920 | 920 |
t.Fatalf("Failed for unexpected reason: %v", err)
|
| 921 | 921 |
} |
| 922 | 922 |
} |
| ... | ... |
@@ -1275,6 +1309,10 @@ func TestValidRemoteDriver(t *testing.T) {
|
| 1275 | 1275 |
w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
|
| 1276 | 1276 |
fmt.Fprintf(w, `{"Implements": ["%s"]}`, driverapi.NetworkPluginEndpointType)
|
| 1277 | 1277 |
}) |
| 1278 |
+ mux.HandleFunc(fmt.Sprintf("/%s.CreateNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
|
|
| 1279 |
+ w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
|
|
| 1280 |
+ fmt.Fprintf(w, "null") |
|
| 1281 |
+ }) |
|
| 1278 | 1282 |
|
| 1279 | 1283 |
if err := os.MkdirAll("/usr/share/docker/plugins", 0755); err != nil {
|
| 1280 | 1284 |
t.Fatal(err) |
| ... | ... |
@@ -1296,7 +1334,7 @@ func TestValidRemoteDriver(t *testing.T) {
|
| 1296 | 1296 |
|
| 1297 | 1297 |
_, err = controller.NewNetwork("valid-network-driver", "dummy",
|
| 1298 | 1298 |
libnetwork.NetworkOptionGeneric(getEmptyGenericOption())) |
| 1299 |
- if err != nil && err != driverapi.ErrNotImplemented {
|
|
| 1299 |
+ if err != nil {
|
|
| 1300 | 1300 |
t.Fatal(err) |
| 1301 | 1301 |
} |
| 1302 | 1302 |
} |
| ... | ... |
@@ -1370,8 +1408,10 @@ func parallelJoin(t *testing.T, ep libnetwork.Endpoint, thrNumber int) {
|
| 1370 | 1370 |
_, err := ep.Join("racing_container")
|
| 1371 | 1371 |
runtime.LockOSThread() |
| 1372 | 1372 |
if err != nil {
|
| 1373 |
- if err != libnetwork.ErrNoContainer && err != libnetwork.ErrInvalidJoin {
|
|
| 1374 |
- t.Fatal(err) |
|
| 1373 |
+ if _, ok := err.(libnetwork.ErrNoContainer); !ok {
|
|
| 1374 |
+ if _, ok := err.(libnetwork.ErrInvalidJoin); !ok {
|
|
| 1375 |
+ t.Fatal(err) |
|
| 1376 |
+ } |
|
| 1375 | 1377 |
} |
| 1376 | 1378 |
debugf("JE%d(%v).", thrNumber, err)
|
| 1377 | 1379 |
} |
| ... | ... |
@@ -1383,8 +1423,10 @@ func parallelLeave(t *testing.T, ep libnetwork.Endpoint, thrNumber int) {
|
| 1383 | 1383 |
err := ep.Leave("racing_container")
|
| 1384 | 1384 |
runtime.LockOSThread() |
| 1385 | 1385 |
if err != nil {
|
| 1386 |
- if err != libnetwork.ErrNoContainer && err != libnetwork.ErrInvalidJoin {
|
|
| 1387 |
- t.Fatal(err) |
|
| 1386 |
+ if _, ok := err.(libnetwork.ErrNoContainer); !ok {
|
|
| 1387 |
+ if _, ok := err.(libnetwork.ErrInvalidJoin); !ok {
|
|
| 1388 |
+ t.Fatal(err) |
|
| 1389 |
+ } |
|
| 1388 | 1390 |
} |
| 1389 | 1391 |
debugf("LE%d(%v).", thrNumber, err)
|
| 1390 | 1392 |
} |
| ... | ... |
@@ -3,14 +3,12 @@ |
| 3 | 3 |
package netutils |
| 4 | 4 |
|
| 5 | 5 |
import ( |
| 6 |
- "bytes" |
|
| 7 | 6 |
"crypto/rand" |
| 8 | 7 |
"encoding/hex" |
| 9 | 8 |
"errors" |
| 10 | 9 |
"fmt" |
| 11 | 10 |
"io" |
| 12 | 11 |
"net" |
| 13 |
- "strings" |
|
| 14 | 12 |
|
| 15 | 13 |
"github.com/vishvananda/netlink" |
| 16 | 14 |
) |
| ... | ... |
@@ -26,144 +24,6 @@ var ( |
| 26 | 26 |
networkGetRoutesFct = netlink.RouteList |
| 27 | 27 |
) |
| 28 | 28 |
|
| 29 |
-// ErrInvalidProtocolBinding is returned when the port binding protocol is not valid. |
|
| 30 |
-type ErrInvalidProtocolBinding string |
|
| 31 |
- |
|
| 32 |
-func (ipb ErrInvalidProtocolBinding) Error() string {
|
|
| 33 |
- return fmt.Sprintf("invalid transport protocol: %s", string(ipb))
|
|
| 34 |
-} |
|
| 35 |
- |
|
| 36 |
-// TransportPort represent a local Layer 4 endpoint |
|
| 37 |
-type TransportPort struct {
|
|
| 38 |
- Proto Protocol |
|
| 39 |
- Port uint16 |
|
| 40 |
-} |
|
| 41 |
- |
|
| 42 |
-// GetCopy returns a copy of this TransportPort structure instance |
|
| 43 |
-func (t *TransportPort) GetCopy() TransportPort {
|
|
| 44 |
- return TransportPort{Proto: t.Proto, Port: t.Port}
|
|
| 45 |
-} |
|
| 46 |
- |
|
| 47 |
-// PortBinding represent a port binding between the container an the host |
|
| 48 |
-type PortBinding struct {
|
|
| 49 |
- Proto Protocol |
|
| 50 |
- IP net.IP |
|
| 51 |
- Port uint16 |
|
| 52 |
- HostIP net.IP |
|
| 53 |
- HostPort uint16 |
|
| 54 |
-} |
|
| 55 |
- |
|
| 56 |
-// HostAddr returns the host side transport address |
|
| 57 |
-func (p PortBinding) HostAddr() (net.Addr, error) {
|
|
| 58 |
- switch p.Proto {
|
|
| 59 |
- case UDP: |
|
| 60 |
- return &net.UDPAddr{IP: p.HostIP, Port: int(p.HostPort)}, nil
|
|
| 61 |
- case TCP: |
|
| 62 |
- return &net.TCPAddr{IP: p.HostIP, Port: int(p.HostPort)}, nil
|
|
| 63 |
- default: |
|
| 64 |
- return nil, ErrInvalidProtocolBinding(p.Proto.String()) |
|
| 65 |
- } |
|
| 66 |
-} |
|
| 67 |
- |
|
| 68 |
-// ContainerAddr returns the container side transport address |
|
| 69 |
-func (p PortBinding) ContainerAddr() (net.Addr, error) {
|
|
| 70 |
- switch p.Proto {
|
|
| 71 |
- case UDP: |
|
| 72 |
- return &net.UDPAddr{IP: p.IP, Port: int(p.Port)}, nil
|
|
| 73 |
- case TCP: |
|
| 74 |
- return &net.TCPAddr{IP: p.IP, Port: int(p.Port)}, nil
|
|
| 75 |
- default: |
|
| 76 |
- return nil, ErrInvalidProtocolBinding(p.Proto.String()) |
|
| 77 |
- } |
|
| 78 |
-} |
|
| 79 |
- |
|
| 80 |
-// GetCopy returns a copy of this PortBinding structure instance |
|
| 81 |
-func (p *PortBinding) GetCopy() PortBinding {
|
|
| 82 |
- return PortBinding{
|
|
| 83 |
- Proto: p.Proto, |
|
| 84 |
- IP: GetIPCopy(p.IP), |
|
| 85 |
- Port: p.Port, |
|
| 86 |
- HostIP: GetIPCopy(p.HostIP), |
|
| 87 |
- HostPort: p.HostPort, |
|
| 88 |
- } |
|
| 89 |
-} |
|
| 90 |
- |
|
| 91 |
-// Equal checks if this instance of PortBinding is equal to the passed one |
|
| 92 |
-func (p *PortBinding) Equal(o *PortBinding) bool {
|
|
| 93 |
- if p == o {
|
|
| 94 |
- return true |
|
| 95 |
- } |
|
| 96 |
- |
|
| 97 |
- if o == nil {
|
|
| 98 |
- return false |
|
| 99 |
- } |
|
| 100 |
- |
|
| 101 |
- if p.Proto != o.Proto || p.Port != o.Port || p.HostPort != o.HostPort {
|
|
| 102 |
- return false |
|
| 103 |
- } |
|
| 104 |
- |
|
| 105 |
- if p.IP != nil {
|
|
| 106 |
- if !p.IP.Equal(o.IP) {
|
|
| 107 |
- return false |
|
| 108 |
- } |
|
| 109 |
- } else {
|
|
| 110 |
- if o.IP != nil {
|
|
| 111 |
- return false |
|
| 112 |
- } |
|
| 113 |
- } |
|
| 114 |
- |
|
| 115 |
- if p.HostIP != nil {
|
|
| 116 |
- if !p.HostIP.Equal(o.HostIP) {
|
|
| 117 |
- return false |
|
| 118 |
- } |
|
| 119 |
- } else {
|
|
| 120 |
- if o.HostIP != nil {
|
|
| 121 |
- return false |
|
| 122 |
- } |
|
| 123 |
- } |
|
| 124 |
- |
|
| 125 |
- return true |
|
| 126 |
-} |
|
| 127 |
- |
|
| 128 |
-const ( |
|
| 129 |
- // ICMP is for the ICMP ip protocol |
|
| 130 |
- ICMP = 1 |
|
| 131 |
- // TCP is for the TCP ip protocol |
|
| 132 |
- TCP = 6 |
|
| 133 |
- // UDP is for the UDP ip protocol |
|
| 134 |
- UDP = 17 |
|
| 135 |
-) |
|
| 136 |
- |
|
| 137 |
-// Protocol represents a IP protocol number |
|
| 138 |
-type Protocol uint8 |
|
| 139 |
- |
|
| 140 |
-func (p Protocol) String() string {
|
|
| 141 |
- switch p {
|
|
| 142 |
- case ICMP: |
|
| 143 |
- return "icmp" |
|
| 144 |
- case TCP: |
|
| 145 |
- return "tcp" |
|
| 146 |
- case UDP: |
|
| 147 |
- return "udp" |
|
| 148 |
- default: |
|
| 149 |
- return fmt.Sprintf("%d", p)
|
|
| 150 |
- } |
|
| 151 |
-} |
|
| 152 |
- |
|
| 153 |
-// ParseProtocol returns the respective Protocol type for the passed string |
|
| 154 |
-func ParseProtocol(s string) Protocol {
|
|
| 155 |
- switch strings.ToLower(s) {
|
|
| 156 |
- case "icmp": |
|
| 157 |
- return ICMP |
|
| 158 |
- case "udp": |
|
| 159 |
- return UDP |
|
| 160 |
- case "tcp": |
|
| 161 |
- return TCP |
|
| 162 |
- default: |
|
| 163 |
- return 0 |
|
| 164 |
- } |
|
| 165 |
-} |
|
| 166 |
- |
|
| 167 | 29 |
// CheckNameserverOverlaps checks whether the passed network overlaps with any of the nameservers |
| 168 | 30 |
func CheckNameserverOverlaps(nameservers []string, toCheck *net.IPNet) error {
|
| 169 | 31 |
if len(nameservers) > 0 {
|
| ... | ... |
@@ -287,38 +147,3 @@ func GenerateRandomName(prefix string, size int) (string, error) {
|
| 287 | 287 |
} |
| 288 | 288 |
return prefix + hex.EncodeToString(id)[:size], nil |
| 289 | 289 |
} |
| 290 |
- |
|
| 291 |
-// GetMacCopy returns a copy of the passed MAC address |
|
| 292 |
-func GetMacCopy(from net.HardwareAddr) net.HardwareAddr {
|
|
| 293 |
- to := make(net.HardwareAddr, len(from)) |
|
| 294 |
- copy(to, from) |
|
| 295 |
- return to |
|
| 296 |
-} |
|
| 297 |
- |
|
| 298 |
-// GetIPCopy returns a copy of the passed IP address |
|
| 299 |
-func GetIPCopy(from net.IP) net.IP {
|
|
| 300 |
- to := make(net.IP, len(from)) |
|
| 301 |
- copy(to, from) |
|
| 302 |
- return to |
|
| 303 |
-} |
|
| 304 |
- |
|
| 305 |
-// GetIPNetCopy returns a copy of the passed IP Network |
|
| 306 |
-func GetIPNetCopy(from *net.IPNet) *net.IPNet {
|
|
| 307 |
- if from == nil {
|
|
| 308 |
- return nil |
|
| 309 |
- } |
|
| 310 |
- bm := make(net.IPMask, len(from.Mask)) |
|
| 311 |
- copy(bm, from.Mask) |
|
| 312 |
- return &net.IPNet{IP: GetIPCopy(from.IP), Mask: bm}
|
|
| 313 |
-} |
|
| 314 |
- |
|
| 315 |
-// CompareIPNet returns equal if the two IP Networks are equal |
|
| 316 |
-func CompareIPNet(a, b *net.IPNet) bool {
|
|
| 317 |
- if a == b {
|
|
| 318 |
- return true |
|
| 319 |
- } |
|
| 320 |
- if a == nil || b == nil {
|
|
| 321 |
- return false |
|
| 322 |
- } |
|
| 323 |
- return a.IP.Equal(b.IP) && bytes.Equal(a.Mask, b.Mask) |
|
| 324 |
-} |
| ... | ... |
@@ -209,135 +209,3 @@ func TestUtilGenerateRandomMAC(t *testing.T) {
|
| 209 | 209 |
t.Fatalf("mac1 %s should not equal mac2 %s", mac1, mac2)
|
| 210 | 210 |
} |
| 211 | 211 |
} |
| 212 |
- |
|
| 213 |
-func TestCompareIPNet(t *testing.T) {
|
|
| 214 |
- if CompareIPNet(nil, nil) == false {
|
|
| 215 |
- t.Fatalf("Failed to detect two nil net.IPNets are equal")
|
|
| 216 |
- } |
|
| 217 |
- |
|
| 218 |
- _, net1, _ := net.ParseCIDR("192.168.30.22/24")
|
|
| 219 |
- if CompareIPNet(net1, net1) == false {
|
|
| 220 |
- t.Fatalf("Failed to detect same net.IPNet pointers equality")
|
|
| 221 |
- } |
|
| 222 |
- |
|
| 223 |
- _, net2, _ := net.ParseCIDR("192.168.30.22/24")
|
|
| 224 |
- if CompareIPNet(net1, net2) == false {
|
|
| 225 |
- t.Fatalf("Failed to detect same net.IPNet object equality")
|
|
| 226 |
- } |
|
| 227 |
- |
|
| 228 |
- _, net3, _ := net.ParseCIDR("192.168.30.33/24")
|
|
| 229 |
- if CompareIPNet(net1, net3) == false {
|
|
| 230 |
- t.Fatalf("Failed to detect semantically equivalent net.IPNets")
|
|
| 231 |
- } |
|
| 232 |
- |
|
| 233 |
- _, net3, _ = net.ParseCIDR("192.168.31.33/24")
|
|
| 234 |
- if CompareIPNet(net2, net3) == true {
|
|
| 235 |
- t.Fatalf("Failed to detect different net.IPNets")
|
|
| 236 |
- } |
|
| 237 |
-} |
|
| 238 |
- |
|
| 239 |
-func TestIPCopyFunctions(t *testing.T) {
|
|
| 240 |
- ip := net.ParseIP("172.28.30.134")
|
|
| 241 |
- cp := GetIPCopy(ip) |
|
| 242 |
- |
|
| 243 |
- if !ip.Equal(cp) {
|
|
| 244 |
- t.Fatalf("Failed to return a copy of net.IP")
|
|
| 245 |
- } |
|
| 246 |
- |
|
| 247 |
- if &ip == &cp {
|
|
| 248 |
- t.Fatalf("Failed to return a true copy of net.IP")
|
|
| 249 |
- } |
|
| 250 |
-} |
|
| 251 |
- |
|
| 252 |
-func TestNetIPCopyFunctions(t *testing.T) {
|
|
| 253 |
- _, net, _ := net.ParseCIDR("192.168.30.23/24")
|
|
| 254 |
- cp := GetIPNetCopy(net) |
|
| 255 |
- |
|
| 256 |
- if CompareIPNet(net, cp) == false {
|
|
| 257 |
- t.Fatalf("Failed to return a copy of net.IPNet")
|
|
| 258 |
- } |
|
| 259 |
- |
|
| 260 |
- if net == cp {
|
|
| 261 |
- t.Fatalf("Failed to return a true copy of net.IPNet")
|
|
| 262 |
- } |
|
| 263 |
-} |
|
| 264 |
- |
|
| 265 |
-func TestPortBindingEqual(t *testing.T) {
|
|
| 266 |
- pb1 := &PortBinding{
|
|
| 267 |
- Proto: TCP, |
|
| 268 |
- IP: net.ParseIP("172.17.0.1"),
|
|
| 269 |
- Port: 80, |
|
| 270 |
- HostIP: net.ParseIP("192.168.100.1"),
|
|
| 271 |
- HostPort: 8080, |
|
| 272 |
- } |
|
| 273 |
- |
|
| 274 |
- pb2 := &PortBinding{
|
|
| 275 |
- Proto: UDP, |
|
| 276 |
- IP: net.ParseIP("172.17.0.1"),
|
|
| 277 |
- Port: 22, |
|
| 278 |
- HostIP: net.ParseIP("192.168.100.1"),
|
|
| 279 |
- HostPort: 2222, |
|
| 280 |
- } |
|
| 281 |
- if !pb1.Equal(pb1) {
|
|
| 282 |
- t.Fatalf("PortBinding.Equal() returned false negative")
|
|
| 283 |
- } |
|
| 284 |
- |
|
| 285 |
- if pb1.Equal(nil) {
|
|
| 286 |
- t.Fatalf("PortBinding.Equal() returned false negative")
|
|
| 287 |
- } |
|
| 288 |
- |
|
| 289 |
- if pb1.Equal(pb2) {
|
|
| 290 |
- t.Fatalf("PortBinding.Equal() returned false positive")
|
|
| 291 |
- } |
|
| 292 |
- |
|
| 293 |
- if pb1.Equal(pb2) != pb2.Equal(pb1) {
|
|
| 294 |
- t.Fatalf("PortBinding.Equal() failed commutative check")
|
|
| 295 |
- } |
|
| 296 |
-} |
|
| 297 |
- |
|
| 298 |
-func TestPortBindingGetCopy(t *testing.T) {
|
|
| 299 |
- pb := &PortBinding{
|
|
| 300 |
- Proto: TCP, |
|
| 301 |
- IP: net.ParseIP("172.17.0.1"),
|
|
| 302 |
- Port: 80, |
|
| 303 |
- HostIP: net.ParseIP("192.168.100.1"),
|
|
| 304 |
- HostPort: 8080, |
|
| 305 |
- } |
|
| 306 |
- cp := pb.GetCopy() |
|
| 307 |
- |
|
| 308 |
- if !pb.Equal(&cp) {
|
|
| 309 |
- t.Fatalf("Failed to return a copy of PortBinding")
|
|
| 310 |
- } |
|
| 311 |
- |
|
| 312 |
- if pb == &cp {
|
|
| 313 |
- t.Fatalf("Failed to return a true copy of PortBinding")
|
|
| 314 |
- } |
|
| 315 |
-} |
|
| 316 |
- |
|
| 317 |
-func TestPortBindingContainerAddr(t *testing.T) {
|
|
| 318 |
- pb := PortBinding{
|
|
| 319 |
- Proto: TCP, |
|
| 320 |
- IP: net.ParseIP("172.17.0.1"),
|
|
| 321 |
- Port: 80, |
|
| 322 |
- HostIP: net.ParseIP("192.168.100.1"),
|
|
| 323 |
- HostPort: 8080, |
|
| 324 |
- } |
|
| 325 |
- |
|
| 326 |
- container, err := pb.ContainerAddr() |
|
| 327 |
- |
|
| 328 |
- if err != nil {
|
|
| 329 |
- t.Fatal(err) |
|
| 330 |
- } |
|
| 331 |
- |
|
| 332 |
- switch netAddr := container.(type) {
|
|
| 333 |
- case *net.TCPAddr: |
|
| 334 |
- if !pb.IP.Equal(netAddr.IP) {
|
|
| 335 |
- t.Fatalf("PortBinding.ContainerAddr() Failed to return a ContainerAddr")
|
|
| 336 |
- } |
|
| 337 |
- if int(pb.Port) != netAddr.Port {
|
|
| 338 |
- t.Fatalf("PortBinding.ContainerAddr() Failed to return a ContainerAddr")
|
|
| 339 |
- } |
|
| 340 |
- case *net.UDPAddr: |
|
| 341 |
- t.Fatalf("PortBinding.ContainerAddr() Failed to check correct proto")
|
|
| 342 |
- } |
|
| 343 |
-} |
| ... | ... |
@@ -133,7 +133,7 @@ func (n *network) Delete() error {
|
| 133 | 133 |
|
| 134 | 134 |
func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoint, error) {
|
| 135 | 135 |
if name == "" {
|
| 136 |
- return nil, ErrInvalidName |
|
| 136 |
+ return nil, ErrInvalidName(name) |
|
| 137 | 137 |
} |
| 138 | 138 |
ep := &endpoint{name: name, iFaces: []*endpointInterface{}, generic: make(map[string]interface{})}
|
| 139 | 139 |
ep.id = types.UUID(stringid.GenerateRandomID()) |
| ... | ... |
@@ -173,7 +173,7 @@ func (n *network) WalkEndpoints(walker EndpointWalker) {
|
| 173 | 173 |
|
| 174 | 174 |
func (n *network) EndpointByName(name string) (Endpoint, error) {
|
| 175 | 175 |
if name == "" {
|
| 176 |
- return nil, ErrInvalidName |
|
| 176 |
+ return nil, ErrInvalidName(name) |
|
| 177 | 177 |
} |
| 178 | 178 |
var e Endpoint |
| 179 | 179 |
|
| ... | ... |
@@ -188,7 +188,7 @@ func (n *network) EndpointByName(name string) (Endpoint, error) {
|
| 188 | 188 |
n.WalkEndpoints(s) |
| 189 | 189 |
|
| 190 | 190 |
if e == nil {
|
| 191 |
- return nil, ErrNoSuchEndpoint |
|
| 191 |
+ return nil, ErrNoSuchEndpoint(name) |
|
| 192 | 192 |
} |
| 193 | 193 |
|
| 194 | 194 |
return e, nil |
| ... | ... |
@@ -196,12 +196,12 @@ func (n *network) EndpointByName(name string) (Endpoint, error) {
|
| 196 | 196 |
|
| 197 | 197 |
func (n *network) EndpointByID(id string) (Endpoint, error) {
|
| 198 | 198 |
if id == "" {
|
| 199 |
- return nil, ErrInvalidID |
|
| 199 |
+ return nil, ErrInvalidID(id) |
|
| 200 | 200 |
} |
| 201 | 201 |
n.Lock() |
| 202 | 202 |
defer n.Unlock() |
| 203 | 203 |
if e, ok := n.endpoints[types.UUID(id)]; ok {
|
| 204 | 204 |
return e, nil |
| 205 | 205 |
} |
| 206 |
- return nil, ErrNoSuchEndpoint |
|
| 206 |
+ return nil, ErrNoSuchEndpoint(id) |
|
| 207 | 207 |
} |
| ... | ... |
@@ -84,6 +84,8 @@ func (pm *PortMapper) Map(container net.Addr, hostIP net.IP, hostPort int, usePr |
| 84 | 84 |
|
| 85 | 85 |
if useProxy {
|
| 86 | 86 |
m.userlandProxy = newProxy(proto, hostIP, allocatedHostPort, container.(*net.TCPAddr).IP, container.(*net.TCPAddr).Port) |
| 87 |
+ } else {
|
|
| 88 |
+ m.userlandProxy = newDummyProxy(proto, hostIP, allocatedHostPort) |
|
| 87 | 89 |
} |
| 88 | 90 |
case *net.UDPAddr: |
| 89 | 91 |
proto = "udp" |
| ... | ... |
@@ -99,6 +101,8 @@ func (pm *PortMapper) Map(container net.Addr, hostIP net.IP, hostPort int, usePr |
| 99 | 99 |
|
| 100 | 100 |
if useProxy {
|
| 101 | 101 |
m.userlandProxy = newProxy(proto, hostIP, allocatedHostPort, container.(*net.UDPAddr).IP, container.(*net.UDPAddr).Port) |
| 102 |
+ } else {
|
|
| 103 |
+ m.userlandProxy = newDummyProxy(proto, hostIP, allocatedHostPort) |
|
| 102 | 104 |
} |
| 103 | 105 |
default: |
| 104 | 106 |
return nil, ErrUnknownBackendAddressType |
| ... | ... |
@@ -123,9 +127,7 @@ func (pm *PortMapper) Map(container net.Addr, hostIP net.IP, hostPort int, usePr |
| 123 | 123 |
|
| 124 | 124 |
cleanup := func() error {
|
| 125 | 125 |
// need to undo the iptables rules before we return |
| 126 |
- if m.userlandProxy != nil {
|
|
| 127 |
- m.userlandProxy.Stop() |
|
| 128 |
- } |
|
| 126 |
+ m.userlandProxy.Stop() |
|
| 129 | 127 |
pm.forward(iptables.Delete, m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort) |
| 130 | 128 |
if err := pm.Allocator.ReleasePort(hostIP, m.proto, allocatedHostPort); err != nil {
|
| 131 | 129 |
return err |
| ... | ... |
@@ -134,13 +136,11 @@ func (pm *PortMapper) Map(container net.Addr, hostIP net.IP, hostPort int, usePr |
| 134 | 134 |
return nil |
| 135 | 135 |
} |
| 136 | 136 |
|
| 137 |
- if m.userlandProxy != nil {
|
|
| 138 |
- if err := m.userlandProxy.Start(); err != nil {
|
|
| 139 |
- if err := cleanup(); err != nil {
|
|
| 140 |
- return nil, fmt.Errorf("Error during port allocation cleanup: %v", err)
|
|
| 141 |
- } |
|
| 142 |
- return nil, err |
|
| 137 |
+ if err := m.userlandProxy.Start(); err != nil {
|
|
| 138 |
+ if err := cleanup(); err != nil {
|
|
| 139 |
+ return nil, fmt.Errorf("Error during port allocation cleanup: %v", err)
|
|
| 143 | 140 |
} |
| 141 |
+ return nil, err |
|
| 144 | 142 |
} |
| 145 | 143 |
|
| 146 | 144 |
pm.currentMappings[key] = m |
| ... | ... |
@@ -2,20 +2,16 @@ package portmapper |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 | 4 |
"net" |
| 5 |
- "os" |
|
| 5 |
+ "strings" |
|
| 6 | 6 |
"testing" |
| 7 |
- "time" |
|
| 8 | 7 |
|
| 9 |
- "github.com/docker/docker/pkg/reexec" |
|
| 10 | 8 |
"github.com/docker/libnetwork/iptables" |
| 11 |
- "github.com/docker/libnetwork/netutils" |
|
| 9 |
+ _ "github.com/docker/libnetwork/netutils" |
|
| 12 | 10 |
) |
| 13 | 11 |
|
| 14 |
-func TestMain(m *testing.M) {
|
|
| 15 |
- if reexec.Init() {
|
|
| 16 |
- return |
|
| 17 |
- } |
|
| 18 |
- os.Exit(m.Run()) |
|
| 12 |
+func init() {
|
|
| 13 |
+ // override this func to mock out the proxy server |
|
| 14 |
+ newProxy = newMockProxyCommand |
|
| 19 | 15 |
} |
| 20 | 16 |
|
| 21 | 17 |
func TestSetIptablesChain(t *testing.T) {
|
| ... | ... |
@@ -37,7 +33,6 @@ func TestSetIptablesChain(t *testing.T) {
|
| 37 | 37 |
} |
| 38 | 38 |
|
| 39 | 39 |
func TestMapTCPPorts(t *testing.T) {
|
| 40 |
- defer netutils.SetupTestNetNS(t)() |
|
| 41 | 40 |
pm := New() |
| 42 | 41 |
dstIP1 := net.ParseIP("192.168.0.1")
|
| 43 | 42 |
dstIP2 := net.ParseIP("192.168.0.2")
|
| ... | ... |
@@ -117,7 +112,6 @@ func TestGetUDPIPAndPort(t *testing.T) {
|
| 117 | 117 |
} |
| 118 | 118 |
|
| 119 | 119 |
func TestMapUDPPorts(t *testing.T) {
|
| 120 |
- defer netutils.SetupTestNetNS(t)() |
|
| 121 | 120 |
pm := New() |
| 122 | 121 |
dstIP1 := net.ParseIP("192.168.0.1")
|
| 123 | 122 |
dstIP2 := net.ParseIP("192.168.0.2")
|
| ... | ... |
@@ -164,11 +158,6 @@ func TestMapUDPPorts(t *testing.T) {
|
| 164 | 164 |
} |
| 165 | 165 |
|
| 166 | 166 |
func TestMapAllPortsSingleInterface(t *testing.T) {
|
| 167 |
- newProxy = newMockProxyCommand |
|
| 168 |
- defer func() {
|
|
| 169 |
- newProxy = newProxyCommand |
|
| 170 |
- }() |
|
| 171 |
- defer netutils.SetupTestNetNS(t)() |
|
| 172 | 167 |
pm := New() |
| 173 | 168 |
dstIP1 := net.ParseIP("0.0.0.0")
|
| 174 | 169 |
srcAddr1 := &net.TCPAddr{Port: 1080, IP: net.ParseIP("172.16.0.1")}
|
| ... | ... |
@@ -177,6 +166,12 @@ func TestMapAllPortsSingleInterface(t *testing.T) {
|
| 177 | 177 |
var host net.Addr |
| 178 | 178 |
var err error |
| 179 | 179 |
|
| 180 |
+ defer func() {
|
|
| 181 |
+ for _, val := range hosts {
|
|
| 182 |
+ pm.Unmap(val) |
|
| 183 |
+ } |
|
| 184 |
+ }() |
|
| 185 |
+ |
|
| 180 | 186 |
for i := 0; i < 10; i++ {
|
| 181 | 187 |
start, end := pm.Allocator.Begin, pm.Allocator.End |
| 182 | 188 |
for i := start; i < end; i++ {
|
| ... | ... |
@@ -201,27 +196,76 @@ func TestMapAllPortsSingleInterface(t *testing.T) {
|
| 201 | 201 |
} |
| 202 | 202 |
} |
| 203 | 203 |
|
| 204 |
-func TestExecProxy(t *testing.T) {
|
|
| 205 |
- defer netutils.SetupTestNetNS(t)() |
|
| 206 |
- args := []string{
|
|
| 207 |
- userlandProxyCommandName, |
|
| 208 |
- "-proto", "tcp", |
|
| 209 |
- "-host-ip", "0.0.0.0", |
|
| 210 |
- "-host-port", "9999", |
|
| 211 |
- "-container-ip", "172.168.1.1", |
|
| 212 |
- "-container-port", "8888", |
|
| 213 |
- } |
|
| 214 |
- os.Args = args |
|
| 215 |
- doneChan := make(chan bool) |
|
| 216 |
- go func() {
|
|
| 217 |
- execProxy() |
|
| 218 |
- doneChan <- true |
|
| 219 |
- }() |
|
| 204 |
+func TestMapTCPDummyListen(t *testing.T) {
|
|
| 205 |
+ pm := New() |
|
| 206 |
+ dstIP := net.ParseIP("0.0.0.0")
|
|
| 207 |
+ dstAddr := &net.TCPAddr{IP: dstIP, Port: 80}
|
|
| 208 |
+ |
|
| 209 |
+ // no-op for dummy |
|
| 210 |
+ srcAddr := &net.TCPAddr{Port: 1080, IP: net.ParseIP("172.16.0.1")}
|
|
| 211 |
+ |
|
| 212 |
+ addrEqual := func(addr1, addr2 net.Addr) bool {
|
|
| 213 |
+ return (addr1.Network() == addr2.Network()) && (addr1.String() == addr2.String()) |
|
| 214 |
+ } |
|
| 220 | 215 |
|
| 221 |
- select {
|
|
| 222 |
- case <-doneChan: |
|
| 223 |
- t.Fatal("execProxy is not supposed to exit")
|
|
| 224 |
- case <-time.After(3 * time.Second): |
|
| 225 |
- return |
|
| 216 |
+ if host, err := pm.Map(srcAddr, dstIP, 80, false); err != nil {
|
|
| 217 |
+ t.Fatalf("Failed to allocate port: %s", err)
|
|
| 218 |
+ } else if !addrEqual(dstAddr, host) {
|
|
| 219 |
+ t.Fatalf("Incorrect mapping result: expected %s:%s, got %s:%s",
|
|
| 220 |
+ dstAddr.String(), dstAddr.Network(), host.String(), host.Network()) |
|
| 221 |
+ } |
|
| 222 |
+ if _, err := net.Listen("tcp", "0.0.0.0:80"); err == nil {
|
|
| 223 |
+ t.Fatal("Listen on mapped port without proxy should fail")
|
|
| 224 |
+ } else {
|
|
| 225 |
+ if !strings.Contains(err.Error(), "address already in use") {
|
|
| 226 |
+ t.Fatalf("Error should be about address already in use, got %v", err)
|
|
| 227 |
+ } |
|
| 228 |
+ } |
|
| 229 |
+ if _, err := net.Listen("tcp", "0.0.0.0:81"); err != nil {
|
|
| 230 |
+ t.Fatal(err) |
|
| 231 |
+ } |
|
| 232 |
+ if host, err := pm.Map(srcAddr, dstIP, 81, false); err == nil {
|
|
| 233 |
+ t.Fatalf("Bound port shouldn't be allocated, but it was on: %v", host)
|
|
| 234 |
+ } else {
|
|
| 235 |
+ if !strings.Contains(err.Error(), "address already in use") {
|
|
| 236 |
+ t.Fatalf("Error should be about address already in use, got %v", err)
|
|
| 237 |
+ } |
|
| 238 |
+ } |
|
| 239 |
+} |
|
| 240 |
+ |
|
| 241 |
+func TestMapUDPDummyListen(t *testing.T) {
|
|
| 242 |
+ pm := New() |
|
| 243 |
+ dstIP := net.ParseIP("0.0.0.0")
|
|
| 244 |
+ dstAddr := &net.UDPAddr{IP: dstIP, Port: 80}
|
|
| 245 |
+ |
|
| 246 |
+ // no-op for dummy |
|
| 247 |
+ srcAddr := &net.UDPAddr{Port: 1080, IP: net.ParseIP("172.16.0.1")}
|
|
| 248 |
+ |
|
| 249 |
+ addrEqual := func(addr1, addr2 net.Addr) bool {
|
|
| 250 |
+ return (addr1.Network() == addr2.Network()) && (addr1.String() == addr2.String()) |
|
| 251 |
+ } |
|
| 252 |
+ |
|
| 253 |
+ if host, err := pm.Map(srcAddr, dstIP, 80, false); err != nil {
|
|
| 254 |
+ t.Fatalf("Failed to allocate port: %s", err)
|
|
| 255 |
+ } else if !addrEqual(dstAddr, host) {
|
|
| 256 |
+ t.Fatalf("Incorrect mapping result: expected %s:%s, got %s:%s",
|
|
| 257 |
+ dstAddr.String(), dstAddr.Network(), host.String(), host.Network()) |
|
| 258 |
+ } |
|
| 259 |
+ if _, err := net.ListenUDP("udp", &net.UDPAddr{IP: dstIP, Port: 80}); err == nil {
|
|
| 260 |
+ t.Fatal("Listen on mapped port without proxy should fail")
|
|
| 261 |
+ } else {
|
|
| 262 |
+ if !strings.Contains(err.Error(), "address already in use") {
|
|
| 263 |
+ t.Fatalf("Error should be about address already in use, got %v", err)
|
|
| 264 |
+ } |
|
| 265 |
+ } |
|
| 266 |
+ if _, err := net.ListenUDP("udp", &net.UDPAddr{IP: dstIP, Port: 81}); err != nil {
|
|
| 267 |
+ t.Fatal(err) |
|
| 268 |
+ } |
|
| 269 |
+ if host, err := pm.Map(srcAddr, dstIP, 81, false); err == nil {
|
|
| 270 |
+ t.Fatalf("Bound port shouldn't be allocated, but it was on: %v", host)
|
|
| 271 |
+ } else {
|
|
| 272 |
+ if !strings.Contains(err.Error(), "address already in use") {
|
|
| 273 |
+ t.Fatalf("Error should be about address already in use, got %v", err)
|
|
| 274 |
+ } |
|
| 226 | 275 |
} |
| 227 | 276 |
} |
| ... | ... |
@@ -3,6 +3,7 @@ package portmapper |
| 3 | 3 |
import ( |
| 4 | 4 |
"flag" |
| 5 | 5 |
"fmt" |
| 6 |
+ "io" |
|
| 6 | 7 |
"io/ioutil" |
| 7 | 8 |
"log" |
| 8 | 9 |
"net" |
| ... | ... |
@@ -159,3 +160,50 @@ func (p *proxyCommand) Stop() error {
|
| 159 | 159 |
} |
| 160 | 160 |
return nil |
| 161 | 161 |
} |
| 162 |
+ |
|
| 163 |
+// dummyProxy just listen on some port, it is needed to prevent accidental |
|
| 164 |
+// port allocations on bound port, because without userland proxy we using |
|
| 165 |
+// iptables rules and not net.Listen |
|
| 166 |
+type dummyProxy struct {
|
|
| 167 |
+ listener io.Closer |
|
| 168 |
+ addr net.Addr |
|
| 169 |
+} |
|
| 170 |
+ |
|
| 171 |
+func newDummyProxy(proto string, hostIP net.IP, hostPort int) userlandProxy {
|
|
| 172 |
+ switch proto {
|
|
| 173 |
+ case "tcp": |
|
| 174 |
+ addr := &net.TCPAddr{IP: hostIP, Port: hostPort}
|
|
| 175 |
+ return &dummyProxy{addr: addr}
|
|
| 176 |
+ case "udp": |
|
| 177 |
+ addr := &net.UDPAddr{IP: hostIP, Port: hostPort}
|
|
| 178 |
+ return &dummyProxy{addr: addr}
|
|
| 179 |
+ } |
|
| 180 |
+ return nil |
|
| 181 |
+} |
|
| 182 |
+ |
|
| 183 |
+func (p *dummyProxy) Start() error {
|
|
| 184 |
+ switch addr := p.addr.(type) {
|
|
| 185 |
+ case *net.TCPAddr: |
|
| 186 |
+ l, err := net.ListenTCP("tcp", addr)
|
|
| 187 |
+ if err != nil {
|
|
| 188 |
+ return err |
|
| 189 |
+ } |
|
| 190 |
+ p.listener = l |
|
| 191 |
+ case *net.UDPAddr: |
|
| 192 |
+ l, err := net.ListenUDP("udp", addr)
|
|
| 193 |
+ if err != nil {
|
|
| 194 |
+ return err |
|
| 195 |
+ } |
|
| 196 |
+ p.listener = l |
|
| 197 |
+ default: |
|
| 198 |
+ return fmt.Errorf("Unknown addr type: %T", p.addr)
|
|
| 199 |
+ } |
|
| 200 |
+ return nil |
|
| 201 |
+} |
|
| 202 |
+ |
|
| 203 |
+func (p *dummyProxy) Stop() error {
|
|
| 204 |
+ if p.listener != nil {
|
|
| 205 |
+ return p.listener.Close() |
|
| 206 |
+ } |
|
| 207 |
+ return nil |
|
| 208 |
+} |
| ... | ... |
@@ -20,8 +20,10 @@ var once sync.Once |
| 20 | 20 |
// interface. It represents a linux network namespace, and moves an interface |
| 21 | 21 |
// into it when called on method AddInterface or sets the gateway etc. |
| 22 | 22 |
type networkNamespace struct {
|
| 23 |
- path string |
|
| 24 |
- sinfo *Info |
|
| 23 |
+ path string |
|
| 24 |
+ sinfo *Info |
|
| 25 |
+ nextIfIndex int |
|
| 26 |
+ sync.Mutex |
|
| 25 | 27 |
} |
| 26 | 28 |
|
| 27 | 29 |
func createBasePath() {
|
| ... | ... |
@@ -167,6 +169,11 @@ func (n *networkNamespace) RemoveInterface(i *Interface) error {
|
| 167 | 167 |
} |
| 168 | 168 |
|
| 169 | 169 |
func (n *networkNamespace) AddInterface(i *Interface) error {
|
| 170 |
+ n.Lock() |
|
| 171 |
+ i.DstName = fmt.Sprintf("%s%d", i.DstName, n.nextIfIndex)
|
|
| 172 |
+ n.nextIfIndex++ |
|
| 173 |
+ n.Unlock() |
|
| 174 |
+ |
|
| 170 | 175 |
runtime.LockOSThread() |
| 171 | 176 |
defer runtime.UnlockOSThread() |
| 172 | 177 |
|
| ... | ... |
@@ -214,7 +221,10 @@ func (n *networkNamespace) AddInterface(i *Interface) error {
|
| 214 | 214 |
return err |
| 215 | 215 |
} |
| 216 | 216 |
|
| 217 |
+ n.Lock() |
|
| 217 | 218 |
n.sinfo.Interfaces = append(n.sinfo.Interfaces, i) |
| 219 |
+ n.Unlock() |
|
| 220 |
+ |
|
| 218 | 221 |
return nil |
| 219 | 222 |
} |
| 220 | 223 |
|
| ... | ... |
@@ -3,7 +3,7 @@ package sandbox |
| 3 | 3 |
import ( |
| 4 | 4 |
"net" |
| 5 | 5 |
|
| 6 |
- "github.com/docker/libnetwork/netutils" |
|
| 6 |
+ "github.com/docker/libnetwork/types" |
|
| 7 | 7 |
) |
| 8 | 8 |
|
| 9 | 9 |
// Sandbox represents a network sandbox, identified by a specific key. It |
| ... | ... |
@@ -20,7 +20,9 @@ type Sandbox interface {
|
| 20 | 20 |
|
| 21 | 21 |
// Add an existing Interface to this sandbox. The operation will rename |
| 22 | 22 |
// from the Interface SrcName to DstName as it moves, and reconfigure the |
| 23 |
- // interface according to the specified settings. |
|
| 23 |
+ // interface according to the specified settings. The caller is expected |
|
| 24 |
+ // to only provide a prefix for DstName. The AddInterface api will auto-generate |
|
| 25 |
+ // an appropriate suffix for the DstName to disambiguate. |
|
| 24 | 26 |
AddInterface(*Interface) error |
| 25 | 27 |
|
| 26 | 28 |
// Remove an interface from the sandbox by renamin to original name |
| ... | ... |
@@ -62,7 +64,9 @@ type Interface struct {
|
| 62 | 62 |
SrcName string |
| 63 | 63 |
|
| 64 | 64 |
// The name that will be assigned to the interface once moves inside a |
| 65 |
- // network namespace. |
|
| 65 |
+ // network namespace. When the caller passes in a DstName, it is only |
|
| 66 |
+ // expected to pass a prefix. The name will modified with an appropriately |
|
| 67 |
+ // auto-generated suffix. |
|
| 66 | 68 |
DstName string |
| 67 | 69 |
|
| 68 | 70 |
// IPv4 address for the interface. |
| ... | ... |
@@ -77,8 +81,8 @@ func (i *Interface) GetCopy() *Interface {
|
| 77 | 77 |
return &Interface{
|
| 78 | 78 |
SrcName: i.SrcName, |
| 79 | 79 |
DstName: i.DstName, |
| 80 |
- Address: netutils.GetIPNetCopy(i.Address), |
|
| 81 |
- AddressIPv6: netutils.GetIPNetCopy(i.AddressIPv6), |
|
| 80 |
+ Address: types.GetIPNetCopy(i.Address), |
|
| 81 |
+ AddressIPv6: types.GetIPNetCopy(i.AddressIPv6), |
|
| 82 | 82 |
} |
| 83 | 83 |
} |
| 84 | 84 |
|
| ... | ... |
@@ -96,11 +100,11 @@ func (i *Interface) Equal(o *Interface) bool {
|
| 96 | 96 |
return false |
| 97 | 97 |
} |
| 98 | 98 |
|
| 99 |
- if !netutils.CompareIPNet(i.Address, o.Address) {
|
|
| 99 |
+ if !types.CompareIPNet(i.Address, o.Address) {
|
|
| 100 | 100 |
return false |
| 101 | 101 |
} |
| 102 | 102 |
|
| 103 |
- if !netutils.CompareIPNet(i.AddressIPv6, o.AddressIPv6) {
|
|
| 103 |
+ if !types.CompareIPNet(i.AddressIPv6, o.AddressIPv6) {
|
|
| 104 | 104 |
return false |
| 105 | 105 |
} |
| 106 | 106 |
|
| ... | ... |
@@ -113,8 +117,8 @@ func (s *Info) GetCopy() *Info {
|
| 113 | 113 |
for i, iface := range s.Interfaces {
|
| 114 | 114 |
list[i] = iface.GetCopy() |
| 115 | 115 |
} |
| 116 |
- gw := netutils.GetIPCopy(s.Gateway) |
|
| 117 |
- gw6 := netutils.GetIPCopy(s.GatewayIPv6) |
|
| 116 |
+ gw := types.GetIPCopy(s.Gateway) |
|
| 117 |
+ gw6 := types.GetIPCopy(s.GatewayIPv6) |
|
| 118 | 118 |
|
| 119 | 119 |
return &Info{Interfaces: list, Gateway: gw, GatewayIPv6: gw6}
|
| 120 | 120 |
} |
| ... | ... |
@@ -15,6 +15,8 @@ import ( |
| 15 | 15 |
const ( |
| 16 | 16 |
vethName1 = "wierdlongname1" |
| 17 | 17 |
vethName2 = "wierdlongname2" |
| 18 |
+ vethName3 = "wierdlongname3" |
|
| 19 |
+ vethName4 = "wierdlongname4" |
|
| 18 | 20 |
sboxIfaceName = "containername" |
| 19 | 21 |
) |
| 20 | 22 |
|
| ... | ... |
@@ -36,33 +38,59 @@ func newInfo(t *testing.T) (*Info, error) {
|
| 36 | 36 |
veth := &netlink.Veth{
|
| 37 | 37 |
LinkAttrs: netlink.LinkAttrs{Name: vethName1, TxQLen: 0},
|
| 38 | 38 |
PeerName: vethName2} |
| 39 |
- err := netlink.LinkAdd(veth) |
|
| 40 |
- if err != nil {
|
|
| 39 |
+ if err := netlink.LinkAdd(veth); err != nil {
|
|
| 41 | 40 |
return nil, err |
| 42 | 41 |
} |
| 43 | 42 |
|
| 44 | 43 |
// Store the sandbox side pipe interface |
| 45 | 44 |
// This is needed for cleanup on DeleteEndpoint() |
| 46 |
- intf := &Interface{}
|
|
| 47 |
- intf.SrcName = vethName2 |
|
| 48 |
- intf.DstName = sboxIfaceName |
|
| 45 |
+ intf1 := &Interface{}
|
|
| 46 |
+ intf1.SrcName = vethName2 |
|
| 47 |
+ intf1.DstName = sboxIfaceName |
|
| 49 | 48 |
|
| 50 | 49 |
ip4, addr, err := net.ParseCIDR("192.168.1.100/24")
|
| 51 | 50 |
if err != nil {
|
| 52 | 51 |
return nil, err |
| 53 | 52 |
} |
| 54 |
- intf.Address = addr |
|
| 55 |
- intf.Address.IP = ip4 |
|
| 53 |
+ intf1.Address = addr |
|
| 54 |
+ intf1.Address.IP = ip4 |
|
| 56 | 55 |
|
| 57 | 56 |
// ip6, addrv6, err := net.ParseCIDR("2001:DB8::ABCD/48")
|
| 58 | 57 |
ip6, addrv6, err := net.ParseCIDR("fe80::2/64")
|
| 59 | 58 |
if err != nil {
|
| 60 | 59 |
return nil, err |
| 61 | 60 |
} |
| 62 |
- intf.AddressIPv6 = addrv6 |
|
| 63 |
- intf.AddressIPv6.IP = ip6 |
|
| 61 |
+ intf1.AddressIPv6 = addrv6 |
|
| 62 |
+ intf1.AddressIPv6.IP = ip6 |
|
| 63 |
+ |
|
| 64 |
+ veth = &netlink.Veth{
|
|
| 65 |
+ LinkAttrs: netlink.LinkAttrs{Name: vethName3, TxQLen: 0},
|
|
| 66 |
+ PeerName: vethName4} |
|
| 67 |
+ |
|
| 68 |
+ if err := netlink.LinkAdd(veth); err != nil {
|
|
| 69 |
+ return nil, err |
|
| 70 |
+ } |
|
| 71 |
+ |
|
| 72 |
+ intf2 := &Interface{}
|
|
| 73 |
+ intf2.SrcName = vethName4 |
|
| 74 |
+ intf2.DstName = sboxIfaceName |
|
| 75 |
+ |
|
| 76 |
+ ip4, addr, err = net.ParseCIDR("192.168.2.100/24")
|
|
| 77 |
+ if err != nil {
|
|
| 78 |
+ return nil, err |
|
| 79 |
+ } |
|
| 80 |
+ intf2.Address = addr |
|
| 81 |
+ intf2.Address.IP = ip4 |
|
| 64 | 82 |
|
| 65 |
- sinfo := &Info{Interfaces: []*Interface{intf}}
|
|
| 83 |
+ // ip6, addrv6, err := net.ParseCIDR("2001:DB8::ABCD/48")
|
|
| 84 |
+ ip6, addrv6, err = net.ParseCIDR("fe80::3/64")
|
|
| 85 |
+ if err != nil {
|
|
| 86 |
+ return nil, err |
|
| 87 |
+ } |
|
| 88 |
+ intf2.AddressIPv6 = addrv6 |
|
| 89 |
+ intf2.AddressIPv6.IP = ip6 |
|
| 90 |
+ |
|
| 91 |
+ sinfo := &Info{Interfaces: []*Interface{intf1, intf2}}
|
|
| 66 | 92 |
sinfo.Gateway = net.ParseIP("192.168.1.1")
|
| 67 | 93 |
// sinfo.GatewayIPv6 = net.ParseIP("2001:DB8::1")
|
| 68 | 94 |
sinfo.GatewayIPv6 = net.ParseIP("fe80::1")
|
| ... | ... |
@@ -97,7 +125,13 @@ func verifySandbox(t *testing.T, s Sandbox) {
|
| 97 | 97 |
} |
| 98 | 98 |
defer netns.Set(origns) |
| 99 | 99 |
|
| 100 |
- _, err = netlink.LinkByName(sboxIfaceName) |
|
| 100 |
+ _, err = netlink.LinkByName(sboxIfaceName + "0") |
|
| 101 |
+ if err != nil {
|
|
| 102 |
+ t.Fatalf("Could not find the interface %s inside the sandbox: %v", sboxIfaceName,
|
|
| 103 |
+ err) |
|
| 104 |
+ } |
|
| 105 |
+ |
|
| 106 |
+ _, err = netlink.LinkByName(sboxIfaceName + "1") |
|
| 101 | 107 |
if err != nil {
|
| 102 | 108 |
t.Fatalf("Could not find the interface %s inside the sandbox: %v", sboxIfaceName,
|
| 103 | 109 |
err) |
| ... | ... |
@@ -1,5 +1,345 @@ |
| 1 | 1 |
// Package types contains types that are common across libnetwork project |
| 2 | 2 |
package types |
| 3 | 3 |
|
| 4 |
+import ( |
|
| 5 |
+ "bytes" |
|
| 6 |
+ "fmt" |
|
| 7 |
+ "net" |
|
| 8 |
+ "strings" |
|
| 9 |
+) |
|
| 10 |
+ |
|
| 4 | 11 |
// UUID represents a globally unique ID of various resources like network and endpoint |
| 5 | 12 |
type UUID string |
| 13 |
+ |
|
| 14 |
+// TransportPort represent a local Layer 4 endpoint |
|
| 15 |
+type TransportPort struct {
|
|
| 16 |
+ Proto Protocol |
|
| 17 |
+ Port uint16 |
|
| 18 |
+} |
|
| 19 |
+ |
|
| 20 |
+// GetCopy returns a copy of this TransportPort structure instance |
|
| 21 |
+func (t *TransportPort) GetCopy() TransportPort {
|
|
| 22 |
+ return TransportPort{Proto: t.Proto, Port: t.Port}
|
|
| 23 |
+} |
|
| 24 |
+ |
|
| 25 |
+// PortBinding represent a port binding between the container an the host |
|
| 26 |
+type PortBinding struct {
|
|
| 27 |
+ Proto Protocol |
|
| 28 |
+ IP net.IP |
|
| 29 |
+ Port uint16 |
|
| 30 |
+ HostIP net.IP |
|
| 31 |
+ HostPort uint16 |
|
| 32 |
+} |
|
| 33 |
+ |
|
| 34 |
+// HostAddr returns the host side transport address |
|
| 35 |
+func (p PortBinding) HostAddr() (net.Addr, error) {
|
|
| 36 |
+ switch p.Proto {
|
|
| 37 |
+ case UDP: |
|
| 38 |
+ return &net.UDPAddr{IP: p.HostIP, Port: int(p.HostPort)}, nil
|
|
| 39 |
+ case TCP: |
|
| 40 |
+ return &net.TCPAddr{IP: p.HostIP, Port: int(p.HostPort)}, nil
|
|
| 41 |
+ default: |
|
| 42 |
+ return nil, ErrInvalidProtocolBinding(p.Proto.String()) |
|
| 43 |
+ } |
|
| 44 |
+} |
|
| 45 |
+ |
|
| 46 |
+// ContainerAddr returns the container side transport address |
|
| 47 |
+func (p PortBinding) ContainerAddr() (net.Addr, error) {
|
|
| 48 |
+ switch p.Proto {
|
|
| 49 |
+ case UDP: |
|
| 50 |
+ return &net.UDPAddr{IP: p.IP, Port: int(p.Port)}, nil
|
|
| 51 |
+ case TCP: |
|
| 52 |
+ return &net.TCPAddr{IP: p.IP, Port: int(p.Port)}, nil
|
|
| 53 |
+ default: |
|
| 54 |
+ return nil, ErrInvalidProtocolBinding(p.Proto.String()) |
|
| 55 |
+ } |
|
| 56 |
+} |
|
| 57 |
+ |
|
| 58 |
+// GetCopy returns a copy of this PortBinding structure instance |
|
| 59 |
+func (p *PortBinding) GetCopy() PortBinding {
|
|
| 60 |
+ return PortBinding{
|
|
| 61 |
+ Proto: p.Proto, |
|
| 62 |
+ IP: GetIPCopy(p.IP), |
|
| 63 |
+ Port: p.Port, |
|
| 64 |
+ HostIP: GetIPCopy(p.HostIP), |
|
| 65 |
+ HostPort: p.HostPort, |
|
| 66 |
+ } |
|
| 67 |
+} |
|
| 68 |
+ |
|
| 69 |
+// Equal checks if this instance of PortBinding is equal to the passed one |
|
| 70 |
+func (p *PortBinding) Equal(o *PortBinding) bool {
|
|
| 71 |
+ if p == o {
|
|
| 72 |
+ return true |
|
| 73 |
+ } |
|
| 74 |
+ |
|
| 75 |
+ if o == nil {
|
|
| 76 |
+ return false |
|
| 77 |
+ } |
|
| 78 |
+ |
|
| 79 |
+ if p.Proto != o.Proto || p.Port != o.Port || p.HostPort != o.HostPort {
|
|
| 80 |
+ return false |
|
| 81 |
+ } |
|
| 82 |
+ |
|
| 83 |
+ if p.IP != nil {
|
|
| 84 |
+ if !p.IP.Equal(o.IP) {
|
|
| 85 |
+ return false |
|
| 86 |
+ } |
|
| 87 |
+ } else {
|
|
| 88 |
+ if o.IP != nil {
|
|
| 89 |
+ return false |
|
| 90 |
+ } |
|
| 91 |
+ } |
|
| 92 |
+ |
|
| 93 |
+ if p.HostIP != nil {
|
|
| 94 |
+ if !p.HostIP.Equal(o.HostIP) {
|
|
| 95 |
+ return false |
|
| 96 |
+ } |
|
| 97 |
+ } else {
|
|
| 98 |
+ if o.HostIP != nil {
|
|
| 99 |
+ return false |
|
| 100 |
+ } |
|
| 101 |
+ } |
|
| 102 |
+ |
|
| 103 |
+ return true |
|
| 104 |
+} |
|
| 105 |
+ |
|
| 106 |
+// ErrInvalidProtocolBinding is returned when the port binding protocol is not valid. |
|
| 107 |
+type ErrInvalidProtocolBinding string |
|
| 108 |
+ |
|
| 109 |
+func (ipb ErrInvalidProtocolBinding) Error() string {
|
|
| 110 |
+ return fmt.Sprintf("invalid transport protocol: %s", string(ipb))
|
|
| 111 |
+} |
|
| 112 |
+ |
|
| 113 |
+const ( |
|
| 114 |
+ // ICMP is for the ICMP ip protocol |
|
| 115 |
+ ICMP = 1 |
|
| 116 |
+ // TCP is for the TCP ip protocol |
|
| 117 |
+ TCP = 6 |
|
| 118 |
+ // UDP is for the UDP ip protocol |
|
| 119 |
+ UDP = 17 |
|
| 120 |
+) |
|
| 121 |
+ |
|
| 122 |
+// Protocol represents a IP protocol number |
|
| 123 |
+type Protocol uint8 |
|
| 124 |
+ |
|
| 125 |
+func (p Protocol) String() string {
|
|
| 126 |
+ switch p {
|
|
| 127 |
+ case ICMP: |
|
| 128 |
+ return "icmp" |
|
| 129 |
+ case TCP: |
|
| 130 |
+ return "tcp" |
|
| 131 |
+ case UDP: |
|
| 132 |
+ return "udp" |
|
| 133 |
+ default: |
|
| 134 |
+ return fmt.Sprintf("%d", p)
|
|
| 135 |
+ } |
|
| 136 |
+} |
|
| 137 |
+ |
|
| 138 |
+// ParseProtocol returns the respective Protocol type for the passed string |
|
| 139 |
+func ParseProtocol(s string) Protocol {
|
|
| 140 |
+ switch strings.ToLower(s) {
|
|
| 141 |
+ case "icmp": |
|
| 142 |
+ return ICMP |
|
| 143 |
+ case "udp": |
|
| 144 |
+ return UDP |
|
| 145 |
+ case "tcp": |
|
| 146 |
+ return TCP |
|
| 147 |
+ default: |
|
| 148 |
+ return 0 |
|
| 149 |
+ } |
|
| 150 |
+} |
|
| 151 |
+ |
|
| 152 |
+// GetMacCopy returns a copy of the passed MAC address |
|
| 153 |
+func GetMacCopy(from net.HardwareAddr) net.HardwareAddr {
|
|
| 154 |
+ to := make(net.HardwareAddr, len(from)) |
|
| 155 |
+ copy(to, from) |
|
| 156 |
+ return to |
|
| 157 |
+} |
|
| 158 |
+ |
|
| 159 |
+// GetIPCopy returns a copy of the passed IP address |
|
| 160 |
+func GetIPCopy(from net.IP) net.IP {
|
|
| 161 |
+ to := make(net.IP, len(from)) |
|
| 162 |
+ copy(to, from) |
|
| 163 |
+ return to |
|
| 164 |
+} |
|
| 165 |
+ |
|
| 166 |
+// GetIPNetCopy returns a copy of the passed IP Network |
|
| 167 |
+func GetIPNetCopy(from *net.IPNet) *net.IPNet {
|
|
| 168 |
+ if from == nil {
|
|
| 169 |
+ return nil |
|
| 170 |
+ } |
|
| 171 |
+ bm := make(net.IPMask, len(from.Mask)) |
|
| 172 |
+ copy(bm, from.Mask) |
|
| 173 |
+ return &net.IPNet{IP: GetIPCopy(from.IP), Mask: bm}
|
|
| 174 |
+} |
|
| 175 |
+ |
|
| 176 |
+// CompareIPNet returns equal if the two IP Networks are equal |
|
| 177 |
+func CompareIPNet(a, b *net.IPNet) bool {
|
|
| 178 |
+ if a == b {
|
|
| 179 |
+ return true |
|
| 180 |
+ } |
|
| 181 |
+ if a == nil || b == nil {
|
|
| 182 |
+ return false |
|
| 183 |
+ } |
|
| 184 |
+ return a.IP.Equal(b.IP) && bytes.Equal(a.Mask, b.Mask) |
|
| 185 |
+} |
|
| 186 |
+ |
|
| 187 |
+/****************************** |
|
| 188 |
+ * Well-known Error Interfaces |
|
| 189 |
+ ******************************/ |
|
| 190 |
+ |
|
| 191 |
+// MaskableError is an interface for errors which can be ignored by caller |
|
| 192 |
+type MaskableError interface {
|
|
| 193 |
+ // Maskable makes implementer into MaskableError type |
|
| 194 |
+ Maskable() |
|
| 195 |
+} |
|
| 196 |
+ |
|
| 197 |
+// BadRequestError is an interface for errors originated by a bad request |
|
| 198 |
+type BadRequestError interface {
|
|
| 199 |
+ // BadRequest makes implementer into BadRequestError type |
|
| 200 |
+ BadRequest() |
|
| 201 |
+} |
|
| 202 |
+ |
|
| 203 |
+// NotFoundError is an interface for errors raised because a needed resource is not available |
|
| 204 |
+type NotFoundError interface {
|
|
| 205 |
+ // NotFound makes implementer into NotFoundError type |
|
| 206 |
+ NotFound() |
|
| 207 |
+} |
|
| 208 |
+ |
|
| 209 |
+// ForbiddenError is an interface for errors which denote an valid request that cannot be honored |
|
| 210 |
+type ForbiddenError interface {
|
|
| 211 |
+ // Forbidden makes implementer into ForbiddenError type |
|
| 212 |
+ Forbidden() |
|
| 213 |
+} |
|
| 214 |
+ |
|
| 215 |
+// NoServiceError is an interface for errors returned when the required service is not available |
|
| 216 |
+type NoServiceError interface {
|
|
| 217 |
+ // NoService makes implementer into NoServiceError type |
|
| 218 |
+ NoService() |
|
| 219 |
+} |
|
| 220 |
+ |
|
| 221 |
+// TimeoutError is an interface for errors raised because of timeout |
|
| 222 |
+type TimeoutError interface {
|
|
| 223 |
+ // Timeout makes implementer into TimeoutError type |
|
| 224 |
+ Timeout() |
|
| 225 |
+} |
|
| 226 |
+ |
|
| 227 |
+// NotImplementedError is an interface for errors raised because of requested functionality is not yet implemented |
|
| 228 |
+type NotImplementedError interface {
|
|
| 229 |
+ // NotImplemented makes implementer into NotImplementedError type |
|
| 230 |
+ NotImplemented() |
|
| 231 |
+} |
|
| 232 |
+ |
|
| 233 |
+// InternalError is an interface for errors raised because of an internal error |
|
| 234 |
+type InternalError interface {
|
|
| 235 |
+ // Internal makes implementer into InternalError type |
|
| 236 |
+ Internal() |
|
| 237 |
+} |
|
| 238 |
+ |
|
| 239 |
+/****************************** |
|
| 240 |
+ * Weel-known Error Formatters |
|
| 241 |
+ ******************************/ |
|
| 242 |
+ |
|
| 243 |
+// BadRequestErrorf creates an instance of BadRequestError |
|
| 244 |
+func BadRequestErrorf(format string, params ...interface{}) error {
|
|
| 245 |
+ return badRequest(fmt.Sprintf(format, params...)) |
|
| 246 |
+} |
|
| 247 |
+ |
|
| 248 |
+// NotFoundErrorf creates an instance of NotFoundError |
|
| 249 |
+func NotFoundErrorf(format string, params ...interface{}) error {
|
|
| 250 |
+ return notFound(fmt.Sprintf(format, params...)) |
|
| 251 |
+} |
|
| 252 |
+ |
|
| 253 |
+// ForbiddenErrorf creates an instance of ForbiddenError |
|
| 254 |
+func ForbiddenErrorf(format string, params ...interface{}) error {
|
|
| 255 |
+ return forbidden(fmt.Sprintf(format, params...)) |
|
| 256 |
+} |
|
| 257 |
+ |
|
| 258 |
+// NoServiceErrorf creates an instance of NoServiceError |
|
| 259 |
+func NoServiceErrorf(format string, params ...interface{}) error {
|
|
| 260 |
+ return noService(fmt.Sprintf(format, params...)) |
|
| 261 |
+} |
|
| 262 |
+ |
|
| 263 |
+// NotImplementedErrorf creates an instance of NotImplementedError |
|
| 264 |
+func NotImplementedErrorf(format string, params ...interface{}) error {
|
|
| 265 |
+ return notImpl(fmt.Sprintf(format, params...)) |
|
| 266 |
+} |
|
| 267 |
+ |
|
| 268 |
+// TimeoutErrorf creates an instance of TimeoutError |
|
| 269 |
+func TimeoutErrorf(format string, params ...interface{}) error {
|
|
| 270 |
+ return timeout(fmt.Sprintf(format, params...)) |
|
| 271 |
+} |
|
| 272 |
+ |
|
| 273 |
+// InternalErrorf creates an instance of InternalError |
|
| 274 |
+func InternalErrorf(format string, params ...interface{}) error {
|
|
| 275 |
+ return internal(fmt.Sprintf(format, params...)) |
|
| 276 |
+} |
|
| 277 |
+ |
|
| 278 |
+// InternalMaskableErrorf creates an instance of InternalError and MaskableError |
|
| 279 |
+func InternalMaskableErrorf(format string, params ...interface{}) error {
|
|
| 280 |
+ return maskInternal(fmt.Sprintf(format, params...)) |
|
| 281 |
+} |
|
| 282 |
+ |
|
| 283 |
+/*********************** |
|
| 284 |
+ * Internal Error Types |
|
| 285 |
+ ***********************/ |
|
| 286 |
+type badRequest string |
|
| 287 |
+ |
|
| 288 |
+func (br badRequest) Error() string {
|
|
| 289 |
+ return string(br) |
|
| 290 |
+} |
|
| 291 |
+func (br badRequest) BadRequest() {}
|
|
| 292 |
+ |
|
| 293 |
+type maskBadRequest string |
|
| 294 |
+ |
|
| 295 |
+type notFound string |
|
| 296 |
+ |
|
| 297 |
+func (nf notFound) Error() string {
|
|
| 298 |
+ return string(nf) |
|
| 299 |
+} |
|
| 300 |
+func (nf notFound) NotFound() {}
|
|
| 301 |
+ |
|
| 302 |
+type forbidden string |
|
| 303 |
+ |
|
| 304 |
+func (frb forbidden) Error() string {
|
|
| 305 |
+ return string(frb) |
|
| 306 |
+} |
|
| 307 |
+func (frb forbidden) Forbidden() {}
|
|
| 308 |
+ |
|
| 309 |
+type noService string |
|
| 310 |
+ |
|
| 311 |
+func (ns noService) Error() string {
|
|
| 312 |
+ return string(ns) |
|
| 313 |
+} |
|
| 314 |
+func (ns noService) NoService() {}
|
|
| 315 |
+ |
|
| 316 |
+type maskNoService string |
|
| 317 |
+ |
|
| 318 |
+type timeout string |
|
| 319 |
+ |
|
| 320 |
+func (to timeout) Error() string {
|
|
| 321 |
+ return string(to) |
|
| 322 |
+} |
|
| 323 |
+func (to timeout) Timeout() {}
|
|
| 324 |
+ |
|
| 325 |
+type notImpl string |
|
| 326 |
+ |
|
| 327 |
+func (ni notImpl) Error() string {
|
|
| 328 |
+ return string(ni) |
|
| 329 |
+} |
|
| 330 |
+func (ni notImpl) NotImplemented() {}
|
|
| 331 |
+ |
|
| 332 |
+type internal string |
|
| 333 |
+ |
|
| 334 |
+func (nt internal) Error() string {
|
|
| 335 |
+ return string(nt) |
|
| 336 |
+} |
|
| 337 |
+func (nt internal) Internal() {}
|
|
| 338 |
+ |
|
| 339 |
+type maskInternal string |
|
| 340 |
+ |
|
| 341 |
+func (mnt maskInternal) Error() string {
|
|
| 342 |
+ return string(mnt) |
|
| 343 |
+} |
|
| 344 |
+func (mnt maskInternal) Internal() {}
|
|
| 345 |
+func (mnt maskInternal) Maskable() {}
|
| 6 | 346 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,99 @@ |
| 0 |
+package types |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "testing" |
|
| 4 |
+ |
|
| 5 |
+ _ "github.com/docker/libnetwork/netutils" |
|
| 6 |
+) |
|
| 7 |
+ |
|
| 8 |
+func TestErrorConstructors(t *testing.T) {
|
|
| 9 |
+ var err error |
|
| 10 |
+ |
|
| 11 |
+ err = BadRequestErrorf("Io ho %d uccello", 1)
|
|
| 12 |
+ if err.Error() != "Io ho 1 uccello" {
|
|
| 13 |
+ t.Fatal(err) |
|
| 14 |
+ } |
|
| 15 |
+ if _, ok := err.(BadRequestError); !ok {
|
|
| 16 |
+ t.Fatal(err) |
|
| 17 |
+ } |
|
| 18 |
+ if _, ok := err.(MaskableError); ok {
|
|
| 19 |
+ t.Fatal(err) |
|
| 20 |
+ } |
|
| 21 |
+ |
|
| 22 |
+ err = NotFoundErrorf("Can't find the %s", "keys")
|
|
| 23 |
+ if err.Error() != "Can't find the keys" {
|
|
| 24 |
+ t.Fatal(err) |
|
| 25 |
+ } |
|
| 26 |
+ if _, ok := err.(NotFoundError); !ok {
|
|
| 27 |
+ t.Fatal(err) |
|
| 28 |
+ } |
|
| 29 |
+ if _, ok := err.(MaskableError); ok {
|
|
| 30 |
+ t.Fatal(err) |
|
| 31 |
+ } |
|
| 32 |
+ |
|
| 33 |
+ err = ForbiddenErrorf("Can't open door %d", 2)
|
|
| 34 |
+ if err.Error() != "Can't open door 2" {
|
|
| 35 |
+ t.Fatal(err) |
|
| 36 |
+ } |
|
| 37 |
+ if _, ok := err.(ForbiddenError); !ok {
|
|
| 38 |
+ t.Fatal(err) |
|
| 39 |
+ } |
|
| 40 |
+ if _, ok := err.(MaskableError); ok {
|
|
| 41 |
+ t.Fatal(err) |
|
| 42 |
+ } |
|
| 43 |
+ |
|
| 44 |
+ err = NotImplementedErrorf("Functionality %s is not implemented", "x")
|
|
| 45 |
+ if err.Error() != "Functionality x is not implemented" {
|
|
| 46 |
+ t.Fatal(err) |
|
| 47 |
+ } |
|
| 48 |
+ if _, ok := err.(NotImplementedError); !ok {
|
|
| 49 |
+ t.Fatal(err) |
|
| 50 |
+ } |
|
| 51 |
+ if _, ok := err.(MaskableError); ok {
|
|
| 52 |
+ t.Fatal(err) |
|
| 53 |
+ } |
|
| 54 |
+ |
|
| 55 |
+ err = TimeoutErrorf("Process %s timed out", "abc")
|
|
| 56 |
+ if err.Error() != "Process abc timed out" {
|
|
| 57 |
+ t.Fatal(err) |
|
| 58 |
+ } |
|
| 59 |
+ if _, ok := err.(TimeoutError); !ok {
|
|
| 60 |
+ t.Fatal(err) |
|
| 61 |
+ } |
|
| 62 |
+ if _, ok := err.(MaskableError); ok {
|
|
| 63 |
+ t.Fatal(err) |
|
| 64 |
+ } |
|
| 65 |
+ |
|
| 66 |
+ err = NoServiceErrorf("Driver %s is not available", "mh")
|
|
| 67 |
+ if err.Error() != "Driver mh is not available" {
|
|
| 68 |
+ t.Fatal(err) |
|
| 69 |
+ } |
|
| 70 |
+ if _, ok := err.(NoServiceError); !ok {
|
|
| 71 |
+ t.Fatal(err) |
|
| 72 |
+ } |
|
| 73 |
+ if _, ok := err.(MaskableError); ok {
|
|
| 74 |
+ t.Fatal(err) |
|
| 75 |
+ } |
|
| 76 |
+ |
|
| 77 |
+ err = InternalErrorf("Not sure what happened")
|
|
| 78 |
+ if err.Error() != "Not sure what happened" {
|
|
| 79 |
+ t.Fatal(err) |
|
| 80 |
+ } |
|
| 81 |
+ if _, ok := err.(InternalError); !ok {
|
|
| 82 |
+ t.Fatal(err) |
|
| 83 |
+ } |
|
| 84 |
+ if _, ok := err.(MaskableError); ok {
|
|
| 85 |
+ t.Fatal(err) |
|
| 86 |
+ } |
|
| 87 |
+ |
|
| 88 |
+ err = InternalMaskableErrorf("Minor issue, it can be ignored")
|
|
| 89 |
+ if err.Error() != "Minor issue, it can be ignored" {
|
|
| 90 |
+ t.Fatal(err) |
|
| 91 |
+ } |
|
| 92 |
+ if _, ok := err.(InternalError); !ok {
|
|
| 93 |
+ t.Fatal(err) |
|
| 94 |
+ } |
|
| 95 |
+ if _, ok := err.(MaskableError); !ok {
|
|
| 96 |
+ t.Fatal(err) |
|
| 97 |
+ } |
|
| 98 |
+} |