From 414dfbf681d956c11c83d9b7598962a1294f2c5d Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Wed, 2 Sep 2015 16:42:01 -0700 Subject: [PATCH 1/2] Vendor libnetwork dc52820147f40fe424c8959987af3b396f842639 Main changes in this vendoring are to allow user name space integration in docker. And it includes major fix for network namespace handling Signed-off-by: Alessandro Boch Signed-off-by: Alessandro Boch --- hack/vendor.sh | 2 +- .../src/github.com/docker/libnetwork/Makefile | 18 +- .../github.com/docker/libnetwork/README.md | 18 +- .../github.com/docker/libnetwork/api/api.go | 255 ++++-- .../github.com/docker/libnetwork/api/types.go | 42 +- .../docker/libnetwork/bitseq/sequence.go | 425 ++++++---- .../docker/libnetwork/bitseq/store.go | 2 +- .../docker/libnetwork/client/service.go | 28 +- .../docker/libnetwork/client/types.go | 47 +- .../docker/libnetwork/controller.go | 144 +++- .../docker/libnetwork/driverapi/driverapi.go | 26 +- .../libnetwork/drivers/bridge/bridge.go | 59 +- .../netlink_deprecated_linux_armppc64.go | 2 +- .../bridge/netlink_deprecated_linux_notarm.go | 2 +- .../docker/libnetwork/drivers/host/host.go | 22 +- .../docker/libnetwork/drivers/null/null.go | 16 +- .../libnetwork/drivers/overlay/joinleave.go | 5 +- .../libnetwork/drivers/overlay/ov_endpoint.go | 17 +- .../libnetwork/drivers/overlay/ov_network.go | 29 +- .../libnetwork/drivers/overlay/ov_serf.go | 13 +- .../libnetwork/drivers/overlay/ov_utils.go | 10 +- .../libnetwork/drivers/overlay/overlay.go | 3 +- .../libnetwork/drivers/overlay/peerdb.go | 20 +- .../libnetwork/drivers/remote/api/api.go | 2 - .../libnetwork/drivers/remote/driver.go | 44 +- .../libnetwork/drivers/windows/windows.go | 19 +- .../github.com/docker/libnetwork/endpoint.go | 674 +++------------- .../docker/libnetwork/endpoint_info.go | 63 +- .../github.com/docker/libnetwork/idm/idm.go | 46 +- .../docker/libnetwork/netutils/test_utils.go | 33 +- .../docker/libnetwork/netutils/utils.go | 62 +- .../github.com/docker/libnetwork/network.go | 41 +- .../docker/libnetwork/options/options.go | 15 + .../{sandbox => osl}/interface_freebsd.go | 2 +- .../{sandbox => osl}/interface_linux.go | 2 +- .../{sandbox => osl}/interface_windows.go | 2 +- .../{sandbox => osl}/namespace_linux.go | 44 +- .../{sandbox => osl}/namespace_unsupported.go | 2 +- .../{sandbox => osl}/namespace_windows.go | 14 +- .../{sandbox => osl}/neigh_freebsd.go | 2 +- .../{sandbox => osl}/neigh_linux.go | 2 +- .../{sandbox => osl}/neigh_windows.go | 2 +- .../{sandbox => osl}/options_linux.go | 2 +- .../{sandbox => osl}/route_linux.go | 2 +- .../libnetwork/{sandbox => osl}/sandbox.go | 3 +- .../{sandbox => osl}/sandbox_freebsd.go | 14 +- .../{sandbox => osl}/sandbox_unsupported.go | 2 +- .../docker/libnetwork/portmapper/mapper.go | 2 + .../libnetwork/resolvconf/resolvconf.go | 102 ++- .../github.com/docker/libnetwork/sandbox.go | 744 ++++++++++++++++++ .../docker/libnetwork/sandboxdata.go | 259 ------ .../src/github.com/docker/libnetwork/store.go | 17 +- .../docker/libnetwork/types/types.go | 53 ++ .../github.com/docker/libnetwork/wrapmake.sh | 11 + 54 files changed, 1942 insertions(+), 1545 deletions(-) rename vendor/src/github.com/docker/libnetwork/{sandbox => osl}/interface_freebsd.go (85%) rename vendor/src/github.com/docker/libnetwork/{sandbox => osl}/interface_linux.go (99%) rename vendor/src/github.com/docker/libnetwork/{sandbox => osl}/interface_windows.go (85%) rename vendor/src/github.com/docker/libnetwork/{sandbox => osl}/namespace_linux.go (88%) rename vendor/src/github.com/docker/libnetwork/{sandbox => osl}/namespace_unsupported.go (89%) rename vendor/src/github.com/docker/libnetwork/{sandbox => osl}/namespace_windows.go (63%) rename vendor/src/github.com/docker/libnetwork/{sandbox => osl}/neigh_freebsd.go (84%) rename vendor/src/github.com/docker/libnetwork/{sandbox => osl}/neigh_linux.go (99%) rename vendor/src/github.com/docker/libnetwork/{sandbox => osl}/neigh_windows.go (84%) rename vendor/src/github.com/docker/libnetwork/{sandbox => osl}/options_linux.go (98%) rename vendor/src/github.com/docker/libnetwork/{sandbox => osl}/route_linux.go (99%) rename vendor/src/github.com/docker/libnetwork/{sandbox => osl}/sandbox.go (98%) rename vendor/src/github.com/docker/libnetwork/{sandbox => osl}/sandbox_freebsd.go (63%) rename vendor/src/github.com/docker/libnetwork/{sandbox => osl}/sandbox_unsupported.go (97%) create mode 100644 vendor/src/github.com/docker/libnetwork/sandbox.go delete mode 100644 vendor/src/github.com/docker/libnetwork/sandboxdata.go create mode 100755 vendor/src/github.com/docker/libnetwork/wrapmake.sh diff --git a/hack/vendor.sh b/hack/vendor.sh index b0c461ca83..53aeba3644 100755 --- a/hack/vendor.sh +++ b/hack/vendor.sh @@ -21,7 +21,7 @@ clone git golang.org/x/net 3cffabab72adf04f8e3b01c5baf775361837b5fe https://gith clone hg code.google.com/p/gosqlite 74691fb6f837 #get libnetwork packages -clone git github.com/docker/libnetwork 22dc04d06067b40a9e7ef575aee6d1bb69d4dcc3 +clone git github.com/docker/libnetwork dc52820147f40fe424c8959987af3b396f842639 clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec clone git github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b clone git github.com/hashicorp/memberlist 9a1e242e454d2443df330bdd51a436d5a9058fc4 diff --git a/vendor/src/github.com/docker/libnetwork/Makefile b/vendor/src/github.com/docker/libnetwork/Makefile index deb510cf8c..830a75b046 100644 --- a/vendor/src/github.com/docker/libnetwork/Makefile +++ b/vendor/src/github.com/docker/libnetwork/Makefile @@ -3,12 +3,12 @@ SHELL=/bin/bash build_image=libnetwork-build dockerargs = --privileged -v $(shell pwd):/go/src/github.com/docker/libnetwork -w /go/src/github.com/docker/libnetwork container_env = -e "INSIDECONTAINER=-incontainer=true" -docker = docker run --rm ${dockerargs} ${container_env} ${build_image} +docker = docker run --rm -it ${dockerargs} ${container_env} ${build_image} ciargs = -e "COVERALLS_TOKEN=$$COVERALLS_TOKEN" -e "INSIDECONTAINER=-incontainer=true" cidocker = docker run ${ciargs} ${dockerargs} golang:1.4 all: ${build_image}.created - ${docker} make all-local + ${docker} ./wrapmake.sh all-local all-local: check-local build-local @@ -19,13 +19,13 @@ ${build_image}.created: touch ${build_image}.created build: ${build_image}.created - ${docker} make build-local + ${docker} ./wrapmake.sh build-local build-local: $(shell which godep) go build -tags libnetwork_discovery ./... check: ${build_image}.created - ${docker} make check-local + ${docker} ./wrapmake.sh check-local check-code: @echo "Checking code... " @@ -49,15 +49,15 @@ run-tests: ret=$$? ;\ if [ $$ret -ne 0 ]; then exit $$ret; fi ;\ popd &> /dev/null; \ - if [ -f $$dir/profile.tmp ]; then \ - cat $$dir/profile.tmp | tail -n +2 >> coverage.coverprofile ; \ + if [ -f $$dir/profile.tmp ]; then \ + cat $$dir/profile.tmp | tail -n +2 >> coverage.coverprofile ; \ rm $$dir/profile.tmp ; \ - fi ; \ - fi ; \ + fi ; \ + fi ; \ done @echo "Done running tests" -check-local: check-format check-code run-tests +check-local: check-format check-code run-tests install-deps: apt-get update && apt-get -y install iptables diff --git a/vendor/src/github.com/docker/libnetwork/README.md b/vendor/src/github.com/docker/libnetwork/README.md index d71c5b31e4..62a0205fc7 100644 --- a/vendor/src/github.com/docker/libnetwork/README.md +++ b/vendor/src/github.com/docker/libnetwork/README.md @@ -29,13 +29,13 @@ There are many networking solutions available to suit a broad range of use-cases driverOptions := options.Generic{} genericOption := make(map[string]interface{}) genericOption[netlabel.GenericData] = driverOptions - err := controller.ConfigureNetworkDriver(networkType, genericOption) + err = controller.ConfigureNetworkDriver(networkType, genericOption) if err != nil { return } // Create a network for containers to join. - // NewNetwork accepts Variadic optional arguments that libnetwork and Drivers can make of + // NewNetwork accepts Variadic optional arguments that libnetwork and Drivers can use. network, err := controller.NewNetwork(networkType, "network1") if err != nil { return @@ -50,12 +50,14 @@ There are many networking solutions available to suit a broad range of use-cases return } - // A container can join the endpoint by providing the container ID to the join - // api. - // Join accepts Variadic arguments which will be made use of by libnetwork and Drivers - err = ep.Join("container1", - libnetwork.JoinOptionHostname("test"), - libnetwork.JoinOptionDomainname("docker.io")) + // Create the sandbox for the containr. + sbx, err := controller.NewSandbox("container1", + libnetwork.OptionHostname("test"), + libnetwork.OptionDomainname("docker.io")) + + // A sandbox can join the endpoint via the join api. + // Join accepts Variadic arguments which libnetwork and Drivers can use. + err = ep.Join(sbx) if err != nil { return } diff --git a/vendor/src/github.com/docker/libnetwork/api/api.go b/vendor/src/github.com/docker/libnetwork/api/api.go index 2bfc81b078..07ebf8bf59 100644 --- a/vendor/src/github.com/docker/libnetwork/api/api.go +++ b/vendor/src/github.com/docker/libnetwork/api/api.go @@ -35,7 +35,10 @@ const ( epNameQr = "{" + urlEpName + ":" + qregx + "}" epID = "{" + urlEpID + ":" + regex + "}" epPIDQr = "{" + urlEpPID + ":" + qregx + "}" - cnID = "{" + urlCnID + ":" + regex + "}" + sbID = "{" + urlSbID + ":" + regex + "}" + sbPIDQr = "{" + urlSbPID + ":" + qregx + "}" + cnIDQr = "{" + urlCnID + ":" + qregx + "}" + cnPIDQr = "{" + urlCnPID + ":" + qregx + "}" // Internal URL variable name.They can be anything as // long as they do not collide with query fields. @@ -45,7 +48,10 @@ const ( urlEpName = "endpoint-name" urlEpID = "endpoint-id" urlEpPID = "endpoint-partial-id" + urlSbID = "sandbox-id" + urlSbPID = "sandbox-partial-id" urlCnID = "container-id" + urlCnPID = "container-partial-id" // BridgeNetworkDriver is the built-in default for Network Driver BridgeNetworkDriver = "bridge" @@ -106,21 +112,28 @@ func (h *httpHandler) initRouter() { {"/services", []string{"partial-id", epPIDQr}, procGetServices}, {"/services", nil, procGetServices}, {"/services/" + epID, nil, procGetService}, - {"/services/" + epID + "/backend", nil, procGetContainers}, + {"/services/" + epID + "/backend", nil, procGetSandbox}, + {"/sandboxes", []string{"partial-container-id", cnPIDQr}, procGetSandboxes}, + {"/sandboxes", []string{"container-id", cnIDQr}, procGetSandboxes}, + {"/sandboxes", []string{"partial-id", sbPIDQr}, procGetSandboxes}, + {"/sandboxes", nil, procGetSandboxes}, + {"/sandboxes/" + sbID, nil, procGetSandbox}, }, "POST": { {"/networks", nil, procCreateNetwork}, {"/networks/" + nwID + "/endpoints", nil, procCreateEndpoint}, - {"/networks/" + nwID + "/endpoints/" + epID + "/containers", nil, procJoinEndpoint}, + {"/networks/" + nwID + "/endpoints/" + epID + "/sandboxes", nil, procJoinEndpoint}, {"/services", nil, procPublishService}, {"/services/" + epID + "/backend", nil, procAttachBackend}, + {"/sandboxes", nil, procCreateSandbox}, }, "DELETE": { {"/networks/" + nwID, nil, procDeleteNetwork}, {"/networks/" + nwID + "/endpoints/" + epID, nil, procDeleteEndpoint}, - {"/networks/" + nwID + "/endpoints/" + epID + "/containers/" + cnID, nil, procLeaveEndpoint}, + {"/networks/" + nwID + "/endpoints/" + epID + "/sandboxes/" + sbID, nil, procLeaveEndpoint}, {"/services/" + epID, nil, procUnpublishService}, - {"/services/" + epID + "/backend/" + cnID, nil, procDetachBackend}, + {"/services/" + epID + "/backend/" + sbID, nil, procDetachBackend}, + {"/sandboxes/" + sbID, nil, procDeleteSandbox}, }, } @@ -155,6 +168,10 @@ func makeHandler(ctrl libnetwork.NetworkController, fct processor) http.HandlerF } res, rsp := fct(ctrl, mux.Vars(req), body) + if !rsp.isOK() { + http.Error(w, rsp.Status, rsp.StatusCode) + return + } if res != nil { writeJSON(w, rsp.StatusCode, res) } @@ -191,10 +208,12 @@ func buildEndpointResource(ep libnetwork.Endpoint) *endpointResource { return r } -func buildContainerResource(ci libnetwork.ContainerInfo) *containerResource { - r := &containerResource{} - if ci != nil { - r.ID = ci.ID() +func buildSandboxResource(sb libnetwork.Sandbox) *sandboxResource { + r := &sandboxResource{} + if sb != nil { + r.ID = sb.ID() + r.Key = sb.Key() + r.ContainerID = sb.ContainerID() } return r } @@ -213,41 +232,41 @@ func (nc *networkCreate) parseOptions() []libnetwork.NetworkOption { return setFctList } -func (ej *endpointJoin) parseOptions() []libnetwork.EndpointOption { - var setFctList []libnetwork.EndpointOption - if ej.HostName != "" { - setFctList = append(setFctList, libnetwork.JoinOptionHostname(ej.HostName)) +func (sc *sandboxCreate) parseOptions() []libnetwork.SandboxOption { + var setFctList []libnetwork.SandboxOption + if sc.HostName != "" { + setFctList = append(setFctList, libnetwork.OptionHostname(sc.HostName)) } - if ej.DomainName != "" { - setFctList = append(setFctList, libnetwork.JoinOptionDomainname(ej.DomainName)) + if sc.DomainName != "" { + setFctList = append(setFctList, libnetwork.OptionDomainname(sc.DomainName)) } - if ej.HostsPath != "" { - setFctList = append(setFctList, libnetwork.JoinOptionHostsPath(ej.HostsPath)) + if sc.HostsPath != "" { + setFctList = append(setFctList, libnetwork.OptionHostsPath(sc.HostsPath)) } - if ej.ResolvConfPath != "" { - setFctList = append(setFctList, libnetwork.JoinOptionResolvConfPath(ej.ResolvConfPath)) + if sc.ResolvConfPath != "" { + setFctList = append(setFctList, libnetwork.OptionResolvConfPath(sc.ResolvConfPath)) } - if ej.UseDefaultSandbox { - setFctList = append(setFctList, libnetwork.JoinOptionUseDefaultSandbox()) + if sc.UseDefaultSandbox { + setFctList = append(setFctList, libnetwork.OptionUseDefaultSandbox()) } - if ej.DNS != nil { - for _, d := range ej.DNS { - setFctList = append(setFctList, libnetwork.JoinOptionDNS(d)) + if sc.DNS != nil { + for _, d := range sc.DNS { + setFctList = append(setFctList, libnetwork.OptionDNS(d)) } } - if ej.ExtraHosts != nil { - for _, e := range ej.ExtraHosts { - setFctList = append(setFctList, libnetwork.JoinOptionExtraHost(e.Name, e.Address)) - } - } - if ej.ParentUpdates != nil { - for _, p := range ej.ParentUpdates { - setFctList = append(setFctList, libnetwork.JoinOptionParentUpdate(p.EndpointID, p.Name, p.Address)) + if sc.ExtraHosts != nil { + for _, e := range sc.ExtraHosts { + setFctList = append(setFctList, libnetwork.OptionExtraHost(e.Name, e.Address)) } } return setFctList } +func (ej *endpointJoin) parseOptions() []libnetwork.EndpointOption { + // priority will go here + return []libnetwork.EndpointOption{} +} + /****************** Process functions *******************/ @@ -337,6 +356,22 @@ func procGetNetworks(c libnetwork.NetworkController, vars map[string]string, bod return list, &successResponse } +func procCreateSandbox(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) { + var create sandboxCreate + + err := json.Unmarshal(body, &create) + if err != nil { + return "", &responseStatus{Status: "Invalid body: " + err.Error(), StatusCode: http.StatusBadRequest} + } + + sb, err := c.NewSandbox(create.ContainerID, create.parseOptions()...) + if err != nil { + return "", convertNetworkError(err) + } + + return sb.ID(), &createdResponse +} + /****************** Network interface *******************/ @@ -456,11 +491,16 @@ func procJoinEndpoint(c libnetwork.NetworkController, vars map[string]string, bo return nil, errRsp } - err = ep.Join(ej.ContainerID, ej.parseOptions()...) + sb, errRsp := findSandbox(c, ej.SandboxID, byID) + if !errRsp.isOK() { + return nil, errRsp + } + + err = ep.Join(sb) if err != nil { return nil, convertNetworkError(err) } - return ep.Info().SandboxKey(), &successResponse + return sb.Key(), &successResponse } func procLeaveEndpoint(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) { @@ -472,7 +512,12 @@ func procLeaveEndpoint(c libnetwork.NetworkController, vars map[string]string, b return nil, errRsp } - err := ep.Leave(vars[urlCnID]) + sb, errRsp := findSandbox(c, vars[urlSbID], byID) + if !errRsp.isOK() { + return nil, errRsp + } + + err := ep.Leave(sb) if err != nil { return nil, convertNetworkError(err) } @@ -567,19 +612,6 @@ func procGetService(c libnetwork.NetworkController, vars map[string]string, body return buildEndpointResource(sv), &successResponse } -func procGetContainers(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) { - epT, epBy := detectEndpointTarget(vars) - sv, errRsp := findService(c, epT, epBy) - if !errRsp.isOK() { - return nil, endpointToService(errRsp) - } - var list []*containerResource - if sv.ContainerInfo() != nil { - list = append(list, buildContainerResource(sv.ContainerInfo())) - } - return list, &successResponse -} - func procPublishService(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) { var sp servicePublish @@ -635,11 +667,16 @@ func procAttachBackend(c libnetwork.NetworkController, vars map[string]string, b return nil, errRsp } - err = sv.Join(bk.ContainerID, bk.parseOptions()...) + sb, errRsp := findSandbox(c, bk.SandboxID, byID) + if !errRsp.isOK() { + return nil, errRsp + } + + err = sv.Join(sb) if err != nil { return nil, convertNetworkError(err) } - return sv.Info().SandboxKey(), &successResponse + return sb.Key(), &successResponse } func procDetachBackend(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) { @@ -649,7 +686,94 @@ func procDetachBackend(c libnetwork.NetworkController, vars map[string]string, b return nil, errRsp } - err := sv.Leave(vars[urlCnID]) + sb, errRsp := findSandbox(c, vars[urlSbID], byID) + if !errRsp.isOK() { + return nil, errRsp + } + + err := sv.Leave(sb) + if err != nil { + return nil, convertNetworkError(err) + } + + return nil, &successResponse +} + +/****************** + Sandbox interface +*******************/ +func procGetSandbox(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) { + if epT, ok := vars[urlEpID]; ok { + sv, errRsp := findService(c, epT, byID) + if !errRsp.isOK() { + return nil, endpointToService(errRsp) + } + return buildSandboxResource(sv.Info().Sandbox()), &successResponse + } + + sbT, by := detectSandboxTarget(vars) + sb, errRsp := findSandbox(c, sbT, by) + if !errRsp.isOK() { + return nil, errRsp + } + return buildSandboxResource(sb), &successResponse +} + +type cndFnMkr func(string) cndFn +type cndFn func(libnetwork.Sandbox) bool + +// list of (query type, condition function makers) couples +var cndMkrList = []struct { + identifier string + maker cndFnMkr +}{ + {urlSbPID, func(id string) cndFn { + return func(sb libnetwork.Sandbox) bool { return strings.HasPrefix(sb.ID(), id) } + }}, + {urlCnID, func(id string) cndFn { + return func(sb libnetwork.Sandbox) bool { return sb.ContainerID() == id } + }}, + {urlCnPID, func(id string) cndFn { + return func(sb libnetwork.Sandbox) bool { return strings.HasPrefix(sb.ContainerID(), id) } + }}, +} + +func getQueryCondition(vars map[string]string) func(libnetwork.Sandbox) bool { + for _, im := range cndMkrList { + if val, ok := vars[im.identifier]; ok { + return im.maker(val) + } + } + return func(sb libnetwork.Sandbox) bool { return true } +} + +func sandboxWalker(condition cndFn, list *[]*sandboxResource) libnetwork.SandboxWalker { + return func(sb libnetwork.Sandbox) bool { + if condition(sb) { + *list = append(*list, buildSandboxResource(sb)) + } + return false + } +} + +func procGetSandboxes(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) { + var list []*sandboxResource + + cnd := getQueryCondition(vars) + c.WalkSandboxes(sandboxWalker(cnd, &list)) + + return list, &successResponse +} + +func procDeleteSandbox(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) { + sbT, by := detectSandboxTarget(vars) + + sb, errRsp := findSandbox(c, sbT, by) + if !errRsp.isOK() { + return nil, errRsp + } + + err := sb.Delete() if err != nil { return nil, convertNetworkError(err) } @@ -676,6 +800,14 @@ func detectNetworkTarget(vars map[string]string) (string, int) { panic("Missing URL variable parameter for network") } +func detectSandboxTarget(vars map[string]string) (string, int) { + if target, ok := vars[urlSbID]; ok { + return target, byID + } + // vars are populated from the URL, following cannot happen + panic("Missing URL variable parameter for sandbox") +} + func detectEndpointTarget(vars map[string]string) (string, int) { if target, ok := vars[urlEpName]; ok { return target, byName @@ -712,6 +844,27 @@ func findNetwork(c libnetwork.NetworkController, s string, by int) (libnetwork.N return nw, &successResponse } +func findSandbox(c libnetwork.NetworkController, s string, by int) (libnetwork.Sandbox, *responseStatus) { + var ( + sb libnetwork.Sandbox + err error + ) + + switch by { + case byID: + sb, err = c.SandboxByID(s) + default: + panic(fmt.Sprintf("unexpected selector for sandbox search: %d", by)) + } + if err != nil { + if _, ok := err.(types.NotFoundError); ok { + return nil, &responseStatus{Status: "Resource not found: Sandbox", StatusCode: http.StatusNotFound} + } + return nil, &responseStatus{Status: err.Error(), StatusCode: http.StatusBadRequest} + } + return sb, &successResponse +} + func findEndpoint(c libnetwork.NetworkController, ns, es string, nwBy, epBy int) (libnetwork.Endpoint, *responseStatus) { nw, errRsp := findNetwork(c, ns, nwBy) if !errRsp.isOK() { diff --git a/vendor/src/github.com/docker/libnetwork/api/types.go b/vendor/src/github.com/docker/libnetwork/api/types.go index 72f20db24f..d734a97c0e 100644 --- a/vendor/src/github.com/docker/libnetwork/api/types.go +++ b/vendor/src/github.com/docker/libnetwork/api/types.go @@ -21,9 +21,11 @@ type endpointResource struct { Network string `json:"network"` } -// containerResource is the body of "get service backend" response message -type containerResource struct { - ID string `json:"id"` +// sandboxResource is the body of "get service backend" response message +type sandboxResource struct { + ID string `json:"id"` + Key string `json:"key"` + ContainerID string `json:"container_id"` // will add more fields once labels change is in } @@ -45,17 +47,21 @@ type endpointCreate struct { PortMapping []types.PortBinding `json:"port_mapping"` } +// sandboxCreate is the expected body of the "create sandbox" http request message +type sandboxCreate struct { + ContainerID string `json:"container_id"` + HostName string `json:"host_name"` + DomainName string `json:"domain_name"` + HostsPath string `json:"hosts_path"` + ResolvConfPath string `json:"resolv_conf_path"` + DNS []string `json:"dns"` + ExtraHosts []extraHost `json:"extra_hosts"` + UseDefaultSandbox bool `json:"use_default_sandbox"` +} + // endpointJoin represents the expected body of the "join endpoint" or "leave endpoint" http request messages type endpointJoin struct { - ContainerID string `json:"container_id"` - HostName string `json:"host_name"` - DomainName string `json:"domain_name"` - HostsPath string `json:"hosts_path"` - ResolvConfPath string `json:"resolv_conf_path"` - DNS []string `json:"dns"` - ExtraHosts []endpointExtraHost `json:"extra_hosts"` - ParentUpdates []endpointParentUpdate `json:"parent_updates"` - UseDefaultSandbox bool `json:"use_default_sandbox"` + SandboxID string `json:"sandbox_id"` } // servicePublish represents the body of the "publish service" http request message @@ -66,16 +72,8 @@ type servicePublish struct { PortMapping []types.PortBinding `json:"port_mapping"` } -// EndpointExtraHost represents the extra host object -type endpointExtraHost struct { +// extraHost represents the extra host object +type extraHost struct { Name string `json:"name"` Address string `json:"address"` } - -// EndpointParentUpdate is the object carrying the information about the -// endpoint parent that needs to be updated -type endpointParentUpdate struct { - EndpointID string `json:"endpoint_id"` - Name string `json:"name"` - Address string `json:"address"` -} diff --git a/vendor/src/github.com/docker/libnetwork/bitseq/sequence.go b/vendor/src/github.com/docker/libnetwork/bitseq/sequence.go index d9c9ad5272..d71d76b3ec 100644 --- a/vendor/src/github.com/docker/libnetwork/bitseq/sequence.go +++ b/vendor/src/github.com/docker/libnetwork/bitseq/sequence.go @@ -4,27 +4,33 @@ package bitseq import ( + "encoding/binary" "fmt" "sync" "github.com/docker/libnetwork/datastore" - "github.com/docker/libnetwork/netutils" + "github.com/docker/libnetwork/types" ) -// Block Sequence constants +// block sequence constants // If needed we can think of making these configurable const ( - blockLen = 32 + blockLen = uint32(32) blockBytes = blockLen / 8 - blockMAX = 1<%s", s.Block, s.Count, nextBlock) + return fmt.Sprintf("(0x%x, %d)->%s", s.block, s.count, nextBlock) } // GetAvailableBit returns the position of the first unset bit in the bitmask represented by this sequence -func (s *Sequence) GetAvailableBit() (bytePos, bitPos int) { - if s.Block == blockMAX || s.Count == 0 { - return -1, -1 +func (s *sequence) getAvailableBit() (uint32, uint32, error) { + if s.block == blockMAX || s.count == 0 { + return invalidPos, invalidPos, fmt.Errorf("no available bit") } - bits := 0 - bitSel := uint32(blockFirstBit) - for bitSel > 0 && s.Block&bitSel != 0 { + bits := uint32(0) + bitSel := blockFirstBit + for bitSel > 0 && s.block&bitSel != 0 { bitSel >>= 1 bits++ } - return bits / 8, bits % 8 + return bits / 8, bits % 8, nil } // GetCopy returns a copy of the linked list rooted at this node -func (s *Sequence) GetCopy() *Sequence { - n := &Sequence{Block: s.Block, Count: s.Count} +func (s *sequence) getCopy() *sequence { + n := &sequence{block: s.block, count: s.count} pn := n - ps := s.Next + ps := s.next for ps != nil { - pn.Next = &Sequence{Block: ps.Block, Count: ps.Count} - pn = pn.Next - ps = ps.Next + pn.next = &sequence{block: ps.block, count: ps.count} + pn = pn.next + ps = ps.next } return n } // Equal checks if this sequence is equal to the passed one -func (s *Sequence) Equal(o *Sequence) bool { +func (s *sequence) equal(o *sequence) bool { this := s other := o for this != nil { if other == nil { return false } - if this.Block != other.Block || this.Count != other.Count { + if this.block != other.block || this.count != other.count { return false } - this = this.Next - other = other.Next + this = this.next + other = other.next } // Check if other is longer than this if other != nil { @@ -134,23 +135,23 @@ func (s *Sequence) Equal(o *Sequence) bool { } // ToByteArray converts the sequence into a byte array -// TODO (aboch): manage network/host order stuff -func (s *Sequence) ToByteArray() ([]byte, error) { +func (s *sequence) toByteArray() ([]byte, error) { var bb []byte p := s for p != nil { - bb = append(bb, netutils.U32ToA(p.Block)...) - bb = append(bb, netutils.U32ToA(p.Count)...) - p = p.Next + b := make([]byte, 8) + binary.BigEndian.PutUint32(b[0:], p.block) + binary.BigEndian.PutUint32(b[4:], p.count) + bb = append(bb, b...) + p = p.next } return bb, nil } -// FromByteArray construct the sequence from the byte array -// TODO (aboch): manage network/host order stuff -func (s *Sequence) FromByteArray(data []byte) error { +// fromByteArray construct the sequence from the byte array +func (s *sequence) fromByteArray(data []byte) error { l := len(data) if l%8 != 0 { return fmt.Errorf("cannot deserialize byte sequence of lenght %d (%v)", l, data) @@ -159,69 +160,141 @@ func (s *Sequence) FromByteArray(data []byte) error { p := s i := 0 for { - p.Block = netutils.ATo32(data[i : i+4]) - p.Count = netutils.ATo32(data[i+4 : i+8]) + p.block = binary.BigEndian.Uint32(data[i : i+4]) + p.count = binary.BigEndian.Uint32(data[i+4 : i+8]) i += 8 if i == l { break } - p.Next = &Sequence{} - p = p.Next + p.next = &sequence{} + p = p.next } return nil } -// GetFirstAvailable returns the byte and bit position of the first unset bit -func (h *Handle) GetFirstAvailable() (int, int, error) { - h.Lock() - defer h.Unlock() - return GetFirstAvailable(h.head) +func (h *Handle) getCopy() *Handle { + return &Handle{ + bits: h.bits, + unselected: h.unselected, + head: h.head.getCopy(), + app: h.app, + id: h.id, + dbIndex: h.dbIndex, + dbExists: h.dbExists, + store: h.store, + } } -// CheckIfAvailable checks if the bit correspondent to the specified ordinal is unset -// If the ordinal is beyond the Sequence limits, a negative response is returned -func (h *Handle) CheckIfAvailable(ordinal int) (int, int, error) { - h.Lock() - defer h.Unlock() - return CheckIfAvailable(h.head, ordinal) +// SetAny atomically sets the first unset bit in the sequence and returns the corresponding ordinal +func (h *Handle) SetAny() (uint32, error) { + if h.Unselected() == 0 { + return invalidPos, errNoBitAvailable + } + return h.set(0, true, false) } -// PushReservation pushes the bit reservation inside the bitmask. -func (h *Handle) PushReservation(bytePos, bitPos int, release bool) error { - // Create a copy of the current handler - h.Lock() - nh := &Handle{ - app: h.app, - id: h.id, - store: h.store, - dbIndex: h.dbIndex, - head: h.head.GetCopy(), - dbExists: h.dbExists, +// Set atomically sets the corresponding bit in the sequence +func (h *Handle) Set(ordinal uint32) error { + if err := h.validateOrdinal(ordinal); err != nil { + return err } - h.Unlock() - - nh.head = PushReservation(bytePos, bitPos, nh.head, release) - - err := nh.writeToStore() - if err == nil { - // Commit went through, save locally - h.Lock() - h.head = nh.head - if release { - h.unselected++ - } else { - h.unselected-- - } - // Can't use SetIndex() since we're locked. - h.dbIndex = nh.Index() - h.dbExists = true - h.Unlock() - } - + _, err := h.set(ordinal, false, false) return err } +// Unset atomically unsets the corresponding bit in the sequence +func (h *Handle) Unset(ordinal uint32) error { + if err := h.validateOrdinal(ordinal); err != nil { + return err + } + _, err := h.set(ordinal, false, true) + return err +} + +// IsSet atomically checks if the ordinal bit is set. In case ordinal +// is outside of the bit sequence limits, false is returned. +func (h *Handle) IsSet(ordinal uint32) bool { + if err := h.validateOrdinal(ordinal); err != nil { + return false + } + h.Lock() + _, _, err := checkIfAvailable(h.head, ordinal) + h.Unlock() + return err != nil +} + +// set/reset the bit +func (h *Handle) set(ordinal uint32, any bool, release bool) (uint32, error) { + var ( + bitPos uint32 + bytePos uint32 + ret uint32 + err error + ) + + for { + h.Lock() + // Get position if available + if release { + bytePos, bitPos = ordinalToPos(ordinal) + } else { + if any { + bytePos, bitPos, err = getFirstAvailable(h.head) + ret = posToOrdinal(bytePos, bitPos) + } else { + bytePos, bitPos, err = checkIfAvailable(h.head, ordinal) + ret = ordinal + } + } + if err != nil { + h.Unlock() + return ret, err + } + + // Create a private copy of h and work on it, also copy the current db index + nh := h.getCopy() + ci := h.dbIndex + h.Unlock() + + nh.head = pushReservation(bytePos, bitPos, nh.head, release) + if release { + nh.unselected++ + } else { + nh.unselected-- + } + + // Attempt to write private copy to store + if err := nh.writeToStore(); err != nil { + if _, ok := err.(types.RetryError); !ok { + return ret, fmt.Errorf("internal failure while setting the bit: %v", err) + } + // Retry + continue + } + + // Unless unexpected error, save private copy to local copy + h.Lock() + defer h.Unlock() + if h.dbIndex != ci { + return ret, fmt.Errorf("unexected database index change") + } + h.unselected = nh.unselected + h.head = nh.head + h.dbExists = nh.dbExists + h.dbIndex = nh.dbIndex + return ret, nil + } +} + +// checks is needed because to cover the case where the number of bits is not a multiple of blockLen +func (h *Handle) validateOrdinal(ordinal uint32) error { + if ordinal > h.bits { + return fmt.Errorf("bit does not belong to the sequence") + } + return nil +} + // Destroy removes from the datastore the data belonging to this handle func (h *Handle) Destroy() { h.deleteFromStore() @@ -229,13 +302,13 @@ func (h *Handle) Destroy() { // ToByteArray converts this handle's data into a byte array func (h *Handle) ToByteArray() ([]byte, error) { - ba := make([]byte, 8) h.Lock() defer h.Unlock() - copy(ba[0:4], netutils.U32ToA(h.bits)) - copy(ba[4:8], netutils.U32ToA(h.unselected)) - bm, err := h.head.ToByteArray() + ba := make([]byte, 8) + binary.BigEndian.PutUint32(ba[0:], h.bits) + binary.BigEndian.PutUint32(ba[4:], h.unselected) + bm, err := h.head.toByteArray() if err != nil { return nil, fmt.Errorf("failed to serialize head: %s", err.Error()) } @@ -250,16 +323,16 @@ func (h *Handle) FromByteArray(ba []byte) error { return fmt.Errorf("nil byte array") } - nh := &Sequence{} - err := nh.FromByteArray(ba[8:]) + nh := &sequence{} + err := nh.fromByteArray(ba[8:]) if err != nil { return fmt.Errorf("failed to deserialize head: %s", err.Error()) } h.Lock() h.head = nh - h.bits = netutils.ATo32(ba[0:4]) - h.unselected = netutils.ATo32(ba[4:8]) + h.bits = binary.BigEndian.Uint32(ba[0:4]) + h.unselected = binary.BigEndian.Uint32(ba[4:8]) h.Unlock() return nil @@ -277,64 +350,70 @@ func (h *Handle) Unselected() uint32 { return h.unselected } -// GetFirstAvailable looks for the first unset bit in passed mask -func GetFirstAvailable(head *Sequence) (int, int, error) { - byteIndex := 0 - current := head - for current != nil { - if current.Block != blockMAX { - bytePos, bitPos := current.GetAvailableBit() - return byteIndex + bytePos, bitPos, nil - } - byteIndex += int(current.Count * blockBytes) - current = current.Next - } - return -1, -1, fmt.Errorf("no bit available") +func (h *Handle) String() string { + h.Lock() + defer h.Unlock() + return fmt.Sprintf("App: %s, ID: %s, DBIndex: 0x%x, bits: %d, unselected: %d, sequence: %s", + h.app, h.id, h.dbIndex, h.bits, h.unselected, h.head.toString()) } -// CheckIfAvailable checks if the bit correspondent to the specified ordinal is unset -// If the ordinal is beyond the Sequence limits, a negative response is returned -func CheckIfAvailable(head *Sequence, ordinal int) (int, int, error) { +// getFirstAvailable looks for the first unset bit in passed mask +func getFirstAvailable(head *sequence) (uint32, uint32, error) { + byteIndex := uint32(0) + current := head + for current != nil { + if current.block != blockMAX { + bytePos, bitPos, err := current.getAvailableBit() + return byteIndex + bytePos, bitPos, err + } + byteIndex += current.count * blockBytes + current = current.next + } + return invalidPos, invalidPos, errNoBitAvailable +} + +// checkIfAvailable checks if the bit correspondent to the specified ordinal is unset +// If the ordinal is beyond the sequence limits, a negative response is returned +func checkIfAvailable(head *sequence, ordinal uint32) (uint32, uint32, error) { bytePos := ordinal / 8 bitPos := ordinal % 8 - // Find the Sequence containing this byte + // Find the sequence containing this byte current, _, _, inBlockBytePos := findSequence(head, bytePos) - if current != nil { // Check whether the bit corresponding to the ordinal address is unset - bitSel := uint32(blockFirstBit >> uint(inBlockBytePos*8+bitPos)) - if current.Block&bitSel == 0 { + bitSel := blockFirstBit >> (inBlockBytePos*8 + bitPos) + if current.block&bitSel == 0 { return bytePos, bitPos, nil } } - return -1, -1, fmt.Errorf("requested bit is not available") + return invalidPos, invalidPos, fmt.Errorf("requested bit is not available") } // Given the byte position and the sequences list head, return the pointer to the // sequence containing the byte (current), the pointer to the previous sequence, // the number of blocks preceding the block containing the byte inside the current sequence. -// If bytePos is outside of the list, function will return (nil, nil, 0, -1) -func findSequence(head *Sequence, bytePos int) (*Sequence, *Sequence, uint32, int) { - // Find the Sequence containing this byte +// If bytePos is outside of the list, function will return (nil, nil, 0, invalidPos) +func findSequence(head *sequence, bytePos uint32) (*sequence, *sequence, uint32, uint32) { + // Find the sequence containing this byte previous := head current := head n := bytePos - for current.Next != nil && n >= int(current.Count*blockBytes) { // Nil check for less than 32 addresses masks - n -= int(current.Count * blockBytes) + for current.next != nil && n >= (current.count*blockBytes) { // Nil check for less than 32 addresses masks + n -= (current.count * blockBytes) previous = current - current = current.Next + current = current.next } // If byte is outside of the list, let caller know - if n >= int(current.Count*blockBytes) { - return nil, nil, 0, -1 + if n >= (current.count * blockBytes) { + return nil, nil, 0, invalidPos } // Find the byte position inside the block and the number of blocks // preceding the block containing the byte inside this sequence - precBlocks := uint32(n / blockBytes) + precBlocks := n / blockBytes inBlockBytePos := bytePos % blockBytes return current, previous, precBlocks, inBlockBytePos @@ -343,33 +422,33 @@ func findSequence(head *Sequence, bytePos int) (*Sequence, *Sequence, uint32, in // PushReservation pushes the bit reservation inside the bitmask. // Given byte and bit positions, identify the sequence (current) which holds the block containing the affected bit. // Create a new block with the modified bit according to the operation (allocate/release). -// Create a new Sequence containing the new Block and insert it in the proper position. +// Create a new sequence containing the new block and insert it in the proper position. // Remove current sequence if empty. -// Check if new Sequence can be merged with neighbour (previous/Next) sequences. +// Check if new sequence can be merged with neighbour (previous/next) sequences. // // -// Identify "current" Sequence containing block: -// [prev seq] [current seq] [Next seq] +// Identify "current" sequence containing block: +// [prev seq] [current seq] [next seq] // // Based on block position, resulting list of sequences can be any of three forms: // -// Block position Resulting list of sequences -// A) Block is first in current: [prev seq] [new] [modified current seq] [Next seq] -// B) Block is last in current: [prev seq] [modified current seq] [new] [Next seq] -// C) Block is in the middle of current: [prev seq] [curr pre] [new] [curr post] [Next seq] -func PushReservation(bytePos, bitPos int, head *Sequence, release bool) *Sequence { +// block position Resulting list of sequences +// A) block is first in current: [prev seq] [new] [modified current seq] [next seq] +// B) block is last in current: [prev seq] [modified current seq] [new] [next seq] +// C) block is in the middle of current: [prev seq] [curr pre] [new] [curr post] [next seq] +func pushReservation(bytePos, bitPos uint32, head *sequence, release bool) *sequence { // Store list's head newHead := head - // Find the Sequence containing this byte + // Find the sequence containing this byte current, previous, precBlocks, inBlockBytePos := findSequence(head, bytePos) if current == nil { return newHead } // Construct updated block - bitSel := uint32(blockFirstBit >> uint(inBlockBytePos*8+bitPos)) - newBlock := current.Block + bitSel := blockFirstBit >> (inBlockBytePos*8 + bitPos) + newBlock := current.block if release { newBlock &^= bitSel } else { @@ -377,40 +456,40 @@ func PushReservation(bytePos, bitPos int, head *Sequence, release bool) *Sequenc } // Quit if it was a redundant request - if current.Block == newBlock { + if current.block == newBlock { return newHead } - // Current Sequence inevitably looses one block, upadate Count - current.Count-- + // Current sequence inevitably looses one block, upadate count + current.count-- // Create new sequence - newSequence := &Sequence{Block: newBlock, Count: 1} + newSequence := &sequence{block: newBlock, count: 1} // Insert the new sequence in the list based on block position if precBlocks == 0 { // First in sequence (A) - newSequence.Next = current + newSequence.next = current if current == head { newHead = newSequence previous = newHead } else { - previous.Next = newSequence + previous.next = newSequence } removeCurrentIfEmpty(&newHead, newSequence, current) mergeSequences(previous) - } else if precBlocks == current.Count-2 { // Last in sequence (B) - newSequence.Next = current.Next - current.Next = newSequence + } else if precBlocks == current.count-2 { // Last in sequence (B) + newSequence.next = current.next + current.next = newSequence mergeSequences(current) } else { // In between the sequence (C) - currPre := &Sequence{Block: current.Block, Count: precBlocks, Next: newSequence} + currPre := &sequence{block: current.block, count: precBlocks, next: newSequence} currPost := current - currPost.Count -= precBlocks - newSequence.Next = currPost + currPost.count -= precBlocks + newSequence.next = currPost if currPost == head { newHead = currPre } else { - previous.Next = currPre + previous.next = currPre } // No merging or empty current possible here } @@ -419,29 +498,29 @@ func PushReservation(bytePos, bitPos int, head *Sequence, release bool) *Sequenc } // Removes the current sequence from the list if empty, adjusting the head pointer if needed -func removeCurrentIfEmpty(head **Sequence, previous, current *Sequence) { - if current.Count == 0 { +func removeCurrentIfEmpty(head **sequence, previous, current *sequence) { + if current.count == 0 { if current == *head { - *head = current.Next + *head = current.next } else { - previous.Next = current.Next - current = current.Next + previous.next = current.next + current = current.next } } } -// Given a pointer to a Sequence, it checks if it can be merged with any following sequences +// Given a pointer to a sequence, it checks if it can be merged with any following sequences // It stops when no more merging is possible. // TODO: Optimization: only attempt merge from start to end sequence, no need to scan till the end of the list -func mergeSequences(seq *Sequence) { +func mergeSequences(seq *sequence) { if seq != nil { // Merge all what possible from seq - for seq.Next != nil && seq.Block == seq.Next.Block { - seq.Count += seq.Next.Count - seq.Next = seq.Next.Next + for seq.next != nil && seq.block == seq.next.block { + seq.count += seq.next.count + seq.next = seq.next.next } - // Move to Next - mergeSequences(seq.Next) + // Move to next + mergeSequences(seq.next) } } @@ -452,3 +531,11 @@ func getNumBlocks(numBits uint32) uint32 { } return numBlocks } + +func ordinalToPos(ordinal uint32) (uint32, uint32) { + return ordinal / 8, ordinal % 8 +} + +func posToOrdinal(bytePos, bitPos uint32) uint32 { + return bytePos*8 + bitPos +} diff --git a/vendor/src/github.com/docker/libnetwork/bitseq/store.go b/vendor/src/github.com/docker/libnetwork/bitseq/store.go index b5b3f23142..553f2cdf4e 100644 --- a/vendor/src/github.com/docker/libnetwork/bitseq/store.go +++ b/vendor/src/github.com/docker/libnetwork/bitseq/store.go @@ -122,7 +122,7 @@ func (h *Handle) writeToStore() error { } err := store.PutObjectAtomic(h) if err == datastore.ErrKeyModified { - return types.RetryErrorf("failed to perform atomic write (%v). retry might fix the error", err) + return types.RetryErrorf("failed to perform atomic write (%v). Retry might fix the error", err) } return err } diff --git a/vendor/src/github.com/docker/libnetwork/client/service.go b/vendor/src/github.com/docker/libnetwork/client/service.go index 35e040f805..b2f4101629 100644 --- a/vendor/src/github.com/docker/libnetwork/client/service.go +++ b/vendor/src/github.com/docker/libnetwork/client/service.go @@ -114,6 +114,25 @@ func lookupContainerID(cli *NetworkCli, cnNameID string) (string, error) { return "", fmt.Errorf("Cannot find container ID in json response") } +func lookupSandboxID(cli *NetworkCli, containerID string) (string, error) { + obj, _, err := readBody(cli.call("GET", fmt.Sprintf("/sandboxes?container-id=%s", containerID), nil, nil)) + if err != nil { + return "", err + } + + var sandboxList []sandboxResource + err = json.Unmarshal(obj, &sandboxList) + if err != nil { + return "", err + } + + if len(sandboxList) == 0 { + return "", fmt.Errorf("cannot find sandbox for container: %s", containerID) + } + + return sandboxList[0].ID, nil +} + // CmdService handles the service UI func (cli *NetworkCli) CmdService(chain string, args ...string) error { cmd := cli.Subcmd(chain, "service", "COMMAND [OPTIONS] [arg...]", serviceUsage(chain), false) @@ -249,7 +268,7 @@ func getBackendID(cli *NetworkCli, servID string) (string, error) { ) if obj, _, err = readBody(cli.call("GET", "/services/"+servID+"/backend", nil, nil)); err == nil { - var bkl []backendResource + var bkl []sandboxResource if err := json.NewDecoder(bytes.NewReader(obj)).Decode(&bkl); err == nil { if len(bkl) > 0 { bk = bkl[0].ID @@ -310,13 +329,18 @@ func (cli *NetworkCli) CmdServiceAttach(chain string, args ...string) error { return err } + sandboxID, err := lookupSandboxID(cli, containerID) + if err != nil { + return err + } + sn, nn := parseServiceName(cmd.Arg(1)) serviceID, err := lookupServiceID(cli, nn, sn) if err != nil { return err } - nc := serviceAttach{ContainerID: containerID} + nc := serviceAttach{SandboxID: sandboxID} _, _, err = readBody(cli.call("POST", "/services/"+serviceID+"/backend", nc, nil)) diff --git a/vendor/src/github.com/docker/libnetwork/client/types.go b/vendor/src/github.com/docker/libnetwork/client/types.go index e14460aba7..f215a4efed 100644 --- a/vendor/src/github.com/docker/libnetwork/client/types.go +++ b/vendor/src/github.com/docker/libnetwork/client/types.go @@ -21,9 +21,11 @@ type serviceResource struct { Network string `json:"network"` } -// backendResource is the body of "get service backend" response message -type backendResource struct { - ID string `json:"id"` +// sandboxResource is the body of "get service backend" response message +type sandboxResource struct { + ID string `json:"id"` + Key string `json:"key"` + ContainerID string `json:"container_id"` } /*********** @@ -45,29 +47,32 @@ type serviceCreate struct { PortMapping []types.PortBinding `json:"port_mapping"` } -// serviceAttach represents the expected body of the "attach/detach backend to/from service" http request messages +// serviceAttach represents the expected body of the "attach/detach sandbox to/from service" http request messages type serviceAttach struct { - ContainerID string `json:"container_id"` - HostName string `json:"host_name"` - DomainName string `json:"domain_name"` - HostsPath string `json:"hosts_path"` - ResolvConfPath string `json:"resolv_conf_path"` - DNS []string `json:"dns"` - ExtraHosts []serviceExtraHost `json:"extra_hosts"` - ParentUpdates []serviceParentUpdate `json:"parent_updates"` - UseDefaultSandbox bool `json:"use_default_sandbox"` + SandboxID string `json:"sandbox_id"` } -// serviceExtraHost represents the extra host object -type serviceExtraHost struct { +type sandboxCreate struct { + ContainerID string `json:"container_id"` + HostName string `json:"host_name"` + DomainName string `json:"domain_name"` + HostsPath string `json:"hosts_path"` + ResolvConfPath string `json:"resolv_conf_path"` + DNS []string `json:"dns"` + ExtraHosts []extraHost `json:"extra_hosts"` + UseDefaultSandbox bool `json:"use_default_sandbox"` +} + +// extraHost represents the extra host object +type extraHost struct { Name string `json:"name"` Address string `json:"address"` } -// EndpointParentUpdate is the object carrying the information about the -// endpoint parent that needs to be updated -type serviceParentUpdate struct { - EndpointID string `json:"service_id"` - Name string `json:"name"` - Address string `json:"address"` +// sandboxParentUpdate is the object carrying the information about the +// sanbox parent that needs to be updated +type sandboxParentUpdate struct { + ContainerID string `json:"container_id"` + Name string `json:"name"` + Address string `json:"address"` } diff --git a/vendor/src/github.com/docker/libnetwork/controller.go b/vendor/src/github.com/docker/libnetwork/controller.go index 02a9f7eb2a..178c57b7da 100644 --- a/vendor/src/github.com/docker/libnetwork/controller.go +++ b/vendor/src/github.com/docker/libnetwork/controller.go @@ -17,7 +17,7 @@ create network namespaces and allocate interfaces for containers to use. } // Create a network for containers to join. - // NewNetwork accepts Variadic optional arguments that libnetwork and Drivers can make of + // NewNetwork accepts Variadic optional arguments that libnetwork and Drivers can make use of network, err := controller.NewNetwork(networkType, "network1") if err != nil { return @@ -32,8 +32,7 @@ create network namespaces and allocate interfaces for containers to use. return } - // A container can join the endpoint by providing the container ID to the join - // api. + // A container can join the endpoint by providing the container ID to the join api. // Join accepts Variadic arguments which will be made use of by libnetwork and Drivers err = ep.Join("container1", libnetwork.JoinOptionHostname("test"), @@ -45,6 +44,7 @@ create network namespaces and allocate interfaces for containers to use. package libnetwork import ( + "container/heap" "fmt" "net" "strings" @@ -58,7 +58,7 @@ import ( "github.com/docker/libnetwork/driverapi" "github.com/docker/libnetwork/hostdiscovery" "github.com/docker/libnetwork/netlabel" - "github.com/docker/libnetwork/sandbox" + "github.com/docker/libnetwork/osl" "github.com/docker/libnetwork/types" ) @@ -87,8 +87,17 @@ type NetworkController interface { // NetworkByID returns the Network which has the passed id. If not found, the error ErrNoSuchNetwork is returned. NetworkByID(id string) (Network, error) - // LeaveAll accepts a container id and attempts to leave all endpoints that the container has joined - LeaveAll(id string) error + // NewSandbox cretes a new network sandbox for the passed container id + NewSandbox(containerID string, options ...SandboxOption) (Sandbox, error) + + // Sandboxes returns the list of Sandbox(s) managed by this controller. + Sandboxes() []Sandbox + + // WlakSandboxes uses the provided function to walk the Sandbox(s) managed by this controller. + WalkSandboxes(walker SandboxWalker) + + // SandboxByID returns the Sandbox which has the passed id. If not found, a types.NotFoundError is returned. + SandboxByID(id string) (Sandbox, error) // GC triggers immediate garbage collection of resources which are garbage collected. GC() @@ -98,15 +107,19 @@ type NetworkController interface { // When the function returns true, the walk will stop. type NetworkWalker func(nw Network) bool +// SandboxWalker is a client provided function which will be used to walk the Sandboxes. +// When the function returns true, the walk will stop. +type SandboxWalker func(sb Sandbox) bool + type driverData struct { driver driverapi.Driver capability driverapi.Capability } type driverTable map[string]*driverData -type networkTable map[types.UUID]*network -type endpointTable map[types.UUID]*endpoint -type sandboxTable map[string]*sandboxData +type networkTable map[string]*network +type endpointTable map[string]*endpoint +type sandboxTable map[string]*sandbox type controller struct { networks networkTable @@ -250,7 +263,7 @@ func (c *controller) NewNetwork(networkType, name string, options ...NetworkOpti network := &network{ name: name, networkType: networkType, - id: types.UUID(stringid.GenerateRandomID()), + id: stringid.GenerateRandomID(), ctrlr: c, endpoints: endpointTable{}, } @@ -356,12 +369,119 @@ func (c *controller) NetworkByID(id string) (Network, error) { } c.Lock() defer c.Unlock() - if n, ok := c.networks[types.UUID(id)]; ok { + if n, ok := c.networks[id]; ok { return n, nil } return nil, ErrNoSuchNetwork(id) } +// NewSandbox creates a new sandbox for the passed container id +func (c *controller) NewSandbox(containerID string, options ...SandboxOption) (Sandbox, error) { + var err error + + if containerID == "" { + return nil, types.BadRequestErrorf("invalid container ID") + } + + var existing Sandbox + look := SandboxContainerWalker(&existing, containerID) + c.WalkSandboxes(look) + if existing != nil { + return nil, types.BadRequestErrorf("container %s is already present: %v", containerID, existing) + } + + // Create sandbox and process options first. Key generation depends on an option + sb := &sandbox{ + id: stringid.GenerateRandomID(), + containerID: containerID, + endpoints: epHeap{}, + epPriority: map[string]int{}, + config: containerConfig{}, + controller: c, + } + // This sandbox may be using an existing osl sandbox, sharing it with another sandbox + var peerSb Sandbox + c.WalkSandboxes(SandboxKeyWalker(&peerSb, sb.Key())) + if peerSb != nil { + sb.osSbox = peerSb.(*sandbox).osSbox + } + + heap.Init(&sb.endpoints) + + sb.processOptions(options...) + + if err = sb.setupResolutionFiles(); err != nil { + return nil, err + } + + if sb.osSbox == nil { + if sb.osSbox, err = osl.NewSandbox(sb.Key(), !sb.config.useDefaultSandBox); err != nil { + return nil, fmt.Errorf("failed to create new osl sandbox: %v", err) + } + } + + c.Lock() + c.sandboxes[sb.id] = sb + c.Unlock() + + return sb, nil +} + +func (c *controller) Sandboxes() []Sandbox { + c.Lock() + defer c.Unlock() + + list := make([]Sandbox, 0, len(c.sandboxes)) + for _, s := range c.sandboxes { + list = append(list, s) + } + + return list +} + +func (c *controller) WalkSandboxes(walker SandboxWalker) { + for _, sb := range c.Sandboxes() { + if walker(sb) { + return + } + } +} + +func (c *controller) SandboxByID(id string) (Sandbox, error) { + if id == "" { + return nil, ErrInvalidID(id) + } + c.Lock() + s, ok := c.sandboxes[id] + c.Unlock() + if !ok { + return nil, types.NotFoundErrorf("sandbox %s not found", id) + } + return s, nil +} + +// SandboxContainerWalker returns a Sandbox Walker function which looks for an existing Sandbox with the passed containerID +func SandboxContainerWalker(out *Sandbox, containerID string) SandboxWalker { + return func(sb Sandbox) bool { + if sb.ContainerID() == containerID { + *out = sb + return true + } + return false + } +} + +// SandboxKeyWalker returns a Sandbox Walker function which looks for an existing Sandbox with the passed key +func SandboxKeyWalker(out *Sandbox, key string) SandboxWalker { + return func(sb Sandbox) bool { + if sb.Key() == key { + *out = sb + return true + } + return false + } +} + func (c *controller) loadDriver(networkType string) (*driverData, error) { // Plugins pkg performs lazy loading of plugins that acts as remote drivers. // As per the design, this Get call will result in remote driver discovery if there is a corresponding plugin available. @@ -395,5 +515,5 @@ func (c *controller) isDriverGlobalScoped(networkType string) (bool, error) { } func (c *controller) GC() { - sandbox.GC() + osl.GC() } diff --git a/vendor/src/github.com/docker/libnetwork/driverapi/driverapi.go b/vendor/src/github.com/docker/libnetwork/driverapi/driverapi.go index e53947d82e..97813a9824 100644 --- a/vendor/src/github.com/docker/libnetwork/driverapi/driverapi.go +++ b/vendor/src/github.com/docker/libnetwork/driverapi/driverapi.go @@ -1,10 +1,6 @@ package driverapi -import ( - "net" - - "github.com/docker/libnetwork/types" -) +import "net" // NetworkPluginEndpointType represents the Endpoint Type used by Plugin system const NetworkPluginEndpointType = "NetworkDriver" @@ -17,31 +13,31 @@ type Driver interface { // CreateNetwork invokes the driver method to create a network passing // the network id and network specific config. The config mechanism will // eventually be replaced with labels which are yet to be introduced. - CreateNetwork(nid types.UUID, options map[string]interface{}) error + CreateNetwork(nid string, options map[string]interface{}) error // DeleteNetwork invokes the driver method to delete network passing // the network id. - DeleteNetwork(nid types.UUID) error + DeleteNetwork(nid string) error // CreateEndpoint invokes the driver method to create an endpoint // passing the network id, endpoint id endpoint information and driver // specific config. The endpoint information can be either consumed by // the driver or populated by the driver. The config mechanism will // eventually be replaced with labels which are yet to be introduced. - CreateEndpoint(nid, eid types.UUID, epInfo EndpointInfo, options map[string]interface{}) error + CreateEndpoint(nid, eid string, epInfo EndpointInfo, options map[string]interface{}) error // DeleteEndpoint invokes the driver method to delete an endpoint // passing the network id and endpoint id. - DeleteEndpoint(nid, eid types.UUID) error + DeleteEndpoint(nid, eid string) error // EndpointOperInfo retrieves from the driver the operational data related to the specified endpoint - EndpointOperInfo(nid, eid types.UUID) (map[string]interface{}, error) + EndpointOperInfo(nid, eid string) (map[string]interface{}, error) // Join method is invoked when a Sandbox is attached to an endpoint. - Join(nid, eid types.UUID, sboxKey string, jinfo JoinInfo, options map[string]interface{}) error + Join(nid, eid string, sboxKey string, jinfo JoinInfo, options map[string]interface{}) error // Leave method is invoked when a Sandbox detaches from an endpoint. - Leave(nid, eid types.UUID) error + Leave(nid, eid string) error // Type returns the the type of this driver, the network type this driver manages Type() string @@ -107,12 +103,6 @@ type JoinInfo interface { // AddStaticRoute adds a routes to the sandbox. // It may be used in addtion to or instead of a default gateway (as above). AddStaticRoute(destination *net.IPNet, routeType int, nextHop net.IP, interfaceID int) error - - // SetHostsPath sets the overriding /etc/hosts path to use for the container. - SetHostsPath(string) error - - // SetResolvConfPath sets the overriding /etc/resolv.conf path to use for the container. - SetResolvConfPath(string) error } // DriverCallback provides a Callback interface for Drivers into LibNetwork diff --git a/vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go b/vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go index a6a88b5cb8..2d3f55ed4d 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go @@ -20,6 +20,7 @@ import ( "github.com/docker/libnetwork/netlabel" "github.com/docker/libnetwork/netutils" "github.com/docker/libnetwork/options" + "github.com/docker/libnetwork/osl" "github.com/docker/libnetwork/portmapper" "github.com/docker/libnetwork/types" "github.com/vishvananda/netlink" @@ -75,7 +76,7 @@ type containerConfiguration struct { } type bridgeEndpoint struct { - id types.UUID + id string srcName string addr *net.IPNet addrv6 *net.IPNet @@ -86,10 +87,10 @@ type bridgeEndpoint struct { } type bridgeNetwork struct { - id types.UUID + id string bridge *bridgeInterface // The bridge's L3 interface config *networkConfiguration - endpoints map[types.UUID]*bridgeEndpoint // key: endpoint id + endpoints map[string]*bridgeEndpoint // key: endpoint id portMapper *portmapper.PortMapper driver *driver // The network's driver sync.Mutex @@ -100,7 +101,7 @@ type driver struct { network *bridgeNetwork natChain *iptables.ChainInfo filterChain *iptables.ChainInfo - networks map[types.UUID]*bridgeNetwork + networks map[string]*bridgeNetwork sync.Mutex } @@ -110,7 +111,7 @@ func init() { // New constructs a new bridge driver func newDriver() driverapi.Driver { - return &driver{networks: map[types.UUID]*bridgeNetwork{}} + return &driver{networks: map[string]*bridgeNetwork{}} } // Init registers a new instance of bridge driver @@ -346,7 +347,7 @@ func (n *bridgeNetwork) getNetworkBridgeName() string { return config.BridgeName } -func (n *bridgeNetwork) getEndpoint(eid types.UUID) (*bridgeEndpoint, error) { +func (n *bridgeNetwork) getEndpoint(eid string) (*bridgeEndpoint, error) { n.Lock() defer n.Unlock() @@ -394,7 +395,7 @@ func (n *bridgeNetwork) isolateNetwork(others []*bridgeNetwork, enable bool) err } // Checks whether this network's configuration for the network with this id conflicts with any of the passed networks -func (c *networkConfiguration) conflictsWithNetworks(id types.UUID, others []*bridgeNetwork) error { +func (c *networkConfiguration) conflictsWithNetworks(id string, others []*bridgeNetwork) error { for _, nw := range others { nw.Lock() @@ -475,7 +476,7 @@ func (d *driver) Config(option map[string]interface{}) error { return nil } -func (d *driver) getNetwork(id types.UUID) (*bridgeNetwork, error) { +func (d *driver) getNetwork(id string) (*bridgeNetwork, error) { d.Lock() defer d.Unlock() @@ -567,9 +568,11 @@ func (d *driver) getNetworks() []*bridgeNetwork { } // Create a new network using bridge plugin -func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) error { +func (d *driver) CreateNetwork(id string, option map[string]interface{}) error { var err error + defer osl.InitOSContext()() + // Sanity checks d.Lock() if _, ok := d.networks[id]; ok { @@ -596,7 +599,7 @@ func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) err // Create and set network handler in driver network := &bridgeNetwork{ id: id, - endpoints: make(map[types.UUID]*bridgeEndpoint), + endpoints: make(map[string]*bridgeEndpoint), config: config, portMapper: portmapper.New(), driver: d, @@ -719,9 +722,11 @@ func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) err return nil } -func (d *driver) DeleteNetwork(nid types.UUID) error { +func (d *driver) DeleteNetwork(nid string) error { var err error + defer osl.InitOSContext()() + // Get network handler and remove it from driver d.Lock() n, ok := d.networks[nid] @@ -843,12 +848,14 @@ func setHairpinMode(link netlink.Link, enable bool) error { return nil } -func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error { +func (d *driver) CreateEndpoint(nid, eid string, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error { var ( ipv6Addr *net.IPNet err error ) + defer osl.InitOSContext()() + if epInfo == nil { return errors.New("invalid endpoint info passed") } @@ -927,13 +934,13 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn LinkAttrs: netlink.LinkAttrs{Name: hostIfName, TxQLen: 0}, PeerName: containerIfName} if err = netlink.LinkAdd(veth); err != nil { - return err + return types.InternalErrorf("failed to add the host (%s) <=> sandbox (%s) pair interfaces: %v", hostIfName, containerIfName, err) } // Get the host side pipe interface handler host, err := netlink.LinkByName(hostIfName) if err != nil { - return err + return types.InternalErrorf("failed to find host side interface %s: %v", hostIfName, err) } defer func() { if err != nil { @@ -944,7 +951,7 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn // Get the sandbox side pipe interface handler sbox, err := netlink.LinkByName(containerIfName) if err != nil { - return err + return types.InternalErrorf("failed to find sandbox side interface %s: %v", containerIfName, err) } defer func() { if err != nil { @@ -960,11 +967,11 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn if config.Mtu != 0 { err = netlink.LinkSetMTU(host, config.Mtu) if err != nil { - return err + return types.InternalErrorf("failed to set MTU on host interface %s: %v", hostIfName, err) } err = netlink.LinkSetMTU(sbox, config.Mtu) if err != nil { - return err + return types.InternalErrorf("failed to set MTU on sandbox interface %s: %v", containerIfName, err) } } @@ -1054,9 +1061,11 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn return nil } -func (d *driver) DeleteEndpoint(nid, eid types.UUID) error { +func (d *driver) DeleteEndpoint(nid, eid string) error { var err error + defer osl.InitOSContext()() + // Get the network handler and make sure it exists d.Lock() n, ok := d.networks[nid] @@ -1138,7 +1147,7 @@ func (d *driver) DeleteEndpoint(nid, eid types.UUID) error { return nil } -func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{}, error) { +func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) { // Get the network handler and make sure it exists d.Lock() n, ok := d.networks[nid] @@ -1195,7 +1204,9 @@ func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{}, } // Join method is invoked when a Sandbox is attached to an endpoint. -func (d *driver) Join(nid, eid types.UUID, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error { +func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error { + defer osl.InitOSContext()() + network, err := d.getNetwork(nid) if err != nil { return err @@ -1238,7 +1249,9 @@ func (d *driver) Join(nid, eid types.UUID, sboxKey string, jinfo driverapi.JoinI } // Leave method is invoked when a Sandbox detaches from an endpoint. -func (d *driver) Leave(nid, eid types.UUID) error { +func (d *driver) Leave(nid, eid string) error { + defer osl.InitOSContext()() + network, err := d.getNetwork(nid) if err != nil { return err @@ -1282,7 +1295,7 @@ func (d *driver) link(network *bridgeNetwork, endpoint *bridgeEndpoint, options if endpoint.config != nil && endpoint.config.ExposedPorts != nil { for _, p := range cc.ParentEndpoints { var parentEndpoint *bridgeEndpoint - parentEndpoint, err = network.getEndpoint(types.UUID(p)) + parentEndpoint, err = network.getEndpoint(p) if err != nil { return err } @@ -1312,7 +1325,7 @@ func (d *driver) link(network *bridgeNetwork, endpoint *bridgeEndpoint, options for _, c := range cc.ChildEndpoints { var childEndpoint *bridgeEndpoint - childEndpoint, err = network.getEndpoint(types.UUID(c)) + childEndpoint, err = network.getEndpoint(c) if err != nil { return err } diff --git a/vendor/src/github.com/docker/libnetwork/drivers/bridge/netlink_deprecated_linux_armppc64.go b/vendor/src/github.com/docker/libnetwork/drivers/bridge/netlink_deprecated_linux_armppc64.go index d3eadfa21c..739d9c6ba3 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/bridge/netlink_deprecated_linux_armppc64.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/bridge/netlink_deprecated_linux_armppc64.go @@ -1,4 +1,4 @@ -// +build arm ppc64 +// +build arm ppc64 ppc64le package bridge diff --git a/vendor/src/github.com/docker/libnetwork/drivers/bridge/netlink_deprecated_linux_notarm.go b/vendor/src/github.com/docker/libnetwork/drivers/bridge/netlink_deprecated_linux_notarm.go index 97f51e1edc..df526952f7 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/bridge/netlink_deprecated_linux_notarm.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/bridge/netlink_deprecated_linux_notarm.go @@ -1,4 +1,4 @@ -// +build !arm,!ppc64 +// +build !arm,!ppc64,!ppc64le package bridge diff --git a/vendor/src/github.com/docker/libnetwork/drivers/host/host.go b/vendor/src/github.com/docker/libnetwork/drivers/host/host.go index 5dbc4ef2fb..2c9d172d9f 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/host/host.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/host/host.go @@ -10,7 +10,7 @@ import ( const networkType = "host" type driver struct { - network types.UUID + network string sync.Mutex } @@ -26,7 +26,7 @@ func (d *driver) Config(option map[string]interface{}) error { return nil } -func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) error { +func (d *driver) CreateNetwork(id string, option map[string]interface{}) error { d.Lock() defer d.Unlock() @@ -39,33 +39,29 @@ func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) err return nil } -func (d *driver) DeleteNetwork(nid types.UUID) error { +func (d *driver) DeleteNetwork(nid string) error { return types.ForbiddenErrorf("network of type \"%s\" cannot be deleted", networkType) } -func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error { +func (d *driver) CreateEndpoint(nid, eid string, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error { return nil } -func (d *driver) DeleteEndpoint(nid, eid types.UUID) error { +func (d *driver) DeleteEndpoint(nid, eid string) error { return nil } -func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{}, error) { +func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) { return make(map[string]interface{}, 0), nil } // Join method is invoked when a Sandbox is attached to an endpoint. -func (d *driver) Join(nid, eid types.UUID, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error { - if err := jinfo.SetHostsPath("/etc/hosts"); err != nil { - return err - } - - return jinfo.SetResolvConfPath("/etc/resolv.conf") +func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error { + return nil } // Leave method is invoked when a Sandbox detaches from an endpoint. -func (d *driver) Leave(nid, eid types.UUID) error { +func (d *driver) Leave(nid, eid string) error { return nil } diff --git a/vendor/src/github.com/docker/libnetwork/drivers/null/null.go b/vendor/src/github.com/docker/libnetwork/drivers/null/null.go index d1f2797e5d..e0bf6b15ca 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/null/null.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/null/null.go @@ -10,7 +10,7 @@ import ( const networkType = "null" type driver struct { - network types.UUID + network string sync.Mutex } @@ -26,7 +26,7 @@ func (d *driver) Config(option map[string]interface{}) error { return nil } -func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) error { +func (d *driver) CreateNetwork(id string, option map[string]interface{}) error { d.Lock() defer d.Unlock() @@ -39,29 +39,29 @@ func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) err return nil } -func (d *driver) DeleteNetwork(nid types.UUID) error { +func (d *driver) DeleteNetwork(nid string) error { return types.ForbiddenErrorf("network of type \"%s\" cannot be deleted", networkType) } -func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error { +func (d *driver) CreateEndpoint(nid, eid string, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error { return nil } -func (d *driver) DeleteEndpoint(nid, eid types.UUID) error { +func (d *driver) DeleteEndpoint(nid, eid string) error { return nil } -func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{}, error) { +func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) { return make(map[string]interface{}, 0), nil } // Join method is invoked when a Sandbox is attached to an endpoint. -func (d *driver) Join(nid, eid types.UUID, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error { +func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error { return nil } // Leave method is invoked when a Sandbox detaches from an endpoint. -func (d *driver) Leave(nid, eid types.UUID) error { +func (d *driver) Leave(nid, eid string) error { return nil } diff --git a/vendor/src/github.com/docker/libnetwork/drivers/overlay/joinleave.go b/vendor/src/github.com/docker/libnetwork/drivers/overlay/joinleave.go index 474970bcf5..0d428b2b04 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/overlay/joinleave.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/overlay/joinleave.go @@ -4,12 +4,11 @@ import ( "fmt" "github.com/docker/libnetwork/driverapi" - "github.com/docker/libnetwork/types" "github.com/vishvananda/netlink" ) // Join method is invoked when a Sandbox is attached to an endpoint. -func (d *driver) Join(nid, eid types.UUID, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error { +func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error { if err := validateID(nid, eid); err != nil { return err } @@ -77,7 +76,7 @@ func (d *driver) Join(nid, eid types.UUID, sboxKey string, jinfo driverapi.JoinI } // Leave method is invoked when a Sandbox detaches from an endpoint. -func (d *driver) Leave(nid, eid types.UUID) error { +func (d *driver) Leave(nid, eid string) error { if err := validateID(nid, eid); err != nil { return err } diff --git a/vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_endpoint.go b/vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_endpoint.go index cbcb6074aa..ed9658e3c8 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_endpoint.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_endpoint.go @@ -7,18 +7,17 @@ import ( "github.com/docker/libnetwork/driverapi" "github.com/docker/libnetwork/netutils" - "github.com/docker/libnetwork/types" ) -type endpointTable map[types.UUID]*endpoint +type endpointTable map[string]*endpoint type endpoint struct { - id types.UUID + id string mac net.HardwareAddr addr *net.IPNet } -func (n *network) endpoint(eid types.UUID) *endpoint { +func (n *network) endpoint(eid string) *endpoint { n.Lock() defer n.Unlock() @@ -31,13 +30,13 @@ func (n *network) addEndpoint(ep *endpoint) { n.Unlock() } -func (n *network) deleteEndpoint(eid types.UUID) { +func (n *network) deleteEndpoint(eid string) { n.Lock() delete(n.endpoints, eid) n.Unlock() } -func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointInfo, +func (d *driver) CreateEndpoint(nid, eid string, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error { if err := validateID(nid, eid); err != nil { return err @@ -73,7 +72,7 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn binary.BigEndian.PutUint32(ep.addr.IP, bridgeSubnetInt+ipID) - ep.mac = netutils.GenerateRandomMAC() + ep.mac = netutils.GenerateMACFromIP(ep.addr.IP) err = epInfo.AddInterface(1, ep.mac, *ep.addr, net.IPNet{}) if err != nil { @@ -85,7 +84,7 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn return nil } -func (d *driver) DeleteEndpoint(nid, eid types.UUID) error { +func (d *driver) DeleteEndpoint(nid, eid string) error { if err := validateID(nid, eid); err != nil { return err } @@ -105,6 +104,6 @@ func (d *driver) DeleteEndpoint(nid, eid types.UUID) error { return nil } -func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{}, error) { +func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) { return make(map[string]interface{}, 0), nil } diff --git a/vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_network.go b/vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_network.go index 21009e1685..e55cc2e8ef 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_network.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_network.go @@ -10,20 +10,19 @@ import ( "github.com/Sirupsen/logrus" "github.com/docker/libnetwork/datastore" "github.com/docker/libnetwork/ipallocator" - "github.com/docker/libnetwork/sandbox" - "github.com/docker/libnetwork/types" + "github.com/docker/libnetwork/osl" "github.com/vishvananda/netlink" "github.com/vishvananda/netlink/nl" ) -type networkTable map[types.UUID]*network +type networkTable map[string]*network type network struct { - id types.UUID + id string vni uint32 dbIndex uint64 dbExists bool - sbox sandbox.Sandbox + sbox osl.Sandbox endpoints endpointTable ipAllocator *ipallocator.IPAllocator gw net.IP @@ -36,7 +35,7 @@ type network struct { sync.Mutex } -func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) error { +func (d *driver) CreateNetwork(id string, option map[string]interface{}) error { if id == "" { return fmt.Errorf("invalid network id") } @@ -59,7 +58,7 @@ func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) err return nil } -func (d *driver) DeleteNetwork(nid types.UUID) error { +func (d *driver) DeleteNetwork(nid string) error { if nid == "" { return fmt.Errorf("invalid network id") } @@ -140,8 +139,8 @@ func (n *network) initSandbox() error { n.initEpoch++ n.Unlock() - sbox, err := sandbox.NewSandbox( - sandbox.GenerateKey(fmt.Sprintf("%d-", n.initEpoch)+string(n.id)), true) + sbox, err := osl.NewSandbox( + osl.GenerateKey(fmt.Sprintf("%d-", n.initEpoch)+n.id), true) if err != nil { return fmt.Errorf("could not create network sandbox: %v", err) } @@ -216,7 +215,7 @@ func (n *network) watchMiss(nlSock *nl.NetlinkSocket) { continue } - if err := n.driver.peerAdd(n.id, types.UUID("dummy"), neigh.IP, mac, vtep, true); err != nil { + if err := n.driver.peerAdd(n.id, "dummy", neigh.IP, mac, vtep, true); err != nil { logrus.Errorf("could not add neighbor entry for missed peer: %v", err) } } @@ -229,27 +228,27 @@ func (d *driver) addNetwork(n *network) { d.Unlock() } -func (d *driver) deleteNetwork(nid types.UUID) { +func (d *driver) deleteNetwork(nid string) { d.Lock() delete(d.networks, nid) d.Unlock() } -func (d *driver) network(nid types.UUID) *network { +func (d *driver) network(nid string) *network { d.Lock() defer d.Unlock() return d.networks[nid] } -func (n *network) sandbox() sandbox.Sandbox { +func (n *network) sandbox() osl.Sandbox { n.Lock() defer n.Unlock() return n.sbox } -func (n *network) setSandbox(sbox sandbox.Sandbox) { +func (n *network) setSandbox(sbox osl.Sandbox) { n.Lock() n.sbox = sbox n.Unlock() @@ -269,7 +268,7 @@ func (n *network) setVxlanID(vni uint32) { } func (n *network) Key() []string { - return []string{"overlay", "network", string(n.id)} + return []string{"overlay", "network", n.id} } func (n *network) KeyPrefix() []string { diff --git a/vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_serf.go b/vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_serf.go index 5f467d19fa..453ef2c912 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_serf.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_serf.go @@ -7,14 +7,13 @@ import ( "time" "github.com/Sirupsen/logrus" - "github.com/docker/libnetwork/types" "github.com/hashicorp/serf/serf" ) type ovNotify struct { action string - eid types.UUID - nid types.UUID + eid string + nid string } type logWriter struct{} @@ -150,12 +149,12 @@ func (d *driver) processEvent(u serf.UserEvent) { switch action { case "join": - if err := d.peerAdd(types.UUID(nid), types.UUID(eid), net.ParseIP(ipStr), mac, + if err := d.peerAdd(nid, eid, net.ParseIP(ipStr), mac, net.ParseIP(vtepStr), true); err != nil { fmt.Printf("Peer add failed in the driver: %v\n", err) } case "leave": - if err := d.peerDelete(types.UUID(nid), types.UUID(eid), net.ParseIP(ipStr), mac, + if err := d.peerDelete(nid, eid, net.ParseIP(ipStr), mac, net.ParseIP(vtepStr), true); err != nil { fmt.Printf("Peer delete failed in the driver: %v\n", err) } @@ -171,7 +170,7 @@ func (d *driver) processQuery(q *serf.Query) { fmt.Printf("Failed to scan query payload string: %v\n", err) } - peerMac, vtep, err := d.peerDbSearch(types.UUID(nid), net.ParseIP(ipStr)) + peerMac, vtep, err := d.peerDbSearch(nid, net.ParseIP(ipStr)) if err != nil { return } @@ -179,7 +178,7 @@ func (d *driver) processQuery(q *serf.Query) { q.Respond([]byte(fmt.Sprintf("%s %s", peerMac.String(), vtep.String()))) } -func (d *driver) resolvePeer(nid types.UUID, peerIP net.IP) (net.HardwareAddr, net.IP, error) { +func (d *driver) resolvePeer(nid string, peerIP net.IP) (net.HardwareAddr, net.IP, error) { qPayload := fmt.Sprintf("%s %s", string(nid), peerIP.String()) resp, err := d.serfInstance.Query("peerlookup", []byte(qPayload), nil) if err != nil { diff --git a/vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_utils.go b/vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_utils.go index 384ec468e1..5bb257bf51 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_utils.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_utils.go @@ -4,12 +4,12 @@ import ( "fmt" "github.com/docker/libnetwork/netutils" - "github.com/docker/libnetwork/types" + "github.com/docker/libnetwork/osl" "github.com/vishvananda/netlink" "github.com/vishvananda/netlink/nl" ) -func validateID(nid, eid types.UUID) error { +func validateID(nid, eid string) error { if nid == "" { return fmt.Errorf("invalid network id") } @@ -22,6 +22,8 @@ func validateID(nid, eid types.UUID) error { } func createVethPair() (string, string, error) { + defer osl.InitOSContext()() + // Generate a name for what will be the host side pipe interface name1, err := netutils.GenerateIfaceName(vethPrefix, vethLen) if err != nil { @@ -46,6 +48,8 @@ func createVethPair() (string, string, error) { } func createVxlan(vni uint32) (string, error) { + defer osl.InitOSContext()() + name, err := netutils.GenerateIfaceName("vxlan", 7) if err != nil { return "", fmt.Errorf("error generating vxlan name: %v", err) @@ -69,6 +73,8 @@ func createVxlan(vni uint32) (string, error) { } func deleteVxlan(name string) error { + defer osl.InitOSContext()() + link, err := netlink.LinkByName(name) if err != nil { return fmt.Errorf("failed to find vxlan interface with name %s: %v", name, err) diff --git a/vendor/src/github.com/docker/libnetwork/drivers/overlay/overlay.go b/vendor/src/github.com/docker/libnetwork/drivers/overlay/overlay.go index c4fcaa3797..9bd63f558f 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/overlay/overlay.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/overlay/overlay.go @@ -11,7 +11,6 @@ import ( "github.com/docker/libnetwork/driverapi" "github.com/docker/libnetwork/idm" "github.com/docker/libnetwork/netlabel" - "github.com/docker/libnetwork/types" "github.com/hashicorp/serf/serf" ) @@ -77,7 +76,7 @@ func Init(dc driverapi.DriverCallback) error { return dc.RegisterDriver(networkType, &driver{ networks: networkTable{}, peerDb: peerNetworkMap{ - mp: map[types.UUID]peerMap{}, + mp: map[string]peerMap{}, }, }, c) } diff --git a/vendor/src/github.com/docker/libnetwork/drivers/overlay/peerdb.go b/vendor/src/github.com/docker/libnetwork/drivers/overlay/peerdb.go index 9e4f7f7e12..acb99dc688 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/overlay/peerdb.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/overlay/peerdb.go @@ -5,8 +5,6 @@ import ( "net" "sync" "syscall" - - "github.com/docker/libnetwork/types" ) type peerKey struct { @@ -15,7 +13,7 @@ type peerKey struct { } type peerEntry struct { - eid types.UUID + eid string vtep net.IP inSandbox bool isLocal bool @@ -27,7 +25,7 @@ type peerMap struct { } type peerNetworkMap struct { - mp map[types.UUID]peerMap + mp map[string]peerMap sync.Mutex } @@ -58,7 +56,7 @@ func (pKey *peerKey) Scan(state fmt.ScanState, verb rune) error { var peerDbWg sync.WaitGroup -func (d *driver) peerDbWalk(nid types.UUID, f func(*peerKey, *peerEntry) bool) error { +func (d *driver) peerDbWalk(nid string, f func(*peerKey, *peerEntry) bool) error { d.peerDb.Lock() pMap, ok := d.peerDb.mp[nid] if !ok { @@ -84,7 +82,7 @@ func (d *driver) peerDbWalk(nid types.UUID, f func(*peerKey, *peerEntry) bool) e return nil } -func (d *driver) peerDbSearch(nid types.UUID, peerIP net.IP) (net.HardwareAddr, net.IP, error) { +func (d *driver) peerDbSearch(nid string, peerIP net.IP) (net.HardwareAddr, net.IP, error) { var ( peerMac net.HardwareAddr vtep net.IP @@ -113,7 +111,7 @@ func (d *driver) peerDbSearch(nid types.UUID, peerIP net.IP) (net.HardwareAddr, return peerMac, vtep, nil } -func (d *driver) peerDbAdd(nid, eid types.UUID, peerIP net.IP, +func (d *driver) peerDbAdd(nid, eid string, peerIP net.IP, peerMac net.HardwareAddr, vtep net.IP, isLocal bool) { peerDbWg.Wait() @@ -145,7 +143,7 @@ func (d *driver) peerDbAdd(nid, eid types.UUID, peerIP net.IP, pMap.Unlock() } -func (d *driver) peerDbDelete(nid, eid types.UUID, peerIP net.IP, +func (d *driver) peerDbDelete(nid, eid string, peerIP net.IP, peerMac net.HardwareAddr, vtep net.IP) { peerDbWg.Wait() @@ -167,7 +165,7 @@ func (d *driver) peerDbDelete(nid, eid types.UUID, peerIP net.IP, pMap.Unlock() } -func (d *driver) peerDbUpdateSandbox(nid types.UUID) { +func (d *driver) peerDbUpdateSandbox(nid string) { d.peerDb.Lock() pMap, ok := d.peerDb.mp[nid] if !ok { @@ -214,7 +212,7 @@ func (d *driver) peerDbUpdateSandbox(nid types.UUID) { peerDbWg.Done() } -func (d *driver) peerAdd(nid, eid types.UUID, peerIP net.IP, +func (d *driver) peerAdd(nid, eid string, peerIP net.IP, peerMac net.HardwareAddr, vtep net.IP, updateDb bool) error { if err := validateID(nid, eid); err != nil { @@ -249,7 +247,7 @@ func (d *driver) peerAdd(nid, eid types.UUID, peerIP net.IP, return nil } -func (d *driver) peerDelete(nid, eid types.UUID, peerIP net.IP, +func (d *driver) peerDelete(nid, eid string, peerIP net.IP, peerMac net.HardwareAddr, vtep net.IP, updateDb bool) error { if err := validateID(nid, eid); err != nil { diff --git a/vendor/src/github.com/docker/libnetwork/drivers/remote/api/api.go b/vendor/src/github.com/docker/libnetwork/drivers/remote/api/api.go index ec703235c6..35ad2bfe15 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/remote/api/api.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/remote/api/api.go @@ -127,8 +127,6 @@ type JoinResponse struct { InterfaceNames []*InterfaceName Gateway string GatewayIPv6 string - HostsPath string - ResolvConfPath string StaticRoutes []StaticRoute } diff --git a/vendor/src/github.com/docker/libnetwork/drivers/remote/driver.go b/vendor/src/github.com/docker/libnetwork/drivers/remote/driver.go index 8cfbe51aa2..88827e5d75 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/remote/driver.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/remote/driver.go @@ -57,20 +57,20 @@ func (d *driver) call(methodName string, arg interface{}, retVal maybeError) err return nil } -func (d *driver) CreateNetwork(id types.UUID, options map[string]interface{}) error { +func (d *driver) CreateNetwork(id string, options map[string]interface{}) error { create := &api.CreateNetworkRequest{ - NetworkID: string(id), + NetworkID: id, Options: options, } return d.call("CreateNetwork", create, &api.CreateNetworkResponse{}) } -func (d *driver) DeleteNetwork(nid types.UUID) error { - delete := &api.DeleteNetworkRequest{NetworkID: string(nid)} +func (d *driver) DeleteNetwork(nid string) error { + delete := &api.DeleteNetworkRequest{NetworkID: nid} return d.call("DeleteNetwork", delete, &api.DeleteNetworkResponse{}) } -func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error { +func (d *driver) CreateEndpoint(nid, eid string, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error { if epInfo == nil { return fmt.Errorf("must not be called with nil EndpointInfo") } @@ -87,8 +87,8 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn } } create := &api.CreateEndpointRequest{ - NetworkID: string(nid), - EndpointID: string(eid), + NetworkID: nid, + EndpointID: eid, Interfaces: reqIfaces, Options: epOptions, } @@ -129,18 +129,18 @@ func errorWithRollback(msg string, err error) error { return fmt.Errorf("%s; %s", msg, rollback) } -func (d *driver) DeleteEndpoint(nid, eid types.UUID) error { +func (d *driver) DeleteEndpoint(nid, eid string) error { delete := &api.DeleteEndpointRequest{ - NetworkID: string(nid), - EndpointID: string(eid), + NetworkID: nid, + EndpointID: eid, } return d.call("DeleteEndpoint", delete, &api.DeleteEndpointResponse{}) } -func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{}, error) { +func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) { info := &api.EndpointInfoRequest{ - NetworkID: string(nid), - EndpointID: string(eid), + NetworkID: nid, + EndpointID: eid, } var res api.EndpointInfoResponse if err := d.call("EndpointOperInfo", info, &res); err != nil { @@ -150,10 +150,10 @@ func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{}, } // Join method is invoked when a Sandbox is attached to an endpoint. -func (d *driver) Join(nid, eid types.UUID, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error { +func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error { join := &api.JoinRequest{ - NetworkID: string(nid), - EndpointID: string(eid), + NetworkID: nid, + EndpointID: eid, SandboxKey: sboxKey, Options: options, } @@ -209,20 +209,14 @@ func (d *driver) Join(nid, eid types.UUID, sboxKey string, jinfo driverapi.JoinI } } } - if jinfo.SetHostsPath(res.HostsPath) != nil { - return errorWithRollback(fmt.Sprintf("failed to set hosts path: %s", res.HostsPath), d.Leave(nid, eid)) - } - if jinfo.SetResolvConfPath(res.ResolvConfPath) != nil { - return errorWithRollback(fmt.Sprintf("failed to set resolv.conf path: %s", res.ResolvConfPath), d.Leave(nid, eid)) - } return nil } // Leave method is invoked when a Sandbox detaches from an endpoint. -func (d *driver) Leave(nid, eid types.UUID) error { +func (d *driver) Leave(nid, eid string) error { leave := &api.LeaveRequest{ - NetworkID: string(nid), - EndpointID: string(eid), + NetworkID: nid, + EndpointID: eid, } return d.call("Leave", leave, &api.LeaveResponse{}) } diff --git a/vendor/src/github.com/docker/libnetwork/drivers/windows/windows.go b/vendor/src/github.com/docker/libnetwork/drivers/windows/windows.go index 925e402bb0..80b5c467c7 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/windows/windows.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/windows/windows.go @@ -1,9 +1,6 @@ package windows -import ( - "github.com/docker/libnetwork/driverapi" - "github.com/docker/libnetwork/types" -) +import "github.com/docker/libnetwork/driverapi" const networkType = "windows" @@ -23,33 +20,33 @@ func (d *driver) Config(option map[string]interface{}) error { return nil } -func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) error { +func (d *driver) CreateNetwork(id string, option map[string]interface{}) error { return nil } -func (d *driver) DeleteNetwork(nid types.UUID) error { +func (d *driver) DeleteNetwork(nid string) error { return nil } -func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error { +func (d *driver) CreateEndpoint(nid, eid string, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error { return nil } -func (d *driver) DeleteEndpoint(nid, eid types.UUID) error { +func (d *driver) DeleteEndpoint(nid, eid string) error { return nil } -func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{}, error) { +func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) { return make(map[string]interface{}, 0), nil } // Join method is invoked when a Sandbox is attached to an endpoint. -func (d *driver) Join(nid, eid types.UUID, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error { +func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error { return nil } // Leave method is invoked when a Sandbox detaches from an endpoint. -func (d *driver) Leave(nid, eid types.UUID) error { +func (d *driver) Leave(nid, eid string) error { return nil } diff --git a/vendor/src/github.com/docker/libnetwork/endpoint.go b/vendor/src/github.com/docker/libnetwork/endpoint.go index 3475e9eafd..0ec9f1d798 100644 --- a/vendor/src/github.com/docker/libnetwork/endpoint.go +++ b/vendor/src/github.com/docker/libnetwork/endpoint.go @@ -1,22 +1,14 @@ package libnetwork import ( - "bytes" "encoding/json" "fmt" - "io/ioutil" - "os" - "path" - "path/filepath" + "net" "sync" log "github.com/Sirupsen/logrus" - "github.com/docker/docker/pkg/ioutils" "github.com/docker/libnetwork/datastore" - "github.com/docker/libnetwork/etchosts" "github.com/docker/libnetwork/netlabel" - "github.com/docker/libnetwork/resolvconf" - "github.com/docker/libnetwork/sandbox" "github.com/docker/libnetwork/types" ) @@ -31,14 +23,12 @@ type Endpoint interface { // Network returns the name of the network to which this endpoint is attached. Network() string - // Join creates a new sandbox for the given container ID and populates the - // network resources allocated for the endpoint and joins the sandbox to - // the endpoint. - Join(containerID string, options ...EndpointOption) error + // Join joins the sandbox to the endpoint and populates into the sandbox + // the network resources allocated for the endpoint. + Join(sandbox Sandbox, options ...EndpointOption) error - // Leave removes the sandbox associated with container ID and detaches - // the network resources populated in the sandbox - Leave(containerID string, options ...EndpointOption) error + // Leave detaches the network resources populated in the sandbox. + Leave(sandbox Sandbox, options ...EndpointOption) error // Return certain operational data belonging to this endpoint Info() EndpointInfo @@ -46,14 +36,8 @@ type Endpoint interface { // DriverInfo returns a collection of driver operational data related to this endpoint retrieved from the driver DriverInfo() (map[string]interface{}, error) - // ContainerInfo returns the info available at the endpoint about the attached container - ContainerInfo() ContainerInfo - // Delete and detaches this endpoint from the network. Delete() error - - // Retrieve the interfaces' statistics from the sandbox - Statistics() (map[string]*sandbox.InterfaceStatistics, error) } // EndpointOption is a option setter function type used to pass varios options to Network @@ -61,68 +45,13 @@ type Endpoint interface { // provided by libnetwork, they look like Option[...](...) type EndpointOption func(ep *endpoint) -// ContainerData is a set of data returned when a container joins an endpoint. -type ContainerData struct { - SandboxKey string -} - -// These are the container configs used to customize container /etc/hosts file. -type hostsPathConfig struct { - hostName string - domainName string - hostsPath string - extraHosts []extraHost - parentUpdates []parentUpdate -} - -// These are the container configs used to customize container /etc/resolv.conf file. -type resolvConfPathConfig struct { - resolvConfPath string - dnsList []string - dnsSearchList []string -} - -type containerConfig struct { - hostsPathConfig - resolvConfPathConfig - generic map[string]interface{} - useDefaultSandBox bool - prio int // higher the value, more the priority -} - -type extraHost struct { - name string - IP string -} - -type parentUpdate struct { - eid string - name string - ip string -} - -type containerInfo struct { - id string - config containerConfig - data ContainerData - sync.Mutex -} - -func (ci *containerInfo) ID() string { - return ci.id -} - -func (ci *containerInfo) Labels() map[string]interface{} { - return ci.config.generic -} - type endpoint struct { name string - id types.UUID + id string network *network iFaces []*endpointInterface joinInfo *endpointJoinInfo - container *containerInfo + sandboxID string exposedPorts []types.TransportPort generic map[string]interface{} joinLeaveDone chan struct{} @@ -131,39 +60,17 @@ type endpoint struct { sync.Mutex } -func (ci *containerInfo) MarshalJSON() ([]byte, error) { - ci.Lock() - defer ci.Unlock() - - // We are just interested in the container ID. This can be expanded to include all of containerInfo if there is a need - return json.Marshal(ci.id) -} - -func (ci *containerInfo) UnmarshalJSON(b []byte) (err error) { - ci.Lock() - defer ci.Unlock() - - var id string - if err := json.Unmarshal(b, &id); err != nil { - return err - } - ci.id = id - return nil -} - func (ep *endpoint) MarshalJSON() ([]byte, error) { ep.Lock() defer ep.Unlock() epMap := make(map[string]interface{}) epMap["name"] = ep.name - epMap["id"] = string(ep.id) + epMap["id"] = ep.id epMap["ep_iface"] = ep.iFaces epMap["exposed_ports"] = ep.exposedPorts epMap["generic"] = ep.generic - if ep.container != nil { - epMap["container"] = ep.container - } + epMap["sandbox"] = ep.sandboxID return json.Marshal(epMap) } @@ -176,7 +83,7 @@ func (ep *endpoint) UnmarshalJSON(b []byte) (err error) { return err } ep.name = epMap["name"].(string) - ep.id = types.UUID(epMap["id"].(string)) + ep.id = epMap["id"].(string) ib, _ := json.Marshal(epMap["ep_iface"]) var ifaces []endpointInterface @@ -191,13 +98,8 @@ func (ep *endpoint) UnmarshalJSON(b []byte) (err error) { json.Unmarshal(tb, &tPorts) ep.exposedPorts = tPorts - epc, ok := epMap["container"] - if ok { - cb, _ := json.Marshal(epc) - var cInfo containerInfo - json.Unmarshal(cb, &cInfo) - ep.container = &cInfo - } + cb, _ := json.Marshal(epMap["sandbox"]) + json.Unmarshal(cb, &ep.sandboxID) if epMap["generic"] != nil { ep.generic = epMap["generic"].(map[string]interface{}) @@ -205,13 +107,11 @@ func (ep *endpoint) UnmarshalJSON(b []byte) (err error) { return nil } -const defaultPrefix = "/var/lib/docker/network/files" - func (ep *endpoint) ID() string { ep.Lock() defer ep.Unlock() - return string(ep.id) + return ep.id } func (ep *endpoint) Name() string { @@ -222,36 +122,27 @@ func (ep *endpoint) Name() string { } func (ep *endpoint) Network() string { - ep.Lock() - defer ep.Unlock() - - return ep.network.name + return ep.getNetwork().name } // endpoint Key structure : endpoint/network-id/endpoint-id func (ep *endpoint) Key() []string { - ep.Lock() - n := ep.network - defer ep.Unlock() - return []string{datastore.EndpointKeyPrefix, string(n.id), string(ep.id)} + return []string{datastore.EndpointKeyPrefix, ep.getNetwork().id, ep.id} } func (ep *endpoint) KeyPrefix() []string { - ep.Lock() - n := ep.network - defer ep.Unlock() - return []string{datastore.EndpointKeyPrefix, string(n.id)} + return []string{datastore.EndpointKeyPrefix, ep.getNetwork().id} } -func (ep *endpoint) networkIDFromKey(key []string) (types.UUID, error) { +func (ep *endpoint) networkIDFromKey(key []string) (string, error) { // endpoint Key structure : endpoint/network-id/endpoint-id // it's an invalid key if the key doesn't have all the 3 key elements above if key == nil || len(key) < 3 || key[0] != datastore.EndpointKeyPrefix { - return types.UUID(""), fmt.Errorf("invalid endpoint key : %v", key) + return "", fmt.Errorf("invalid endpoint key : %v", key) } // network-id is placed at index=1. pls refer to endpoint.Key() method - return types.UUID(key[1]), nil + return key[1], nil } func (ep *endpoint) Value() []byte { @@ -296,27 +187,6 @@ func (ep *endpoint) processOptions(options ...EndpointOption) { } } -func createBasePath(dir string) error { - return os.MkdirAll(dir, 0644) -} - -func createFile(path string) error { - var f *os.File - - dir, _ := filepath.Split(path) - err := createBasePath(dir) - if err != nil { - return err - } - - f, err = os.Create(path) - if err == nil { - f.Close() - } - - return err -} - // joinLeaveStart waits to ensure there are no joins or leaves in progress and // marks this join/leave in progress without race func (ep *endpoint) joinLeaveStart() { @@ -349,44 +219,36 @@ func (ep *endpoint) joinLeaveEnd() { } } -func (ep *endpoint) Join(containerID string, options ...EndpointOption) error { +func (ep *endpoint) Join(sbox Sandbox, options ...EndpointOption) error { var err error - if containerID == "" { - return InvalidContainerIDError(containerID) + if sbox == nil { + return types.BadRequestErrorf("endpoint cannot be joined by nil container") + } + + sb, ok := sbox.(*sandbox) + if !ok { + return types.BadRequestErrorf("not a valid Sandbox interface") } ep.joinLeaveStart() - defer func() { - ep.joinLeaveEnd() - }() + defer ep.joinLeaveEnd() ep.Lock() - if ep.container != nil { + if ep.sandboxID != "" { ep.Unlock() - return ErrInvalidJoin{} + return types.ForbiddenErrorf("a sandbox has already joined the endpoint") } - ep.container = &containerInfo{ - id: containerID, - config: containerConfig{ - hostsPathConfig: hostsPathConfig{ - extraHosts: []extraHost{}, - parentUpdates: []parentUpdate{}, - }, - }} - + ep.sandboxID = sbox.ID() ep.joinInfo = &endpointJoinInfo{} - - container := ep.container network := ep.network epid := ep.id - ep.Unlock() defer func() { if err != nil { ep.Lock() - ep.container = nil + ep.sandboxID = "" ep.Unlock() } }() @@ -394,17 +256,11 @@ func (ep *endpoint) Join(containerID string, options ...EndpointOption) error { network.Lock() driver := network.driver nid := network.id - ctrlr := network.ctrlr network.Unlock() ep.processOptions(options...) - sboxKey := sandbox.GenerateKey(containerID) - if container.config.useDefaultSandBox { - sboxKey = sandbox.GenerateKey("default") - } - - err = driver.Join(nid, epid, sboxKey, ep, container.config.generic) + err = driver.Join(nid, epid, sbox.Key(), ep, sbox.Labels()) if err != nil { return err } @@ -417,36 +273,26 @@ func (ep *endpoint) Join(containerID string, options ...EndpointOption) error { } }() - err = ep.buildHostsFiles() - if err != nil { + address := "" + if ip := ep.getFirstInterfaceAddress(); ip != nil { + address = ip.String() + } + if err = sb.updateHostsFile(address, network.getSvcRecords()); err != nil { return err } - err = ep.updateParentHosts() - if err != nil { + if err = sb.updateDNS(ep.getNetwork().enableIPv6); err != nil { return err } - err = ep.setupDNS() - if err != nil { + if err = network.ctrlr.updateEndpointToStore(ep); err != nil { return err } - sb, err := ctrlr.sandboxAdd(sboxKey, !container.config.useDefaultSandBox, ep) - if err != nil { - return fmt.Errorf("failed sandbox add: %v", err) - } - defer func() { - if err != nil { - ctrlr.sandboxRm(sboxKey, ep) - } - }() - - if err := network.ctrlr.updateEndpointToStore(ep); err != nil { + if err = sb.populateNetworkResources(ep); err != nil { return err } - container.data.SandboxKey = sb.Key() return nil } @@ -463,49 +309,54 @@ func (ep *endpoint) hasInterface(iName string) bool { return false } -func (ep *endpoint) Leave(containerID string, options ...EndpointOption) error { - var err error - +func (ep *endpoint) Leave(sbox Sandbox, options ...EndpointOption) error { ep.joinLeaveStart() defer ep.joinLeaveEnd() + if sbox == nil || sbox.ID() == "" || sbox.Key() == "" { + return types.BadRequestErrorf("invalid Sandbox passed to enpoint leave: %v", sbox) + } + + sb, ok := sbox.(*sandbox) + if !ok { + return types.BadRequestErrorf("not a valid Sandbox interface") + } + + ep.Lock() + sid := ep.sandboxID + ep.Unlock() + + if sid == "" { + return types.ForbiddenErrorf("cannot leave endpoint with no attached sandbox") + } + if sid != sbox.ID() { + return types.ForbiddenErrorf("unexpected sandbox ID in leave request. Expected %s. Got %s", ep.sandboxID, sbox.ID()) + } + ep.processOptions(options...) ep.Lock() - container := ep.container + ep.sandboxID = "" n := ep.network - - if container == nil || container.id == "" || container.data.SandboxKey == "" || - containerID == "" || container.id != containerID { - if container == nil { - err = ErrNoContainer{} - } else { - err = InvalidContainerIDError(containerID) - } - - ep.Unlock() - return err - } - ep.container = nil ep.Unlock() n.Lock() - driver := n.driver - ctrlr := n.ctrlr + c := n.ctrlr + d := n.driver n.Unlock() - if err := ctrlr.updateEndpointToStore(ep); err != nil { + if err := c.updateEndpointToStore(ep); err != nil { ep.Lock() - ep.container = container + ep.sandboxID = sid ep.Unlock() return err } - err = driver.Leave(n.id, ep.id) + if err := d.Leave(n.id, ep.id); err != nil { + return err + } - ctrlr.sandboxRm(container.data.SandboxKey, ep) - - return err + return sb.clearNetworkResources(ep) } func (ep *endpoint) Delete() error { @@ -514,9 +365,9 @@ func (ep *endpoint) Delete() error { epid := ep.id name := ep.name n := ep.network - if ep.container != nil { + if ep.sandboxID != "" { ep.Unlock() - return &ActiveContainerError{name: name, id: string(epid)} + return &ActiveContainerError{name: name, id: epid} } n.Lock() ctrlr := n.ctrlr @@ -556,33 +407,6 @@ func (ep *endpoint) Delete() error { return nil } -func (ep *endpoint) Statistics() (map[string]*sandbox.InterfaceStatistics, error) { - m := make(map[string]*sandbox.InterfaceStatistics) - - ep.Lock() - n := ep.network - skey := ep.container.data.SandboxKey - ep.Unlock() - - n.Lock() - c := n.ctrlr - n.Unlock() - - sbox := c.sandboxGet(skey) - if sbox == nil { - return m, nil - } - - var err error - for _, i := range sbox.Info().Interfaces() { - if m[i.DstName()], err = i.Statistics(); err != nil { - return m, err - } - } - - return m, nil -} - func (ep *endpoint) deleteEndpoint() error { ep.Lock() n := ep.network @@ -616,260 +440,36 @@ func (ep *endpoint) deleteEndpoint() error { return nil } -func (ep *endpoint) addHostEntries(recs []etchosts.Record) { +func (ep *endpoint) getNetwork() *network { ep.Lock() - container := ep.container - ep.Unlock() - - if container == nil { - return - } - - if err := etchosts.Add(container.config.hostsPath, recs); err != nil { - log.Warnf("Failed adding service host entries to the running container: %v", err) - } + defer ep.Unlock() + return ep.network } -func (ep *endpoint) deleteHostEntries(recs []etchosts.Record) { +func (ep *endpoint) getSandbox() (*sandbox, bool) { ep.Lock() - container := ep.container + c := ep.network.getController() + sid := ep.sandboxID ep.Unlock() - if container == nil { - return - } + c.Lock() + ps, ok := c.sandboxes[sid] + c.Unlock() - if err := etchosts.Delete(container.config.hostsPath, recs); err != nil { - log.Warnf("Failed deleting service host entries to the running container: %v", err) - } + return ps, ok } -func (ep *endpoint) buildHostsFiles() error { - var extraContent []etchosts.Record - +func (ep *endpoint) getFirstInterfaceAddress() net.IP { ep.Lock() - container := ep.container - joinInfo := ep.joinInfo - ifaces := ep.iFaces - n := ep.network - ep.Unlock() + defer ep.Unlock() - if container == nil { - return ErrNoContainer{} - } - - if container.config.hostsPath == "" { - container.config.hostsPath = defaultPrefix + "/" + container.id + "/hosts" - } - - dir, _ := filepath.Split(container.config.hostsPath) - err := createBasePath(dir) - if err != nil { - return err - } - - if joinInfo != nil && joinInfo.hostsPath != "" { - content, err := ioutil.ReadFile(joinInfo.hostsPath) - if err != nil && !os.IsNotExist(err) { - return err - } - - if err == nil { - return ioutil.WriteFile(container.config.hostsPath, content, 0644) - } - } - - for _, extraHost := range container.config.extraHosts { - extraContent = append(extraContent, - etchosts.Record{Hosts: extraHost.name, IP: extraHost.IP}) - } - - extraContent = append(extraContent, n.getSvcRecords()...) - - IP := "" - if len(ifaces) != 0 && ifaces[0] != nil { - IP = ifaces[0].addr.IP.String() - } - - return etchosts.Build(container.config.hostsPath, IP, container.config.hostName, - container.config.domainName, extraContent) -} - -func (ep *endpoint) updateParentHosts() error { - ep.Lock() - container := ep.container - network := ep.network - ep.Unlock() - - if container == nil { - return ErrNoContainer{} - } - - for _, update := range container.config.parentUpdates { - network.Lock() - pep, ok := network.endpoints[types.UUID(update.eid)] - if !ok { - network.Unlock() - continue - } - network.Unlock() - - pep.Lock() - pContainer := pep.container - pep.Unlock() - - if pContainer != nil { - if err := etchosts.Update(pContainer.config.hostsPath, update.ip, update.name); err != nil { - return err - } - } + if len(ep.iFaces) != 0 && ep.iFaces[0] != nil { + return ep.iFaces[0].addr.IP } return nil } -func (ep *endpoint) updateDNS(resolvConf []byte) error { - ep.Lock() - container := ep.container - network := ep.network - ep.Unlock() - - if container == nil { - return ErrNoContainer{} - } - - oldHash := []byte{} - hashFile := container.config.resolvConfPath + ".hash" - - resolvBytes, err := ioutil.ReadFile(container.config.resolvConfPath) - if err != nil { - if !os.IsNotExist(err) { - return err - } - } else { - oldHash, err = ioutil.ReadFile(hashFile) - if err != nil { - if !os.IsNotExist(err) { - return err - } - - oldHash = []byte{} - } - } - - curHash, err := ioutils.HashData(bytes.NewReader(resolvBytes)) - if err != nil { - return err - } - - if string(oldHash) != "" && curHash != string(oldHash) { - // Seems the user has changed the container resolv.conf since the last time - // we checked so return without doing anything. - return nil - } - - // replace any localhost/127.* and remove IPv6 nameservers if IPv6 disabled. - resolvConf, _ = resolvconf.FilterResolvDNS(resolvConf, network.enableIPv6) - - newHash, err := ioutils.HashData(bytes.NewReader(resolvConf)) - if err != nil { - return err - } - - // for atomic updates to these files, use temporary files with os.Rename: - dir := path.Dir(container.config.resolvConfPath) - tmpHashFile, err := ioutil.TempFile(dir, "hash") - if err != nil { - return err - } - tmpResolvFile, err := ioutil.TempFile(dir, "resolv") - if err != nil { - return err - } - - // Change the perms to 0644 since ioutil.TempFile creates it by default as 0600 - if err := os.Chmod(tmpResolvFile.Name(), 0644); err != nil { - return err - } - - // write the updates to the temp files - if err = ioutil.WriteFile(tmpHashFile.Name(), []byte(newHash), 0644); err != nil { - return err - } - if err = ioutil.WriteFile(tmpResolvFile.Name(), resolvConf, 0644); err != nil { - return err - } - - // rename the temp files for atomic replace - if err = os.Rename(tmpHashFile.Name(), hashFile); err != nil { - return err - } - return os.Rename(tmpResolvFile.Name(), container.config.resolvConfPath) -} - -func copyFile(src, dst string) error { - sBytes, err := ioutil.ReadFile(src) - if err != nil { - return err - } - - return ioutil.WriteFile(dst, sBytes, 0644) -} - -func (ep *endpoint) setupDNS() error { - ep.Lock() - container := ep.container - joinInfo := ep.joinInfo - ep.Unlock() - - if container == nil { - return ErrNoContainer{} - } - - if container.config.resolvConfPath == "" { - container.config.resolvConfPath = defaultPrefix + "/" + container.id + "/resolv.conf" - } - - dir, _ := filepath.Split(container.config.resolvConfPath) - err := createBasePath(dir) - if err != nil { - return err - } - - if joinInfo.resolvConfPath != "" { - if err := copyFile(joinInfo.resolvConfPath, container.config.resolvConfPath); err != nil { - return fmt.Errorf("could not copy source resolv.conf file %s to %s: %v", joinInfo.resolvConfPath, container.config.resolvConfPath, err) - } - - return nil - } - - resolvConf, err := resolvconf.Get() - if err != nil { - return err - } - - if len(container.config.dnsList) > 0 || - len(container.config.dnsSearchList) > 0 { - var ( - dnsList = resolvconf.GetNameservers(resolvConf) - dnsSearchList = resolvconf.GetSearchDomains(resolvConf) - ) - - if len(container.config.dnsList) > 0 { - dnsList = container.config.dnsList - } - - if len(container.config.dnsSearchList) > 0 { - dnsSearchList = container.config.dnsSearchList - } - - return resolvconf.Build(container.config.resolvConfPath, dnsList, dnsSearchList) - } - - return ep.updateDNS(resolvConf) -} - // EndpointOptionGeneric function returns an option setter for a Generic option defined // in a Dictionary of Key-Value pair func EndpointOptionGeneric(generic map[string]interface{}) EndpointOption { @@ -880,86 +480,6 @@ func EndpointOptionGeneric(generic map[string]interface{}) EndpointOption { } } -// JoinOptionPriority function returns an option setter for priority option to -// be passed to endpoint Join method. -func JoinOptionPriority(prio int) EndpointOption { - return func(ep *endpoint) { - ep.container.config.prio = prio - } -} - -// JoinOptionHostname function returns an option setter for hostname option to -// be passed to endpoint Join method. -func JoinOptionHostname(name string) EndpointOption { - return func(ep *endpoint) { - ep.container.config.hostName = name - } -} - -// JoinOptionDomainname function returns an option setter for domainname option to -// be passed to endpoint Join method. -func JoinOptionDomainname(name string) EndpointOption { - return func(ep *endpoint) { - ep.container.config.domainName = name - } -} - -// JoinOptionHostsPath function returns an option setter for hostspath option to -// be passed to endpoint Join method. -func JoinOptionHostsPath(path string) EndpointOption { - return func(ep *endpoint) { - ep.container.config.hostsPath = path - } -} - -// JoinOptionExtraHost function returns an option setter for extra /etc/hosts options -// which is a name and IP as strings. -func JoinOptionExtraHost(name string, IP string) EndpointOption { - return func(ep *endpoint) { - ep.container.config.extraHosts = append(ep.container.config.extraHosts, extraHost{name: name, IP: IP}) - } -} - -// JoinOptionParentUpdate function returns an option setter for parent container -// which needs to update the IP address for the linked container. -func JoinOptionParentUpdate(eid string, name, ip string) EndpointOption { - return func(ep *endpoint) { - ep.container.config.parentUpdates = append(ep.container.config.parentUpdates, parentUpdate{eid: eid, name: name, ip: ip}) - } -} - -// JoinOptionResolvConfPath function returns an option setter for resolvconfpath option to -// be passed to endpoint Join method. -func JoinOptionResolvConfPath(path string) EndpointOption { - return func(ep *endpoint) { - ep.container.config.resolvConfPath = path - } -} - -// JoinOptionDNS function returns an option setter for dns entry option to -// be passed to endpoint Join method. -func JoinOptionDNS(dns string) EndpointOption { - return func(ep *endpoint) { - ep.container.config.dnsList = append(ep.container.config.dnsList, dns) - } -} - -// JoinOptionDNSSearch function returns an option setter for dns search entry option to -// be passed to endpoint Join method. -func JoinOptionDNSSearch(search string) EndpointOption { - return func(ep *endpoint) { - ep.container.config.dnsSearchList = append(ep.container.config.dnsSearchList, search) - } -} - -// JoinOptionUseDefaultSandbox function returns an option setter for using default sandbox to -// be passed to endpoint Join method. -func JoinOptionUseDefaultSandbox() EndpointOption { - return func(ep *endpoint) { - ep.container.config.useDefaultSandBox = true - } -} - // CreateOptionExposedPorts function returns an option setter for the container exposed // ports option to be passed to network.CreateEndpoint() method. func CreateOptionExposedPorts(exposedPorts []types.TransportPort) EndpointOption { @@ -984,11 +504,19 @@ func CreateOptionPortMapping(portBindings []types.PortBinding) EndpointOption { } } -// JoinOptionGeneric function returns an option setter for Generic configuration -// that is not managed by libNetwork but can be used by the Drivers during the call to -// endpoint join method. Container Labels are a good example. -func JoinOptionGeneric(generic map[string]interface{}) EndpointOption { +// JoinOptionPriority function returns an option setter for priority option to +// be passed to the endpoint.Join() method. +func JoinOptionPriority(ep Endpoint, prio int) EndpointOption { return func(ep *endpoint) { - ep.container.config.generic = generic + // ep lock already acquired + c := ep.network.getController() + c.Lock() + sb, ok := c.sandboxes[ep.sandboxID] + c.Unlock() + if !ok { + log.Errorf("Could not set endpoint priority value during Join to endpoint %s: No sandbox id present in endpoint", ep.id) + return + } + sb.epPriority[ep.id] = prio } } diff --git a/vendor/src/github.com/docker/libnetwork/endpoint_info.go b/vendor/src/github.com/docker/libnetwork/endpoint_info.go index 6c0e117132..d6b528b533 100644 --- a/vendor/src/github.com/docker/libnetwork/endpoint_info.go +++ b/vendor/src/github.com/docker/libnetwork/endpoint_info.go @@ -22,10 +22,8 @@ type EndpointInfo interface { // This will only return a valid value if a container has joined the endpoint. GatewayIPv6() net.IP - // SandboxKey returns the sanbox key for the container which has joined - // the endpoint. If there is no container joined then this will return an - // empty string. - SandboxKey() string + // Sandbox returns the attached sandbox if there, nil otherwise. + Sandbox() Sandbox } // InterfaceInfo provides an interface to retrieve interface addresses bound to the endpoint. @@ -40,14 +38,6 @@ type InterfaceInfo interface { AddressIPv6() net.IPNet } -// ContainerInfo provides an interface to retrieve the info about the container attached to the endpoint -type ContainerInfo interface { - // ID returns the ID of the container - ID() string - // Labels returns the container's labels - Labels() map[string]interface{} -} - type endpointInterface struct { id int mac net.HardwareAddr @@ -115,23 +105,9 @@ func (epi *endpointInterface) UnmarshalJSON(b []byte) (err error) { } type endpointJoinInfo struct { - gw net.IP - gw6 net.IP - hostsPath string - resolvConfPath string - StaticRoutes []*types.StaticRoute -} - -func (ep *endpoint) ContainerInfo() ContainerInfo { - ep.Lock() - ci := ep.container - defer ep.Unlock() - - // Need this since we return the interface - if ci == nil { - return nil - } - return ci + gw net.IP + gw6 net.IP + StaticRoutes []*types.StaticRoute } func (ep *endpoint) Info() EndpointInfo { @@ -257,15 +233,12 @@ func (ep *endpoint) addInterfaceRoute(route *types.StaticRoute) error { route.InterfaceID) } -func (ep *endpoint) SandboxKey() string { - ep.Lock() - defer ep.Unlock() - - if ep.container == nil { - return "" +func (ep *endpoint) Sandbox() Sandbox { + cnt, ok := ep.getSandbox() + if !ok { + return nil } - - return ep.container.data.SandboxKey + return cnt } func (ep *endpoint) Gateway() net.IP { @@ -305,19 +278,3 @@ func (ep *endpoint) SetGatewayIPv6(gw6 net.IP) error { ep.joinInfo.gw6 = types.GetIPCopy(gw6) return nil } - -func (ep *endpoint) SetHostsPath(path string) error { - ep.Lock() - defer ep.Unlock() - - ep.joinInfo.hostsPath = path - return nil -} - -func (ep *endpoint) SetResolvConfPath(path string) error { - ep.Lock() - defer ep.Unlock() - - ep.joinInfo.resolvConfPath = path - return nil -} diff --git a/vendor/src/github.com/docker/libnetwork/idm/idm.go b/vendor/src/github.com/docker/libnetwork/idm/idm.go index 2321d77ea4..8c15cfe4ec 100644 --- a/vendor/src/github.com/docker/libnetwork/idm/idm.go +++ b/vendor/src/github.com/docker/libnetwork/idm/idm.go @@ -1,4 +1,4 @@ -// Package idm manages resevation/release of numerical ids from a configured set of contiguos ids +// Package idm manages reservation/release of numerical ids from a configured set of contiguous ids package idm import ( @@ -6,7 +6,6 @@ import ( "github.com/docker/libnetwork/bitseq" "github.com/docker/libnetwork/datastore" - "github.com/docker/libnetwork/types" ) // Idm manages the reservation/release of numerical ids from a contiguos set @@ -25,7 +24,7 @@ func New(ds datastore.DataStore, id string, start, end uint32) (*Idm, error) { return nil, fmt.Errorf("Invalid set range: [%d, %d]", start, end) } - h, err := bitseq.NewHandle("idm", ds, id, uint32(1+end-start)) + h, err := bitseq.NewHandle("idm", ds, id, 1+end-start) if err != nil { return nil, fmt.Errorf("failed to initialize bit sequence handler: %s", err.Error()) } @@ -38,28 +37,8 @@ func (i *Idm) GetID() (uint32, error) { if i.handle == nil { return 0, fmt.Errorf("ID set is not initialized") } - - for { - bytePos, bitPos, err := i.handle.GetFirstAvailable() - if err != nil { - return 0, fmt.Errorf("no available ids") - } - id := i.start + uint32(bitPos+bytePos*8) - - // for sets which length is non multiple of 32 this check is needed - if i.end < id { - return 0, fmt.Errorf("no available ids") - } - - if err := i.handle.PushReservation(bytePos, bitPos, false); err != nil { - if _, ok := err.(types.RetryError); !ok { - return 0, fmt.Errorf("internal failure while reserving the id: %s", err.Error()) - } - continue - } - - return id, nil - } + ordinal, err := i.handle.SetAny() + return i.start + ordinal, err } // GetSpecificID tries to reserve the specified id @@ -72,23 +51,10 @@ func (i *Idm) GetSpecificID(id uint32) error { return fmt.Errorf("Requested id does not belong to the set") } - for { - bytePos, bitPos, err := i.handle.CheckIfAvailable(int(id - i.start)) - if err != nil { - return fmt.Errorf("requested id is not available") - } - if err := i.handle.PushReservation(bytePos, bitPos, false); err != nil { - if _, ok := err.(types.RetryError); !ok { - return fmt.Errorf("internal failure while reserving the id: %s", err.Error()) - } - continue - } - return nil - } + return i.handle.Set(id - i.start) } // Release releases the specified id func (i *Idm) Release(id uint32) { - ordinal := id - i.start - i.handle.PushReservation(int(ordinal/8), int(ordinal%8), true) + i.handle.Unset(id - i.start) } diff --git a/vendor/src/github.com/docker/libnetwork/netutils/test_utils.go b/vendor/src/github.com/docker/libnetwork/netutils/test_utils.go index d0a2fab789..7ebc16e364 100644 --- a/vendor/src/github.com/docker/libnetwork/netutils/test_utils.go +++ b/vendor/src/github.com/docker/libnetwork/netutils/test_utils.go @@ -1,11 +1,6 @@ package netutils -import ( - "flag" - "runtime" - "syscall" - "testing" -) +import "flag" var runningInContainer = flag.Bool("incontainer", false, "Indicates if the test is running in a container") @@ -13,29 +8,3 @@ var runningInContainer = flag.Bool("incontainer", false, "Indicates if the test func IsRunningInContainer() bool { return (*runningInContainer) } - -// SetupTestNetNS joins a new network namespace, and returns its associated -// teardown function. -// -// Example usage: -// -// defer SetupTestNetNS(t)() -// -func SetupTestNetNS(t *testing.T) func() { - runtime.LockOSThread() - if err := syscall.Unshare(syscall.CLONE_NEWNET); err != nil { - t.Fatalf("Failed to enter netns: %v", err) - } - - fd, err := syscall.Open("/proc/self/ns/net", syscall.O_RDONLY, 0) - if err != nil { - t.Fatal("Failed to open netns file") - } - - return func() { - if err := syscall.Close(fd); err != nil { - t.Logf("Warning: netns closing failed (%v)", err) - } - runtime.UnlockOSThread() - } -} diff --git a/vendor/src/github.com/docker/libnetwork/netutils/utils.go b/vendor/src/github.com/docker/libnetwork/netutils/utils.go index 6ade406db4..7d90b1f52c 100644 --- a/vendor/src/github.com/docker/libnetwork/netutils/utils.go +++ b/vendor/src/github.com/docker/libnetwork/netutils/utils.go @@ -59,17 +59,7 @@ func CheckRouteOverlaps(toCheck *net.IPNet) error { // NetworkOverlaps detects overlap between one IPNet and another func NetworkOverlaps(netX *net.IPNet, netY *net.IPNet) bool { - // Check if both netX and netY are ipv4 or ipv6 - if (netX.IP.To4() != nil && netY.IP.To4() != nil) || - (netX.IP.To4() == nil && netY.IP.To4() == nil) { - if firstIP, _ := NetworkRange(netX); netY.Contains(firstIP) { - return true - } - if firstIP, _ := NetworkRange(netY); netX.Contains(firstIP) { - return true - } - } - return false + return netX.Contains(netY.IP) || netY.Contains(netX.IP) } // NetworkRange calculates the first and last IP addresses in an IPNet @@ -180,53 +170,3 @@ func GenerateIfaceName(prefix string, len int) (string, error) { } return "", types.InternalErrorf("could not generate interface name") } - -func byteArrayToInt(array []byte, numBytes int) uint64 { - if numBytes <= 0 || numBytes > 8 { - panic("Invalid argument") - } - num := 0 - for i := 0; i <= len(array)-1; i++ { - num += int(array[len(array)-1-i]) << uint(i*8) - } - return uint64(num) -} - -// ATo64 converts a byte array into a uint32 -func ATo64(array []byte) uint64 { - return byteArrayToInt(array, 8) -} - -// ATo32 converts a byte array into a uint32 -func ATo32(array []byte) uint32 { - return uint32(byteArrayToInt(array, 4)) -} - -// ATo16 converts a byte array into a uint16 -func ATo16(array []byte) uint16 { - return uint16(byteArrayToInt(array, 2)) -} - -func intToByteArray(val uint64, numBytes int) []byte { - array := make([]byte, numBytes) - for i := numBytes - 1; i >= 0; i-- { - array[i] = byte(val & 0xff) - val = val >> 8 - } - return array -} - -// U64ToA converts a uint64 to a byte array -func U64ToA(val uint64) []byte { - return intToByteArray(uint64(val), 8) -} - -// U32ToA converts a uint64 to a byte array -func U32ToA(val uint32) []byte { - return intToByteArray(uint64(val), 4) -} - -// U16ToA converts a uint64 to a byte array -func U16ToA(val uint16) []byte { - return intToByteArray(uint64(val), 2) -} diff --git a/vendor/src/github.com/docker/libnetwork/network.go b/vendor/src/github.com/docker/libnetwork/network.go index 9ad4381114..ab95292cea 100644 --- a/vendor/src/github.com/docker/libnetwork/network.go +++ b/vendor/src/github.com/docker/libnetwork/network.go @@ -59,7 +59,7 @@ type network struct { ctrlr *controller name string networkType string - id types.UUID + id string driver driverapi.Driver enableIPv6 bool endpointCnt uint64 @@ -83,7 +83,7 @@ func (n *network) ID() string { n.Lock() defer n.Unlock() - return string(n.id) + return n.id } func (n *network) Type() string { @@ -100,7 +100,7 @@ func (n *network) Type() string { func (n *network) Key() []string { n.Lock() defer n.Unlock() - return []string{datastore.NetworkKeyPrefix, string(n.id)} + return []string{datastore.NetworkKeyPrefix, n.id} } func (n *network) KeyPrefix() []string { @@ -162,7 +162,7 @@ func (n *network) DecEndpointCnt() { func (n *network) MarshalJSON() ([]byte, error) { netMap := make(map[string]interface{}) netMap["name"] = n.name - netMap["id"] = string(n.id) + netMap["id"] = n.id netMap["networkType"] = n.networkType netMap["endpointCnt"] = n.endpointCnt netMap["enableIPv6"] = n.enableIPv6 @@ -177,7 +177,7 @@ func (n *network) UnmarshalJSON(b []byte) (err error) { return err } n.name = netMap["name"].(string) - n.id = types.UUID(netMap["id"].(string)) + n.id = netMap["id"].(string) n.networkType = netMap["networkType"].(string) n.endpointCnt = uint64(netMap["endpointCnt"].(float64)) n.enableIPv6 = netMap["enableIPv6"].(bool) @@ -223,12 +223,12 @@ func (n *network) Delete() error { ctrlr.Unlock() if !ok { - return &UnknownNetworkError{name: n.name, id: string(n.id)} + return &UnknownNetworkError{name: n.name, id: n.id} } numEps := n.EndpointCnt() if numEps != 0 { - return &ActiveEndpointsError{name: n.name, id: string(n.id)} + return &ActiveEndpointsError{name: n.name, id: n.id} } // deleteNetworkFromStore performs an atomic delete operation and the network.endpointCnt field will help @@ -287,7 +287,7 @@ func (n *network) addEndpoint(ep *endpoint) error { err = d.CreateEndpoint(n.id, ep.id, ep, ep.generic) if err != nil { - return err + return types.InternalErrorf("failed to create endpoint %s on network %s: %v", ep.Name(), n.Name(), err) } n.updateSvcRecord(ep, true) @@ -307,7 +307,7 @@ func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoi ep := &endpoint{name: name, iFaces: []*endpointInterface{}, generic: make(map[string]interface{})} - ep.id = types.UUID(stringid.GenerateRandomID()) + ep.id = stringid.GenerateRandomID() ep.network = n ep.processOptions(options...) @@ -393,7 +393,7 @@ func (n *network) EndpointByID(id string) (Endpoint, error) { } n.Lock() defer n.Unlock() - if e, ok := n.endpoints[types.UUID(id)]; ok { + if e, ok := n.endpoints[id]; ok { return e, nil } return nil, ErrNoSuchEndpoint(id) @@ -435,22 +435,19 @@ func (n *network) updateSvcRecord(ep *endpoint, isAdd bool) { return } - var epList []*endpoint + var sbList []*sandbox n.WalkEndpoints(func(e Endpoint) bool { - cEp := e.(*endpoint) - cEp.Lock() - if cEp.container != nil { - epList = append(epList, cEp) + if sb, hasSandbox := e.(*endpoint).getSandbox(); hasSandbox { + sbList = append(sbList, sb) } - cEp.Unlock() return false }) - for _, cEp := range epList { + for _, sb := range sbList { if isAdd { - cEp.addHostEntries(recs) + sb.addHostsEntries(recs) } else { - cEp.deleteHostEntries(recs) + sb.deleteHostsEntries(recs) } } } @@ -469,3 +466,9 @@ func (n *network) getSvcRecords() []etchosts.Record { return recs } + +func (n *network) getController() *controller { + n.Lock() + defer n.Unlock() + return n.ctrlr +} diff --git a/vendor/src/github.com/docker/libnetwork/options/options.go b/vendor/src/github.com/docker/libnetwork/options/options.go index e0e93ff9b7..8512ce83f3 100644 --- a/vendor/src/github.com/docker/libnetwork/options/options.go +++ b/vendor/src/github.com/docker/libnetwork/options/options.go @@ -29,6 +29,18 @@ func (e CannotSetFieldError) Error() string { return fmt.Sprintf("cannot set field %q of type %q", e.Field, e.Type) } +// TypeMismatchError is the error returned when the type of the generic value +// for a field mismatches the type of the destination structure. +type TypeMismatchError struct { + Field string + ExpectType string + ActualType string +} + +func (e TypeMismatchError) Error() string { + return fmt.Sprintf("type mismatch, field %s require type %v, actual type %v", e.Field, e.ExpectType, e.ActualType) +} + // Generic is an basic type to store arbitrary settings. type Generic map[string]interface{} @@ -62,6 +74,9 @@ func GenerateFromModel(options Generic, model interface{}) (interface{}, error) if !field.CanSet() { return nil, CannotSetFieldError{name, resType.String()} } + if reflect.TypeOf(value) != field.Type() { + return nil, TypeMismatchError{name, field.Type().String(), reflect.TypeOf(value).String()} + } field.Set(reflect.ValueOf(value)) } diff --git a/vendor/src/github.com/docker/libnetwork/sandbox/interface_freebsd.go b/vendor/src/github.com/docker/libnetwork/osl/interface_freebsd.go similarity index 85% rename from vendor/src/github.com/docker/libnetwork/sandbox/interface_freebsd.go rename to vendor/src/github.com/docker/libnetwork/osl/interface_freebsd.go index 115290d82b..9c0141fd9b 100644 --- a/vendor/src/github.com/docker/libnetwork/sandbox/interface_freebsd.go +++ b/vendor/src/github.com/docker/libnetwork/osl/interface_freebsd.go @@ -1,4 +1,4 @@ -package sandbox +package osl // IfaceOption is a function option type to set interface options type IfaceOption func() diff --git a/vendor/src/github.com/docker/libnetwork/sandbox/interface_linux.go b/vendor/src/github.com/docker/libnetwork/osl/interface_linux.go similarity index 99% rename from vendor/src/github.com/docker/libnetwork/sandbox/interface_linux.go rename to vendor/src/github.com/docker/libnetwork/osl/interface_linux.go index 7fc8c70681..c314b011dc 100644 --- a/vendor/src/github.com/docker/libnetwork/sandbox/interface_linux.go +++ b/vendor/src/github.com/docker/libnetwork/osl/interface_linux.go @@ -1,4 +1,4 @@ -package sandbox +package osl import ( "fmt" diff --git a/vendor/src/github.com/docker/libnetwork/sandbox/interface_windows.go b/vendor/src/github.com/docker/libnetwork/osl/interface_windows.go similarity index 85% rename from vendor/src/github.com/docker/libnetwork/sandbox/interface_windows.go rename to vendor/src/github.com/docker/libnetwork/osl/interface_windows.go index 115290d82b..9c0141fd9b 100644 --- a/vendor/src/github.com/docker/libnetwork/sandbox/interface_windows.go +++ b/vendor/src/github.com/docker/libnetwork/osl/interface_windows.go @@ -1,4 +1,4 @@ -package sandbox +package osl // IfaceOption is a function option type to set interface options type IfaceOption func() diff --git a/vendor/src/github.com/docker/libnetwork/sandbox/namespace_linux.go b/vendor/src/github.com/docker/libnetwork/osl/namespace_linux.go similarity index 88% rename from vendor/src/github.com/docker/libnetwork/sandbox/namespace_linux.go rename to vendor/src/github.com/docker/libnetwork/osl/namespace_linux.go index 214da312d0..55e57a1fa2 100644 --- a/vendor/src/github.com/docker/libnetwork/sandbox/namespace_linux.go +++ b/vendor/src/github.com/docker/libnetwork/osl/namespace_linux.go @@ -1,4 +1,4 @@ -package sandbox +package osl import ( "fmt" @@ -26,6 +26,8 @@ var ( gpmWg sync.WaitGroup gpmCleanupPeriod = 60 * time.Second gpmChan = make(chan chan struct{}) + nsOnce sync.Once + initNs netns.NsHandle ) // The networkNamespace type is the linux implementation of the Sandbox @@ -242,15 +244,37 @@ func (n *networkNamespace) InvokeFunc(f func()) error { }) } -func nsInvoke(path string, prefunc func(nsFD int) error, postfunc func(callerFD int) error) error { - runtime.LockOSThread() - defer runtime.UnlockOSThread() +func getLink() (string, error) { + return os.Readlink(fmt.Sprintf("/proc/%d/task/%d/ns/net", os.Getpid(), syscall.Gettid())) +} - origns, err := netns.Get() - if err != nil { - return err +func nsInit() { + var err error + + if initNs, err = netns.Get(); err != nil { + log.Errorf("could not get initial namespace: %v", err) } - defer origns.Close() +} + +// InitOSContext initializes OS context while configuring network resources +func InitOSContext() func() { + runtime.LockOSThread() + nsOnce.Do(nsInit) + if err := netns.Set(initNs); err != nil { + linkInfo, linkErr := getLink() + if linkErr != nil { + linkInfo = linkErr.Error() + } + + log.Errorf("failed to set to initial namespace, %v, initns fd %d: %v", + linkInfo, initNs, err) + } + + return runtime.UnlockOSThread +} + +func nsInvoke(path string, prefunc func(nsFD int) error, postfunc func(callerFD int) error) error { + defer InitOSContext()() f, err := os.OpenFile(path, os.O_RDONLY, 0) if err != nil { @@ -269,10 +293,10 @@ func nsInvoke(path string, prefunc func(nsFD int) error, postfunc func(callerFD if err = netns.Set(netns.NsHandle(nsFD)); err != nil { return err } - defer netns.Set(origns) + defer netns.Set(initNs) // Invoked after the namespace switch. - return postfunc(int(origns)) + return postfunc(int(initNs)) } func (n *networkNamespace) nsPath() string { diff --git a/vendor/src/github.com/docker/libnetwork/sandbox/namespace_unsupported.go b/vendor/src/github.com/docker/libnetwork/osl/namespace_unsupported.go similarity index 89% rename from vendor/src/github.com/docker/libnetwork/sandbox/namespace_unsupported.go rename to vendor/src/github.com/docker/libnetwork/osl/namespace_unsupported.go index 9d38206bd7..77f286e5ea 100644 --- a/vendor/src/github.com/docker/libnetwork/sandbox/namespace_unsupported.go +++ b/vendor/src/github.com/docker/libnetwork/osl/namespace_unsupported.go @@ -1,6 +1,6 @@ // +build !linux,!windows,!freebsd -package sandbox +package osl // GC triggers garbage collection of namespace path right away // and waits for it. diff --git a/vendor/src/github.com/docker/libnetwork/sandbox/namespace_windows.go b/vendor/src/github.com/docker/libnetwork/osl/namespace_windows.go similarity index 63% rename from vendor/src/github.com/docker/libnetwork/sandbox/namespace_windows.go rename to vendor/src/github.com/docker/libnetwork/osl/namespace_windows.go index 4aa7787113..36bd6c8002 100644 --- a/vendor/src/github.com/docker/libnetwork/sandbox/namespace_windows.go +++ b/vendor/src/github.com/docker/libnetwork/osl/namespace_windows.go @@ -1,4 +1,6 @@ -package sandbox +package osl + +import "testing" // GenerateKey generates a sandbox key based on the passed // container id. @@ -21,3 +23,13 @@ func NewSandbox(key string, osCreate bool) (Sandbox, error) { // and waits for it. func GC() { } + +// InitOSContext initializes OS context while configuring network resources +func InitOSContext() func() { + return func() {} +} + +// SetupTestOSContext sets up a separate test OS context in which tests will be executed. +func SetupTestOSContext(t *testing.T) func() { + return func() {} +} diff --git a/vendor/src/github.com/docker/libnetwork/sandbox/neigh_freebsd.go b/vendor/src/github.com/docker/libnetwork/osl/neigh_freebsd.go similarity index 84% rename from vendor/src/github.com/docker/libnetwork/sandbox/neigh_freebsd.go rename to vendor/src/github.com/docker/libnetwork/osl/neigh_freebsd.go index 58b30587e2..280f006396 100644 --- a/vendor/src/github.com/docker/libnetwork/sandbox/neigh_freebsd.go +++ b/vendor/src/github.com/docker/libnetwork/osl/neigh_freebsd.go @@ -1,4 +1,4 @@ -package sandbox +package osl // NeighOption is a function option type to set neighbor options type NeighOption func() diff --git a/vendor/src/github.com/docker/libnetwork/sandbox/neigh_linux.go b/vendor/src/github.com/docker/libnetwork/osl/neigh_linux.go similarity index 99% rename from vendor/src/github.com/docker/libnetwork/sandbox/neigh_linux.go rename to vendor/src/github.com/docker/libnetwork/osl/neigh_linux.go index 873f14f193..a221e712da 100644 --- a/vendor/src/github.com/docker/libnetwork/sandbox/neigh_linux.go +++ b/vendor/src/github.com/docker/libnetwork/osl/neigh_linux.go @@ -1,4 +1,4 @@ -package sandbox +package osl import ( "bytes" diff --git a/vendor/src/github.com/docker/libnetwork/sandbox/neigh_windows.go b/vendor/src/github.com/docker/libnetwork/osl/neigh_windows.go similarity index 84% rename from vendor/src/github.com/docker/libnetwork/sandbox/neigh_windows.go rename to vendor/src/github.com/docker/libnetwork/osl/neigh_windows.go index 58b30587e2..280f006396 100644 --- a/vendor/src/github.com/docker/libnetwork/sandbox/neigh_windows.go +++ b/vendor/src/github.com/docker/libnetwork/osl/neigh_windows.go @@ -1,4 +1,4 @@ -package sandbox +package osl // NeighOption is a function option type to set neighbor options type NeighOption func() diff --git a/vendor/src/github.com/docker/libnetwork/sandbox/options_linux.go b/vendor/src/github.com/docker/libnetwork/osl/options_linux.go similarity index 98% rename from vendor/src/github.com/docker/libnetwork/sandbox/options_linux.go rename to vendor/src/github.com/docker/libnetwork/osl/options_linux.go index e34699c790..5295eb85c5 100644 --- a/vendor/src/github.com/docker/libnetwork/sandbox/options_linux.go +++ b/vendor/src/github.com/docker/libnetwork/osl/options_linux.go @@ -1,4 +1,4 @@ -package sandbox +package osl import "net" diff --git a/vendor/src/github.com/docker/libnetwork/sandbox/route_linux.go b/vendor/src/github.com/docker/libnetwork/osl/route_linux.go similarity index 99% rename from vendor/src/github.com/docker/libnetwork/sandbox/route_linux.go rename to vendor/src/github.com/docker/libnetwork/osl/route_linux.go index 946e364860..3ebaaec77c 100644 --- a/vendor/src/github.com/docker/libnetwork/sandbox/route_linux.go +++ b/vendor/src/github.com/docker/libnetwork/osl/route_linux.go @@ -1,4 +1,4 @@ -package sandbox +package osl import ( "fmt" diff --git a/vendor/src/github.com/docker/libnetwork/sandbox/sandbox.go b/vendor/src/github.com/docker/libnetwork/osl/sandbox.go similarity index 98% rename from vendor/src/github.com/docker/libnetwork/sandbox/sandbox.go rename to vendor/src/github.com/docker/libnetwork/osl/sandbox.go index f32bcfe30a..9e87f472b8 100644 --- a/vendor/src/github.com/docker/libnetwork/sandbox/sandbox.go +++ b/vendor/src/github.com/docker/libnetwork/osl/sandbox.go @@ -1,4 +1,5 @@ -package sandbox +// Package osl describes structures and interfaces which abstract os entities +package osl import ( "fmt" diff --git a/vendor/src/github.com/docker/libnetwork/sandbox/sandbox_freebsd.go b/vendor/src/github.com/docker/libnetwork/osl/sandbox_freebsd.go similarity index 63% rename from vendor/src/github.com/docker/libnetwork/sandbox/sandbox_freebsd.go rename to vendor/src/github.com/docker/libnetwork/osl/sandbox_freebsd.go index 4aa7787113..36bd6c8002 100644 --- a/vendor/src/github.com/docker/libnetwork/sandbox/sandbox_freebsd.go +++ b/vendor/src/github.com/docker/libnetwork/osl/sandbox_freebsd.go @@ -1,4 +1,6 @@ -package sandbox +package osl + +import "testing" // GenerateKey generates a sandbox key based on the passed // container id. @@ -21,3 +23,13 @@ func NewSandbox(key string, osCreate bool) (Sandbox, error) { // and waits for it. func GC() { } + +// InitOSContext initializes OS context while configuring network resources +func InitOSContext() func() { + return func() {} +} + +// SetupTestOSContext sets up a separate test OS context in which tests will be executed. +func SetupTestOSContext(t *testing.T) func() { + return func() {} +} diff --git a/vendor/src/github.com/docker/libnetwork/sandbox/sandbox_unsupported.go b/vendor/src/github.com/docker/libnetwork/osl/sandbox_unsupported.go similarity index 97% rename from vendor/src/github.com/docker/libnetwork/sandbox/sandbox_unsupported.go rename to vendor/src/github.com/docker/libnetwork/osl/sandbox_unsupported.go index 4ed3c9f58b..3bc6c38500 100644 --- a/vendor/src/github.com/docker/libnetwork/sandbox/sandbox_unsupported.go +++ b/vendor/src/github.com/docker/libnetwork/osl/sandbox_unsupported.go @@ -1,6 +1,6 @@ // +build !linux,!windows,!freebsd -package sandbox +package osl import "errors" diff --git a/vendor/src/github.com/docker/libnetwork/portmapper/mapper.go b/vendor/src/github.com/docker/libnetwork/portmapper/mapper.go index bbdedaa3ca..d125fa8d4b 100644 --- a/vendor/src/github.com/docker/libnetwork/portmapper/mapper.go +++ b/vendor/src/github.com/docker/libnetwork/portmapper/mapper.go @@ -188,6 +188,8 @@ func (pm *PortMapper) Unmap(host net.Addr) error { //ReMapAll will re-apply all port mappings func (pm *PortMapper) ReMapAll() { + pm.lock.Lock() + defer pm.lock.Unlock() logrus.Debugln("Re-applying all port mappings.") for _, data := range pm.currentMappings { containerIP, containerPort := getIPAndPort(data.container) diff --git a/vendor/src/github.com/docker/libnetwork/resolvconf/resolvconf.go b/vendor/src/github.com/docker/libnetwork/resolvconf/resolvconf.go index ebe3b71aa4..d5169ada35 100644 --- a/vendor/src/github.com/docker/libnetwork/resolvconf/resolvconf.go +++ b/vendor/src/github.com/docker/libnetwork/resolvconf/resolvconf.go @@ -30,6 +30,7 @@ var ( nsIPv6Regexp = regexp.MustCompile(`(?m)^nameserver\s+` + ipv6Address + `\s*\n*`) nsRegexp = regexp.MustCompile(`^\s*nameserver\s*((` + ipv4Address + `)|(` + ipv6Address + `))\s*$`) searchRegexp = regexp.MustCompile(`^\s*search\s*(([^\s]+\s*)*)$`) + optionsRegexp = regexp.MustCompile(`^\s*options\s*(([^\s]+\s*)*)$`) ) var lastModified struct { @@ -38,46 +39,69 @@ var lastModified struct { contents []byte } -// Get returns the contents of /etc/resolv.conf -func Get() ([]byte, error) { +// File contains the resolv.conf content and its hash +type File struct { + Content []byte + Hash string +} + +// Get returns the contents of /etc/resolv.conf and its hash +func Get() (*File, error) { resolv, err := ioutil.ReadFile("/etc/resolv.conf") if err != nil { return nil, err } - return resolv, nil + hash, err := ioutils.HashData(bytes.NewReader(resolv)) + if err != nil { + return nil, err + } + return &File{Content: resolv, Hash: hash}, nil +} + +// GetSpecific returns the contents of the user specified resolv.conf file and its hash +func GetSpecific(path string) (*File, error) { + resolv, err := ioutil.ReadFile(path) + if err != nil { + return nil, err + } + hash, err := ioutils.HashData(bytes.NewReader(resolv)) + if err != nil { + return nil, err + } + return &File{Content: resolv, Hash: hash}, nil } // GetIfChanged retrieves the host /etc/resolv.conf file, checks against the last hash // and, if modified since last check, returns the bytes and new hash. // This feature is used by the resolv.conf updater for containers -func GetIfChanged() ([]byte, string, error) { +func GetIfChanged() (*File, error) { lastModified.Lock() defer lastModified.Unlock() resolv, err := ioutil.ReadFile("/etc/resolv.conf") if err != nil { - return nil, "", err + return nil, err } newHash, err := ioutils.HashData(bytes.NewReader(resolv)) if err != nil { - return nil, "", err + return nil, err } if lastModified.sha256 != newHash { lastModified.sha256 = newHash lastModified.contents = resolv - return resolv, newHash, nil + return &File{Content: resolv, Hash: newHash}, nil } // nothing changed, so return no data - return nil, "", nil + return nil, nil } // GetLastModified retrieves the last used contents and hash of the host resolv.conf. // Used by containers updating on restart -func GetLastModified() ([]byte, string) { +func GetLastModified() *File { lastModified.Lock() defer lastModified.Unlock() - return lastModified.contents, lastModified.sha256 + return &File{Content: lastModified.contents, Hash: lastModified.sha256} } // FilterResolvDNS cleans up the config in resolvConf. It has two main jobs: @@ -87,9 +111,7 @@ func GetLastModified() ([]byte, string) { // 2. Given the caller provides the enable/disable state of IPv6, the filter // code will remove all IPv6 nameservers if it is not enabled for containers // -// It returns a boolean to notify the caller if changes were made at all -func FilterResolvDNS(resolvConf []byte, ipv6Enabled bool) ([]byte, bool) { - changed := false +func FilterResolvDNS(resolvConf []byte, ipv6Enabled bool) (*File, error) { cleanedResolvConf := localhostNSRegexp.ReplaceAll(resolvConf, []byte{}) // if IPv6 is not enabled, also clean out any IPv6 address nameserver if !ipv6Enabled { @@ -106,10 +128,11 @@ func FilterResolvDNS(resolvConf []byte, ipv6Enabled bool) ([]byte, bool) { } cleanedResolvConf = append(cleanedResolvConf, []byte("\n"+strings.Join(dns, "\n"))...) } - if !bytes.Equal(resolvConf, cleanedResolvConf) { - changed = true + hash, err := ioutils.HashData(bytes.NewReader(cleanedResolvConf)) + if err != nil { + return nil, err } - return cleanedResolvConf, changed + return &File{Content: cleanedResolvConf, Hash: hash}, nil } // getLines parses input into lines and strips away comments. @@ -165,23 +188,50 @@ func GetSearchDomains(resolvConf []byte) []string { return domains } -// Build writes a configuration file to path containing a "nameserver" entry -// for every element in dns, and a "search" entry for every element in -// dnsSearch. -func Build(path string, dns, dnsSearch []string) error { - content := bytes.NewBuffer(nil) - for _, dns := range dns { - if _, err := content.WriteString("nameserver " + dns + "\n"); err != nil { - return err +// GetOptions returns options (if any) listed in /etc/resolv.conf +// If more than one options line is encountered, only the contents of the last +// one is returned. +func GetOptions(resolvConf []byte) []string { + options := []string{} + for _, line := range getLines(resolvConf, []byte("#")) { + match := optionsRegexp.FindSubmatch(line) + if match == nil { + continue } + options = strings.Fields(string(match[1])) } + return options +} + +// Build writes a configuration file to path containing a "nameserver" entry +// for every element in dns, a "search" entry for every element in +// dnsSearch, and an "options" entry for every element in dnsOptions. +func Build(path string, dns, dnsSearch, dnsOptions []string) (*File, error) { + content := bytes.NewBuffer(nil) if len(dnsSearch) > 0 { if searchString := strings.Join(dnsSearch, " "); strings.Trim(searchString, " ") != "." { if _, err := content.WriteString("search " + searchString + "\n"); err != nil { - return err + return nil, err + } + } + } + for _, dns := range dns { + if _, err := content.WriteString("nameserver " + dns + "\n"); err != nil { + return nil, err + } + } + if len(dnsOptions) > 0 { + if optsString := strings.Join(dnsOptions, " "); strings.Trim(optsString, " ") != "" { + if _, err := content.WriteString("options " + optsString + "\n"); err != nil { + return nil, err } } } - return ioutil.WriteFile(path, content.Bytes(), 0644) + hash, err := ioutils.HashData(bytes.NewReader(content.Bytes())) + if err != nil { + return nil, err + } + + return &File{Content: content.Bytes(), Hash: hash}, ioutil.WriteFile(path, content.Bytes(), 0644) } diff --git a/vendor/src/github.com/docker/libnetwork/sandbox.go b/vendor/src/github.com/docker/libnetwork/sandbox.go new file mode 100644 index 0000000000..8972abc4d5 --- /dev/null +++ b/vendor/src/github.com/docker/libnetwork/sandbox.go @@ -0,0 +1,744 @@ +package libnetwork + +import ( + "container/heap" + "encoding/json" + "fmt" + "io/ioutil" + "os" + "path" + "path/filepath" + "sync" + + log "github.com/Sirupsen/logrus" + "github.com/docker/libnetwork/etchosts" + "github.com/docker/libnetwork/osl" + "github.com/docker/libnetwork/resolvconf" + "github.com/docker/libnetwork/types" +) + +// Sandbox provides the control over the network container entity. It is a one to one mapping with the container. +type Sandbox interface { + // ID returns the ID of the sandbox + ID() string + // Key returns the sandbox's key + Key() string + // ContainerID returns the container id associated to this sandbox + ContainerID() string + // Labels returns the sandbox's labels + Labels() map[string]interface{} + // Statistics retrieves the interfaces' statistics for the sandbox + Statistics() (map[string]*osl.InterfaceStatistics, error) + // Refresh leaves all the endpoints, resets and re-apply the options, + // re-joins all the endpoints without destroying the osl sandbox + Refresh(options ...SandboxOption) error + // Delete destroys this container after detaching it from all connected endpoints. + Delete() error +} + +// SandboxOption is a option setter function type used to pass varios options to +// NewNetContainer method. The various setter functions of type SandboxOption are +// provided by libnetwork, they look like ContainerOptionXXXX(...) +type SandboxOption func(sb *sandbox) + +func (sb *sandbox) processOptions(options ...SandboxOption) { + for _, opt := range options { + if opt != nil { + opt(sb) + } + } +} + +type epHeap []*endpoint + +type sandbox struct { + id string + containerID string + config containerConfig + osSbox osl.Sandbox + controller *controller + refCnt int + endpoints epHeap + epPriority map[string]int + //hostsPath string + //resolvConfPath string + joinLeaveDone chan struct{} + sync.Mutex +} + +// These are the container configs used to customize container /etc/hosts file. +type hostsPathConfig struct { + hostName string + domainName string + hostsPath string + originHostsPath string + extraHosts []extraHost + parentUpdates []parentUpdate +} + +type parentUpdate struct { + cid string + name string + ip string +} + +type extraHost struct { + name string + IP string +} + +// These are the container configs used to customize container /etc/resolv.conf file. +type resolvConfPathConfig struct { + resolvConfPath string + originResolvConfPath string + resolvConfHashFile string + dnsList []string + dnsSearchList []string + dnsOptionsList []string +} + +type containerConfig struct { + hostsPathConfig + resolvConfPathConfig + generic map[string]interface{} + useDefaultSandBox bool + prio int // higher the value, more the priority +} + +func (sb *sandbox) ID() string { + return sb.id +} + +func (sb *sandbox) ContainerID() string { + return sb.containerID +} + +func (sb *sandbox) Key() string { + if sb.config.useDefaultSandBox { + return osl.GenerateKey("default") + } + return osl.GenerateKey(sb.id) +} + +func (sb *sandbox) Labels() map[string]interface{} { + return sb.config.generic +} + +func (sb *sandbox) Statistics() (map[string]*osl.InterfaceStatistics, error) { + m := make(map[string]*osl.InterfaceStatistics) + + if sb.osSbox == nil { + return m, nil + } + + var err error + for _, i := range sb.osSbox.Info().Interfaces() { + if m[i.DstName()], err = i.Statistics(); err != nil { + return m, err + } + } + + return m, nil +} + +func (sb *sandbox) Delete() error { + c := sb.controller + + // Detach from all endpoints + for _, ep := range sb.getConnectedEndpoints() { + if err := ep.Leave(sb); err != nil { + log.Warnf("Failed detaching sandbox %s from endpoint %s: %v\n", sb.ID(), ep.ID(), err) + } + } + + if sb.osSbox != nil { + sb.osSbox.Destroy() + } + + c.Lock() + delete(c.sandboxes, sb.ID()) + c.Unlock() + + return nil +} + +func (sb *sandbox) Refresh(options ...SandboxOption) error { + // Store connected endpoints + epList := sb.getConnectedEndpoints() + + // Detach from all endpoints + for _, ep := range epList { + if err := ep.Leave(sb); err != nil { + log.Warnf("Failed detaching sandbox %s from endpoint %s: %v\n", sb.ID(), ep.ID(), err) + } + } + + // Re-apply options + sb.config = containerConfig{} + sb.processOptions(options...) + + // Setup discovery files + if err := sb.setupResolutionFiles(); err != nil { + return err + } + + // Re -connect to all endpoints + for _, ep := range epList { + if err := ep.Join(sb); err != nil { + log.Warnf("Failed attach sandbox %s to endpoint %s: %v\n", sb.ID(), ep.ID(), err) + } + } + + return nil +} + +func (sb *sandbox) MarshalJSON() ([]byte, error) { + sb.Lock() + defer sb.Unlock() + + // We are just interested in the container ID. This can be expanded to include all of containerInfo if there is a need + return json.Marshal(sb.id) +} + +func (sb *sandbox) UnmarshalJSON(b []byte) (err error) { + sb.Lock() + defer sb.Unlock() + + var id string + if err := json.Unmarshal(b, &id); err != nil { + return err + } + sb.id = id + return nil +} + +func (sb *sandbox) setupResolutionFiles() error { + if err := sb.buildHostsFile(); err != nil { + return err + } + + if err := sb.updateParentHosts(); err != nil { + return err + } + + if err := sb.setupDNS(); err != nil { + return err + } + + return nil +} + +func (sb *sandbox) getConnectedEndpoints() []*endpoint { + sb.Lock() + defer sb.Unlock() + + eps := make([]*endpoint, len(sb.endpoints)) + for i, ep := range sb.endpoints { + eps[i] = ep + } + + return eps +} + +func (sb *sandbox) updateGateway(ep *endpoint) error { + sb.osSbox.UnsetGateway() + sb.osSbox.UnsetGatewayIPv6() + + if ep == nil { + return nil + } + + ep.Lock() + joinInfo := ep.joinInfo + ep.Unlock() + + if err := sb.osSbox.SetGateway(joinInfo.gw); err != nil { + return fmt.Errorf("failed to set gateway while updating gateway: %v", err) + } + + if err := sb.osSbox.SetGatewayIPv6(joinInfo.gw6); err != nil { + return fmt.Errorf("failed to set IPv6 gateway while updating gateway: %v", err) + } + + return nil +} + +func (sb *sandbox) populateNetworkResources(ep *endpoint) error { + ep.Lock() + joinInfo := ep.joinInfo + ifaces := ep.iFaces + ep.Unlock() + + for _, i := range ifaces { + var ifaceOptions []osl.IfaceOption + + ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().Address(&i.addr), sb.osSbox.InterfaceOptions().Routes(i.routes)) + if i.addrv6.IP.To16() != nil { + ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().AddressIPv6(&i.addrv6)) + } + + if err := sb.osSbox.AddInterface(i.srcName, i.dstPrefix, ifaceOptions...); err != nil { + return fmt.Errorf("failed to add interface %s to sandbox: %v", i.srcName, err) + } + } + + if joinInfo != nil { + // Set up non-interface routes. + for _, r := range joinInfo.StaticRoutes { + if err := sb.osSbox.AddStaticRoute(r); err != nil { + return fmt.Errorf("failed to add static route %s: %v", r.Destination.String(), err) + } + } + } + + sb.Lock() + heap.Push(&sb.endpoints, ep) + highEp := sb.endpoints[0] + sb.Unlock() + if ep == highEp { + if err := sb.updateGateway(ep); err != nil { + return err + } + } + + return nil +} + +func (sb *sandbox) clearNetworkResources(ep *endpoint) error { + + for _, i := range sb.osSbox.Info().Interfaces() { + // Only remove the interfaces owned by this endpoint from the sandbox. + if ep.hasInterface(i.SrcName()) { + if err := i.Remove(); err != nil { + log.Debugf("Remove interface failed: %v", err) + } + } + } + + ep.Lock() + joinInfo := ep.joinInfo + ep.Unlock() + + // Remove non-interface routes. + for _, r := range joinInfo.StaticRoutes { + if err := sb.osSbox.RemoveStaticRoute(r); err != nil { + log.Debugf("Remove route failed: %v", err) + } + } + + sb.Lock() + if len(sb.endpoints) == 0 { + // sb.endpoints should never be empty and this is unexpected error condition + // We log an error message to note this down for debugging purposes. + log.Errorf("No endpoints in sandbox while trying to remove endpoint %s", ep.Name()) + sb.Unlock() + return nil + } + + highEpBefore := sb.endpoints[0] + var ( + i int + e *endpoint + ) + for i, e = range sb.endpoints { + if e == ep { + break + } + } + heap.Remove(&sb.endpoints, i) + var highEpAfter *endpoint + if len(sb.endpoints) > 0 { + highEpAfter = sb.endpoints[0] + } + delete(sb.epPriority, ep.ID()) + sb.Unlock() + + if highEpBefore != highEpAfter { + sb.updateGateway(highEpAfter) + } + + return nil +} + +const ( + defaultPrefix = "/var/lib/docker/network/files" + filePerm = 0644 +) + +func (sb *sandbox) buildHostsFile() error { + if sb.config.hostsPath == "" { + sb.config.hostsPath = defaultPrefix + "/" + sb.id + "/hosts" + } + + dir, _ := filepath.Split(sb.config.hostsPath) + if err := createBasePath(dir); err != nil { + return err + } + + // This is for the host mode networking + if sb.config.originHostsPath != "" { + if err := copyFile(sb.config.originHostsPath, sb.config.hostsPath); err != nil && !os.IsNotExist(err) { + return types.InternalErrorf("could not copy source hosts file %s to %s: %v", sb.config.originHostsPath, sb.config.hostsPath, err) + } + return nil + } + + extraContent := make([]etchosts.Record, 0, len(sb.config.extraHosts)) + for _, extraHost := range sb.config.extraHosts { + extraContent = append(extraContent, etchosts.Record{Hosts: extraHost.name, IP: extraHost.IP}) + } + + return etchosts.Build(sb.config.hostsPath, "", sb.config.hostName, sb.config.domainName, extraContent) +} + +func (sb *sandbox) updateHostsFile(ifaceIP string, svcRecords []etchosts.Record) error { + if sb.config.originHostsPath != "" { + return nil + } + + // Rebuild the hosts file accounting for the passed interface IP and service records + extraContent := make([]etchosts.Record, 0, len(sb.config.extraHosts)+len(svcRecords)) + + for _, extraHost := range sb.config.extraHosts { + extraContent = append(extraContent, etchosts.Record{Hosts: extraHost.name, IP: extraHost.IP}) + } + + for _, svc := range svcRecords { + extraContent = append(extraContent, svc) + } + + return etchosts.Build(sb.config.hostsPath, ifaceIP, sb.config.hostName, sb.config.domainName, extraContent) +} + +func (sb *sandbox) addHostsEntries(recs []etchosts.Record) { + if err := etchosts.Add(sb.config.hostsPath, recs); err != nil { + log.Warnf("Failed adding service host entries to the running container: %v", err) + } +} + +func (sb *sandbox) deleteHostsEntries(recs []etchosts.Record) { + if err := etchosts.Delete(sb.config.hostsPath, recs); err != nil { + log.Warnf("Failed deleting service host entries to the running container: %v", err) + } +} + +func (sb *sandbox) updateParentHosts() error { + var pSb Sandbox + + for _, update := range sb.config.parentUpdates { + sb.controller.WalkSandboxes(SandboxContainerWalker(&pSb, update.cid)) + if pSb == nil { + continue + } + if err := etchosts.Update(pSb.(*sandbox).config.hostsPath, update.ip, update.name); err != nil { + return err + } + } + + return nil +} + +func (sb *sandbox) setupDNS() error { + var newRC *resolvconf.File + + if sb.config.resolvConfPath == "" { + sb.config.resolvConfPath = defaultPrefix + "/" + sb.id + "/resolv.conf" + } + + sb.config.resolvConfHashFile = sb.config.resolvConfPath + ".hash" + + dir, _ := filepath.Split(sb.config.resolvConfPath) + if err := createBasePath(dir); err != nil { + return err + } + + // This is for the host mode networking + if sb.config.originResolvConfPath != "" { + if err := copyFile(sb.config.originResolvConfPath, sb.config.resolvConfPath); err != nil { + return fmt.Errorf("could not copy source resolv.conf file %s to %s: %v", sb.config.originResolvConfPath, sb.config.resolvConfPath, err) + } + return nil + } + + currRC, err := resolvconf.Get() + if err != nil { + return err + } + + if len(sb.config.dnsList) > 0 || len(sb.config.dnsSearchList) > 0 || len(sb.config.dnsOptionsList) > 0 { + var ( + err error + dnsList = resolvconf.GetNameservers(currRC.Content) + dnsSearchList = resolvconf.GetSearchDomains(currRC.Content) + dnsOptionsList = resolvconf.GetOptions(currRC.Content) + ) + if len(sb.config.dnsList) > 0 { + dnsList = sb.config.dnsList + } + if len(sb.config.dnsSearchList) > 0 { + dnsSearchList = sb.config.dnsSearchList + } + if len(sb.config.dnsOptionsList) > 0 { + dnsOptionsList = sb.config.dnsOptionsList + } + newRC, err = resolvconf.Build(sb.config.resolvConfPath, dnsList, dnsSearchList, dnsOptionsList) + if err != nil { + return err + } + } else { + // Replace any localhost/127.* (at this point we have no info about ipv6, pass it as true) + if newRC, err = resolvconf.FilterResolvDNS(currRC.Content, true); err != nil { + return err + } + // No contention on container resolv.conf file at sandbox creation + if err := ioutil.WriteFile(sb.config.resolvConfPath, newRC.Content, filePerm); err != nil { + return types.InternalErrorf("failed to write unhaltered resolv.conf file content when setting up dns for sandbox %s: %v", sb.ID(), err) + } + } + + // Write hash + if err := ioutil.WriteFile(sb.config.resolvConfHashFile, []byte(newRC.Hash), filePerm); err != nil { + return types.InternalErrorf("failed to write resolv.conf hash file when setting up dns for sandbox %s: %v", sb.ID(), err) + } + + return nil +} + +func (sb *sandbox) updateDNS(ipv6Enabled bool) error { + var ( + currHash string + hashFile = sb.config.resolvConfHashFile + ) + + if len(sb.config.dnsList) > 0 || len(sb.config.dnsSearchList) > 0 || len(sb.config.dnsOptionsList) > 0 { + return nil + } + + currRC, err := resolvconf.GetSpecific(sb.config.resolvConfPath) + if err != nil { + if !os.IsNotExist(err) { + return err + } + } else { + h, err := ioutil.ReadFile(hashFile) + if err != nil { + if !os.IsNotExist(err) { + return err + } + } else { + currHash = string(h) + } + } + + if currHash != "" && currHash != currRC.Hash { + // Seems the user has changed the container resolv.conf since the last time + // we checked so return without doing anything. + log.Infof("Skipping update of resolv.conf file with ipv6Enabled: %t because file was touched by user", ipv6Enabled) + return nil + } + + // replace any localhost/127.* and remove IPv6 nameservers if IPv6 disabled. + newRC, err := resolvconf.FilterResolvDNS(currRC.Content, ipv6Enabled) + if err != nil { + return err + } + + // for atomic updates to these files, use temporary files with os.Rename: + dir := path.Dir(sb.config.resolvConfPath) + tmpHashFile, err := ioutil.TempFile(dir, "hash") + if err != nil { + return err + } + tmpResolvFile, err := ioutil.TempFile(dir, "resolv") + if err != nil { + return err + } + + // Change the perms to filePerm (0644) since ioutil.TempFile creates it by default as 0600 + if err := os.Chmod(tmpResolvFile.Name(), filePerm); err != nil { + return err + } + + // write the updates to the temp files + if err = ioutil.WriteFile(tmpHashFile.Name(), []byte(newRC.Hash), filePerm); err != nil { + return err + } + if err = ioutil.WriteFile(tmpResolvFile.Name(), newRC.Content, filePerm); err != nil { + return err + } + + // rename the temp files for atomic replace + if err = os.Rename(tmpHashFile.Name(), hashFile); err != nil { + return err + } + return os.Rename(tmpResolvFile.Name(), sb.config.resolvConfPath) +} + +// OptionHostname function returns an option setter for hostname option to +// be passed to NewSandbox method. +func OptionHostname(name string) SandboxOption { + return func(sb *sandbox) { + sb.config.hostName = name + } +} + +// OptionDomainname function returns an option setter for domainname option to +// be passed to NewSandbox method. +func OptionDomainname(name string) SandboxOption { + return func(sb *sandbox) { + sb.config.domainName = name + } +} + +// OptionHostsPath function returns an option setter for hostspath option to +// be passed to NewSandbox method. +func OptionHostsPath(path string) SandboxOption { + return func(sb *sandbox) { + sb.config.hostsPath = path + } +} + +// OptionOriginHostsPath function returns an option setter for origin hosts file path +// tbeo passed to NewSandbox method. +func OptionOriginHostsPath(path string) SandboxOption { + return func(sb *sandbox) { + sb.config.originHostsPath = path + } +} + +// OptionExtraHost function returns an option setter for extra /etc/hosts options +// which is a name and IP as strings. +func OptionExtraHost(name string, IP string) SandboxOption { + return func(sb *sandbox) { + sb.config.extraHosts = append(sb.config.extraHosts, extraHost{name: name, IP: IP}) + } +} + +// OptionParentUpdate function returns an option setter for parent container +// which needs to update the IP address for the linked container. +func OptionParentUpdate(cid string, name, ip string) SandboxOption { + return func(sb *sandbox) { + sb.config.parentUpdates = append(sb.config.parentUpdates, parentUpdate{cid: cid, name: name, ip: ip}) + } +} + +// OptionResolvConfPath function returns an option setter for resolvconfpath option to +// be passed to net container methods. +func OptionResolvConfPath(path string) SandboxOption { + return func(sb *sandbox) { + sb.config.resolvConfPath = path + } +} + +// OptionOriginResolvConfPath function returns an option setter to set the path to the +// origin resolv.conf file to be passed to net container methods. +func OptionOriginResolvConfPath(path string) SandboxOption { + return func(sb *sandbox) { + sb.config.originResolvConfPath = path + } +} + +// OptionDNS function returns an option setter for dns entry option to +// be passed to container Create method. +func OptionDNS(dns string) SandboxOption { + return func(sb *sandbox) { + sb.config.dnsList = append(sb.config.dnsList, dns) + } +} + +// OptionDNSSearch function returns an option setter for dns search entry option to +// be passed to container Create method. +func OptionDNSSearch(search string) SandboxOption { + return func(sb *sandbox) { + sb.config.dnsSearchList = append(sb.config.dnsSearchList, search) + } +} + +// OptionDNSOptions function returns an option setter for dns options entry option to +// be passed to container Create method. +func OptionDNSOptions(options string) SandboxOption { + return func(sb *sandbox) { + sb.config.dnsOptionsList = append(sb.config.dnsOptionsList, options) + } +} + +// OptionUseDefaultSandbox function returns an option setter for using default sandbox to +// be passed to container Create method. +func OptionUseDefaultSandbox() SandboxOption { + return func(sb *sandbox) { + sb.config.useDefaultSandBox = true + } +} + +// OptionGeneric function returns an option setter for Generic configuration +// that is not managed by libNetwork but can be used by the Drivers during the call to +// net container creation method. Container Labels are a good example. +func OptionGeneric(generic map[string]interface{}) SandboxOption { + return func(sb *sandbox) { + sb.config.generic = generic + } +} + +func (eh epHeap) Len() int { return len(eh) } + +func (eh epHeap) Less(i, j int) bool { + ci, _ := eh[i].getSandbox() + cj, _ := eh[j].getSandbox() + + cip, ok := ci.epPriority[eh[i].ID()] + if !ok { + cip = 0 + } + cjp, ok := cj.epPriority[eh[j].ID()] + if !ok { + cjp = 0 + } + if cip == cjp { + return eh[i].getNetwork().Name() < eh[j].getNetwork().Name() + } + + return cip > cjp +} + +func (eh epHeap) Swap(i, j int) { eh[i], eh[j] = eh[j], eh[i] } + +func (eh *epHeap) Push(x interface{}) { + *eh = append(*eh, x.(*endpoint)) +} + +func (eh *epHeap) Pop() interface{} { + old := *eh + n := len(old) + x := old[n-1] + *eh = old[0 : n-1] + return x +} + +func createBasePath(dir string) error { + return os.MkdirAll(dir, filePerm) +} + +func createFile(path string) error { + var f *os.File + + dir, _ := filepath.Split(path) + err := createBasePath(dir) + if err != nil { + return err + } + + f, err = os.Create(path) + if err == nil { + f.Close() + } + + return err +} + +func copyFile(src, dst string) error { + sBytes, err := ioutil.ReadFile(src) + if err != nil { + return err + } + return ioutil.WriteFile(dst, sBytes, filePerm) +} diff --git a/vendor/src/github.com/docker/libnetwork/sandboxdata.go b/vendor/src/github.com/docker/libnetwork/sandboxdata.go deleted file mode 100644 index 9b0d8ea1bf..0000000000 --- a/vendor/src/github.com/docker/libnetwork/sandboxdata.go +++ /dev/null @@ -1,259 +0,0 @@ -package libnetwork - -import ( - "container/heap" - "fmt" - "sync" - - "github.com/Sirupsen/logrus" - "github.com/docker/libnetwork/sandbox" -) - -type epHeap []*endpoint - -type sandboxData struct { - sbox sandbox.Sandbox - refCnt int - endpoints epHeap - sync.Mutex -} - -func (eh epHeap) Len() int { return len(eh) } - -func (eh epHeap) Less(i, j int) bool { - eh[i].Lock() - eh[j].Lock() - defer eh[j].Unlock() - defer eh[i].Unlock() - - if eh[i].container.config.prio == eh[j].container.config.prio { - return eh[i].network.Name() < eh[j].network.Name() - } - - return eh[i].container.config.prio > eh[j].container.config.prio -} - -func (eh epHeap) Swap(i, j int) { eh[i], eh[j] = eh[j], eh[i] } - -func (eh *epHeap) Push(x interface{}) { - *eh = append(*eh, x.(*endpoint)) -} - -func (eh *epHeap) Pop() interface{} { - old := *eh - n := len(old) - x := old[n-1] - *eh = old[0 : n-1] - return x -} - -func (s *sandboxData) updateGateway(ep *endpoint) error { - sb := s.sandbox() - - sb.UnsetGateway() - sb.UnsetGatewayIPv6() - - if ep == nil { - return nil - } - - ep.Lock() - joinInfo := ep.joinInfo - ep.Unlock() - - if err := sb.SetGateway(joinInfo.gw); err != nil { - return fmt.Errorf("failed to set gateway while updating gateway: %v", err) - } - - if err := sb.SetGatewayIPv6(joinInfo.gw6); err != nil { - return fmt.Errorf("failed to set IPv6 gateway while updating gateway: %v", err) - } - - return nil -} - -func (s *sandboxData) addEndpoint(ep *endpoint) error { - ep.Lock() - joinInfo := ep.joinInfo - ifaces := ep.iFaces - ep.Unlock() - - sb := s.sandbox() - for _, i := range ifaces { - var ifaceOptions []sandbox.IfaceOption - - ifaceOptions = append(ifaceOptions, sb.InterfaceOptions().Address(&i.addr), - sb.InterfaceOptions().Routes(i.routes)) - if i.addrv6.IP.To16() != nil { - ifaceOptions = append(ifaceOptions, - sb.InterfaceOptions().AddressIPv6(&i.addrv6)) - } - - if err := sb.AddInterface(i.srcName, i.dstPrefix, ifaceOptions...); err != nil { - return fmt.Errorf("failed to add interface %s to sandbox: %v", i.srcName, err) - } - } - - if joinInfo != nil { - // Set up non-interface routes. - for _, r := range ep.joinInfo.StaticRoutes { - if err := sb.AddStaticRoute(r); err != nil { - return fmt.Errorf("failed to add static route %s: %v", r.Destination.String(), err) - } - } - } - - s.Lock() - heap.Push(&s.endpoints, ep) - highEp := s.endpoints[0] - s.Unlock() - - if ep == highEp { - if err := s.updateGateway(ep); err != nil { - return err - } - } - - return nil -} - -func (s *sandboxData) rmEndpoint(ep *endpoint) { - ep.Lock() - joinInfo := ep.joinInfo - ep.Unlock() - - sb := s.sandbox() - for _, i := range sb.Info().Interfaces() { - // Only remove the interfaces owned by this endpoint from the sandbox. - if ep.hasInterface(i.SrcName()) { - if err := i.Remove(); err != nil { - logrus.Debugf("Remove interface failed: %v", err) - } - } - } - - // Remove non-interface routes. - for _, r := range joinInfo.StaticRoutes { - if err := sb.RemoveStaticRoute(r); err != nil { - logrus.Debugf("Remove route failed: %v", err) - } - } - - s.Lock() - if len(s.endpoints) == 0 { - // s.endpoints should never be empty and this is unexpected error condition - // We log an error message to note this down for debugging purposes. - logrus.Errorf("No endpoints in sandbox while trying to remove endpoint %s", ep.Name()) - s.Unlock() - return - } - - highEpBefore := s.endpoints[0] - var ( - i int - e *endpoint - ) - for i, e = range s.endpoints { - if e == ep { - break - } - } - heap.Remove(&s.endpoints, i) - var highEpAfter *endpoint - if len(s.endpoints) > 0 { - highEpAfter = s.endpoints[0] - } - - s.Unlock() - - if highEpBefore != highEpAfter { - s.updateGateway(highEpAfter) - } -} - -func (s *sandboxData) sandbox() sandbox.Sandbox { - s.Lock() - defer s.Unlock() - - return s.sbox -} - -func (c *controller) sandboxAdd(key string, create bool, ep *endpoint) (sandbox.Sandbox, error) { - c.Lock() - sData, ok := c.sandboxes[key] - c.Unlock() - - if !ok { - sb, err := sandbox.NewSandbox(key, create) - if err != nil { - return nil, fmt.Errorf("failed to create new sandbox: %v", err) - } - - sData = &sandboxData{ - sbox: sb, - endpoints: epHeap{}, - } - - heap.Init(&sData.endpoints) - c.Lock() - c.sandboxes[key] = sData - c.Unlock() - } - - if err := sData.addEndpoint(ep); err != nil { - return nil, err - } - - return sData.sandbox(), nil -} - -func (c *controller) sandboxRm(key string, ep *endpoint) { - c.Lock() - sData := c.sandboxes[key] - c.Unlock() - - sData.rmEndpoint(ep) -} - -func (c *controller) sandboxGet(key string) sandbox.Sandbox { - c.Lock() - sData, ok := c.sandboxes[key] - c.Unlock() - - if !ok { - return nil - } - - return sData.sandbox() -} - -func (c *controller) LeaveAll(id string) error { - c.Lock() - sData, ok := c.sandboxes[sandbox.GenerateKey(id)] - c.Unlock() - - if !ok { - return fmt.Errorf("could not find sandbox for container id %s", id) - } - - sData.Lock() - eps := make([]*endpoint, len(sData.endpoints)) - for i, ep := range sData.endpoints { - eps[i] = ep - } - sData.Unlock() - - for _, ep := range eps { - if err := ep.Leave(id); err != nil { - logrus.Warnf("Failed leaving endpoint id %s: %v\n", ep.ID(), err) - } - } - - sData.sandbox().Destroy() - - c.Lock() - delete(c.sandboxes, sandbox.GenerateKey(id)) - c.Unlock() - - return nil -} diff --git a/vendor/src/github.com/docker/libnetwork/store.go b/vendor/src/github.com/docker/libnetwork/store.go index a832adf01b..e14aa72b01 100644 --- a/vendor/src/github.com/docker/libnetwork/store.go +++ b/vendor/src/github.com/docker/libnetwork/store.go @@ -7,7 +7,6 @@ import ( log "github.com/Sirupsen/logrus" "github.com/docker/libkv/store" "github.com/docker/libnetwork/datastore" - "github.com/docker/libnetwork/types" ) func (c *controller) validateDatastoreConfig() bool { @@ -91,7 +90,7 @@ func (c *controller) deleteNetworkFromStore(n *network) error { return nil } -func (c *controller) getNetworkFromStore(nid types.UUID) (*network, error) { +func (c *controller) getNetworkFromStore(nid string) (*network, error) { n := network{id: nid} if err := c.store.GetObject(datastore.Key(n.Key()...), &n); err != nil { return nil, err @@ -105,7 +104,7 @@ func (c *controller) newEndpointFromStore(key string, ep *endpoint) error { id := ep.id ep.Unlock() - _, err := n.EndpointByID(string(id)) + _, err := n.EndpointByID(id) if err != nil { if _, ok := err.(ErrNoSuchEndpoint); ok { return n.addEndpoint(ep) @@ -134,7 +133,7 @@ func (c *controller) updateEndpointToStore(ep *endpoint) error { return cs.PutObjectAtomic(ep) } -func (c *controller) getEndpointFromStore(eid types.UUID) (*endpoint, error) { +func (c *controller) getEndpointFromStore(eid string) (*endpoint, error) { ep := endpoint{id: eid} if err := c.store.GetObject(datastore.Key(ep.Key()...), &ep); err != nil { return nil, err @@ -346,7 +345,7 @@ func (c *controller) processEndpointUpdate(ep *endpoint) bool { if !ok { return true } - existing, _ := n.EndpointByID(string(ep.id)) + existing, _ := n.EndpointByID(ep.id) if existing == nil { return true } @@ -357,13 +356,7 @@ func (c *controller) processEndpointUpdate(ep *endpoint) bool { // Can't use SetIndex() because ee is locked. ee.dbIndex = ep.Index() ee.dbExists = true - if ee.container != nil && ep.container != nil { - // we care only about the container id - ee.container.id = ep.container.id - } else { - // we still care only about the container id, but this is a short-cut to communicate join or leave operation - ee.container = ep.container - } + ee.sandboxID = ep.sandboxID } ee.Unlock() diff --git a/vendor/src/github.com/docker/libnetwork/types/types.go b/vendor/src/github.com/docker/libnetwork/types/types.go index 3f394baa19..176f40d0f1 100644 --- a/vendor/src/github.com/docker/libnetwork/types/types.go +++ b/vendor/src/github.com/docker/libnetwork/types/types.go @@ -197,6 +197,59 @@ func CompareIPNet(a, b *net.IPNet) bool { return a.IP.Equal(b.IP) && bytes.Equal(a.Mask, b.Mask) } +// GetMinimalIP returns the address in its shortest form +func GetMinimalIP(ip net.IP) net.IP { + if ip != nil && ip.To4() != nil { + return ip.To4() + } + return ip +} + +// GetMinimalIPNet returns a copy of the passed IP Network with congruent ip and mask notation +func GetMinimalIPNet(nw *net.IPNet) *net.IPNet { + if nw == nil { + return nil + } + if len(nw.IP) == 16 && nw.IP.To4() != nil { + m := nw.Mask + if len(m) == 16 { + m = m[12:16] + } + return &net.IPNet{IP: nw.IP.To4(), Mask: m} + } + return nw +} + +var v4inV6MaskPrefix = []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} + +// GetHostPartIP returns the host portion of the ip address identified by the mask. +// IP address representation is not modified. If address and mask are not compatible +// an error is returned. +func GetHostPartIP(ip net.IP, mask net.IPMask) (net.IP, error) { + // Find the effective starting of address and mask + is := 0 + ms := 0 + if len(ip) == net.IPv6len && ip.To4() != nil { + is = 12 + } + if len(ip[is:]) == net.IPv4len && len(mask) == net.IPv6len && bytes.Equal(mask[:12], v4inV6MaskPrefix) { + ms = 12 + } + + // Check if address and mask are semantically compatible + if len(ip[is:]) != len(mask[ms:]) { + return nil, fmt.Errorf("cannot compute host portion ip address as ip and mask are not compatible: (%#v, %#v)", ip, mask) + } + + // Compute host portion + out := GetIPCopy(ip) + for i := 0; i < len(mask[ms:]); i++ { + out[is+i] &= ^mask[ms+i] + } + + return out, nil +} + const ( // NEXTHOP indicates a StaticRoute with an IP next hop. NEXTHOP = iota diff --git a/vendor/src/github.com/docker/libnetwork/wrapmake.sh b/vendor/src/github.com/docker/libnetwork/wrapmake.sh new file mode 100755 index 0000000000..d1a51a845f --- /dev/null +++ b/vendor/src/github.com/docker/libnetwork/wrapmake.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +set -e + +function raise() +{ + kill -$1 0 +} + +trap "raise SIGINT" SIGINT +make $1 From 56fdb05258d1ab2153fec268ed22cf9d1227c356 Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Wed, 2 Sep 2015 16:43:28 -0700 Subject: [PATCH 2/2] Docker changes for libnetwork Sandbox - Ground-work for integrating with user namespace support Signed-off-by: Alessandro Boch --- daemon/container_unix.go | 119 ++++++++++++---------- daemon/network/settings.go | 1 + daemon/stats.go | 12 +-- integration-cli/docker_cli_daemon_test.go | 19 ++-- integration-cli/docker_cli_run_test.go | 8 +- 5 files changed, 85 insertions(+), 74 deletions(-) diff --git a/daemon/container_unix.go b/daemon/container_unix.go index 722b25dc18..f3ae95dcf2 100644 --- a/daemon/container_unix.go +++ b/daemon/container_unix.go @@ -392,32 +392,34 @@ func (container *Container) buildHostnameFile() error { return ioutil.WriteFile(container.HostnamePath, []byte(container.Config.Hostname+"\n"), 0644) } -func (container *Container) buildJoinOptions() ([]libnetwork.EndpointOption, error) { +func (container *Container) buildSandboxOptions() ([]libnetwork.SandboxOption, error) { var ( - joinOptions []libnetwork.EndpointOption + sboxOptions []libnetwork.SandboxOption err error dns []string dnsSearch []string ) - joinOptions = append(joinOptions, libnetwork.JoinOptionHostname(container.Config.Hostname), - libnetwork.JoinOptionDomainname(container.Config.Domainname)) + sboxOptions = append(sboxOptions, libnetwork.OptionHostname(container.Config.Hostname), + libnetwork.OptionDomainname(container.Config.Domainname)) if container.hostConfig.NetworkMode.IsHost() { - joinOptions = append(joinOptions, libnetwork.JoinOptionUseDefaultSandbox()) + sboxOptions = append(sboxOptions, libnetwork.OptionUseDefaultSandbox()) + sboxOptions = append(sboxOptions, libnetwork.OptionOriginHostsPath("/etc/hosts")) + sboxOptions = append(sboxOptions, libnetwork.OptionOriginResolvConfPath("/etc/resolv.conf")) } container.HostsPath, err = container.getRootResourcePath("hosts") if err != nil { return nil, err } - joinOptions = append(joinOptions, libnetwork.JoinOptionHostsPath(container.HostsPath)) + sboxOptions = append(sboxOptions, libnetwork.OptionHostsPath(container.HostsPath)) container.ResolvConfPath, err = container.getRootResourcePath("resolv.conf") if err != nil { return nil, err } - joinOptions = append(joinOptions, libnetwork.JoinOptionResolvConfPath(container.ResolvConfPath)) + sboxOptions = append(sboxOptions, libnetwork.OptionResolvConfPath(container.ResolvConfPath)) if len(container.hostConfig.DNS) > 0 { dns = container.hostConfig.DNS @@ -426,7 +428,7 @@ func (container *Container) buildJoinOptions() ([]libnetwork.EndpointOption, err } for _, d := range dns { - joinOptions = append(joinOptions, libnetwork.JoinOptionDNS(d)) + sboxOptions = append(sboxOptions, libnetwork.OptionDNS(d)) } if len(container.hostConfig.DNSSearch) > 0 { @@ -436,7 +438,7 @@ func (container *Container) buildJoinOptions() ([]libnetwork.EndpointOption, err } for _, ds := range dnsSearch { - joinOptions = append(joinOptions, libnetwork.JoinOptionDNSSearch(ds)) + sboxOptions = append(sboxOptions, libnetwork.OptionDNSSearch(ds)) } if container.NetworkSettings.SecondaryIPAddresses != nil { @@ -446,7 +448,7 @@ func (container *Container) buildJoinOptions() ([]libnetwork.EndpointOption, err } for _, a := range container.NetworkSettings.SecondaryIPAddresses { - joinOptions = append(joinOptions, libnetwork.JoinOptionExtraHost(name, a.Addr)) + sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(name, a.Addr)) } } @@ -465,7 +467,7 @@ func (container *Container) buildJoinOptions() ([]libnetwork.EndpointOption, err if alias != child.Name[1:] { aliasList = aliasList + " " + child.Name[1:] } - joinOptions = append(joinOptions, libnetwork.JoinOptionExtraHost(aliasList, child.NetworkSettings.IPAddress)) + sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(aliasList, child.NetworkSettings.IPAddress)) if child.NetworkSettings.EndpointID != "" { childEndpoints = append(childEndpoints, child.NetworkSettings.EndpointID) } @@ -474,7 +476,7 @@ func (container *Container) buildJoinOptions() ([]libnetwork.EndpointOption, err for _, extraHost := range container.hostConfig.ExtraHosts { // allow IPv6 addresses in extra hosts; only split on first ":" parts := strings.SplitN(extraHost, ":", 2) - joinOptions = append(joinOptions, libnetwork.JoinOptionExtraHost(parts[0], parts[1])) + sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(parts[0], parts[1])) } refs := container.daemon.containerGraph().RefPaths(container.ID) @@ -490,7 +492,7 @@ func (container *Container) buildJoinOptions() ([]libnetwork.EndpointOption, err if c != nil && !container.daemon.configStore.DisableBridge && container.hostConfig.NetworkMode.IsPrivate() { logrus.Debugf("Update /etc/hosts of %s for alias %s with ip %s", c.ID, ref.Name, container.NetworkSettings.IPAddress) - joinOptions = append(joinOptions, libnetwork.JoinOptionParentUpdate(c.NetworkSettings.EndpointID, ref.Name, container.NetworkSettings.IPAddress)) + sboxOptions = append(sboxOptions, libnetwork.OptionParentUpdate(c.ID, ref.Name, container.NetworkSettings.IPAddress)) if c.NetworkSettings.EndpointID != "" { parentEndpoints = append(parentEndpoints, c.NetworkSettings.EndpointID) } @@ -504,9 +506,9 @@ func (container *Container) buildJoinOptions() ([]libnetwork.EndpointOption, err }, } - joinOptions = append(joinOptions, libnetwork.JoinOptionGeneric(linkOptions)) + sboxOptions = append(sboxOptions, libnetwork.OptionGeneric(linkOptions)) - return joinOptions, nil + return sboxOptions, nil } func (container *Container) buildPortMapInfo(n libnetwork.Network, ep libnetwork.Endpoint, networkSettings *network.Settings) (*network.Settings, error) { @@ -630,12 +632,10 @@ func (container *Container) updateJoinInfo(ep libnetwork.Endpoint) error { container.NetworkSettings.IPv6Gateway = epInfo.GatewayIPv6().String() } - container.NetworkSettings.SandboxKey = epInfo.SandboxKey() - return nil } -func (container *Container) updateNetworkSettings(n libnetwork.Network, ep libnetwork.Endpoint) error { +func (container *Container) updateEndpointNetworkSettings(n libnetwork.Network, ep libnetwork.Endpoint) error { networkSettings := &network.Settings{NetworkID: n.ID(), EndpointID: ep.ID()} networkSettings, err := container.buildPortMapInfo(n, ep, networkSettings) @@ -656,35 +656,30 @@ func (container *Container) updateNetworkSettings(n libnetwork.Network, ep libne return nil } +func (container *Container) updateSandboxNetworkSettings(sb libnetwork.Sandbox) error { + container.NetworkSettings.SandboxID = sb.ID() + container.NetworkSettings.SandboxKey = sb.Key() + return nil +} + // UpdateNetwork is used to update the container's network (e.g. when linked containers // get removed/unlinked). func (container *Container) updateNetwork() error { - n, err := container.daemon.netController.NetworkByID(container.NetworkSettings.NetworkID) + ctrl := container.daemon.netController + sid := container.NetworkSettings.SandboxID + + sb, err := ctrl.SandboxByID(sid) if err != nil { - return fmt.Errorf("error locating network id %s: %v", container.NetworkSettings.NetworkID, err) + return fmt.Errorf("error locating sandbox id %s: %v", sid, err) } - ep, err := n.EndpointByID(container.NetworkSettings.EndpointID) - if err != nil { - return fmt.Errorf("error locating endpoint id %s: %v", container.NetworkSettings.EndpointID, err) - } - - if err := ep.Leave(container.ID); err != nil { - return fmt.Errorf("endpoint leave failed: %v", err) - - } - - joinOptions, err := container.buildJoinOptions() + options, err := container.buildSandboxOptions() if err != nil { return fmt.Errorf("Update network failed: %v", err) } - if err := ep.Join(container.ID, joinOptions...); err != nil { - return fmt.Errorf("endpoint join failed: %v", err) - } - - if err := container.updateJoinInfo(ep); err != nil { - return fmt.Errorf("Updating join info failed: %v", err) + if err := sb.Refresh(options...); err != nil { + return fmt.Errorf("Update network failed: Failure in refresh sandbox %s: %v", sid, err) } return nil @@ -871,6 +866,7 @@ func (container *Container) allocateNetwork() error { func (container *Container) configureNetwork(networkName, service, networkDriver string, canCreateNetwork bool) error { controller := container.daemon.netController + n, err := controller.NetworkByName(networkName) if err != nil { if _, ok := err.(libnetwork.ErrNoSuchNetwork); !ok || !canCreateNetwork { @@ -899,16 +895,32 @@ func (container *Container) configureNetwork(networkName, service, networkDriver } } - if err := container.updateNetworkSettings(n, ep); err != nil { + if err := container.updateEndpointNetworkSettings(n, ep); err != nil { return err } - joinOptions, err := container.buildJoinOptions() - if err != nil { - return err + var sb libnetwork.Sandbox + controller.WalkSandboxes(func(s libnetwork.Sandbox) bool { + if s.ContainerID() == container.ID { + sb = s + return true + } + return false + }) + if sb == nil { + options, err := container.buildSandboxOptions() + if err != nil { + return err + } + sb, err = controller.NewSandbox(container.ID, options...) + if err != nil { + return err + } } - if err := ep.Join(container.ID, joinOptions...); err != nil { + container.updateSandboxNetworkSettings(sb) + + if err := ep.Join(sb); err != nil { return err } @@ -1038,12 +1050,19 @@ func (container *Container) releaseNetwork() { return } + sid := container.NetworkSettings.SandboxID eid := container.NetworkSettings.EndpointID nid := container.NetworkSettings.NetworkID container.NetworkSettings = &network.Settings{} - if nid == "" || eid == "" { + if sid == "" || nid == "" || eid == "" { + return + } + + sb, err := container.daemon.netController.SandboxByID(sid) + if err != nil { + logrus.Errorf("error locating sandbox id %s: %v", sid, err) return } @@ -1059,17 +1078,9 @@ func (container *Container) releaseNetwork() { return } - switch { - case container.hostConfig.NetworkMode.IsHost(): - if err := ep.Leave(container.ID); err != nil { - logrus.Errorf("Error leaving endpoint id %s for container %s: %v", eid, container.ID, err) - return - } - default: - if err := container.daemon.netController.LeaveAll(container.ID); err != nil { - logrus.Errorf("Leave all failed for %s: %v", container.ID, err) - return - } + if err := sb.Delete(); err != nil { + logrus.Errorf("Error deleting sandbox id %s for container %s: %v", sid, container.ID, err) + return } // In addition to leaving all endpoints, delete implicitly created endpoint diff --git a/daemon/network/settings.go b/daemon/network/settings.go index df4822f6c3..725b399c31 100644 --- a/daemon/network/settings.go +++ b/daemon/network/settings.go @@ -13,6 +13,7 @@ type Address struct { type Settings struct { Bridge string EndpointID string + SandboxID string Gateway string GlobalIPv6Address string GlobalIPv6PrefixLen int diff --git a/daemon/stats.go b/daemon/stats.go index b31b8ba993..aa356633b7 100644 --- a/daemon/stats.go +++ b/daemon/stats.go @@ -6,7 +6,7 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/docker/daemon/execdriver" - "github.com/docker/libnetwork/sandbox" + "github.com/docker/libnetwork/osl" "github.com/opencontainers/runc/libcontainer" ) @@ -86,16 +86,12 @@ func (daemon *Daemon) getNetworkStats(name string) ([]*libcontainer.NetworkInter return list, err } - nw, err := daemon.netController.NetworkByID(c.NetworkSettings.NetworkID) - if err != nil { - return list, err - } - ep, err := nw.EndpointByID(c.NetworkSettings.EndpointID) + sb, err := daemon.netController.SandboxByID(c.NetworkSettings.SandboxID) if err != nil { return list, err } - stats, err := ep.Statistics() + stats, err := sb.Statistics() if err != nil { return list, err } @@ -108,7 +104,7 @@ func (daemon *Daemon) getNetworkStats(name string) ([]*libcontainer.NetworkInter return list, nil } -func convertLnNetworkStats(name string, stats *sandbox.InterfaceStatistics) *libcontainer.NetworkInterface { +func convertLnNetworkStats(name string, stats *osl.InterfaceStatistics) *libcontainer.NetworkInterface { n := &libcontainer.NetworkInterface{Name: name} n.RxBytes = stats.RxBytes n.RxPackets = stats.RxPackets diff --git a/integration-cli/docker_cli_daemon_test.go b/integration-cli/docker_cli_daemon_test.go index dea981edbb..46843c596e 100644 --- a/integration-cli/docker_cli_daemon_test.go +++ b/integration-cli/docker_cli_daemon_test.go @@ -1524,19 +1524,23 @@ func (s *DockerDaemonSuite) TestDaemonRestartCleanupNetns(c *check.C) { if err != nil { c.Fatal(out, err) } + + // Get sandbox key via inspect + out, err = s.d.Cmd("inspect", "--format", "'{{.NetworkSettings.SandboxKey}}'", "netns") + if err != nil { + c.Fatalf("Error inspecting container: %s, %v", out, err) + } + fileName := strings.Trim(out, " \r\n'") + if out, err := s.d.Cmd("stop", "netns"); err != nil { c.Fatal(out, err) } - // Construct netns file name from container id - out = strings.TrimSpace(out) - nsFile := out[:12] - // Test if the file still exists - out, _, err = runCommandWithOutput(exec.Command("stat", "-c", "%n", "/var/run/docker/netns/"+nsFile)) + out, _, err = runCommandWithOutput(exec.Command("stat", "-c", "%n", fileName)) out = strings.TrimSpace(out) c.Assert(err, check.IsNil, check.Commentf("Output: %s", out)) - c.Assert(out, check.Equals, "/var/run/docker/netns/"+nsFile, check.Commentf("Output: %s", out)) + c.Assert(out, check.Equals, fileName, check.Commentf("Output: %s", out)) // Remove the container and restart the daemon if out, err := s.d.Cmd("rm", "netns"); err != nil { @@ -1548,10 +1552,9 @@ func (s *DockerDaemonSuite) TestDaemonRestartCleanupNetns(c *check.C) { } // Test again and see now the netns file does not exist - out, _, err = runCommandWithOutput(exec.Command("stat", "-c", "%n", "/var/run/docker/netns/"+nsFile)) + out, _, err = runCommandWithOutput(exec.Command("stat", "-c", "%n", fileName)) out = strings.TrimSpace(out) c.Assert(err, check.Not(check.IsNil), check.Commentf("Output: %s", out)) - // c.Assert(out, check.Equals, "", check.Commentf("Output: %s", out)) } // tests regression detailed in #13964 where DOCKER_TLS_VERIFY env is ignored diff --git a/integration-cli/docker_cli_run_test.go b/integration-cli/docker_cli_run_test.go index 64da7c2c29..dab5edf748 100644 --- a/integration-cli/docker_cli_run_test.go +++ b/integration-cli/docker_cli_run_test.go @@ -865,7 +865,7 @@ func (s *DockerSuite) TestRunDnsDefaultOptions(c *check.C) { // check that the actual defaults are appended to the commented out // localhost resolver (which should be preserved) // NOTE: if we ever change the defaults from google dns, this will break - expected := "#nameserver 127.0.2.1\n\nnameserver 8.8.8.8\nnameserver 8.8.4.4" + expected := "#nameserver 127.0.2.1\n\nnameserver 8.8.8.8\nnameserver 8.8.4.4\n" if actual != expected { c.Fatalf("expected resolv.conf be: %q, but was: %q", expected, actual) } @@ -880,7 +880,7 @@ func (s *DockerSuite) TestRunDnsOptions(c *check.C) { } actual := strings.Replace(strings.Trim(out, "\r\n"), "\n", " ", -1) - if actual != "nameserver 127.0.0.1 search mydomain" { + if actual != "search mydomain nameserver 127.0.0.1" { c.Fatalf("expected 'nameserver 127.0.0.1 search mydomain', but says: %q", actual) } @@ -1001,7 +1001,7 @@ func (s *DockerSuite) TestRunNonRootUserResolvName(c *check.C) { func (s *DockerSuite) TestRunResolvconfUpdate(c *check.C) { testRequires(c, SameHostDaemon) - tmpResolvConf := []byte("search pommesfrites.fr\nnameserver 12.34.56.78") + tmpResolvConf := []byte("search pommesfrites.fr\nnameserver 12.34.56.78\n") tmpLocalhostResolvConf := []byte("nameserver 127.0.0.1") //take a copy of resolv.conf for restoring after test completes @@ -1131,7 +1131,7 @@ func (s *DockerSuite) TestRunResolvconfUpdate(c *check.C) { c.Fatal(err) } - expected := "\nnameserver 8.8.8.8\nnameserver 8.8.4.4" + expected := "\nnameserver 8.8.8.8\nnameserver 8.8.4.4\n" if !bytes.Equal(containerResolv, []byte(expected)) { c.Fatalf("Container does not have cleaned/replaced DNS in resolv.conf; expected %q, got %q", expected, string(containerResolv)) }