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 <aboch@docker.com> Signed-off-by: Alessandro Boch <aboch@docker.com>
This commit is contained in:
parent
c6dd451073
commit
414dfbf681
54 changed files with 1942 additions and 1545 deletions
|
@ -21,7 +21,7 @@ clone git golang.org/x/net 3cffabab72adf04f8e3b01c5baf775361837b5fe https://gith
|
||||||
clone hg code.google.com/p/gosqlite 74691fb6f837
|
clone hg code.google.com/p/gosqlite 74691fb6f837
|
||||||
|
|
||||||
#get libnetwork packages
|
#get libnetwork packages
|
||||||
clone git github.com/docker/libnetwork 22dc04d06067b40a9e7ef575aee6d1bb69d4dcc3
|
clone git github.com/docker/libnetwork dc52820147f40fe424c8959987af3b396f842639
|
||||||
clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
|
clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
|
||||||
clone git github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b
|
clone git github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b
|
||||||
clone git github.com/hashicorp/memberlist 9a1e242e454d2443df330bdd51a436d5a9058fc4
|
clone git github.com/hashicorp/memberlist 9a1e242e454d2443df330bdd51a436d5a9058fc4
|
||||||
|
|
18
vendor/src/github.com/docker/libnetwork/Makefile
vendored
18
vendor/src/github.com/docker/libnetwork/Makefile
vendored
|
@ -3,12 +3,12 @@ SHELL=/bin/bash
|
||||||
build_image=libnetwork-build
|
build_image=libnetwork-build
|
||||||
dockerargs = --privileged -v $(shell pwd):/go/src/github.com/docker/libnetwork -w /go/src/github.com/docker/libnetwork
|
dockerargs = --privileged -v $(shell pwd):/go/src/github.com/docker/libnetwork -w /go/src/github.com/docker/libnetwork
|
||||||
container_env = -e "INSIDECONTAINER=-incontainer=true"
|
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"
|
ciargs = -e "COVERALLS_TOKEN=$$COVERALLS_TOKEN" -e "INSIDECONTAINER=-incontainer=true"
|
||||||
cidocker = docker run ${ciargs} ${dockerargs} golang:1.4
|
cidocker = docker run ${ciargs} ${dockerargs} golang:1.4
|
||||||
|
|
||||||
all: ${build_image}.created
|
all: ${build_image}.created
|
||||||
${docker} make all-local
|
${docker} ./wrapmake.sh all-local
|
||||||
|
|
||||||
all-local: check-local build-local
|
all-local: check-local build-local
|
||||||
|
|
||||||
|
@ -19,13 +19,13 @@ ${build_image}.created:
|
||||||
touch ${build_image}.created
|
touch ${build_image}.created
|
||||||
|
|
||||||
build: ${build_image}.created
|
build: ${build_image}.created
|
||||||
${docker} make build-local
|
${docker} ./wrapmake.sh build-local
|
||||||
|
|
||||||
build-local:
|
build-local:
|
||||||
$(shell which godep) go build -tags libnetwork_discovery ./...
|
$(shell which godep) go build -tags libnetwork_discovery ./...
|
||||||
|
|
||||||
check: ${build_image}.created
|
check: ${build_image}.created
|
||||||
${docker} make check-local
|
${docker} ./wrapmake.sh check-local
|
||||||
|
|
||||||
check-code:
|
check-code:
|
||||||
@echo "Checking code... "
|
@echo "Checking code... "
|
||||||
|
@ -49,15 +49,15 @@ run-tests:
|
||||||
ret=$$? ;\
|
ret=$$? ;\
|
||||||
if [ $$ret -ne 0 ]; then exit $$ret; fi ;\
|
if [ $$ret -ne 0 ]; then exit $$ret; fi ;\
|
||||||
popd &> /dev/null; \
|
popd &> /dev/null; \
|
||||||
if [ -f $$dir/profile.tmp ]; then \
|
if [ -f $$dir/profile.tmp ]; then \
|
||||||
cat $$dir/profile.tmp | tail -n +2 >> coverage.coverprofile ; \
|
cat $$dir/profile.tmp | tail -n +2 >> coverage.coverprofile ; \
|
||||||
rm $$dir/profile.tmp ; \
|
rm $$dir/profile.tmp ; \
|
||||||
fi ; \
|
fi ; \
|
||||||
fi ; \
|
fi ; \
|
||||||
done
|
done
|
||||||
@echo "Done running tests"
|
@echo "Done running tests"
|
||||||
|
|
||||||
check-local: check-format check-code run-tests
|
check-local: check-format check-code run-tests
|
||||||
|
|
||||||
install-deps:
|
install-deps:
|
||||||
apt-get update && apt-get -y install iptables
|
apt-get update && apt-get -y install iptables
|
||||||
|
|
|
@ -29,13 +29,13 @@ There are many networking solutions available to suit a broad range of use-cases
|
||||||
driverOptions := options.Generic{}
|
driverOptions := options.Generic{}
|
||||||
genericOption := make(map[string]interface{})
|
genericOption := make(map[string]interface{})
|
||||||
genericOption[netlabel.GenericData] = driverOptions
|
genericOption[netlabel.GenericData] = driverOptions
|
||||||
err := controller.ConfigureNetworkDriver(networkType, genericOption)
|
err = controller.ConfigureNetworkDriver(networkType, genericOption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a network for containers to join.
|
// 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")
|
network, err := controller.NewNetwork(networkType, "network1")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
@ -50,12 +50,14 @@ There are many networking solutions available to suit a broad range of use-cases
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// A container can join the endpoint by providing the container ID to the join
|
// Create the sandbox for the containr.
|
||||||
// api.
|
sbx, err := controller.NewSandbox("container1",
|
||||||
// Join accepts Variadic arguments which will be made use of by libnetwork and Drivers
|
libnetwork.OptionHostname("test"),
|
||||||
err = ep.Join("container1",
|
libnetwork.OptionDomainname("docker.io"))
|
||||||
libnetwork.JoinOptionHostname("test"),
|
|
||||||
libnetwork.JoinOptionDomainname("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 {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
255
vendor/src/github.com/docker/libnetwork/api/api.go
vendored
255
vendor/src/github.com/docker/libnetwork/api/api.go
vendored
|
@ -35,7 +35,10 @@ const (
|
||||||
epNameQr = "{" + urlEpName + ":" + qregx + "}"
|
epNameQr = "{" + urlEpName + ":" + qregx + "}"
|
||||||
epID = "{" + urlEpID + ":" + regex + "}"
|
epID = "{" + urlEpID + ":" + regex + "}"
|
||||||
epPIDQr = "{" + urlEpPID + ":" + qregx + "}"
|
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
|
// Internal URL variable name.They can be anything as
|
||||||
// long as they do not collide with query fields.
|
// long as they do not collide with query fields.
|
||||||
|
@ -45,7 +48,10 @@ const (
|
||||||
urlEpName = "endpoint-name"
|
urlEpName = "endpoint-name"
|
||||||
urlEpID = "endpoint-id"
|
urlEpID = "endpoint-id"
|
||||||
urlEpPID = "endpoint-partial-id"
|
urlEpPID = "endpoint-partial-id"
|
||||||
|
urlSbID = "sandbox-id"
|
||||||
|
urlSbPID = "sandbox-partial-id"
|
||||||
urlCnID = "container-id"
|
urlCnID = "container-id"
|
||||||
|
urlCnPID = "container-partial-id"
|
||||||
|
|
||||||
// BridgeNetworkDriver is the built-in default for Network Driver
|
// BridgeNetworkDriver is the built-in default for Network Driver
|
||||||
BridgeNetworkDriver = "bridge"
|
BridgeNetworkDriver = "bridge"
|
||||||
|
@ -106,21 +112,28 @@ func (h *httpHandler) initRouter() {
|
||||||
{"/services", []string{"partial-id", epPIDQr}, procGetServices},
|
{"/services", []string{"partial-id", epPIDQr}, procGetServices},
|
||||||
{"/services", nil, procGetServices},
|
{"/services", nil, procGetServices},
|
||||||
{"/services/" + epID, nil, procGetService},
|
{"/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": {
|
"POST": {
|
||||||
{"/networks", nil, procCreateNetwork},
|
{"/networks", nil, procCreateNetwork},
|
||||||
{"/networks/" + nwID + "/endpoints", nil, procCreateEndpoint},
|
{"/networks/" + nwID + "/endpoints", nil, procCreateEndpoint},
|
||||||
{"/networks/" + nwID + "/endpoints/" + epID + "/containers", nil, procJoinEndpoint},
|
{"/networks/" + nwID + "/endpoints/" + epID + "/sandboxes", nil, procJoinEndpoint},
|
||||||
{"/services", nil, procPublishService},
|
{"/services", nil, procPublishService},
|
||||||
{"/services/" + epID + "/backend", nil, procAttachBackend},
|
{"/services/" + epID + "/backend", nil, procAttachBackend},
|
||||||
|
{"/sandboxes", nil, procCreateSandbox},
|
||||||
},
|
},
|
||||||
"DELETE": {
|
"DELETE": {
|
||||||
{"/networks/" + nwID, nil, procDeleteNetwork},
|
{"/networks/" + nwID, nil, procDeleteNetwork},
|
||||||
{"/networks/" + nwID + "/endpoints/" + epID, nil, procDeleteEndpoint},
|
{"/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, 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)
|
res, rsp := fct(ctrl, mux.Vars(req), body)
|
||||||
|
if !rsp.isOK() {
|
||||||
|
http.Error(w, rsp.Status, rsp.StatusCode)
|
||||||
|
return
|
||||||
|
}
|
||||||
if res != nil {
|
if res != nil {
|
||||||
writeJSON(w, rsp.StatusCode, res)
|
writeJSON(w, rsp.StatusCode, res)
|
||||||
}
|
}
|
||||||
|
@ -191,10 +208,12 @@ func buildEndpointResource(ep libnetwork.Endpoint) *endpointResource {
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildContainerResource(ci libnetwork.ContainerInfo) *containerResource {
|
func buildSandboxResource(sb libnetwork.Sandbox) *sandboxResource {
|
||||||
r := &containerResource{}
|
r := &sandboxResource{}
|
||||||
if ci != nil {
|
if sb != nil {
|
||||||
r.ID = ci.ID()
|
r.ID = sb.ID()
|
||||||
|
r.Key = sb.Key()
|
||||||
|
r.ContainerID = sb.ContainerID()
|
||||||
}
|
}
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
@ -213,41 +232,41 @@ func (nc *networkCreate) parseOptions() []libnetwork.NetworkOption {
|
||||||
return setFctList
|
return setFctList
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ej *endpointJoin) parseOptions() []libnetwork.EndpointOption {
|
func (sc *sandboxCreate) parseOptions() []libnetwork.SandboxOption {
|
||||||
var setFctList []libnetwork.EndpointOption
|
var setFctList []libnetwork.SandboxOption
|
||||||
if ej.HostName != "" {
|
if sc.HostName != "" {
|
||||||
setFctList = append(setFctList, libnetwork.JoinOptionHostname(ej.HostName))
|
setFctList = append(setFctList, libnetwork.OptionHostname(sc.HostName))
|
||||||
}
|
}
|
||||||
if ej.DomainName != "" {
|
if sc.DomainName != "" {
|
||||||
setFctList = append(setFctList, libnetwork.JoinOptionDomainname(ej.DomainName))
|
setFctList = append(setFctList, libnetwork.OptionDomainname(sc.DomainName))
|
||||||
}
|
}
|
||||||
if ej.HostsPath != "" {
|
if sc.HostsPath != "" {
|
||||||
setFctList = append(setFctList, libnetwork.JoinOptionHostsPath(ej.HostsPath))
|
setFctList = append(setFctList, libnetwork.OptionHostsPath(sc.HostsPath))
|
||||||
}
|
}
|
||||||
if ej.ResolvConfPath != "" {
|
if sc.ResolvConfPath != "" {
|
||||||
setFctList = append(setFctList, libnetwork.JoinOptionResolvConfPath(ej.ResolvConfPath))
|
setFctList = append(setFctList, libnetwork.OptionResolvConfPath(sc.ResolvConfPath))
|
||||||
}
|
}
|
||||||
if ej.UseDefaultSandbox {
|
if sc.UseDefaultSandbox {
|
||||||
setFctList = append(setFctList, libnetwork.JoinOptionUseDefaultSandbox())
|
setFctList = append(setFctList, libnetwork.OptionUseDefaultSandbox())
|
||||||
}
|
}
|
||||||
if ej.DNS != nil {
|
if sc.DNS != nil {
|
||||||
for _, d := range ej.DNS {
|
for _, d := range sc.DNS {
|
||||||
setFctList = append(setFctList, libnetwork.JoinOptionDNS(d))
|
setFctList = append(setFctList, libnetwork.OptionDNS(d))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ej.ExtraHosts != nil {
|
if sc.ExtraHosts != nil {
|
||||||
for _, e := range ej.ExtraHosts {
|
for _, e := range sc.ExtraHosts {
|
||||||
setFctList = append(setFctList, libnetwork.JoinOptionExtraHost(e.Name, e.Address))
|
setFctList = append(setFctList, libnetwork.OptionExtraHost(e.Name, e.Address))
|
||||||
}
|
|
||||||
}
|
|
||||||
if ej.ParentUpdates != nil {
|
|
||||||
for _, p := range ej.ParentUpdates {
|
|
||||||
setFctList = append(setFctList, libnetwork.JoinOptionParentUpdate(p.EndpointID, p.Name, p.Address))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return setFctList
|
return setFctList
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ej *endpointJoin) parseOptions() []libnetwork.EndpointOption {
|
||||||
|
// priority will go here
|
||||||
|
return []libnetwork.EndpointOption{}
|
||||||
|
}
|
||||||
|
|
||||||
/******************
|
/******************
|
||||||
Process functions
|
Process functions
|
||||||
*******************/
|
*******************/
|
||||||
|
@ -337,6 +356,22 @@ func procGetNetworks(c libnetwork.NetworkController, vars map[string]string, bod
|
||||||
return list, &successResponse
|
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
|
Network interface
|
||||||
*******************/
|
*******************/
|
||||||
|
@ -456,11 +491,16 @@ func procJoinEndpoint(c libnetwork.NetworkController, vars map[string]string, bo
|
||||||
return nil, errRsp
|
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 {
|
if err != nil {
|
||||||
return nil, convertNetworkError(err)
|
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) {
|
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
|
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 {
|
if err != nil {
|
||||||
return nil, convertNetworkError(err)
|
return nil, convertNetworkError(err)
|
||||||
}
|
}
|
||||||
|
@ -567,19 +612,6 @@ func procGetService(c libnetwork.NetworkController, vars map[string]string, body
|
||||||
return buildEndpointResource(sv), &successResponse
|
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) {
|
func procPublishService(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
|
||||||
var sp servicePublish
|
var sp servicePublish
|
||||||
|
|
||||||
|
@ -635,11 +667,16 @@ func procAttachBackend(c libnetwork.NetworkController, vars map[string]string, b
|
||||||
return nil, errRsp
|
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 {
|
if err != nil {
|
||||||
return nil, convertNetworkError(err)
|
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) {
|
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
|
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 {
|
if err != nil {
|
||||||
return nil, convertNetworkError(err)
|
return nil, convertNetworkError(err)
|
||||||
}
|
}
|
||||||
|
@ -676,6 +800,14 @@ func detectNetworkTarget(vars map[string]string) (string, int) {
|
||||||
panic("Missing URL variable parameter for network")
|
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) {
|
func detectEndpointTarget(vars map[string]string) (string, int) {
|
||||||
if target, ok := vars[urlEpName]; ok {
|
if target, ok := vars[urlEpName]; ok {
|
||||||
return target, byName
|
return target, byName
|
||||||
|
@ -712,6 +844,27 @@ func findNetwork(c libnetwork.NetworkController, s string, by int) (libnetwork.N
|
||||||
return nw, &successResponse
|
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) {
|
func findEndpoint(c libnetwork.NetworkController, ns, es string, nwBy, epBy int) (libnetwork.Endpoint, *responseStatus) {
|
||||||
nw, errRsp := findNetwork(c, ns, nwBy)
|
nw, errRsp := findNetwork(c, ns, nwBy)
|
||||||
if !errRsp.isOK() {
|
if !errRsp.isOK() {
|
||||||
|
|
|
@ -21,9 +21,11 @@ type endpointResource struct {
|
||||||
Network string `json:"network"`
|
Network string `json:"network"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// containerResource is the body of "get service backend" response message
|
// sandboxResource is the body of "get service backend" response message
|
||||||
type containerResource struct {
|
type sandboxResource struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
|
Key string `json:"key"`
|
||||||
|
ContainerID string `json:"container_id"`
|
||||||
// will add more fields once labels change is in
|
// will add more fields once labels change is in
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,17 +47,21 @@ type endpointCreate struct {
|
||||||
PortMapping []types.PortBinding `json:"port_mapping"`
|
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
|
// endpointJoin represents the expected body of the "join endpoint" or "leave endpoint" http request messages
|
||||||
type endpointJoin struct {
|
type endpointJoin struct {
|
||||||
ContainerID string `json:"container_id"`
|
SandboxID string `json:"sandbox_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"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// servicePublish represents the body of the "publish service" http request message
|
// servicePublish represents the body of the "publish service" http request message
|
||||||
|
@ -66,16 +72,8 @@ type servicePublish struct {
|
||||||
PortMapping []types.PortBinding `json:"port_mapping"`
|
PortMapping []types.PortBinding `json:"port_mapping"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// EndpointExtraHost represents the extra host object
|
// extraHost represents the extra host object
|
||||||
type endpointExtraHost struct {
|
type extraHost struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Address string `json:"address"`
|
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"`
|
|
||||||
}
|
|
||||||
|
|
|
@ -4,27 +4,33 @@
|
||||||
package bitseq
|
package bitseq
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/docker/libnetwork/datastore"
|
"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
|
// If needed we can think of making these configurable
|
||||||
const (
|
const (
|
||||||
blockLen = 32
|
blockLen = uint32(32)
|
||||||
blockBytes = blockLen / 8
|
blockBytes = blockLen / 8
|
||||||
blockMAX = 1<<blockLen - 1
|
blockMAX = uint32(1<<blockLen - 1)
|
||||||
blockFirstBit = 1 << (blockLen - 1)
|
blockFirstBit = uint32(1) << (blockLen - 1)
|
||||||
|
invalidPos = blockMAX
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errNoBitAvailable = fmt.Errorf("no bit available")
|
||||||
)
|
)
|
||||||
|
|
||||||
// Handle contains the sequece representing the bitmask and its identifier
|
// Handle contains the sequece representing the bitmask and its identifier
|
||||||
type Handle struct {
|
type Handle struct {
|
||||||
bits uint32
|
bits uint32
|
||||||
unselected uint32
|
unselected uint32
|
||||||
head *Sequence
|
head *sequence
|
||||||
app string
|
app string
|
||||||
id string
|
id string
|
||||||
dbIndex uint64
|
dbIndex uint64
|
||||||
|
@ -41,9 +47,9 @@ func NewHandle(app string, ds datastore.DataStore, id string, numElements uint32
|
||||||
store: ds,
|
store: ds,
|
||||||
bits: numElements,
|
bits: numElements,
|
||||||
unselected: numElements,
|
unselected: numElements,
|
||||||
head: &Sequence{
|
head: &sequence{
|
||||||
Block: 0x0,
|
block: 0x0,
|
||||||
Count: getNumBlocks(numElements),
|
count: getNumBlocks(numElements),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,69 +68,64 @@ func NewHandle(app string, ds datastore.DataStore, id string, numElements uint32
|
||||||
return h, nil
|
return h, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sequence reresents a recurring sequence of 32 bits long bitmasks
|
// sequence represents a recurring sequence of 32 bits long bitmasks
|
||||||
type Sequence struct {
|
type sequence struct {
|
||||||
Block uint32 // block representing 4 byte long allocation bitmask
|
block uint32 // block is a symbol representing 4 byte long allocation bitmask
|
||||||
Count uint32 // number of consecutive blocks
|
count uint32 // number of consecutive blocks (symbols)
|
||||||
Next *Sequence // next sequence
|
next *sequence // next sequence
|
||||||
}
|
|
||||||
|
|
||||||
// NewSequence returns a sequence initialized to represent a bitmaks of numElements bits
|
|
||||||
func NewSequence(numElements uint32) *Sequence {
|
|
||||||
return &Sequence{Block: 0x0, Count: getNumBlocks(numElements), Next: nil}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns a string representation of the block sequence starting from this block
|
// String returns a string representation of the block sequence starting from this block
|
||||||
func (s *Sequence) String() string {
|
func (s *sequence) toString() string {
|
||||||
var nextBlock string
|
var nextBlock string
|
||||||
if s.Next == nil {
|
if s.next == nil {
|
||||||
nextBlock = "end"
|
nextBlock = "end"
|
||||||
} else {
|
} else {
|
||||||
nextBlock = s.Next.String()
|
nextBlock = s.next.toString()
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("(0x%x, %d)->%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
|
// GetAvailableBit returns the position of the first unset bit in the bitmask represented by this sequence
|
||||||
func (s *Sequence) GetAvailableBit() (bytePos, bitPos int) {
|
func (s *sequence) getAvailableBit() (uint32, uint32, error) {
|
||||||
if s.Block == blockMAX || s.Count == 0 {
|
if s.block == blockMAX || s.count == 0 {
|
||||||
return -1, -1
|
return invalidPos, invalidPos, fmt.Errorf("no available bit")
|
||||||
}
|
}
|
||||||
bits := 0
|
bits := uint32(0)
|
||||||
bitSel := uint32(blockFirstBit)
|
bitSel := blockFirstBit
|
||||||
for bitSel > 0 && s.Block&bitSel != 0 {
|
for bitSel > 0 && s.block&bitSel != 0 {
|
||||||
bitSel >>= 1
|
bitSel >>= 1
|
||||||
bits++
|
bits++
|
||||||
}
|
}
|
||||||
return bits / 8, bits % 8
|
return bits / 8, bits % 8, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCopy returns a copy of the linked list rooted at this node
|
// GetCopy returns a copy of the linked list rooted at this node
|
||||||
func (s *Sequence) GetCopy() *Sequence {
|
func (s *sequence) getCopy() *sequence {
|
||||||
n := &Sequence{Block: s.Block, Count: s.Count}
|
n := &sequence{block: s.block, count: s.count}
|
||||||
pn := n
|
pn := n
|
||||||
ps := s.Next
|
ps := s.next
|
||||||
for ps != nil {
|
for ps != nil {
|
||||||
pn.Next = &Sequence{Block: ps.Block, Count: ps.Count}
|
pn.next = &sequence{block: ps.block, count: ps.count}
|
||||||
pn = pn.Next
|
pn = pn.next
|
||||||
ps = ps.Next
|
ps = ps.next
|
||||||
}
|
}
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
// Equal checks if this sequence is equal to the passed one
|
// 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
|
this := s
|
||||||
other := o
|
other := o
|
||||||
for this != nil {
|
for this != nil {
|
||||||
if other == nil {
|
if other == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if this.Block != other.Block || this.Count != other.Count {
|
if this.block != other.block || this.count != other.count {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
this = this.Next
|
this = this.next
|
||||||
other = other.Next
|
other = other.next
|
||||||
}
|
}
|
||||||
// Check if other is longer than this
|
// Check if other is longer than this
|
||||||
if other != nil {
|
if other != nil {
|
||||||
|
@ -134,23 +135,23 @@ func (s *Sequence) Equal(o *Sequence) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToByteArray converts the sequence into a byte array
|
// 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
|
var bb []byte
|
||||||
|
|
||||||
p := s
|
p := s
|
||||||
for p != nil {
|
for p != nil {
|
||||||
bb = append(bb, netutils.U32ToA(p.Block)...)
|
b := make([]byte, 8)
|
||||||
bb = append(bb, netutils.U32ToA(p.Count)...)
|
binary.BigEndian.PutUint32(b[0:], p.block)
|
||||||
p = p.Next
|
binary.BigEndian.PutUint32(b[4:], p.count)
|
||||||
|
bb = append(bb, b...)
|
||||||
|
p = p.next
|
||||||
}
|
}
|
||||||
|
|
||||||
return bb, nil
|
return bb, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// FromByteArray construct the sequence from the byte array
|
// fromByteArray construct the sequence from the byte array
|
||||||
// TODO (aboch): manage network/host order stuff
|
func (s *sequence) fromByteArray(data []byte) error {
|
||||||
func (s *Sequence) FromByteArray(data []byte) error {
|
|
||||||
l := len(data)
|
l := len(data)
|
||||||
if l%8 != 0 {
|
if l%8 != 0 {
|
||||||
return fmt.Errorf("cannot deserialize byte sequence of lenght %d (%v)", l, data)
|
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
|
p := s
|
||||||
i := 0
|
i := 0
|
||||||
for {
|
for {
|
||||||
p.Block = netutils.ATo32(data[i : i+4])
|
p.block = binary.BigEndian.Uint32(data[i : i+4])
|
||||||
p.Count = netutils.ATo32(data[i+4 : i+8])
|
p.count = binary.BigEndian.Uint32(data[i+4 : i+8])
|
||||||
i += 8
|
i += 8
|
||||||
if i == l {
|
if i == l {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
p.Next = &Sequence{}
|
p.next = &sequence{}
|
||||||
p = p.Next
|
p = p.next
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFirstAvailable returns the byte and bit position of the first unset bit
|
func (h *Handle) getCopy() *Handle {
|
||||||
func (h *Handle) GetFirstAvailable() (int, int, error) {
|
return &Handle{
|
||||||
h.Lock()
|
bits: h.bits,
|
||||||
defer h.Unlock()
|
unselected: h.unselected,
|
||||||
return GetFirstAvailable(h.head)
|
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
|
// SetAny atomically sets the first unset bit in the sequence and returns the corresponding ordinal
|
||||||
// If the ordinal is beyond the Sequence limits, a negative response is returned
|
func (h *Handle) SetAny() (uint32, error) {
|
||||||
func (h *Handle) CheckIfAvailable(ordinal int) (int, int, error) {
|
if h.Unselected() == 0 {
|
||||||
h.Lock()
|
return invalidPos, errNoBitAvailable
|
||||||
defer h.Unlock()
|
}
|
||||||
return CheckIfAvailable(h.head, ordinal)
|
return h.set(0, true, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PushReservation pushes the bit reservation inside the bitmask.
|
// Set atomically sets the corresponding bit in the sequence
|
||||||
func (h *Handle) PushReservation(bytePos, bitPos int, release bool) error {
|
func (h *Handle) Set(ordinal uint32) error {
|
||||||
// Create a copy of the current handler
|
if err := h.validateOrdinal(ordinal); err != nil {
|
||||||
h.Lock()
|
return err
|
||||||
nh := &Handle{
|
|
||||||
app: h.app,
|
|
||||||
id: h.id,
|
|
||||||
store: h.store,
|
|
||||||
dbIndex: h.dbIndex,
|
|
||||||
head: h.head.GetCopy(),
|
|
||||||
dbExists: h.dbExists,
|
|
||||||
}
|
}
|
||||||
h.Unlock()
|
_, err := h.set(ordinal, false, false)
|
||||||
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
|
|
||||||
return err
|
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
|
// Destroy removes from the datastore the data belonging to this handle
|
||||||
func (h *Handle) Destroy() {
|
func (h *Handle) Destroy() {
|
||||||
h.deleteFromStore()
|
h.deleteFromStore()
|
||||||
|
@ -229,13 +302,13 @@ func (h *Handle) Destroy() {
|
||||||
|
|
||||||
// ToByteArray converts this handle's data into a byte array
|
// ToByteArray converts this handle's data into a byte array
|
||||||
func (h *Handle) ToByteArray() ([]byte, error) {
|
func (h *Handle) ToByteArray() ([]byte, error) {
|
||||||
ba := make([]byte, 8)
|
|
||||||
|
|
||||||
h.Lock()
|
h.Lock()
|
||||||
defer h.Unlock()
|
defer h.Unlock()
|
||||||
copy(ba[0:4], netutils.U32ToA(h.bits))
|
ba := make([]byte, 8)
|
||||||
copy(ba[4:8], netutils.U32ToA(h.unselected))
|
binary.BigEndian.PutUint32(ba[0:], h.bits)
|
||||||
bm, err := h.head.ToByteArray()
|
binary.BigEndian.PutUint32(ba[4:], h.unselected)
|
||||||
|
bm, err := h.head.toByteArray()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to serialize head: %s", err.Error())
|
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")
|
return fmt.Errorf("nil byte array")
|
||||||
}
|
}
|
||||||
|
|
||||||
nh := &Sequence{}
|
nh := &sequence{}
|
||||||
err := nh.FromByteArray(ba[8:])
|
err := nh.fromByteArray(ba[8:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to deserialize head: %s", err.Error())
|
return fmt.Errorf("failed to deserialize head: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
h.Lock()
|
h.Lock()
|
||||||
h.head = nh
|
h.head = nh
|
||||||
h.bits = netutils.ATo32(ba[0:4])
|
h.bits = binary.BigEndian.Uint32(ba[0:4])
|
||||||
h.unselected = netutils.ATo32(ba[4:8])
|
h.unselected = binary.BigEndian.Uint32(ba[4:8])
|
||||||
h.Unlock()
|
h.Unlock()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -277,64 +350,70 @@ func (h *Handle) Unselected() uint32 {
|
||||||
return h.unselected
|
return h.unselected
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFirstAvailable looks for the first unset bit in passed mask
|
func (h *Handle) String() string {
|
||||||
func GetFirstAvailable(head *Sequence) (int, int, error) {
|
h.Lock()
|
||||||
byteIndex := 0
|
defer h.Unlock()
|
||||||
current := head
|
return fmt.Sprintf("App: %s, ID: %s, DBIndex: 0x%x, bits: %d, unselected: %d, sequence: %s",
|
||||||
for current != nil {
|
h.app, h.id, h.dbIndex, h.bits, h.unselected, h.head.toString())
|
||||||
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")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckIfAvailable checks if the bit correspondent to the specified ordinal is unset
|
// getFirstAvailable looks for the first unset bit in passed mask
|
||||||
// If the ordinal is beyond the Sequence limits, a negative response is returned
|
func getFirstAvailable(head *sequence) (uint32, uint32, error) {
|
||||||
func CheckIfAvailable(head *Sequence, ordinal int) (int, int, 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
|
bytePos := ordinal / 8
|
||||||
bitPos := ordinal % 8
|
bitPos := ordinal % 8
|
||||||
|
|
||||||
// Find the Sequence containing this byte
|
// Find the sequence containing this byte
|
||||||
current, _, _, inBlockBytePos := findSequence(head, bytePos)
|
current, _, _, inBlockBytePos := findSequence(head, bytePos)
|
||||||
|
|
||||||
if current != nil {
|
if current != nil {
|
||||||
// Check whether the bit corresponding to the ordinal address is unset
|
// Check whether the bit corresponding to the ordinal address is unset
|
||||||
bitSel := uint32(blockFirstBit >> uint(inBlockBytePos*8+bitPos))
|
bitSel := blockFirstBit >> (inBlockBytePos*8 + bitPos)
|
||||||
if current.Block&bitSel == 0 {
|
if current.block&bitSel == 0 {
|
||||||
return bytePos, bitPos, nil
|
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
|
// 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,
|
// 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.
|
// 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)
|
// If bytePos is outside of the list, function will return (nil, nil, 0, invalidPos)
|
||||||
func findSequence(head *Sequence, bytePos int) (*Sequence, *Sequence, uint32, int) {
|
func findSequence(head *sequence, bytePos uint32) (*sequence, *sequence, uint32, uint32) {
|
||||||
// Find the Sequence containing this byte
|
// Find the sequence containing this byte
|
||||||
previous := head
|
previous := head
|
||||||
current := head
|
current := head
|
||||||
n := bytePos
|
n := bytePos
|
||||||
for current.Next != nil && n >= int(current.Count*blockBytes) { // Nil check for less than 32 addresses masks
|
for current.next != nil && n >= (current.count*blockBytes) { // Nil check for less than 32 addresses masks
|
||||||
n -= int(current.Count * blockBytes)
|
n -= (current.count * blockBytes)
|
||||||
previous = current
|
previous = current
|
||||||
current = current.Next
|
current = current.next
|
||||||
}
|
}
|
||||||
|
|
||||||
// If byte is outside of the list, let caller know
|
// If byte is outside of the list, let caller know
|
||||||
if n >= int(current.Count*blockBytes) {
|
if n >= (current.count * blockBytes) {
|
||||||
return nil, nil, 0, -1
|
return nil, nil, 0, invalidPos
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the byte position inside the block and the number of blocks
|
// Find the byte position inside the block and the number of blocks
|
||||||
// preceding the block containing the byte inside this sequence
|
// preceding the block containing the byte inside this sequence
|
||||||
precBlocks := uint32(n / blockBytes)
|
precBlocks := n / blockBytes
|
||||||
inBlockBytePos := bytePos % blockBytes
|
inBlockBytePos := bytePos % blockBytes
|
||||||
|
|
||||||
return current, previous, precBlocks, inBlockBytePos
|
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.
|
// 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.
|
// 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 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.
|
// 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:
|
// Identify "current" sequence containing block:
|
||||||
// [prev seq] [current seq] [Next seq]
|
// [prev seq] [current seq] [next seq]
|
||||||
//
|
//
|
||||||
// Based on block position, resulting list of sequences can be any of three forms:
|
// Based on block position, resulting list of sequences can be any of three forms:
|
||||||
//
|
//
|
||||||
// Block position Resulting list of sequences
|
// block position Resulting list of sequences
|
||||||
// A) Block is first in current: [prev seq] [new] [modified current seq] [Next seq]
|
// 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]
|
// 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]
|
// 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 {
|
func pushReservation(bytePos, bitPos uint32, head *sequence, release bool) *sequence {
|
||||||
// Store list's head
|
// Store list's head
|
||||||
newHead := head
|
newHead := head
|
||||||
|
|
||||||
// Find the Sequence containing this byte
|
// Find the sequence containing this byte
|
||||||
current, previous, precBlocks, inBlockBytePos := findSequence(head, bytePos)
|
current, previous, precBlocks, inBlockBytePos := findSequence(head, bytePos)
|
||||||
if current == nil {
|
if current == nil {
|
||||||
return newHead
|
return newHead
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct updated block
|
// Construct updated block
|
||||||
bitSel := uint32(blockFirstBit >> uint(inBlockBytePos*8+bitPos))
|
bitSel := blockFirstBit >> (inBlockBytePos*8 + bitPos)
|
||||||
newBlock := current.Block
|
newBlock := current.block
|
||||||
if release {
|
if release {
|
||||||
newBlock &^= bitSel
|
newBlock &^= bitSel
|
||||||
} else {
|
} else {
|
||||||
|
@ -377,40 +456,40 @@ func PushReservation(bytePos, bitPos int, head *Sequence, release bool) *Sequenc
|
||||||
}
|
}
|
||||||
|
|
||||||
// Quit if it was a redundant request
|
// Quit if it was a redundant request
|
||||||
if current.Block == newBlock {
|
if current.block == newBlock {
|
||||||
return newHead
|
return newHead
|
||||||
}
|
}
|
||||||
|
|
||||||
// Current Sequence inevitably looses one block, upadate Count
|
// Current sequence inevitably looses one block, upadate count
|
||||||
current.Count--
|
current.count--
|
||||||
|
|
||||||
// Create new sequence
|
// 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
|
// Insert the new sequence in the list based on block position
|
||||||
if precBlocks == 0 { // First in sequence (A)
|
if precBlocks == 0 { // First in sequence (A)
|
||||||
newSequence.Next = current
|
newSequence.next = current
|
||||||
if current == head {
|
if current == head {
|
||||||
newHead = newSequence
|
newHead = newSequence
|
||||||
previous = newHead
|
previous = newHead
|
||||||
} else {
|
} else {
|
||||||
previous.Next = newSequence
|
previous.next = newSequence
|
||||||
}
|
}
|
||||||
removeCurrentIfEmpty(&newHead, newSequence, current)
|
removeCurrentIfEmpty(&newHead, newSequence, current)
|
||||||
mergeSequences(previous)
|
mergeSequences(previous)
|
||||||
} else if precBlocks == current.Count-2 { // Last in sequence (B)
|
} else if precBlocks == current.count-2 { // Last in sequence (B)
|
||||||
newSequence.Next = current.Next
|
newSequence.next = current.next
|
||||||
current.Next = newSequence
|
current.next = newSequence
|
||||||
mergeSequences(current)
|
mergeSequences(current)
|
||||||
} else { // In between the sequence (C)
|
} 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 := current
|
||||||
currPost.Count -= precBlocks
|
currPost.count -= precBlocks
|
||||||
newSequence.Next = currPost
|
newSequence.next = currPost
|
||||||
if currPost == head {
|
if currPost == head {
|
||||||
newHead = currPre
|
newHead = currPre
|
||||||
} else {
|
} else {
|
||||||
previous.Next = currPre
|
previous.next = currPre
|
||||||
}
|
}
|
||||||
// No merging or empty current possible here
|
// 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
|
// Removes the current sequence from the list if empty, adjusting the head pointer if needed
|
||||||
func removeCurrentIfEmpty(head **Sequence, previous, current *Sequence) {
|
func removeCurrentIfEmpty(head **sequence, previous, current *sequence) {
|
||||||
if current.Count == 0 {
|
if current.count == 0 {
|
||||||
if current == *head {
|
if current == *head {
|
||||||
*head = current.Next
|
*head = current.next
|
||||||
} else {
|
} else {
|
||||||
previous.Next = current.Next
|
previous.next = current.next
|
||||||
current = 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.
|
// 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
|
// 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 {
|
if seq != nil {
|
||||||
// Merge all what possible from seq
|
// Merge all what possible from seq
|
||||||
for seq.Next != nil && seq.Block == seq.Next.Block {
|
for seq.next != nil && seq.block == seq.next.block {
|
||||||
seq.Count += seq.Next.Count
|
seq.count += seq.next.count
|
||||||
seq.Next = seq.Next.Next
|
seq.next = seq.next.next
|
||||||
}
|
}
|
||||||
// Move to Next
|
// Move to next
|
||||||
mergeSequences(seq.Next)
|
mergeSequences(seq.next)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -452,3 +531,11 @@ func getNumBlocks(numBits uint32) uint32 {
|
||||||
}
|
}
|
||||||
return numBlocks
|
return numBlocks
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ordinalToPos(ordinal uint32) (uint32, uint32) {
|
||||||
|
return ordinal / 8, ordinal % 8
|
||||||
|
}
|
||||||
|
|
||||||
|
func posToOrdinal(bytePos, bitPos uint32) uint32 {
|
||||||
|
return bytePos*8 + bitPos
|
||||||
|
}
|
||||||
|
|
|
@ -122,7 +122,7 @@ func (h *Handle) writeToStore() error {
|
||||||
}
|
}
|
||||||
err := store.PutObjectAtomic(h)
|
err := store.PutObjectAtomic(h)
|
||||||
if err == datastore.ErrKeyModified {
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,6 +114,25 @@ func lookupContainerID(cli *NetworkCli, cnNameID string) (string, error) {
|
||||||
return "", fmt.Errorf("Cannot find container ID in json response")
|
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
|
// CmdService handles the service UI
|
||||||
func (cli *NetworkCli) CmdService(chain string, args ...string) error {
|
func (cli *NetworkCli) CmdService(chain string, args ...string) error {
|
||||||
cmd := cli.Subcmd(chain, "service", "COMMAND [OPTIONS] [arg...]", serviceUsage(chain), false)
|
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 {
|
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 err := json.NewDecoder(bytes.NewReader(obj)).Decode(&bkl); err == nil {
|
||||||
if len(bkl) > 0 {
|
if len(bkl) > 0 {
|
||||||
bk = bkl[0].ID
|
bk = bkl[0].ID
|
||||||
|
@ -310,13 +329,18 @@ func (cli *NetworkCli) CmdServiceAttach(chain string, args ...string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sandboxID, err := lookupSandboxID(cli, containerID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
sn, nn := parseServiceName(cmd.Arg(1))
|
sn, nn := parseServiceName(cmd.Arg(1))
|
||||||
serviceID, err := lookupServiceID(cli, nn, sn)
|
serviceID, err := lookupServiceID(cli, nn, sn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
nc := serviceAttach{ContainerID: containerID}
|
nc := serviceAttach{SandboxID: sandboxID}
|
||||||
|
|
||||||
_, _, err = readBody(cli.call("POST", "/services/"+serviceID+"/backend", nc, nil))
|
_, _, err = readBody(cli.call("POST", "/services/"+serviceID+"/backend", nc, nil))
|
||||||
|
|
||||||
|
|
|
@ -21,9 +21,11 @@ type serviceResource struct {
|
||||||
Network string `json:"network"`
|
Network string `json:"network"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// backendResource is the body of "get service backend" response message
|
// sandboxResource is the body of "get service backend" response message
|
||||||
type backendResource struct {
|
type sandboxResource struct {
|
||||||
ID string `json:"id"`
|
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"`
|
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 {
|
type serviceAttach struct {
|
||||||
ContainerID string `json:"container_id"`
|
SandboxID string `json:"sandbox_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"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// serviceExtraHost represents the extra host object
|
type sandboxCreate struct {
|
||||||
type serviceExtraHost 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"`
|
Name string `json:"name"`
|
||||||
Address string `json:"address"`
|
Address string `json:"address"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// EndpointParentUpdate is the object carrying the information about the
|
// sandboxParentUpdate is the object carrying the information about the
|
||||||
// endpoint parent that needs to be updated
|
// sanbox parent that needs to be updated
|
||||||
type serviceParentUpdate struct {
|
type sandboxParentUpdate struct {
|
||||||
EndpointID string `json:"service_id"`
|
ContainerID string `json:"container_id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Address string `json:"address"`
|
Address string `json:"address"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ create network namespaces and allocate interfaces for containers to use.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a network for containers to join.
|
// 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")
|
network, err := controller.NewNetwork(networkType, "network1")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
@ -32,8 +32,7 @@ create network namespaces and allocate interfaces for containers to use.
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// A container can join the endpoint by providing the container ID to the join
|
// A container can join the endpoint by providing the container ID to the join api.
|
||||||
// api.
|
|
||||||
// Join accepts Variadic arguments which will be made use of by libnetwork and Drivers
|
// Join accepts Variadic arguments which will be made use of by libnetwork and Drivers
|
||||||
err = ep.Join("container1",
|
err = ep.Join("container1",
|
||||||
libnetwork.JoinOptionHostname("test"),
|
libnetwork.JoinOptionHostname("test"),
|
||||||
|
@ -45,6 +44,7 @@ create network namespaces and allocate interfaces for containers to use.
|
||||||
package libnetwork
|
package libnetwork
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"container/heap"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -58,7 +58,7 @@ import (
|
||||||
"github.com/docker/libnetwork/driverapi"
|
"github.com/docker/libnetwork/driverapi"
|
||||||
"github.com/docker/libnetwork/hostdiscovery"
|
"github.com/docker/libnetwork/hostdiscovery"
|
||||||
"github.com/docker/libnetwork/netlabel"
|
"github.com/docker/libnetwork/netlabel"
|
||||||
"github.com/docker/libnetwork/sandbox"
|
"github.com/docker/libnetwork/osl"
|
||||||
"github.com/docker/libnetwork/types"
|
"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 returns the Network which has the passed id. If not found, the error ErrNoSuchNetwork is returned.
|
||||||
NetworkByID(id string) (Network, error)
|
NetworkByID(id string) (Network, error)
|
||||||
|
|
||||||
// LeaveAll accepts a container id and attempts to leave all endpoints that the container has joined
|
// NewSandbox cretes a new network sandbox for the passed container id
|
||||||
LeaveAll(id string) error
|
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 triggers immediate garbage collection of resources which are garbage collected.
|
||||||
GC()
|
GC()
|
||||||
|
@ -98,15 +107,19 @@ type NetworkController interface {
|
||||||
// When the function returns true, the walk will stop.
|
// When the function returns true, the walk will stop.
|
||||||
type NetworkWalker func(nw Network) bool
|
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 {
|
type driverData struct {
|
||||||
driver driverapi.Driver
|
driver driverapi.Driver
|
||||||
capability driverapi.Capability
|
capability driverapi.Capability
|
||||||
}
|
}
|
||||||
|
|
||||||
type driverTable map[string]*driverData
|
type driverTable map[string]*driverData
|
||||||
type networkTable map[types.UUID]*network
|
type networkTable map[string]*network
|
||||||
type endpointTable map[types.UUID]*endpoint
|
type endpointTable map[string]*endpoint
|
||||||
type sandboxTable map[string]*sandboxData
|
type sandboxTable map[string]*sandbox
|
||||||
|
|
||||||
type controller struct {
|
type controller struct {
|
||||||
networks networkTable
|
networks networkTable
|
||||||
|
@ -250,7 +263,7 @@ func (c *controller) NewNetwork(networkType, name string, options ...NetworkOpti
|
||||||
network := &network{
|
network := &network{
|
||||||
name: name,
|
name: name,
|
||||||
networkType: networkType,
|
networkType: networkType,
|
||||||
id: types.UUID(stringid.GenerateRandomID()),
|
id: stringid.GenerateRandomID(),
|
||||||
ctrlr: c,
|
ctrlr: c,
|
||||||
endpoints: endpointTable{},
|
endpoints: endpointTable{},
|
||||||
}
|
}
|
||||||
|
@ -356,12 +369,119 @@ func (c *controller) NetworkByID(id string) (Network, error) {
|
||||||
}
|
}
|
||||||
c.Lock()
|
c.Lock()
|
||||||
defer c.Unlock()
|
defer c.Unlock()
|
||||||
if n, ok := c.networks[types.UUID(id)]; ok {
|
if n, ok := c.networks[id]; ok {
|
||||||
return n, nil
|
return n, nil
|
||||||
}
|
}
|
||||||
return nil, ErrNoSuchNetwork(id)
|
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) {
|
func (c *controller) loadDriver(networkType string) (*driverData, error) {
|
||||||
// Plugins pkg performs lazy loading of plugins that acts as remote drivers.
|
// 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.
|
// 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() {
|
func (c *controller) GC() {
|
||||||
sandbox.GC()
|
osl.GC()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,6 @@
|
||||||
package driverapi
|
package driverapi
|
||||||
|
|
||||||
import (
|
import "net"
|
||||||
"net"
|
|
||||||
|
|
||||||
"github.com/docker/libnetwork/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
// NetworkPluginEndpointType represents the Endpoint Type used by Plugin system
|
// NetworkPluginEndpointType represents the Endpoint Type used by Plugin system
|
||||||
const NetworkPluginEndpointType = "NetworkDriver"
|
const NetworkPluginEndpointType = "NetworkDriver"
|
||||||
|
@ -17,31 +13,31 @@ type Driver interface {
|
||||||
// CreateNetwork invokes the driver method to create a network passing
|
// CreateNetwork invokes the driver method to create a network passing
|
||||||
// the network id and network specific config. The config mechanism will
|
// the network id and network specific config. The config mechanism will
|
||||||
// eventually be replaced with labels which are yet to be introduced.
|
// 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
|
// DeleteNetwork invokes the driver method to delete network passing
|
||||||
// the network id.
|
// the network id.
|
||||||
DeleteNetwork(nid types.UUID) error
|
DeleteNetwork(nid string) error
|
||||||
|
|
||||||
// CreateEndpoint invokes the driver method to create an endpoint
|
// CreateEndpoint invokes the driver method to create an endpoint
|
||||||
// passing the network id, endpoint id endpoint information and driver
|
// passing the network id, endpoint id endpoint information and driver
|
||||||
// specific config. The endpoint information can be either consumed by
|
// specific config. The endpoint information can be either consumed by
|
||||||
// the driver or populated by the driver. The config mechanism will
|
// the driver or populated by the driver. The config mechanism will
|
||||||
// eventually be replaced with labels which are yet to be introduced.
|
// 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
|
// DeleteEndpoint invokes the driver method to delete an endpoint
|
||||||
// passing the network id and endpoint id.
|
// 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 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 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 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 returns the the type of this driver, the network type this driver manages
|
||||||
Type() string
|
Type() string
|
||||||
|
@ -107,12 +103,6 @@ type JoinInfo interface {
|
||||||
// AddStaticRoute adds a routes to the sandbox.
|
// AddStaticRoute adds a routes to the sandbox.
|
||||||
// It may be used in addtion to or instead of a default gateway (as above).
|
// 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
|
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
|
// DriverCallback provides a Callback interface for Drivers into LibNetwork
|
||||||
|
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"github.com/docker/libnetwork/netlabel"
|
"github.com/docker/libnetwork/netlabel"
|
||||||
"github.com/docker/libnetwork/netutils"
|
"github.com/docker/libnetwork/netutils"
|
||||||
"github.com/docker/libnetwork/options"
|
"github.com/docker/libnetwork/options"
|
||||||
|
"github.com/docker/libnetwork/osl"
|
||||||
"github.com/docker/libnetwork/portmapper"
|
"github.com/docker/libnetwork/portmapper"
|
||||||
"github.com/docker/libnetwork/types"
|
"github.com/docker/libnetwork/types"
|
||||||
"github.com/vishvananda/netlink"
|
"github.com/vishvananda/netlink"
|
||||||
|
@ -75,7 +76,7 @@ type containerConfiguration struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type bridgeEndpoint struct {
|
type bridgeEndpoint struct {
|
||||||
id types.UUID
|
id string
|
||||||
srcName string
|
srcName string
|
||||||
addr *net.IPNet
|
addr *net.IPNet
|
||||||
addrv6 *net.IPNet
|
addrv6 *net.IPNet
|
||||||
|
@ -86,10 +87,10 @@ type bridgeEndpoint struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type bridgeNetwork struct {
|
type bridgeNetwork struct {
|
||||||
id types.UUID
|
id string
|
||||||
bridge *bridgeInterface // The bridge's L3 interface
|
bridge *bridgeInterface // The bridge's L3 interface
|
||||||
config *networkConfiguration
|
config *networkConfiguration
|
||||||
endpoints map[types.UUID]*bridgeEndpoint // key: endpoint id
|
endpoints map[string]*bridgeEndpoint // key: endpoint id
|
||||||
portMapper *portmapper.PortMapper
|
portMapper *portmapper.PortMapper
|
||||||
driver *driver // The network's driver
|
driver *driver // The network's driver
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
|
@ -100,7 +101,7 @@ type driver struct {
|
||||||
network *bridgeNetwork
|
network *bridgeNetwork
|
||||||
natChain *iptables.ChainInfo
|
natChain *iptables.ChainInfo
|
||||||
filterChain *iptables.ChainInfo
|
filterChain *iptables.ChainInfo
|
||||||
networks map[types.UUID]*bridgeNetwork
|
networks map[string]*bridgeNetwork
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,7 +111,7 @@ func init() {
|
||||||
|
|
||||||
// New constructs a new bridge driver
|
// New constructs a new bridge driver
|
||||||
func newDriver() driverapi.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
|
// Init registers a new instance of bridge driver
|
||||||
|
@ -346,7 +347,7 @@ func (n *bridgeNetwork) getNetworkBridgeName() string {
|
||||||
return config.BridgeName
|
return config.BridgeName
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *bridgeNetwork) getEndpoint(eid types.UUID) (*bridgeEndpoint, error) {
|
func (n *bridgeNetwork) getEndpoint(eid string) (*bridgeEndpoint, error) {
|
||||||
n.Lock()
|
n.Lock()
|
||||||
defer n.Unlock()
|
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
|
// 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 {
|
for _, nw := range others {
|
||||||
|
|
||||||
nw.Lock()
|
nw.Lock()
|
||||||
|
@ -475,7 +476,7 @@ func (d *driver) Config(option map[string]interface{}) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *driver) getNetwork(id types.UUID) (*bridgeNetwork, error) {
|
func (d *driver) getNetwork(id string) (*bridgeNetwork, error) {
|
||||||
d.Lock()
|
d.Lock()
|
||||||
defer d.Unlock()
|
defer d.Unlock()
|
||||||
|
|
||||||
|
@ -567,9 +568,11 @@ func (d *driver) getNetworks() []*bridgeNetwork {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new network using bridge plugin
|
// 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
|
var err error
|
||||||
|
|
||||||
|
defer osl.InitOSContext()()
|
||||||
|
|
||||||
// Sanity checks
|
// Sanity checks
|
||||||
d.Lock()
|
d.Lock()
|
||||||
if _, ok := d.networks[id]; ok {
|
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
|
// Create and set network handler in driver
|
||||||
network := &bridgeNetwork{
|
network := &bridgeNetwork{
|
||||||
id: id,
|
id: id,
|
||||||
endpoints: make(map[types.UUID]*bridgeEndpoint),
|
endpoints: make(map[string]*bridgeEndpoint),
|
||||||
config: config,
|
config: config,
|
||||||
portMapper: portmapper.New(),
|
portMapper: portmapper.New(),
|
||||||
driver: d,
|
driver: d,
|
||||||
|
@ -719,9 +722,11 @@ func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) err
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *driver) DeleteNetwork(nid types.UUID) error {
|
func (d *driver) DeleteNetwork(nid string) error {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
defer osl.InitOSContext()()
|
||||||
|
|
||||||
// Get network handler and remove it from driver
|
// Get network handler and remove it from driver
|
||||||
d.Lock()
|
d.Lock()
|
||||||
n, ok := d.networks[nid]
|
n, ok := d.networks[nid]
|
||||||
|
@ -843,12 +848,14 @@ func setHairpinMode(link netlink.Link, enable bool) error {
|
||||||
return nil
|
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 (
|
var (
|
||||||
ipv6Addr *net.IPNet
|
ipv6Addr *net.IPNet
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
|
|
||||||
|
defer osl.InitOSContext()()
|
||||||
|
|
||||||
if epInfo == nil {
|
if epInfo == nil {
|
||||||
return errors.New("invalid endpoint info passed")
|
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},
|
LinkAttrs: netlink.LinkAttrs{Name: hostIfName, TxQLen: 0},
|
||||||
PeerName: containerIfName}
|
PeerName: containerIfName}
|
||||||
if err = netlink.LinkAdd(veth); err != nil {
|
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
|
// Get the host side pipe interface handler
|
||||||
host, err := netlink.LinkByName(hostIfName)
|
host, err := netlink.LinkByName(hostIfName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return types.InternalErrorf("failed to find host side interface %s: %v", hostIfName, err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
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
|
// Get the sandbox side pipe interface handler
|
||||||
sbox, err := netlink.LinkByName(containerIfName)
|
sbox, err := netlink.LinkByName(containerIfName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return types.InternalErrorf("failed to find sandbox side interface %s: %v", containerIfName, err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -960,11 +967,11 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn
|
||||||
if config.Mtu != 0 {
|
if config.Mtu != 0 {
|
||||||
err = netlink.LinkSetMTU(host, config.Mtu)
|
err = netlink.LinkSetMTU(host, config.Mtu)
|
||||||
if err != nil {
|
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)
|
err = netlink.LinkSetMTU(sbox, config.Mtu)
|
||||||
if err != nil {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *driver) DeleteEndpoint(nid, eid types.UUID) error {
|
func (d *driver) DeleteEndpoint(nid, eid string) error {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
defer osl.InitOSContext()()
|
||||||
|
|
||||||
// Get the network handler and make sure it exists
|
// Get the network handler and make sure it exists
|
||||||
d.Lock()
|
d.Lock()
|
||||||
n, ok := d.networks[nid]
|
n, ok := d.networks[nid]
|
||||||
|
@ -1138,7 +1147,7 @@ func (d *driver) DeleteEndpoint(nid, eid types.UUID) error {
|
||||||
return nil
|
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
|
// Get the network handler and make sure it exists
|
||||||
d.Lock()
|
d.Lock()
|
||||||
n, ok := d.networks[nid]
|
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.
|
// 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)
|
network, err := d.getNetwork(nid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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.
|
// 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)
|
network, err := d.getNetwork(nid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -1282,7 +1295,7 @@ func (d *driver) link(network *bridgeNetwork, endpoint *bridgeEndpoint, options
|
||||||
if endpoint.config != nil && endpoint.config.ExposedPorts != nil {
|
if endpoint.config != nil && endpoint.config.ExposedPorts != nil {
|
||||||
for _, p := range cc.ParentEndpoints {
|
for _, p := range cc.ParentEndpoints {
|
||||||
var parentEndpoint *bridgeEndpoint
|
var parentEndpoint *bridgeEndpoint
|
||||||
parentEndpoint, err = network.getEndpoint(types.UUID(p))
|
parentEndpoint, err = network.getEndpoint(p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1312,7 +1325,7 @@ func (d *driver) link(network *bridgeNetwork, endpoint *bridgeEndpoint, options
|
||||||
|
|
||||||
for _, c := range cc.ChildEndpoints {
|
for _, c := range cc.ChildEndpoints {
|
||||||
var childEndpoint *bridgeEndpoint
|
var childEndpoint *bridgeEndpoint
|
||||||
childEndpoint, err = network.getEndpoint(types.UUID(c))
|
childEndpoint, err = network.getEndpoint(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// +build arm ppc64
|
// +build arm ppc64 ppc64le
|
||||||
|
|
||||||
package bridge
|
package bridge
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// +build !arm,!ppc64
|
// +build !arm,!ppc64,!ppc64le
|
||||||
|
|
||||||
package bridge
|
package bridge
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
const networkType = "host"
|
const networkType = "host"
|
||||||
|
|
||||||
type driver struct {
|
type driver struct {
|
||||||
network types.UUID
|
network string
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ func (d *driver) Config(option map[string]interface{}) error {
|
||||||
return nil
|
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()
|
d.Lock()
|
||||||
defer d.Unlock()
|
defer d.Unlock()
|
||||||
|
|
||||||
|
@ -39,33 +39,29 @@ func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) err
|
||||||
return nil
|
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)
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *driver) DeleteEndpoint(nid, eid types.UUID) error {
|
func (d *driver) DeleteEndpoint(nid, eid string) error {
|
||||||
return nil
|
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
|
return make(map[string]interface{}, 0), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Join method is invoked when a Sandbox is attached to an endpoint.
|
// Join method is invoked when a Sandbox is attached to an endpoint.
|
||||||
func (d *driver) Join(nid, eid types.UUID, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
|
func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
|
||||||
if err := jinfo.SetHostsPath("/etc/hosts"); err != nil {
|
return nil
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return jinfo.SetResolvConfPath("/etc/resolv.conf")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Leave method is invoked when a Sandbox detaches from an endpoint.
|
// Leave method is invoked when a Sandbox detaches from an endpoint.
|
||||||
func (d *driver) Leave(nid, eid types.UUID) error {
|
func (d *driver) Leave(nid, eid string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
const networkType = "null"
|
const networkType = "null"
|
||||||
|
|
||||||
type driver struct {
|
type driver struct {
|
||||||
network types.UUID
|
network string
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ func (d *driver) Config(option map[string]interface{}) error {
|
||||||
return nil
|
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()
|
d.Lock()
|
||||||
defer d.Unlock()
|
defer d.Unlock()
|
||||||
|
|
||||||
|
@ -39,29 +39,29 @@ func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) err
|
||||||
return nil
|
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)
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *driver) DeleteEndpoint(nid, eid types.UUID) error {
|
func (d *driver) DeleteEndpoint(nid, eid string) error {
|
||||||
return nil
|
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
|
return make(map[string]interface{}, 0), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Join method is invoked when a Sandbox is attached to an endpoint.
|
// Join method is invoked when a Sandbox is attached to an endpoint.
|
||||||
func (d *driver) Join(nid, eid types.UUID, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
|
func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Leave method is invoked when a Sandbox detaches from an endpoint.
|
// Leave method is invoked when a Sandbox detaches from an endpoint.
|
||||||
func (d *driver) Leave(nid, eid types.UUID) error {
|
func (d *driver) Leave(nid, eid string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,12 +4,11 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/docker/libnetwork/driverapi"
|
"github.com/docker/libnetwork/driverapi"
|
||||||
"github.com/docker/libnetwork/types"
|
|
||||||
"github.com/vishvananda/netlink"
|
"github.com/vishvananda/netlink"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Join method is invoked when a Sandbox is attached to an endpoint.
|
// Join method is invoked when a Sandbox is attached to an endpoint.
|
||||||
func (d *driver) Join(nid, eid types.UUID, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
|
func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
|
||||||
if err := validateID(nid, eid); err != nil {
|
if err := validateID(nid, eid); err != nil {
|
||||||
return err
|
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.
|
// 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 {
|
if err := validateID(nid, eid); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,18 +7,17 @@ import (
|
||||||
|
|
||||||
"github.com/docker/libnetwork/driverapi"
|
"github.com/docker/libnetwork/driverapi"
|
||||||
"github.com/docker/libnetwork/netutils"
|
"github.com/docker/libnetwork/netutils"
|
||||||
"github.com/docker/libnetwork/types"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type endpointTable map[types.UUID]*endpoint
|
type endpointTable map[string]*endpoint
|
||||||
|
|
||||||
type endpoint struct {
|
type endpoint struct {
|
||||||
id types.UUID
|
id string
|
||||||
mac net.HardwareAddr
|
mac net.HardwareAddr
|
||||||
addr *net.IPNet
|
addr *net.IPNet
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *network) endpoint(eid types.UUID) *endpoint {
|
func (n *network) endpoint(eid string) *endpoint {
|
||||||
n.Lock()
|
n.Lock()
|
||||||
defer n.Unlock()
|
defer n.Unlock()
|
||||||
|
|
||||||
|
@ -31,13 +30,13 @@ func (n *network) addEndpoint(ep *endpoint) {
|
||||||
n.Unlock()
|
n.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *network) deleteEndpoint(eid types.UUID) {
|
func (n *network) deleteEndpoint(eid string) {
|
||||||
n.Lock()
|
n.Lock()
|
||||||
delete(n.endpoints, eid)
|
delete(n.endpoints, eid)
|
||||||
n.Unlock()
|
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 {
|
epOptions map[string]interface{}) error {
|
||||||
if err := validateID(nid, eid); err != nil {
|
if err := validateID(nid, eid); err != nil {
|
||||||
return err
|
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)
|
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{})
|
err = epInfo.AddInterface(1, ep.mac, *ep.addr, net.IPNet{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -85,7 +84,7 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn
|
||||||
return nil
|
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 {
|
if err := validateID(nid, eid); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -105,6 +104,6 @@ func (d *driver) DeleteEndpoint(nid, eid types.UUID) error {
|
||||||
return nil
|
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
|
return make(map[string]interface{}, 0), nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,20 +10,19 @@ import (
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
"github.com/docker/libnetwork/datastore"
|
"github.com/docker/libnetwork/datastore"
|
||||||
"github.com/docker/libnetwork/ipallocator"
|
"github.com/docker/libnetwork/ipallocator"
|
||||||
"github.com/docker/libnetwork/sandbox"
|
"github.com/docker/libnetwork/osl"
|
||||||
"github.com/docker/libnetwork/types"
|
|
||||||
"github.com/vishvananda/netlink"
|
"github.com/vishvananda/netlink"
|
||||||
"github.com/vishvananda/netlink/nl"
|
"github.com/vishvananda/netlink/nl"
|
||||||
)
|
)
|
||||||
|
|
||||||
type networkTable map[types.UUID]*network
|
type networkTable map[string]*network
|
||||||
|
|
||||||
type network struct {
|
type network struct {
|
||||||
id types.UUID
|
id string
|
||||||
vni uint32
|
vni uint32
|
||||||
dbIndex uint64
|
dbIndex uint64
|
||||||
dbExists bool
|
dbExists bool
|
||||||
sbox sandbox.Sandbox
|
sbox osl.Sandbox
|
||||||
endpoints endpointTable
|
endpoints endpointTable
|
||||||
ipAllocator *ipallocator.IPAllocator
|
ipAllocator *ipallocator.IPAllocator
|
||||||
gw net.IP
|
gw net.IP
|
||||||
|
@ -36,7 +35,7 @@ type network struct {
|
||||||
sync.Mutex
|
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 == "" {
|
if id == "" {
|
||||||
return fmt.Errorf("invalid network 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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *driver) DeleteNetwork(nid types.UUID) error {
|
func (d *driver) DeleteNetwork(nid string) error {
|
||||||
if nid == "" {
|
if nid == "" {
|
||||||
return fmt.Errorf("invalid network id")
|
return fmt.Errorf("invalid network id")
|
||||||
}
|
}
|
||||||
|
@ -140,8 +139,8 @@ func (n *network) initSandbox() error {
|
||||||
n.initEpoch++
|
n.initEpoch++
|
||||||
n.Unlock()
|
n.Unlock()
|
||||||
|
|
||||||
sbox, err := sandbox.NewSandbox(
|
sbox, err := osl.NewSandbox(
|
||||||
sandbox.GenerateKey(fmt.Sprintf("%d-", n.initEpoch)+string(n.id)), true)
|
osl.GenerateKey(fmt.Sprintf("%d-", n.initEpoch)+n.id), true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not create network sandbox: %v", err)
|
return fmt.Errorf("could not create network sandbox: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -216,7 +215,7 @@ func (n *network) watchMiss(nlSock *nl.NetlinkSocket) {
|
||||||
continue
|
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)
|
logrus.Errorf("could not add neighbor entry for missed peer: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -229,27 +228,27 @@ func (d *driver) addNetwork(n *network) {
|
||||||
d.Unlock()
|
d.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *driver) deleteNetwork(nid types.UUID) {
|
func (d *driver) deleteNetwork(nid string) {
|
||||||
d.Lock()
|
d.Lock()
|
||||||
delete(d.networks, nid)
|
delete(d.networks, nid)
|
||||||
d.Unlock()
|
d.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *driver) network(nid types.UUID) *network {
|
func (d *driver) network(nid string) *network {
|
||||||
d.Lock()
|
d.Lock()
|
||||||
defer d.Unlock()
|
defer d.Unlock()
|
||||||
|
|
||||||
return d.networks[nid]
|
return d.networks[nid]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *network) sandbox() sandbox.Sandbox {
|
func (n *network) sandbox() osl.Sandbox {
|
||||||
n.Lock()
|
n.Lock()
|
||||||
defer n.Unlock()
|
defer n.Unlock()
|
||||||
|
|
||||||
return n.sbox
|
return n.sbox
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *network) setSandbox(sbox sandbox.Sandbox) {
|
func (n *network) setSandbox(sbox osl.Sandbox) {
|
||||||
n.Lock()
|
n.Lock()
|
||||||
n.sbox = sbox
|
n.sbox = sbox
|
||||||
n.Unlock()
|
n.Unlock()
|
||||||
|
@ -269,7 +268,7 @@ func (n *network) setVxlanID(vni uint32) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *network) Key() []string {
|
func (n *network) Key() []string {
|
||||||
return []string{"overlay", "network", string(n.id)}
|
return []string{"overlay", "network", n.id}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *network) KeyPrefix() []string {
|
func (n *network) KeyPrefix() []string {
|
||||||
|
|
|
@ -7,14 +7,13 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
"github.com/docker/libnetwork/types"
|
|
||||||
"github.com/hashicorp/serf/serf"
|
"github.com/hashicorp/serf/serf"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ovNotify struct {
|
type ovNotify struct {
|
||||||
action string
|
action string
|
||||||
eid types.UUID
|
eid string
|
||||||
nid types.UUID
|
nid string
|
||||||
}
|
}
|
||||||
|
|
||||||
type logWriter struct{}
|
type logWriter struct{}
|
||||||
|
@ -150,12 +149,12 @@ func (d *driver) processEvent(u serf.UserEvent) {
|
||||||
|
|
||||||
switch action {
|
switch action {
|
||||||
case "join":
|
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 {
|
net.ParseIP(vtepStr), true); err != nil {
|
||||||
fmt.Printf("Peer add failed in the driver: %v\n", err)
|
fmt.Printf("Peer add failed in the driver: %v\n", err)
|
||||||
}
|
}
|
||||||
case "leave":
|
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 {
|
net.ParseIP(vtepStr), true); err != nil {
|
||||||
fmt.Printf("Peer delete failed in the driver: %v\n", err)
|
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)
|
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 {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -179,7 +178,7 @@ func (d *driver) processQuery(q *serf.Query) {
|
||||||
q.Respond([]byte(fmt.Sprintf("%s %s", peerMac.String(), vtep.String())))
|
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())
|
qPayload := fmt.Sprintf("%s %s", string(nid), peerIP.String())
|
||||||
resp, err := d.serfInstance.Query("peerlookup", []byte(qPayload), nil)
|
resp, err := d.serfInstance.Query("peerlookup", []byte(qPayload), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -4,12 +4,12 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/docker/libnetwork/netutils"
|
"github.com/docker/libnetwork/netutils"
|
||||||
"github.com/docker/libnetwork/types"
|
"github.com/docker/libnetwork/osl"
|
||||||
"github.com/vishvananda/netlink"
|
"github.com/vishvananda/netlink"
|
||||||
"github.com/vishvananda/netlink/nl"
|
"github.com/vishvananda/netlink/nl"
|
||||||
)
|
)
|
||||||
|
|
||||||
func validateID(nid, eid types.UUID) error {
|
func validateID(nid, eid string) error {
|
||||||
if nid == "" {
|
if nid == "" {
|
||||||
return fmt.Errorf("invalid network id")
|
return fmt.Errorf("invalid network id")
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,8 @@ func validateID(nid, eid types.UUID) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func createVethPair() (string, string, error) {
|
func createVethPair() (string, string, error) {
|
||||||
|
defer osl.InitOSContext()()
|
||||||
|
|
||||||
// Generate a name for what will be the host side pipe interface
|
// Generate a name for what will be the host side pipe interface
|
||||||
name1, err := netutils.GenerateIfaceName(vethPrefix, vethLen)
|
name1, err := netutils.GenerateIfaceName(vethPrefix, vethLen)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -46,6 +48,8 @@ func createVethPair() (string, string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func createVxlan(vni uint32) (string, error) {
|
func createVxlan(vni uint32) (string, error) {
|
||||||
|
defer osl.InitOSContext()()
|
||||||
|
|
||||||
name, err := netutils.GenerateIfaceName("vxlan", 7)
|
name, err := netutils.GenerateIfaceName("vxlan", 7)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("error generating vxlan name: %v", err)
|
return "", fmt.Errorf("error generating vxlan name: %v", err)
|
||||||
|
@ -69,6 +73,8 @@ func createVxlan(vni uint32) (string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteVxlan(name string) error {
|
func deleteVxlan(name string) error {
|
||||||
|
defer osl.InitOSContext()()
|
||||||
|
|
||||||
link, err := netlink.LinkByName(name)
|
link, err := netlink.LinkByName(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to find vxlan interface with name %s: %v", name, err)
|
return fmt.Errorf("failed to find vxlan interface with name %s: %v", name, err)
|
||||||
|
|
|
@ -11,7 +11,6 @@ import (
|
||||||
"github.com/docker/libnetwork/driverapi"
|
"github.com/docker/libnetwork/driverapi"
|
||||||
"github.com/docker/libnetwork/idm"
|
"github.com/docker/libnetwork/idm"
|
||||||
"github.com/docker/libnetwork/netlabel"
|
"github.com/docker/libnetwork/netlabel"
|
||||||
"github.com/docker/libnetwork/types"
|
|
||||||
"github.com/hashicorp/serf/serf"
|
"github.com/hashicorp/serf/serf"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -77,7 +76,7 @@ func Init(dc driverapi.DriverCallback) error {
|
||||||
return dc.RegisterDriver(networkType, &driver{
|
return dc.RegisterDriver(networkType, &driver{
|
||||||
networks: networkTable{},
|
networks: networkTable{},
|
||||||
peerDb: peerNetworkMap{
|
peerDb: peerNetworkMap{
|
||||||
mp: map[types.UUID]peerMap{},
|
mp: map[string]peerMap{},
|
||||||
},
|
},
|
||||||
}, c)
|
}, c)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,6 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/docker/libnetwork/types"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type peerKey struct {
|
type peerKey struct {
|
||||||
|
@ -15,7 +13,7 @@ type peerKey struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type peerEntry struct {
|
type peerEntry struct {
|
||||||
eid types.UUID
|
eid string
|
||||||
vtep net.IP
|
vtep net.IP
|
||||||
inSandbox bool
|
inSandbox bool
|
||||||
isLocal bool
|
isLocal bool
|
||||||
|
@ -27,7 +25,7 @@ type peerMap struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type peerNetworkMap struct {
|
type peerNetworkMap struct {
|
||||||
mp map[types.UUID]peerMap
|
mp map[string]peerMap
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +56,7 @@ func (pKey *peerKey) Scan(state fmt.ScanState, verb rune) error {
|
||||||
|
|
||||||
var peerDbWg sync.WaitGroup
|
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()
|
d.peerDb.Lock()
|
||||||
pMap, ok := d.peerDb.mp[nid]
|
pMap, ok := d.peerDb.mp[nid]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -84,7 +82,7 @@ func (d *driver) peerDbWalk(nid types.UUID, f func(*peerKey, *peerEntry) bool) e
|
||||||
return nil
|
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 (
|
var (
|
||||||
peerMac net.HardwareAddr
|
peerMac net.HardwareAddr
|
||||||
vtep net.IP
|
vtep net.IP
|
||||||
|
@ -113,7 +111,7 @@ func (d *driver) peerDbSearch(nid types.UUID, peerIP net.IP) (net.HardwareAddr,
|
||||||
return peerMac, vtep, nil
|
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) {
|
peerMac net.HardwareAddr, vtep net.IP, isLocal bool) {
|
||||||
|
|
||||||
peerDbWg.Wait()
|
peerDbWg.Wait()
|
||||||
|
@ -145,7 +143,7 @@ func (d *driver) peerDbAdd(nid, eid types.UUID, peerIP net.IP,
|
||||||
pMap.Unlock()
|
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) {
|
peerMac net.HardwareAddr, vtep net.IP) {
|
||||||
peerDbWg.Wait()
|
peerDbWg.Wait()
|
||||||
|
|
||||||
|
@ -167,7 +165,7 @@ func (d *driver) peerDbDelete(nid, eid types.UUID, peerIP net.IP,
|
||||||
pMap.Unlock()
|
pMap.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *driver) peerDbUpdateSandbox(nid types.UUID) {
|
func (d *driver) peerDbUpdateSandbox(nid string) {
|
||||||
d.peerDb.Lock()
|
d.peerDb.Lock()
|
||||||
pMap, ok := d.peerDb.mp[nid]
|
pMap, ok := d.peerDb.mp[nid]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -214,7 +212,7 @@ func (d *driver) peerDbUpdateSandbox(nid types.UUID) {
|
||||||
peerDbWg.Done()
|
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 {
|
peerMac net.HardwareAddr, vtep net.IP, updateDb bool) error {
|
||||||
|
|
||||||
if err := validateID(nid, eid); err != nil {
|
if err := validateID(nid, eid); err != nil {
|
||||||
|
@ -249,7 +247,7 @@ func (d *driver) peerAdd(nid, eid types.UUID, peerIP net.IP,
|
||||||
return nil
|
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 {
|
peerMac net.HardwareAddr, vtep net.IP, updateDb bool) error {
|
||||||
|
|
||||||
if err := validateID(nid, eid); err != nil {
|
if err := validateID(nid, eid); err != nil {
|
||||||
|
|
|
@ -127,8 +127,6 @@ type JoinResponse struct {
|
||||||
InterfaceNames []*InterfaceName
|
InterfaceNames []*InterfaceName
|
||||||
Gateway string
|
Gateway string
|
||||||
GatewayIPv6 string
|
GatewayIPv6 string
|
||||||
HostsPath string
|
|
||||||
ResolvConfPath string
|
|
||||||
StaticRoutes []StaticRoute
|
StaticRoutes []StaticRoute
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -57,20 +57,20 @@ func (d *driver) call(methodName string, arg interface{}, retVal maybeError) err
|
||||||
return nil
|
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{
|
create := &api.CreateNetworkRequest{
|
||||||
NetworkID: string(id),
|
NetworkID: id,
|
||||||
Options: options,
|
Options: options,
|
||||||
}
|
}
|
||||||
return d.call("CreateNetwork", create, &api.CreateNetworkResponse{})
|
return d.call("CreateNetwork", create, &api.CreateNetworkResponse{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *driver) DeleteNetwork(nid types.UUID) error {
|
func (d *driver) DeleteNetwork(nid string) error {
|
||||||
delete := &api.DeleteNetworkRequest{NetworkID: string(nid)}
|
delete := &api.DeleteNetworkRequest{NetworkID: nid}
|
||||||
return d.call("DeleteNetwork", delete, &api.DeleteNetworkResponse{})
|
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 {
|
if epInfo == nil {
|
||||||
return fmt.Errorf("must not be called with nil EndpointInfo")
|
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{
|
create := &api.CreateEndpointRequest{
|
||||||
NetworkID: string(nid),
|
NetworkID: nid,
|
||||||
EndpointID: string(eid),
|
EndpointID: eid,
|
||||||
Interfaces: reqIfaces,
|
Interfaces: reqIfaces,
|
||||||
Options: epOptions,
|
Options: epOptions,
|
||||||
}
|
}
|
||||||
|
@ -129,18 +129,18 @@ func errorWithRollback(msg string, err error) error {
|
||||||
return fmt.Errorf("%s; %s", msg, rollback)
|
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{
|
delete := &api.DeleteEndpointRequest{
|
||||||
NetworkID: string(nid),
|
NetworkID: nid,
|
||||||
EndpointID: string(eid),
|
EndpointID: eid,
|
||||||
}
|
}
|
||||||
return d.call("DeleteEndpoint", delete, &api.DeleteEndpointResponse{})
|
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{
|
info := &api.EndpointInfoRequest{
|
||||||
NetworkID: string(nid),
|
NetworkID: nid,
|
||||||
EndpointID: string(eid),
|
EndpointID: eid,
|
||||||
}
|
}
|
||||||
var res api.EndpointInfoResponse
|
var res api.EndpointInfoResponse
|
||||||
if err := d.call("EndpointOperInfo", info, &res); err != nil {
|
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.
|
// 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{
|
join := &api.JoinRequest{
|
||||||
NetworkID: string(nid),
|
NetworkID: nid,
|
||||||
EndpointID: string(eid),
|
EndpointID: eid,
|
||||||
SandboxKey: sboxKey,
|
SandboxKey: sboxKey,
|
||||||
Options: options,
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Leave method is invoked when a Sandbox detaches from an endpoint.
|
// Leave method is invoked when a Sandbox detaches from an endpoint.
|
||||||
func (d *driver) Leave(nid, eid types.UUID) error {
|
func (d *driver) Leave(nid, eid string) error {
|
||||||
leave := &api.LeaveRequest{
|
leave := &api.LeaveRequest{
|
||||||
NetworkID: string(nid),
|
NetworkID: nid,
|
||||||
EndpointID: string(eid),
|
EndpointID: eid,
|
||||||
}
|
}
|
||||||
return d.call("Leave", leave, &api.LeaveResponse{})
|
return d.call("Leave", leave, &api.LeaveResponse{})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
package windows
|
package windows
|
||||||
|
|
||||||
import (
|
import "github.com/docker/libnetwork/driverapi"
|
||||||
"github.com/docker/libnetwork/driverapi"
|
|
||||||
"github.com/docker/libnetwork/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
const networkType = "windows"
|
const networkType = "windows"
|
||||||
|
|
||||||
|
@ -23,33 +20,33 @@ func (d *driver) Config(option map[string]interface{}) error {
|
||||||
return nil
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *driver) DeleteNetwork(nid types.UUID) error {
|
func (d *driver) DeleteNetwork(nid string) error {
|
||||||
return nil
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *driver) DeleteEndpoint(nid, eid types.UUID) error {
|
func (d *driver) DeleteEndpoint(nid, eid string) error {
|
||||||
return nil
|
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
|
return make(map[string]interface{}, 0), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Join method is invoked when a Sandbox is attached to an endpoint.
|
// Join method is invoked when a Sandbox is attached to an endpoint.
|
||||||
func (d *driver) Join(nid, eid types.UUID, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
|
func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Leave method is invoked when a Sandbox detaches from an endpoint.
|
// Leave method is invoked when a Sandbox detaches from an endpoint.
|
||||||
func (d *driver) Leave(nid, eid types.UUID) error {
|
func (d *driver) Leave(nid, eid string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
674
vendor/src/github.com/docker/libnetwork/endpoint.go
vendored
674
vendor/src/github.com/docker/libnetwork/endpoint.go
vendored
|
@ -1,22 +1,14 @@
|
||||||
package libnetwork
|
package libnetwork
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"net"
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
"path/filepath"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
log "github.com/Sirupsen/logrus"
|
log "github.com/Sirupsen/logrus"
|
||||||
"github.com/docker/docker/pkg/ioutils"
|
|
||||||
"github.com/docker/libnetwork/datastore"
|
"github.com/docker/libnetwork/datastore"
|
||||||
"github.com/docker/libnetwork/etchosts"
|
|
||||||
"github.com/docker/libnetwork/netlabel"
|
"github.com/docker/libnetwork/netlabel"
|
||||||
"github.com/docker/libnetwork/resolvconf"
|
|
||||||
"github.com/docker/libnetwork/sandbox"
|
|
||||||
"github.com/docker/libnetwork/types"
|
"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 returns the name of the network to which this endpoint is attached.
|
||||||
Network() string
|
Network() string
|
||||||
|
|
||||||
// Join creates a new sandbox for the given container ID and populates the
|
// Join joins the sandbox to the endpoint and populates into the sandbox
|
||||||
// network resources allocated for the endpoint and joins the sandbox to
|
// the network resources allocated for the endpoint.
|
||||||
// the endpoint.
|
Join(sandbox Sandbox, options ...EndpointOption) error
|
||||||
Join(containerID string, options ...EndpointOption) error
|
|
||||||
|
|
||||||
// Leave removes the sandbox associated with container ID and detaches
|
// Leave detaches the network resources populated in the sandbox.
|
||||||
// the network resources populated in the sandbox
|
Leave(sandbox Sandbox, options ...EndpointOption) error
|
||||||
Leave(containerID string, options ...EndpointOption) error
|
|
||||||
|
|
||||||
// Return certain operational data belonging to this endpoint
|
// Return certain operational data belonging to this endpoint
|
||||||
Info() EndpointInfo
|
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 returns a collection of driver operational data related to this endpoint retrieved from the driver
|
||||||
DriverInfo() (map[string]interface{}, error)
|
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 and detaches this endpoint from the network.
|
||||||
Delete() error
|
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
|
// 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 <Create|Join|Leave>Option[...](...)
|
// provided by libnetwork, they look like <Create|Join|Leave>Option[...](...)
|
||||||
type EndpointOption func(ep *endpoint)
|
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 {
|
type endpoint struct {
|
||||||
name string
|
name string
|
||||||
id types.UUID
|
id string
|
||||||
network *network
|
network *network
|
||||||
iFaces []*endpointInterface
|
iFaces []*endpointInterface
|
||||||
joinInfo *endpointJoinInfo
|
joinInfo *endpointJoinInfo
|
||||||
container *containerInfo
|
sandboxID string
|
||||||
exposedPorts []types.TransportPort
|
exposedPorts []types.TransportPort
|
||||||
generic map[string]interface{}
|
generic map[string]interface{}
|
||||||
joinLeaveDone chan struct{}
|
joinLeaveDone chan struct{}
|
||||||
|
@ -131,39 +60,17 @@ type endpoint struct {
|
||||||
sync.Mutex
|
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) {
|
func (ep *endpoint) MarshalJSON() ([]byte, error) {
|
||||||
ep.Lock()
|
ep.Lock()
|
||||||
defer ep.Unlock()
|
defer ep.Unlock()
|
||||||
|
|
||||||
epMap := make(map[string]interface{})
|
epMap := make(map[string]interface{})
|
||||||
epMap["name"] = ep.name
|
epMap["name"] = ep.name
|
||||||
epMap["id"] = string(ep.id)
|
epMap["id"] = ep.id
|
||||||
epMap["ep_iface"] = ep.iFaces
|
epMap["ep_iface"] = ep.iFaces
|
||||||
epMap["exposed_ports"] = ep.exposedPorts
|
epMap["exposed_ports"] = ep.exposedPorts
|
||||||
epMap["generic"] = ep.generic
|
epMap["generic"] = ep.generic
|
||||||
if ep.container != nil {
|
epMap["sandbox"] = ep.sandboxID
|
||||||
epMap["container"] = ep.container
|
|
||||||
}
|
|
||||||
return json.Marshal(epMap)
|
return json.Marshal(epMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,7 +83,7 @@ func (ep *endpoint) UnmarshalJSON(b []byte) (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
ep.name = epMap["name"].(string)
|
ep.name = epMap["name"].(string)
|
||||||
ep.id = types.UUID(epMap["id"].(string))
|
ep.id = epMap["id"].(string)
|
||||||
|
|
||||||
ib, _ := json.Marshal(epMap["ep_iface"])
|
ib, _ := json.Marshal(epMap["ep_iface"])
|
||||||
var ifaces []endpointInterface
|
var ifaces []endpointInterface
|
||||||
|
@ -191,13 +98,8 @@ func (ep *endpoint) UnmarshalJSON(b []byte) (err error) {
|
||||||
json.Unmarshal(tb, &tPorts)
|
json.Unmarshal(tb, &tPorts)
|
||||||
ep.exposedPorts = tPorts
|
ep.exposedPorts = tPorts
|
||||||
|
|
||||||
epc, ok := epMap["container"]
|
cb, _ := json.Marshal(epMap["sandbox"])
|
||||||
if ok {
|
json.Unmarshal(cb, &ep.sandboxID)
|
||||||
cb, _ := json.Marshal(epc)
|
|
||||||
var cInfo containerInfo
|
|
||||||
json.Unmarshal(cb, &cInfo)
|
|
||||||
ep.container = &cInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
if epMap["generic"] != nil {
|
if epMap["generic"] != nil {
|
||||||
ep.generic = epMap["generic"].(map[string]interface{})
|
ep.generic = epMap["generic"].(map[string]interface{})
|
||||||
|
@ -205,13 +107,11 @@ func (ep *endpoint) UnmarshalJSON(b []byte) (err error) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultPrefix = "/var/lib/docker/network/files"
|
|
||||||
|
|
||||||
func (ep *endpoint) ID() string {
|
func (ep *endpoint) ID() string {
|
||||||
ep.Lock()
|
ep.Lock()
|
||||||
defer ep.Unlock()
|
defer ep.Unlock()
|
||||||
|
|
||||||
return string(ep.id)
|
return ep.id
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ep *endpoint) Name() string {
|
func (ep *endpoint) Name() string {
|
||||||
|
@ -222,36 +122,27 @@ func (ep *endpoint) Name() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ep *endpoint) Network() string {
|
func (ep *endpoint) Network() string {
|
||||||
ep.Lock()
|
return ep.getNetwork().name
|
||||||
defer ep.Unlock()
|
|
||||||
|
|
||||||
return ep.network.name
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// endpoint Key structure : endpoint/network-id/endpoint-id
|
// endpoint Key structure : endpoint/network-id/endpoint-id
|
||||||
func (ep *endpoint) Key() []string {
|
func (ep *endpoint) Key() []string {
|
||||||
ep.Lock()
|
return []string{datastore.EndpointKeyPrefix, ep.getNetwork().id, ep.id}
|
||||||
n := ep.network
|
|
||||||
defer ep.Unlock()
|
|
||||||
return []string{datastore.EndpointKeyPrefix, string(n.id), string(ep.id)}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ep *endpoint) KeyPrefix() []string {
|
func (ep *endpoint) KeyPrefix() []string {
|
||||||
ep.Lock()
|
return []string{datastore.EndpointKeyPrefix, ep.getNetwork().id}
|
||||||
n := ep.network
|
|
||||||
defer ep.Unlock()
|
|
||||||
return []string{datastore.EndpointKeyPrefix, string(n.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
|
// 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
|
// 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 {
|
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
|
// 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 {
|
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
|
// joinLeaveStart waits to ensure there are no joins or leaves in progress and
|
||||||
// marks this join/leave in progress without race
|
// marks this join/leave in progress without race
|
||||||
func (ep *endpoint) joinLeaveStart() {
|
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
|
var err error
|
||||||
|
|
||||||
if containerID == "" {
|
if sbox == nil {
|
||||||
return InvalidContainerIDError(containerID)
|
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()
|
ep.joinLeaveStart()
|
||||||
defer func() {
|
defer ep.joinLeaveEnd()
|
||||||
ep.joinLeaveEnd()
|
|
||||||
}()
|
|
||||||
|
|
||||||
ep.Lock()
|
ep.Lock()
|
||||||
if ep.container != nil {
|
if ep.sandboxID != "" {
|
||||||
ep.Unlock()
|
ep.Unlock()
|
||||||
return ErrInvalidJoin{}
|
return types.ForbiddenErrorf("a sandbox has already joined the endpoint")
|
||||||
}
|
}
|
||||||
|
|
||||||
ep.container = &containerInfo{
|
ep.sandboxID = sbox.ID()
|
||||||
id: containerID,
|
|
||||||
config: containerConfig{
|
|
||||||
hostsPathConfig: hostsPathConfig{
|
|
||||||
extraHosts: []extraHost{},
|
|
||||||
parentUpdates: []parentUpdate{},
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
|
|
||||||
ep.joinInfo = &endpointJoinInfo{}
|
ep.joinInfo = &endpointJoinInfo{}
|
||||||
|
|
||||||
container := ep.container
|
|
||||||
network := ep.network
|
network := ep.network
|
||||||
epid := ep.id
|
epid := ep.id
|
||||||
|
|
||||||
ep.Unlock()
|
ep.Unlock()
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ep.Lock()
|
ep.Lock()
|
||||||
ep.container = nil
|
ep.sandboxID = ""
|
||||||
ep.Unlock()
|
ep.Unlock()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
@ -394,17 +256,11 @@ func (ep *endpoint) Join(containerID string, options ...EndpointOption) error {
|
||||||
network.Lock()
|
network.Lock()
|
||||||
driver := network.driver
|
driver := network.driver
|
||||||
nid := network.id
|
nid := network.id
|
||||||
ctrlr := network.ctrlr
|
|
||||||
network.Unlock()
|
network.Unlock()
|
||||||
|
|
||||||
ep.processOptions(options...)
|
ep.processOptions(options...)
|
||||||
|
|
||||||
sboxKey := sandbox.GenerateKey(containerID)
|
err = driver.Join(nid, epid, sbox.Key(), ep, sbox.Labels())
|
||||||
if container.config.useDefaultSandBox {
|
|
||||||
sboxKey = sandbox.GenerateKey("default")
|
|
||||||
}
|
|
||||||
|
|
||||||
err = driver.Join(nid, epid, sboxKey, ep, container.config.generic)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -417,36 +273,26 @@ func (ep *endpoint) Join(containerID string, options ...EndpointOption) error {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
err = ep.buildHostsFiles()
|
address := ""
|
||||||
if err != nil {
|
if ip := ep.getFirstInterfaceAddress(); ip != nil {
|
||||||
|
address = ip.String()
|
||||||
|
}
|
||||||
|
if err = sb.updateHostsFile(address, network.getSvcRecords()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = ep.updateParentHosts()
|
if err = sb.updateDNS(ep.getNetwork().enableIPv6); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = ep.setupDNS()
|
if err = network.ctrlr.updateEndpointToStore(ep); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
sb, err := ctrlr.sandboxAdd(sboxKey, !container.config.useDefaultSandBox, ep)
|
if err = sb.populateNetworkResources(ep); err != nil {
|
||||||
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 {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
container.data.SandboxKey = sb.Key()
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -463,49 +309,54 @@ func (ep *endpoint) hasInterface(iName string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ep *endpoint) Leave(containerID string, options ...EndpointOption) error {
|
func (ep *endpoint) Leave(sbox Sandbox, options ...EndpointOption) error {
|
||||||
var err error
|
|
||||||
|
|
||||||
ep.joinLeaveStart()
|
ep.joinLeaveStart()
|
||||||
defer ep.joinLeaveEnd()
|
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.processOptions(options...)
|
||||||
|
|
||||||
ep.Lock()
|
ep.Lock()
|
||||||
container := ep.container
|
ep.sandboxID = ""
|
||||||
n := ep.network
|
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()
|
ep.Unlock()
|
||||||
|
|
||||||
n.Lock()
|
n.Lock()
|
||||||
driver := n.driver
|
c := n.ctrlr
|
||||||
ctrlr := n.ctrlr
|
d := n.driver
|
||||||
n.Unlock()
|
n.Unlock()
|
||||||
|
|
||||||
if err := ctrlr.updateEndpointToStore(ep); err != nil {
|
if err := c.updateEndpointToStore(ep); err != nil {
|
||||||
ep.Lock()
|
ep.Lock()
|
||||||
ep.container = container
|
ep.sandboxID = sid
|
||||||
ep.Unlock()
|
ep.Unlock()
|
||||||
return err
|
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 sb.clearNetworkResources(ep)
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ep *endpoint) Delete() error {
|
func (ep *endpoint) Delete() error {
|
||||||
|
@ -514,9 +365,9 @@ func (ep *endpoint) Delete() error {
|
||||||
epid := ep.id
|
epid := ep.id
|
||||||
name := ep.name
|
name := ep.name
|
||||||
n := ep.network
|
n := ep.network
|
||||||
if ep.container != nil {
|
if ep.sandboxID != "" {
|
||||||
ep.Unlock()
|
ep.Unlock()
|
||||||
return &ActiveContainerError{name: name, id: string(epid)}
|
return &ActiveContainerError{name: name, id: epid}
|
||||||
}
|
}
|
||||||
n.Lock()
|
n.Lock()
|
||||||
ctrlr := n.ctrlr
|
ctrlr := n.ctrlr
|
||||||
|
@ -556,33 +407,6 @@ func (ep *endpoint) Delete() error {
|
||||||
return nil
|
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 {
|
func (ep *endpoint) deleteEndpoint() error {
|
||||||
ep.Lock()
|
ep.Lock()
|
||||||
n := ep.network
|
n := ep.network
|
||||||
|
@ -616,260 +440,36 @@ func (ep *endpoint) deleteEndpoint() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ep *endpoint) addHostEntries(recs []etchosts.Record) {
|
func (ep *endpoint) getNetwork() *network {
|
||||||
ep.Lock()
|
ep.Lock()
|
||||||
container := ep.container
|
defer ep.Unlock()
|
||||||
ep.Unlock()
|
return ep.network
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ep *endpoint) deleteHostEntries(recs []etchosts.Record) {
|
func (ep *endpoint) getSandbox() (*sandbox, bool) {
|
||||||
ep.Lock()
|
ep.Lock()
|
||||||
container := ep.container
|
c := ep.network.getController()
|
||||||
|
sid := ep.sandboxID
|
||||||
ep.Unlock()
|
ep.Unlock()
|
||||||
|
|
||||||
if container == nil {
|
c.Lock()
|
||||||
return
|
ps, ok := c.sandboxes[sid]
|
||||||
}
|
c.Unlock()
|
||||||
|
|
||||||
if err := etchosts.Delete(container.config.hostsPath, recs); err != nil {
|
return ps, ok
|
||||||
log.Warnf("Failed deleting service host entries to the running container: %v", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ep *endpoint) buildHostsFiles() error {
|
func (ep *endpoint) getFirstInterfaceAddress() net.IP {
|
||||||
var extraContent []etchosts.Record
|
|
||||||
|
|
||||||
ep.Lock()
|
ep.Lock()
|
||||||
container := ep.container
|
defer ep.Unlock()
|
||||||
joinInfo := ep.joinInfo
|
|
||||||
ifaces := ep.iFaces
|
|
||||||
n := ep.network
|
|
||||||
ep.Unlock()
|
|
||||||
|
|
||||||
if container == nil {
|
if len(ep.iFaces) != 0 && ep.iFaces[0] != nil {
|
||||||
return ErrNoContainer{}
|
return ep.iFaces[0].addr.IP
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
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
|
// EndpointOptionGeneric function returns an option setter for a Generic option defined
|
||||||
// in a Dictionary of Key-Value pair
|
// in a Dictionary of Key-Value pair
|
||||||
func EndpointOptionGeneric(generic map[string]interface{}) EndpointOption {
|
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
|
// CreateOptionExposedPorts function returns an option setter for the container exposed
|
||||||
// ports option to be passed to network.CreateEndpoint() method.
|
// ports option to be passed to network.CreateEndpoint() method.
|
||||||
func CreateOptionExposedPorts(exposedPorts []types.TransportPort) EndpointOption {
|
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
|
// JoinOptionPriority function returns an option setter for priority option to
|
||||||
// that is not managed by libNetwork but can be used by the Drivers during the call to
|
// be passed to the endpoint.Join() method.
|
||||||
// endpoint join method. Container Labels are a good example.
|
func JoinOptionPriority(ep Endpoint, prio int) EndpointOption {
|
||||||
func JoinOptionGeneric(generic map[string]interface{}) EndpointOption {
|
|
||||||
return func(ep *endpoint) {
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,10 +22,8 @@ type EndpointInfo interface {
|
||||||
// This will only return a valid value if a container has joined the endpoint.
|
// This will only return a valid value if a container has joined the endpoint.
|
||||||
GatewayIPv6() net.IP
|
GatewayIPv6() net.IP
|
||||||
|
|
||||||
// SandboxKey returns the sanbox key for the container which has joined
|
// Sandbox returns the attached sandbox if there, nil otherwise.
|
||||||
// the endpoint. If there is no container joined then this will return an
|
Sandbox() Sandbox
|
||||||
// empty string.
|
|
||||||
SandboxKey() string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// InterfaceInfo provides an interface to retrieve interface addresses bound to the endpoint.
|
// InterfaceInfo provides an interface to retrieve interface addresses bound to the endpoint.
|
||||||
|
@ -40,14 +38,6 @@ type InterfaceInfo interface {
|
||||||
AddressIPv6() net.IPNet
|
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 {
|
type endpointInterface struct {
|
||||||
id int
|
id int
|
||||||
mac net.HardwareAddr
|
mac net.HardwareAddr
|
||||||
|
@ -115,23 +105,9 @@ func (epi *endpointInterface) UnmarshalJSON(b []byte) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
type endpointJoinInfo struct {
|
type endpointJoinInfo struct {
|
||||||
gw net.IP
|
gw net.IP
|
||||||
gw6 net.IP
|
gw6 net.IP
|
||||||
hostsPath string
|
StaticRoutes []*types.StaticRoute
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ep *endpoint) Info() EndpointInfo {
|
func (ep *endpoint) Info() EndpointInfo {
|
||||||
|
@ -257,15 +233,12 @@ func (ep *endpoint) addInterfaceRoute(route *types.StaticRoute) error {
|
||||||
route.InterfaceID)
|
route.InterfaceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ep *endpoint) SandboxKey() string {
|
func (ep *endpoint) Sandbox() Sandbox {
|
||||||
ep.Lock()
|
cnt, ok := ep.getSandbox()
|
||||||
defer ep.Unlock()
|
if !ok {
|
||||||
|
return nil
|
||||||
if ep.container == nil {
|
|
||||||
return ""
|
|
||||||
}
|
}
|
||||||
|
return cnt
|
||||||
return ep.container.data.SandboxKey
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ep *endpoint) Gateway() net.IP {
|
func (ep *endpoint) Gateway() net.IP {
|
||||||
|
@ -305,19 +278,3 @@ func (ep *endpoint) SetGatewayIPv6(gw6 net.IP) error {
|
||||||
ep.joinInfo.gw6 = types.GetIPCopy(gw6)
|
ep.joinInfo.gw6 = types.GetIPCopy(gw6)
|
||||||
return nil
|
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
|
|
||||||
}
|
|
||||||
|
|
|
@ -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
|
package idm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -6,7 +6,6 @@ import (
|
||||||
|
|
||||||
"github.com/docker/libnetwork/bitseq"
|
"github.com/docker/libnetwork/bitseq"
|
||||||
"github.com/docker/libnetwork/datastore"
|
"github.com/docker/libnetwork/datastore"
|
||||||
"github.com/docker/libnetwork/types"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Idm manages the reservation/release of numerical ids from a contiguos set
|
// 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)
|
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 {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to initialize bit sequence handler: %s", err.Error())
|
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 {
|
if i.handle == nil {
|
||||||
return 0, fmt.Errorf("ID set is not initialized")
|
return 0, fmt.Errorf("ID set is not initialized")
|
||||||
}
|
}
|
||||||
|
ordinal, err := i.handle.SetAny()
|
||||||
for {
|
return i.start + ordinal, err
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSpecificID tries to reserve the specified id
|
// 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")
|
return fmt.Errorf("Requested id does not belong to the set")
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
return i.handle.Set(id - i.start)
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Release releases the specified id
|
// Release releases the specified id
|
||||||
func (i *Idm) Release(id uint32) {
|
func (i *Idm) Release(id uint32) {
|
||||||
ordinal := id - i.start
|
i.handle.Unset(id - i.start)
|
||||||
i.handle.PushReservation(int(ordinal/8), int(ordinal%8), true)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,6 @@
|
||||||
package netutils
|
package netutils
|
||||||
|
|
||||||
import (
|
import "flag"
|
||||||
"flag"
|
|
||||||
"runtime"
|
|
||||||
"syscall"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
var runningInContainer = flag.Bool("incontainer", false, "Indicates if the test is running in a container")
|
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 {
|
func IsRunningInContainer() bool {
|
||||||
return (*runningInContainer)
|
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -59,17 +59,7 @@ func CheckRouteOverlaps(toCheck *net.IPNet) error {
|
||||||
|
|
||||||
// NetworkOverlaps detects overlap between one IPNet and another
|
// NetworkOverlaps detects overlap between one IPNet and another
|
||||||
func NetworkOverlaps(netX *net.IPNet, netY *net.IPNet) bool {
|
func NetworkOverlaps(netX *net.IPNet, netY *net.IPNet) bool {
|
||||||
// Check if both netX and netY are ipv4 or ipv6
|
return netX.Contains(netY.IP) || netY.Contains(netX.IP)
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NetworkRange calculates the first and last IP addresses in an IPNet
|
// 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")
|
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)
|
|
||||||
}
|
|
||||||
|
|
|
@ -59,7 +59,7 @@ type network struct {
|
||||||
ctrlr *controller
|
ctrlr *controller
|
||||||
name string
|
name string
|
||||||
networkType string
|
networkType string
|
||||||
id types.UUID
|
id string
|
||||||
driver driverapi.Driver
|
driver driverapi.Driver
|
||||||
enableIPv6 bool
|
enableIPv6 bool
|
||||||
endpointCnt uint64
|
endpointCnt uint64
|
||||||
|
@ -83,7 +83,7 @@ func (n *network) ID() string {
|
||||||
n.Lock()
|
n.Lock()
|
||||||
defer n.Unlock()
|
defer n.Unlock()
|
||||||
|
|
||||||
return string(n.id)
|
return n.id
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *network) Type() string {
|
func (n *network) Type() string {
|
||||||
|
@ -100,7 +100,7 @@ func (n *network) Type() string {
|
||||||
func (n *network) Key() []string {
|
func (n *network) Key() []string {
|
||||||
n.Lock()
|
n.Lock()
|
||||||
defer n.Unlock()
|
defer n.Unlock()
|
||||||
return []string{datastore.NetworkKeyPrefix, string(n.id)}
|
return []string{datastore.NetworkKeyPrefix, n.id}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *network) KeyPrefix() []string {
|
func (n *network) KeyPrefix() []string {
|
||||||
|
@ -162,7 +162,7 @@ func (n *network) DecEndpointCnt() {
|
||||||
func (n *network) MarshalJSON() ([]byte, error) {
|
func (n *network) MarshalJSON() ([]byte, error) {
|
||||||
netMap := make(map[string]interface{})
|
netMap := make(map[string]interface{})
|
||||||
netMap["name"] = n.name
|
netMap["name"] = n.name
|
||||||
netMap["id"] = string(n.id)
|
netMap["id"] = n.id
|
||||||
netMap["networkType"] = n.networkType
|
netMap["networkType"] = n.networkType
|
||||||
netMap["endpointCnt"] = n.endpointCnt
|
netMap["endpointCnt"] = n.endpointCnt
|
||||||
netMap["enableIPv6"] = n.enableIPv6
|
netMap["enableIPv6"] = n.enableIPv6
|
||||||
|
@ -177,7 +177,7 @@ func (n *network) UnmarshalJSON(b []byte) (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
n.name = netMap["name"].(string)
|
n.name = netMap["name"].(string)
|
||||||
n.id = types.UUID(netMap["id"].(string))
|
n.id = netMap["id"].(string)
|
||||||
n.networkType = netMap["networkType"].(string)
|
n.networkType = netMap["networkType"].(string)
|
||||||
n.endpointCnt = uint64(netMap["endpointCnt"].(float64))
|
n.endpointCnt = uint64(netMap["endpointCnt"].(float64))
|
||||||
n.enableIPv6 = netMap["enableIPv6"].(bool)
|
n.enableIPv6 = netMap["enableIPv6"].(bool)
|
||||||
|
@ -223,12 +223,12 @@ func (n *network) Delete() error {
|
||||||
ctrlr.Unlock()
|
ctrlr.Unlock()
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
return &UnknownNetworkError{name: n.name, id: string(n.id)}
|
return &UnknownNetworkError{name: n.name, id: n.id}
|
||||||
}
|
}
|
||||||
|
|
||||||
numEps := n.EndpointCnt()
|
numEps := n.EndpointCnt()
|
||||||
if numEps != 0 {
|
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
|
// 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)
|
err = d.CreateEndpoint(n.id, ep.id, ep, ep.generic)
|
||||||
if err != nil {
|
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)
|
n.updateSvcRecord(ep, true)
|
||||||
|
@ -307,7 +307,7 @@ func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoi
|
||||||
ep := &endpoint{name: name,
|
ep := &endpoint{name: name,
|
||||||
iFaces: []*endpointInterface{},
|
iFaces: []*endpointInterface{},
|
||||||
generic: make(map[string]interface{})}
|
generic: make(map[string]interface{})}
|
||||||
ep.id = types.UUID(stringid.GenerateRandomID())
|
ep.id = stringid.GenerateRandomID()
|
||||||
ep.network = n
|
ep.network = n
|
||||||
ep.processOptions(options...)
|
ep.processOptions(options...)
|
||||||
|
|
||||||
|
@ -393,7 +393,7 @@ func (n *network) EndpointByID(id string) (Endpoint, error) {
|
||||||
}
|
}
|
||||||
n.Lock()
|
n.Lock()
|
||||||
defer n.Unlock()
|
defer n.Unlock()
|
||||||
if e, ok := n.endpoints[types.UUID(id)]; ok {
|
if e, ok := n.endpoints[id]; ok {
|
||||||
return e, nil
|
return e, nil
|
||||||
}
|
}
|
||||||
return nil, ErrNoSuchEndpoint(id)
|
return nil, ErrNoSuchEndpoint(id)
|
||||||
|
@ -435,22 +435,19 @@ func (n *network) updateSvcRecord(ep *endpoint, isAdd bool) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var epList []*endpoint
|
var sbList []*sandbox
|
||||||
n.WalkEndpoints(func(e Endpoint) bool {
|
n.WalkEndpoints(func(e Endpoint) bool {
|
||||||
cEp := e.(*endpoint)
|
if sb, hasSandbox := e.(*endpoint).getSandbox(); hasSandbox {
|
||||||
cEp.Lock()
|
sbList = append(sbList, sb)
|
||||||
if cEp.container != nil {
|
|
||||||
epList = append(epList, cEp)
|
|
||||||
}
|
}
|
||||||
cEp.Unlock()
|
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
|
|
||||||
for _, cEp := range epList {
|
for _, sb := range sbList {
|
||||||
if isAdd {
|
if isAdd {
|
||||||
cEp.addHostEntries(recs)
|
sb.addHostsEntries(recs)
|
||||||
} else {
|
} else {
|
||||||
cEp.deleteHostEntries(recs)
|
sb.deleteHostsEntries(recs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -469,3 +466,9 @@ func (n *network) getSvcRecords() []etchosts.Record {
|
||||||
|
|
||||||
return recs
|
return recs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *network) getController() *controller {
|
||||||
|
n.Lock()
|
||||||
|
defer n.Unlock()
|
||||||
|
return n.ctrlr
|
||||||
|
}
|
||||||
|
|
|
@ -29,6 +29,18 @@ func (e CannotSetFieldError) Error() string {
|
||||||
return fmt.Sprintf("cannot set field %q of type %q", e.Field, e.Type)
|
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.
|
// Generic is an basic type to store arbitrary settings.
|
||||||
type Generic map[string]interface{}
|
type Generic map[string]interface{}
|
||||||
|
|
||||||
|
@ -62,6 +74,9 @@ func GenerateFromModel(options Generic, model interface{}) (interface{}, error)
|
||||||
if !field.CanSet() {
|
if !field.CanSet() {
|
||||||
return nil, CannotSetFieldError{name, resType.String()}
|
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))
|
field.Set(reflect.ValueOf(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package sandbox
|
package osl
|
||||||
|
|
||||||
// IfaceOption is a function option type to set interface options
|
// IfaceOption is a function option type to set interface options
|
||||||
type IfaceOption func()
|
type IfaceOption func()
|
|
@ -1,4 +1,4 @@
|
||||||
package sandbox
|
package osl
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
|
@ -1,4 +1,4 @@
|
||||||
package sandbox
|
package osl
|
||||||
|
|
||||||
// IfaceOption is a function option type to set interface options
|
// IfaceOption is a function option type to set interface options
|
||||||
type IfaceOption func()
|
type IfaceOption func()
|
|
@ -1,4 +1,4 @@
|
||||||
package sandbox
|
package osl
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -26,6 +26,8 @@ var (
|
||||||
gpmWg sync.WaitGroup
|
gpmWg sync.WaitGroup
|
||||||
gpmCleanupPeriod = 60 * time.Second
|
gpmCleanupPeriod = 60 * time.Second
|
||||||
gpmChan = make(chan chan struct{})
|
gpmChan = make(chan chan struct{})
|
||||||
|
nsOnce sync.Once
|
||||||
|
initNs netns.NsHandle
|
||||||
)
|
)
|
||||||
|
|
||||||
// The networkNamespace type is the linux implementation of the Sandbox
|
// 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 {
|
func getLink() (string, error) {
|
||||||
runtime.LockOSThread()
|
return os.Readlink(fmt.Sprintf("/proc/%d/task/%d/ns/net", os.Getpid(), syscall.Gettid()))
|
||||||
defer runtime.UnlockOSThread()
|
}
|
||||||
|
|
||||||
origns, err := netns.Get()
|
func nsInit() {
|
||||||
if err != nil {
|
var err error
|
||||||
return err
|
|
||||||
|
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)
|
f, err := os.OpenFile(path, os.O_RDONLY, 0)
|
||||||
if err != nil {
|
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 {
|
if err = netns.Set(netns.NsHandle(nsFD)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer netns.Set(origns)
|
defer netns.Set(initNs)
|
||||||
|
|
||||||
// Invoked after the namespace switch.
|
// Invoked after the namespace switch.
|
||||||
return postfunc(int(origns))
|
return postfunc(int(initNs))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *networkNamespace) nsPath() string {
|
func (n *networkNamespace) nsPath() string {
|
|
@ -1,6 +1,6 @@
|
||||||
// +build !linux,!windows,!freebsd
|
// +build !linux,!windows,!freebsd
|
||||||
|
|
||||||
package sandbox
|
package osl
|
||||||
|
|
||||||
// GC triggers garbage collection of namespace path right away
|
// GC triggers garbage collection of namespace path right away
|
||||||
// and waits for it.
|
// and waits for it.
|
|
@ -1,4 +1,6 @@
|
||||||
package sandbox
|
package osl
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
// GenerateKey generates a sandbox key based on the passed
|
// GenerateKey generates a sandbox key based on the passed
|
||||||
// container id.
|
// container id.
|
||||||
|
@ -21,3 +23,13 @@ func NewSandbox(key string, osCreate bool) (Sandbox, error) {
|
||||||
// and waits for it.
|
// and waits for it.
|
||||||
func GC() {
|
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() {}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package sandbox
|
package osl
|
||||||
|
|
||||||
// NeighOption is a function option type to set neighbor options
|
// NeighOption is a function option type to set neighbor options
|
||||||
type NeighOption func()
|
type NeighOption func()
|
|
@ -1,4 +1,4 @@
|
||||||
package sandbox
|
package osl
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
|
@ -1,4 +1,4 @@
|
||||||
package sandbox
|
package osl
|
||||||
|
|
||||||
// NeighOption is a function option type to set neighbor options
|
// NeighOption is a function option type to set neighbor options
|
||||||
type NeighOption func()
|
type NeighOption func()
|
|
@ -1,4 +1,4 @@
|
||||||
package sandbox
|
package osl
|
||||||
|
|
||||||
import "net"
|
import "net"
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package sandbox
|
package osl
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
|
@ -1,4 +1,5 @@
|
||||||
package sandbox
|
// Package osl describes structures and interfaces which abstract os entities
|
||||||
|
package osl
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
|
@ -1,4 +1,6 @@
|
||||||
package sandbox
|
package osl
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
// GenerateKey generates a sandbox key based on the passed
|
// GenerateKey generates a sandbox key based on the passed
|
||||||
// container id.
|
// container id.
|
||||||
|
@ -21,3 +23,13 @@ func NewSandbox(key string, osCreate bool) (Sandbox, error) {
|
||||||
// and waits for it.
|
// and waits for it.
|
||||||
func GC() {
|
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() {}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
// +build !linux,!windows,!freebsd
|
// +build !linux,!windows,!freebsd
|
||||||
|
|
||||||
package sandbox
|
package osl
|
||||||
|
|
||||||
import "errors"
|
import "errors"
|
||||||
|
|
|
@ -188,6 +188,8 @@ func (pm *PortMapper) Unmap(host net.Addr) error {
|
||||||
|
|
||||||
//ReMapAll will re-apply all port mappings
|
//ReMapAll will re-apply all port mappings
|
||||||
func (pm *PortMapper) ReMapAll() {
|
func (pm *PortMapper) ReMapAll() {
|
||||||
|
pm.lock.Lock()
|
||||||
|
defer pm.lock.Unlock()
|
||||||
logrus.Debugln("Re-applying all port mappings.")
|
logrus.Debugln("Re-applying all port mappings.")
|
||||||
for _, data := range pm.currentMappings {
|
for _, data := range pm.currentMappings {
|
||||||
containerIP, containerPort := getIPAndPort(data.container)
|
containerIP, containerPort := getIPAndPort(data.container)
|
||||||
|
|
|
@ -30,6 +30,7 @@ var (
|
||||||
nsIPv6Regexp = regexp.MustCompile(`(?m)^nameserver\s+` + ipv6Address + `\s*\n*`)
|
nsIPv6Regexp = regexp.MustCompile(`(?m)^nameserver\s+` + ipv6Address + `\s*\n*`)
|
||||||
nsRegexp = regexp.MustCompile(`^\s*nameserver\s*((` + ipv4Address + `)|(` + ipv6Address + `))\s*$`)
|
nsRegexp = regexp.MustCompile(`^\s*nameserver\s*((` + ipv4Address + `)|(` + ipv6Address + `))\s*$`)
|
||||||
searchRegexp = regexp.MustCompile(`^\s*search\s*(([^\s]+\s*)*)$`)
|
searchRegexp = regexp.MustCompile(`^\s*search\s*(([^\s]+\s*)*)$`)
|
||||||
|
optionsRegexp = regexp.MustCompile(`^\s*options\s*(([^\s]+\s*)*)$`)
|
||||||
)
|
)
|
||||||
|
|
||||||
var lastModified struct {
|
var lastModified struct {
|
||||||
|
@ -38,46 +39,69 @@ var lastModified struct {
|
||||||
contents []byte
|
contents []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get returns the contents of /etc/resolv.conf
|
// File contains the resolv.conf content and its hash
|
||||||
func Get() ([]byte, error) {
|
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")
|
resolv, err := ioutil.ReadFile("/etc/resolv.conf")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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
|
// 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.
|
// and, if modified since last check, returns the bytes and new hash.
|
||||||
// This feature is used by the resolv.conf updater for containers
|
// This feature is used by the resolv.conf updater for containers
|
||||||
func GetIfChanged() ([]byte, string, error) {
|
func GetIfChanged() (*File, error) {
|
||||||
lastModified.Lock()
|
lastModified.Lock()
|
||||||
defer lastModified.Unlock()
|
defer lastModified.Unlock()
|
||||||
|
|
||||||
resolv, err := ioutil.ReadFile("/etc/resolv.conf")
|
resolv, err := ioutil.ReadFile("/etc/resolv.conf")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
newHash, err := ioutils.HashData(bytes.NewReader(resolv))
|
newHash, err := ioutils.HashData(bytes.NewReader(resolv))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
if lastModified.sha256 != newHash {
|
if lastModified.sha256 != newHash {
|
||||||
lastModified.sha256 = newHash
|
lastModified.sha256 = newHash
|
||||||
lastModified.contents = resolv
|
lastModified.contents = resolv
|
||||||
return resolv, newHash, nil
|
return &File{Content: resolv, Hash: newHash}, nil
|
||||||
}
|
}
|
||||||
// nothing changed, so return no data
|
// 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.
|
// GetLastModified retrieves the last used contents and hash of the host resolv.conf.
|
||||||
// Used by containers updating on restart
|
// Used by containers updating on restart
|
||||||
func GetLastModified() ([]byte, string) {
|
func GetLastModified() *File {
|
||||||
lastModified.Lock()
|
lastModified.Lock()
|
||||||
defer lastModified.Unlock()
|
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:
|
// 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
|
// 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
|
// 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) (*File, error) {
|
||||||
func FilterResolvDNS(resolvConf []byte, ipv6Enabled bool) ([]byte, bool) {
|
|
||||||
changed := false
|
|
||||||
cleanedResolvConf := localhostNSRegexp.ReplaceAll(resolvConf, []byte{})
|
cleanedResolvConf := localhostNSRegexp.ReplaceAll(resolvConf, []byte{})
|
||||||
// if IPv6 is not enabled, also clean out any IPv6 address nameserver
|
// if IPv6 is not enabled, also clean out any IPv6 address nameserver
|
||||||
if !ipv6Enabled {
|
if !ipv6Enabled {
|
||||||
|
@ -106,10 +128,11 @@ func FilterResolvDNS(resolvConf []byte, ipv6Enabled bool) ([]byte, bool) {
|
||||||
}
|
}
|
||||||
cleanedResolvConf = append(cleanedResolvConf, []byte("\n"+strings.Join(dns, "\n"))...)
|
cleanedResolvConf = append(cleanedResolvConf, []byte("\n"+strings.Join(dns, "\n"))...)
|
||||||
}
|
}
|
||||||
if !bytes.Equal(resolvConf, cleanedResolvConf) {
|
hash, err := ioutils.HashData(bytes.NewReader(cleanedResolvConf))
|
||||||
changed = true
|
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.
|
// getLines parses input into lines and strips away comments.
|
||||||
|
@ -165,23 +188,50 @@ func GetSearchDomains(resolvConf []byte) []string {
|
||||||
return domains
|
return domains
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build writes a configuration file to path containing a "nameserver" entry
|
// GetOptions returns options (if any) listed in /etc/resolv.conf
|
||||||
// for every element in dns, and a "search" entry for every element in
|
// If more than one options line is encountered, only the contents of the last
|
||||||
// dnsSearch.
|
// one is returned.
|
||||||
func Build(path string, dns, dnsSearch []string) error {
|
func GetOptions(resolvConf []byte) []string {
|
||||||
content := bytes.NewBuffer(nil)
|
options := []string{}
|
||||||
for _, dns := range dns {
|
for _, line := range getLines(resolvConf, []byte("#")) {
|
||||||
if _, err := content.WriteString("nameserver " + dns + "\n"); err != nil {
|
match := optionsRegexp.FindSubmatch(line)
|
||||||
return err
|
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 len(dnsSearch) > 0 {
|
||||||
if searchString := strings.Join(dnsSearch, " "); strings.Trim(searchString, " ") != "." {
|
if searchString := strings.Join(dnsSearch, " "); strings.Trim(searchString, " ") != "." {
|
||||||
if _, err := content.WriteString("search " + searchString + "\n"); err != nil {
|
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)
|
||||||
}
|
}
|
||||||
|
|
744
vendor/src/github.com/docker/libnetwork/sandbox.go
vendored
Normal file
744
vendor/src/github.com/docker/libnetwork/sandbox.go
vendored
Normal file
|
@ -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)
|
||||||
|
}
|
|
@ -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
|
|
||||||
}
|
|
17
vendor/src/github.com/docker/libnetwork/store.go
vendored
17
vendor/src/github.com/docker/libnetwork/store.go
vendored
|
@ -7,7 +7,6 @@ import (
|
||||||
log "github.com/Sirupsen/logrus"
|
log "github.com/Sirupsen/logrus"
|
||||||
"github.com/docker/libkv/store"
|
"github.com/docker/libkv/store"
|
||||||
"github.com/docker/libnetwork/datastore"
|
"github.com/docker/libnetwork/datastore"
|
||||||
"github.com/docker/libnetwork/types"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *controller) validateDatastoreConfig() bool {
|
func (c *controller) validateDatastoreConfig() bool {
|
||||||
|
@ -91,7 +90,7 @@ func (c *controller) deleteNetworkFromStore(n *network) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *controller) getNetworkFromStore(nid types.UUID) (*network, error) {
|
func (c *controller) getNetworkFromStore(nid string) (*network, error) {
|
||||||
n := network{id: nid}
|
n := network{id: nid}
|
||||||
if err := c.store.GetObject(datastore.Key(n.Key()...), &n); err != nil {
|
if err := c.store.GetObject(datastore.Key(n.Key()...), &n); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -105,7 +104,7 @@ func (c *controller) newEndpointFromStore(key string, ep *endpoint) error {
|
||||||
id := ep.id
|
id := ep.id
|
||||||
ep.Unlock()
|
ep.Unlock()
|
||||||
|
|
||||||
_, err := n.EndpointByID(string(id))
|
_, err := n.EndpointByID(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if _, ok := err.(ErrNoSuchEndpoint); ok {
|
if _, ok := err.(ErrNoSuchEndpoint); ok {
|
||||||
return n.addEndpoint(ep)
|
return n.addEndpoint(ep)
|
||||||
|
@ -134,7 +133,7 @@ func (c *controller) updateEndpointToStore(ep *endpoint) error {
|
||||||
return cs.PutObjectAtomic(ep)
|
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}
|
ep := endpoint{id: eid}
|
||||||
if err := c.store.GetObject(datastore.Key(ep.Key()...), &ep); err != nil {
|
if err := c.store.GetObject(datastore.Key(ep.Key()...), &ep); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -346,7 +345,7 @@ func (c *controller) processEndpointUpdate(ep *endpoint) bool {
|
||||||
if !ok {
|
if !ok {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
existing, _ := n.EndpointByID(string(ep.id))
|
existing, _ := n.EndpointByID(ep.id)
|
||||||
if existing == nil {
|
if existing == nil {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -357,13 +356,7 @@ func (c *controller) processEndpointUpdate(ep *endpoint) bool {
|
||||||
// Can't use SetIndex() because ee is locked.
|
// Can't use SetIndex() because ee is locked.
|
||||||
ee.dbIndex = ep.Index()
|
ee.dbIndex = ep.Index()
|
||||||
ee.dbExists = true
|
ee.dbExists = true
|
||||||
if ee.container != nil && ep.container != nil {
|
ee.sandboxID = ep.sandboxID
|
||||||
// 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.Unlock()
|
ee.Unlock()
|
||||||
|
|
||||||
|
|
|
@ -197,6 +197,59 @@ func CompareIPNet(a, b *net.IPNet) bool {
|
||||||
return a.IP.Equal(b.IP) && bytes.Equal(a.Mask, b.Mask)
|
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 (
|
const (
|
||||||
// NEXTHOP indicates a StaticRoute with an IP next hop.
|
// NEXTHOP indicates a StaticRoute with an IP next hop.
|
||||||
NEXTHOP = iota
|
NEXTHOP = iota
|
||||||
|
|
11
vendor/src/github.com/docker/libnetwork/wrapmake.sh
vendored
Executable file
11
vendor/src/github.com/docker/libnetwork/wrapmake.sh
vendored
Executable file
|
@ -0,0 +1,11 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
function raise()
|
||||||
|
{
|
||||||
|
kill -$1 0
|
||||||
|
}
|
||||||
|
|
||||||
|
trap "raise SIGINT" SIGINT
|
||||||
|
make $1
|
Loading…
Reference in a new issue