Introduce Sandbox entity
- Maps 1 to 1 with container's networking stack - It holds container's specific nw options which before were incorrectly owned by Endpoint. - Sandbox creation no longer coupled with Endpoint Join, sandbox and endpoint have now separate lifecycle. - LeaveAll naturally replaced by Sandbox.Delete - some pkg and file renaming in order to have clear mapping between structure name and entity ("sandbox") - Revisited hosts and resolv.conf handling - Removed from JoinInfo interface capability of setting hosts and resolv.conf paths - Changed etchosts.Build() to first write the search domains and then the nameservers Signed-off-by: Alessandro Boch <aboch@docker.com>
This commit is contained in:
parent
6b9d51cbe0
commit
fd43ee1323
54 changed files with 2166 additions and 1649 deletions
|
@ -29,13 +29,13 @@ There are many networking solutions available to suit a broad range of use-cases
|
|||
driverOptions := options.Generic{}
|
||||
genericOption := make(map[string]interface{})
|
||||
genericOption[netlabel.GenericData] = driverOptions
|
||||
err := controller.ConfigureNetworkDriver(networkType, genericOption)
|
||||
err = controller.ConfigureNetworkDriver(networkType, genericOption)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Create a network for containers to join.
|
||||
// NewNetwork accepts Variadic optional arguments that libnetwork and Drivers can make of
|
||||
// NewNetwork accepts Variadic optional arguments that libnetwork and Drivers can use.
|
||||
network, err := controller.NewNetwork(networkType, "network1")
|
||||
if err != nil {
|
||||
return
|
||||
|
@ -50,12 +50,14 @@ There are many networking solutions available to suit a broad range of use-cases
|
|||
return
|
||||
}
|
||||
|
||||
// A container can join the endpoint by providing the container ID to the join
|
||||
// api.
|
||||
// Join accepts Variadic arguments which will be made use of by libnetwork and Drivers
|
||||
err = ep.Join("container1",
|
||||
libnetwork.JoinOptionHostname("test"),
|
||||
libnetwork.JoinOptionDomainname("docker.io"))
|
||||
// Create the sandbox for the containr.
|
||||
sbx, err := controller.NewSandbox("container1",
|
||||
libnetwork.OptionHostname("test"),
|
||||
libnetwork.OptionDomainname("docker.io"))
|
||||
|
||||
// A sandbox can join the endpoint via the join api.
|
||||
// Join accepts Variadic arguments which libnetwork and Drivers can use.
|
||||
err = ep.Join(sbx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -35,7 +35,10 @@ const (
|
|||
epNameQr = "{" + urlEpName + ":" + qregx + "}"
|
||||
epID = "{" + urlEpID + ":" + regex + "}"
|
||||
epPIDQr = "{" + urlEpPID + ":" + qregx + "}"
|
||||
cnID = "{" + urlCnID + ":" + regex + "}"
|
||||
sbID = "{" + urlSbID + ":" + regex + "}"
|
||||
sbPIDQr = "{" + urlSbPID + ":" + qregx + "}"
|
||||
cnIDQr = "{" + urlCnID + ":" + qregx + "}"
|
||||
cnPIDQr = "{" + urlCnPID + ":" + qregx + "}"
|
||||
|
||||
// Internal URL variable name.They can be anything as
|
||||
// long as they do not collide with query fields.
|
||||
|
@ -45,7 +48,10 @@ const (
|
|||
urlEpName = "endpoint-name"
|
||||
urlEpID = "endpoint-id"
|
||||
urlEpPID = "endpoint-partial-id"
|
||||
urlSbID = "sandbox-id"
|
||||
urlSbPID = "sandbox-partial-id"
|
||||
urlCnID = "container-id"
|
||||
urlCnPID = "container-partial-id"
|
||||
|
||||
// BridgeNetworkDriver is the built-in default for Network Driver
|
||||
BridgeNetworkDriver = "bridge"
|
||||
|
@ -106,21 +112,28 @@ func (h *httpHandler) initRouter() {
|
|||
{"/services", []string{"partial-id", epPIDQr}, procGetServices},
|
||||
{"/services", nil, procGetServices},
|
||||
{"/services/" + epID, nil, procGetService},
|
||||
{"/services/" + epID + "/backend", nil, procGetContainers},
|
||||
{"/services/" + epID + "/backend", nil, procGetSandbox},
|
||||
{"/sandboxes", []string{"partial-container-id", cnPIDQr}, procGetSandboxes},
|
||||
{"/sandboxes", []string{"container-id", cnIDQr}, procGetSandboxes},
|
||||
{"/sandboxes", []string{"partial-id", sbPIDQr}, procGetSandboxes},
|
||||
{"/sandboxes", nil, procGetSandboxes},
|
||||
{"/sandboxes/" + sbID, nil, procGetSandbox},
|
||||
},
|
||||
"POST": {
|
||||
{"/networks", nil, procCreateNetwork},
|
||||
{"/networks/" + nwID + "/endpoints", nil, procCreateEndpoint},
|
||||
{"/networks/" + nwID + "/endpoints/" + epID + "/containers", nil, procJoinEndpoint},
|
||||
{"/networks/" + nwID + "/endpoints/" + epID + "/sandboxes", nil, procJoinEndpoint},
|
||||
{"/services", nil, procPublishService},
|
||||
{"/services/" + epID + "/backend", nil, procAttachBackend},
|
||||
{"/sandboxes", nil, procCreateSandbox},
|
||||
},
|
||||
"DELETE": {
|
||||
{"/networks/" + nwID, nil, procDeleteNetwork},
|
||||
{"/networks/" + nwID + "/endpoints/" + epID, nil, procDeleteEndpoint},
|
||||
{"/networks/" + nwID + "/endpoints/" + epID + "/containers/" + cnID, nil, procLeaveEndpoint},
|
||||
{"/networks/" + nwID + "/endpoints/" + epID + "/sandboxes/" + sbID, nil, procLeaveEndpoint},
|
||||
{"/services/" + epID, nil, procUnpublishService},
|
||||
{"/services/" + epID + "/backend/" + cnID, nil, procDetachBackend},
|
||||
{"/services/" + epID + "/backend/" + sbID, nil, procDetachBackend},
|
||||
{"/sandboxes/" + sbID, nil, procDeleteSandbox},
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -191,10 +204,12 @@ func buildEndpointResource(ep libnetwork.Endpoint) *endpointResource {
|
|||
return r
|
||||
}
|
||||
|
||||
func buildContainerResource(ci libnetwork.ContainerInfo) *containerResource {
|
||||
r := &containerResource{}
|
||||
if ci != nil {
|
||||
r.ID = ci.ID()
|
||||
func buildSandboxResource(sb libnetwork.Sandbox) *sandboxResource {
|
||||
r := &sandboxResource{}
|
||||
if sb != nil {
|
||||
r.ID = sb.ID()
|
||||
r.Key = sb.Key()
|
||||
r.ContainerID = sb.ContainerID()
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
@ -213,41 +228,41 @@ func (nc *networkCreate) parseOptions() []libnetwork.NetworkOption {
|
|||
return setFctList
|
||||
}
|
||||
|
||||
func (ej *endpointJoin) parseOptions() []libnetwork.EndpointOption {
|
||||
var setFctList []libnetwork.EndpointOption
|
||||
if ej.HostName != "" {
|
||||
setFctList = append(setFctList, libnetwork.JoinOptionHostname(ej.HostName))
|
||||
func (sc *sandboxCreate) parseOptions() []libnetwork.SandboxOption {
|
||||
var setFctList []libnetwork.SandboxOption
|
||||
if sc.HostName != "" {
|
||||
setFctList = append(setFctList, libnetwork.OptionHostname(sc.HostName))
|
||||
}
|
||||
if ej.DomainName != "" {
|
||||
setFctList = append(setFctList, libnetwork.JoinOptionDomainname(ej.DomainName))
|
||||
if sc.DomainName != "" {
|
||||
setFctList = append(setFctList, libnetwork.OptionDomainname(sc.DomainName))
|
||||
}
|
||||
if ej.HostsPath != "" {
|
||||
setFctList = append(setFctList, libnetwork.JoinOptionHostsPath(ej.HostsPath))
|
||||
if sc.HostsPath != "" {
|
||||
setFctList = append(setFctList, libnetwork.OptionHostsPath(sc.HostsPath))
|
||||
}
|
||||
if ej.ResolvConfPath != "" {
|
||||
setFctList = append(setFctList, libnetwork.JoinOptionResolvConfPath(ej.ResolvConfPath))
|
||||
if sc.ResolvConfPath != "" {
|
||||
setFctList = append(setFctList, libnetwork.OptionResolvConfPath(sc.ResolvConfPath))
|
||||
}
|
||||
if ej.UseDefaultSandbox {
|
||||
setFctList = append(setFctList, libnetwork.JoinOptionUseDefaultSandbox())
|
||||
if sc.UseDefaultSandbox {
|
||||
setFctList = append(setFctList, libnetwork.OptionUseDefaultSandbox())
|
||||
}
|
||||
if ej.DNS != nil {
|
||||
for _, d := range ej.DNS {
|
||||
setFctList = append(setFctList, libnetwork.JoinOptionDNS(d))
|
||||
if sc.DNS != nil {
|
||||
for _, d := range sc.DNS {
|
||||
setFctList = append(setFctList, libnetwork.OptionDNS(d))
|
||||
}
|
||||
}
|
||||
if ej.ExtraHosts != nil {
|
||||
for _, e := range ej.ExtraHosts {
|
||||
setFctList = append(setFctList, libnetwork.JoinOptionExtraHost(e.Name, e.Address))
|
||||
}
|
||||
}
|
||||
if ej.ParentUpdates != nil {
|
||||
for _, p := range ej.ParentUpdates {
|
||||
setFctList = append(setFctList, libnetwork.JoinOptionParentUpdate(p.EndpointID, p.Name, p.Address))
|
||||
if sc.ExtraHosts != nil {
|
||||
for _, e := range sc.ExtraHosts {
|
||||
setFctList = append(setFctList, libnetwork.OptionExtraHost(e.Name, e.Address))
|
||||
}
|
||||
}
|
||||
return setFctList
|
||||
}
|
||||
|
||||
func (ej *endpointJoin) parseOptions() []libnetwork.EndpointOption {
|
||||
// priority will go here
|
||||
return []libnetwork.EndpointOption{}
|
||||
}
|
||||
|
||||
/******************
|
||||
Process functions
|
||||
*******************/
|
||||
|
@ -337,6 +352,22 @@ func procGetNetworks(c libnetwork.NetworkController, vars map[string]string, bod
|
|||
return list, &successResponse
|
||||
}
|
||||
|
||||
func procCreateSandbox(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
|
||||
var create sandboxCreate
|
||||
|
||||
err := json.Unmarshal(body, &create)
|
||||
if err != nil {
|
||||
return "", &responseStatus{Status: "Invalid body: " + err.Error(), StatusCode: http.StatusBadRequest}
|
||||
}
|
||||
|
||||
sb, err := c.NewSandbox(create.ContainerID, create.parseOptions()...)
|
||||
if err != nil {
|
||||
return "", convertNetworkError(err)
|
||||
}
|
||||
|
||||
return sb.ID(), &createdResponse
|
||||
}
|
||||
|
||||
/******************
|
||||
Network interface
|
||||
*******************/
|
||||
|
@ -456,11 +487,16 @@ func procJoinEndpoint(c libnetwork.NetworkController, vars map[string]string, bo
|
|||
return nil, errRsp
|
||||
}
|
||||
|
||||
err = ep.Join(ej.ContainerID, ej.parseOptions()...)
|
||||
sb, errRsp := findSandbox(c, ej.SandboxID, byID)
|
||||
if !errRsp.isOK() {
|
||||
return nil, errRsp
|
||||
}
|
||||
|
||||
err = ep.Join(sb)
|
||||
if err != nil {
|
||||
return nil, convertNetworkError(err)
|
||||
}
|
||||
return ep.Info().SandboxKey(), &successResponse
|
||||
return sb.Key(), &successResponse
|
||||
}
|
||||
|
||||
func procLeaveEndpoint(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
|
||||
|
@ -472,7 +508,12 @@ func procLeaveEndpoint(c libnetwork.NetworkController, vars map[string]string, b
|
|||
return nil, errRsp
|
||||
}
|
||||
|
||||
err := ep.Leave(vars[urlCnID])
|
||||
sb, errRsp := findSandbox(c, vars[urlSbID], byID)
|
||||
if !errRsp.isOK() {
|
||||
return nil, errRsp
|
||||
}
|
||||
|
||||
err := ep.Leave(sb)
|
||||
if err != nil {
|
||||
return nil, convertNetworkError(err)
|
||||
}
|
||||
|
@ -567,19 +608,6 @@ func procGetService(c libnetwork.NetworkController, vars map[string]string, body
|
|||
return buildEndpointResource(sv), &successResponse
|
||||
}
|
||||
|
||||
func procGetContainers(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
|
||||
epT, epBy := detectEndpointTarget(vars)
|
||||
sv, errRsp := findService(c, epT, epBy)
|
||||
if !errRsp.isOK() {
|
||||
return nil, endpointToService(errRsp)
|
||||
}
|
||||
var list []*containerResource
|
||||
if sv.ContainerInfo() != nil {
|
||||
list = append(list, buildContainerResource(sv.ContainerInfo()))
|
||||
}
|
||||
return list, &successResponse
|
||||
}
|
||||
|
||||
func procPublishService(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
|
||||
var sp servicePublish
|
||||
|
||||
|
@ -635,11 +663,16 @@ func procAttachBackend(c libnetwork.NetworkController, vars map[string]string, b
|
|||
return nil, errRsp
|
||||
}
|
||||
|
||||
err = sv.Join(bk.ContainerID, bk.parseOptions()...)
|
||||
sb, errRsp := findSandbox(c, bk.SandboxID, byID)
|
||||
if !errRsp.isOK() {
|
||||
return nil, errRsp
|
||||
}
|
||||
|
||||
err = sv.Join(sb)
|
||||
if err != nil {
|
||||
return nil, convertNetworkError(err)
|
||||
}
|
||||
return sv.Info().SandboxKey(), &successResponse
|
||||
return sb.Key(), &successResponse
|
||||
}
|
||||
|
||||
func procDetachBackend(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
|
||||
|
@ -649,7 +682,94 @@ func procDetachBackend(c libnetwork.NetworkController, vars map[string]string, b
|
|||
return nil, errRsp
|
||||
}
|
||||
|
||||
err := sv.Leave(vars[urlCnID])
|
||||
sb, errRsp := findSandbox(c, vars[urlSbID], byID)
|
||||
if !errRsp.isOK() {
|
||||
return nil, errRsp
|
||||
}
|
||||
|
||||
err := sv.Leave(sb)
|
||||
if err != nil {
|
||||
return nil, convertNetworkError(err)
|
||||
}
|
||||
|
||||
return nil, &successResponse
|
||||
}
|
||||
|
||||
/******************
|
||||
Sandbox interface
|
||||
*******************/
|
||||
func procGetSandbox(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
|
||||
if epT, ok := vars[urlEpID]; ok {
|
||||
sv, errRsp := findService(c, epT, byID)
|
||||
if !errRsp.isOK() {
|
||||
return nil, endpointToService(errRsp)
|
||||
}
|
||||
return buildSandboxResource(sv.Info().Sandbox()), &successResponse
|
||||
}
|
||||
|
||||
sbT, by := detectSandboxTarget(vars)
|
||||
sb, errRsp := findSandbox(c, sbT, by)
|
||||
if !errRsp.isOK() {
|
||||
return nil, errRsp
|
||||
}
|
||||
return buildSandboxResource(sb), &successResponse
|
||||
}
|
||||
|
||||
type cndFnMkr func(string) cndFn
|
||||
type cndFn func(libnetwork.Sandbox) bool
|
||||
|
||||
// list of (query type, condition function makers) couples
|
||||
var cndMkrList = []struct {
|
||||
identifier string
|
||||
maker cndFnMkr
|
||||
}{
|
||||
{urlSbPID, func(id string) cndFn {
|
||||
return func(sb libnetwork.Sandbox) bool { return strings.HasPrefix(sb.ID(), id) }
|
||||
}},
|
||||
{urlCnID, func(id string) cndFn {
|
||||
return func(sb libnetwork.Sandbox) bool { return sb.ContainerID() == id }
|
||||
}},
|
||||
{urlCnPID, func(id string) cndFn {
|
||||
return func(sb libnetwork.Sandbox) bool { return strings.HasPrefix(sb.ContainerID(), id) }
|
||||
}},
|
||||
}
|
||||
|
||||
func getQueryCondition(vars map[string]string) func(libnetwork.Sandbox) bool {
|
||||
for _, im := range cndMkrList {
|
||||
if val, ok := vars[im.identifier]; ok {
|
||||
return im.maker(val)
|
||||
}
|
||||
}
|
||||
return func(sb libnetwork.Sandbox) bool { return true }
|
||||
}
|
||||
|
||||
func sandboxWalker(condition cndFn, list *[]*sandboxResource) libnetwork.SandboxWalker {
|
||||
return func(sb libnetwork.Sandbox) bool {
|
||||
if condition(sb) {
|
||||
*list = append(*list, buildSandboxResource(sb))
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func procGetSandboxes(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
|
||||
var list []*sandboxResource
|
||||
|
||||
cnd := getQueryCondition(vars)
|
||||
c.WalkSandboxes(sandboxWalker(cnd, &list))
|
||||
|
||||
return list, &successResponse
|
||||
}
|
||||
|
||||
func procDeleteSandbox(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
|
||||
sbT, by := detectSandboxTarget(vars)
|
||||
|
||||
sb, errRsp := findSandbox(c, sbT, by)
|
||||
if !errRsp.isOK() {
|
||||
return nil, errRsp
|
||||
}
|
||||
|
||||
err := sb.Delete()
|
||||
if err != nil {
|
||||
return nil, convertNetworkError(err)
|
||||
}
|
||||
|
@ -676,6 +796,14 @@ func detectNetworkTarget(vars map[string]string) (string, int) {
|
|||
panic("Missing URL variable parameter for network")
|
||||
}
|
||||
|
||||
func detectSandboxTarget(vars map[string]string) (string, int) {
|
||||
if target, ok := vars[urlSbID]; ok {
|
||||
return target, byID
|
||||
}
|
||||
// vars are populated from the URL, following cannot happen
|
||||
panic("Missing URL variable parameter for sandbox")
|
||||
}
|
||||
|
||||
func detectEndpointTarget(vars map[string]string) (string, int) {
|
||||
if target, ok := vars[urlEpName]; ok {
|
||||
return target, byName
|
||||
|
@ -712,6 +840,27 @@ func findNetwork(c libnetwork.NetworkController, s string, by int) (libnetwork.N
|
|||
return nw, &successResponse
|
||||
}
|
||||
|
||||
func findSandbox(c libnetwork.NetworkController, s string, by int) (libnetwork.Sandbox, *responseStatus) {
|
||||
var (
|
||||
sb libnetwork.Sandbox
|
||||
err error
|
||||
)
|
||||
|
||||
switch by {
|
||||
case byID:
|
||||
sb, err = c.SandboxByID(s)
|
||||
default:
|
||||
panic(fmt.Sprintf("unexpected selector for sandbox search: %d", by))
|
||||
}
|
||||
if err != nil {
|
||||
if _, ok := err.(types.NotFoundError); ok {
|
||||
return nil, &responseStatus{Status: "Resource not found: Sandbox", StatusCode: http.StatusNotFound}
|
||||
}
|
||||
return nil, &responseStatus{Status: err.Error(), StatusCode: http.StatusBadRequest}
|
||||
}
|
||||
return sb, &successResponse
|
||||
}
|
||||
|
||||
func findEndpoint(c libnetwork.NetworkController, ns, es string, nwBy, epBy int) (libnetwork.Endpoint, *responseStatus) {
|
||||
nw, errRsp := findNetwork(c, ns, nwBy)
|
||||
if !errRsp.isOK() {
|
||||
|
|
|
@ -71,10 +71,18 @@ func i2nL(i interface{}) []*networkResource {
|
|||
return s
|
||||
}
|
||||
|
||||
func i2cL(i interface{}) []*containerResource {
|
||||
s, ok := i.([]*containerResource)
|
||||
func i2sb(i interface{}) *sandboxResource {
|
||||
s, ok := i.(*sandboxResource)
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("Failed i2cL for %v", i))
|
||||
panic(fmt.Sprintf("Failed i2sb for %v", i))
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func i2sbL(i interface{}) []*sandboxResource {
|
||||
s, ok := i.([]*sandboxResource)
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("Failed i2sbL for %v", i))
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
@ -112,30 +120,27 @@ func TestMain(m *testing.M) {
|
|||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
func TestJoinOptionParser(t *testing.T) {
|
||||
func TestSandboxOptionParser(t *testing.T) {
|
||||
hn := "host1"
|
||||
dn := "docker.com"
|
||||
hp := "/etc/hosts"
|
||||
rc := "/etc/resolv.conf"
|
||||
dnss := []string{"8.8.8.8", "172.28.34.5"}
|
||||
ehs := []endpointExtraHost{endpointExtraHost{Name: "extra1", Address: "172.28.9.1"}, endpointExtraHost{Name: "extra2", Address: "172.28.9.2"}}
|
||||
pus := []endpointParentUpdate{endpointParentUpdate{EndpointID: "abc123def456", Name: "serv1", Address: "172.28.30.123"}}
|
||||
ehs := []extraHost{extraHost{Name: "extra1", Address: "172.28.9.1"}, extraHost{Name: "extra2", Address: "172.28.9.2"}}
|
||||
|
||||
ej := endpointJoin{
|
||||
sb := sandboxCreate{
|
||||
HostName: hn,
|
||||
DomainName: dn,
|
||||
HostsPath: hp,
|
||||
ResolvConfPath: rc,
|
||||
DNS: dnss,
|
||||
ExtraHosts: ehs,
|
||||
ParentUpdates: pus,
|
||||
UseDefaultSandbox: true,
|
||||
}
|
||||
|
||||
if len(ej.parseOptions()) != 10 {
|
||||
t.Fatalf("Failed to generate all libnetwork.EndpointJoinOption methods libnetwork.EndpointJoinOption method")
|
||||
if len(sb.parseOptions()) != 9 {
|
||||
t.Fatalf("Failed to generate all libnetwork.SandboxOption methods")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestJson(t *testing.T) {
|
||||
|
@ -155,7 +160,7 @@ func TestJson(t *testing.T) {
|
|||
t.Fatalf("Incorrect networkCreate after json encoding/deconding: %v", ncp)
|
||||
}
|
||||
|
||||
jl := endpointJoin{ContainerID: "abcdef456789"}
|
||||
jl := endpointJoin{SandboxID: "abcdef456789"}
|
||||
b, err = json.Marshal(jl)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -167,7 +172,7 @@ func TestJson(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if jl.ContainerID != jld.ContainerID {
|
||||
if jl.SandboxID != jld.SandboxID {
|
||||
t.Fatalf("Incorrect endpointJoin after json encoding/deconding: %v", jld)
|
||||
}
|
||||
}
|
||||
|
@ -913,7 +918,8 @@ func TestAttachDetachBackend(t *testing.T) {
|
|||
t.Fatalf("Expected %d. Got: %v", http.StatusNotFound, errRsp)
|
||||
}
|
||||
|
||||
_, errRsp = procGetContainers(c, vars, nil)
|
||||
vars[urlEpID] = "db"
|
||||
_, errRsp = procGetSandbox(c, vars, nil)
|
||||
if errRsp.isOK() {
|
||||
t.Fatalf("Expected failure. Got %v", errRsp)
|
||||
}
|
||||
|
@ -931,7 +937,11 @@ func TestAttachDetachBackend(t *testing.T) {
|
|||
}
|
||||
|
||||
cid := "abcdefghi"
|
||||
jl := endpointJoin{ContainerID: cid}
|
||||
sbox, err := c.NewSandbox(cid)
|
||||
sid := sbox.ID()
|
||||
defer sbox.Delete()
|
||||
|
||||
jl := endpointJoin{SandboxID: sid}
|
||||
jlb, err := json.Marshal(jl)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -942,16 +952,16 @@ func TestAttachDetachBackend(t *testing.T) {
|
|||
t.Fatalf("Unexpected failure, got: %v", errRsp)
|
||||
}
|
||||
|
||||
cli, errRsp := procGetContainers(c, vars, nil)
|
||||
sli, errRsp := procGetSandboxes(c, vars, nil)
|
||||
if errRsp != &successResponse {
|
||||
t.Fatalf("Unexpected failure, got: %v", errRsp)
|
||||
}
|
||||
cl := i2cL(cli)
|
||||
if len(cl) != 1 {
|
||||
t.Fatalf("Did not find expected number of containers attached to the service: %d", len(cl))
|
||||
sl := i2sbL(sli)
|
||||
if len(sl) != 1 {
|
||||
t.Fatalf("Did not find expected number of sandboxes attached to the service: %d", len(sl))
|
||||
}
|
||||
if cl[0].ID != cid {
|
||||
t.Fatalf("Did not find expected container attached to the service: %v", cl[0])
|
||||
if sl[0].ContainerID != cid {
|
||||
t.Fatalf("Did not find expected sandbox attached to the service: %v", sl[0])
|
||||
}
|
||||
|
||||
_, errRsp = procUnpublishService(c, vars, nil)
|
||||
|
@ -980,19 +990,20 @@ func TestAttachDetachBackend(t *testing.T) {
|
|||
t.Fatalf("Expected %d. Got: %v", http.StatusBadRequest, errRsp)
|
||||
}
|
||||
|
||||
vars[urlCnID] = cid
|
||||
vars[urlSbID] = sid
|
||||
_, errRsp = procDetachBackend(c, vars, nil)
|
||||
if errRsp != &successResponse {
|
||||
t.Fatalf("Unexpected failure, got: %v", errRsp)
|
||||
}
|
||||
|
||||
cli, errRsp = procGetContainers(c, vars, nil)
|
||||
delete(vars, urlEpID)
|
||||
si, errRsp := procGetSandbox(c, vars, nil)
|
||||
if errRsp != &successResponse {
|
||||
t.Fatalf("Unexpected failure, got: %v", errRsp)
|
||||
}
|
||||
cl = i2cL(cli)
|
||||
if len(cl) != 0 {
|
||||
t.Fatalf("Did not find expected number of containers attached to the service: %d", len(cl))
|
||||
sb := i2sb(si)
|
||||
if sb.ContainerID != cid {
|
||||
t.Fatalf("Did not find expected sandbox. Got %v", sb)
|
||||
}
|
||||
|
||||
err = ep1.Delete()
|
||||
|
@ -1284,7 +1295,10 @@ func TestJoinLeave(t *testing.T) {
|
|||
}
|
||||
|
||||
cid := "abcdefghi"
|
||||
jl := endpointJoin{ContainerID: cid}
|
||||
sb, err := c.NewSandbox(cid)
|
||||
defer sb.Delete()
|
||||
|
||||
jl := endpointJoin{SandboxID: sb.ID()}
|
||||
jlb, err := json.Marshal(jl)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -1314,7 +1328,7 @@ func TestJoinLeave(t *testing.T) {
|
|||
vars[urlEpName] = "endpoint"
|
||||
key, errRsp := procJoinEndpoint(c, vars, jlb)
|
||||
if errRsp != &successResponse {
|
||||
t.Fatalf("Expected failure, got: %v", errRsp)
|
||||
t.Fatalf("Unexepected failure, got: %v", errRsp)
|
||||
}
|
||||
|
||||
keyStr := i2s(key)
|
||||
|
@ -1371,7 +1385,7 @@ func TestJoinLeave(t *testing.T) {
|
|||
t.Fatalf("Expected failure, got: %v", errRsp)
|
||||
}
|
||||
|
||||
vars[urlCnID] = cid
|
||||
vars[urlSbID] = sb.ID()
|
||||
_, errRsp = procLeaveEndpoint(c, vars, jlb)
|
||||
if errRsp != &successResponse {
|
||||
t.Fatalf("Unexepected failure: %v", errRsp)
|
||||
|
@ -2065,6 +2079,164 @@ func TestEndToEnd(t *testing.T) {
|
|||
if epr.Name != "ep-TwentyTwo" || epr.ID != eid {
|
||||
t.Fatalf("Incongruent resource found: %v", epr)
|
||||
}
|
||||
|
||||
// Store two container ids and one partial ids
|
||||
cid1 := "container10010000000"
|
||||
cid2 := "container20010000000"
|
||||
chars = []byte(cid1)
|
||||
cpid1 := string(chars[0 : len(chars)/2])
|
||||
|
||||
// Create sandboxes
|
||||
sb1, err := json.Marshal(sandboxCreate{ContainerID: cid1})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
lr = newLocalReader(sb1)
|
||||
req, err = http.NewRequest("POST", "/v5.22/sandboxes", lr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
handleRequest(rsp, req)
|
||||
if rsp.statusCode != http.StatusCreated {
|
||||
t.Fatalf("Unexpectded status code. Expected (%d). Got (%d): %s.", http.StatusCreated, rsp.statusCode, string(rsp.body))
|
||||
}
|
||||
if len(rsp.body) == 0 {
|
||||
t.Fatalf("Empty response body")
|
||||
}
|
||||
// Get sandbox id and partial id
|
||||
var sid1 string
|
||||
err = json.Unmarshal(rsp.body, &sid1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
sb2, err := json.Marshal(sandboxCreate{ContainerID: cid2})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
lr = newLocalReader(sb2)
|
||||
req, err = http.NewRequest("POST", "/v5.22/sandboxes", lr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
handleRequest(rsp, req)
|
||||
if rsp.statusCode != http.StatusCreated {
|
||||
t.Fatalf("Unexpectded status code. Expected (%d). Got (%d): %s.", http.StatusCreated, rsp.statusCode, string(rsp.body))
|
||||
}
|
||||
if len(rsp.body) == 0 {
|
||||
t.Fatalf("Empty response body")
|
||||
}
|
||||
// Get sandbox id and partial id
|
||||
var sid2 string
|
||||
err = json.Unmarshal(rsp.body, &sid2)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
chars = []byte(sid2)
|
||||
spid2 := string(chars[0 : len(chars)/2])
|
||||
|
||||
// Query sandboxes
|
||||
req, err = http.NewRequest("GET", "/sandboxes", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
handleRequest(rsp, req)
|
||||
if rsp.statusCode != http.StatusOK {
|
||||
t.Fatalf("Expected StatusOK. Got (%d): %s", rsp.statusCode, rsp.body)
|
||||
}
|
||||
|
||||
var sbList []*sandboxResource
|
||||
err = json.Unmarshal(rsp.body, &sbList)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(sbList) != 2 {
|
||||
t.Fatalf("Expected 2 elements in list. Got %v", sbList)
|
||||
}
|
||||
|
||||
// Get sandbox by id
|
||||
req, err = http.NewRequest("GET", "/sandboxes/"+sid1, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
handleRequest(rsp, req)
|
||||
if rsp.statusCode != http.StatusOK {
|
||||
t.Fatalf("Unexpectded failure: (%d): %s", rsp.statusCode, rsp.body)
|
||||
}
|
||||
|
||||
var sbr sandboxResource
|
||||
err = json.Unmarshal(rsp.body, &sbr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if sbr.ContainerID != cid1 {
|
||||
t.Fatalf("Incongruent resource found: %v", sbr)
|
||||
}
|
||||
|
||||
// Query sandbox by partial sandbox id
|
||||
req, err = http.NewRequest("GET", "/sandboxes?partial-id="+spid2, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
handleRequest(rsp, req)
|
||||
if rsp.statusCode != http.StatusOK {
|
||||
t.Fatalf("Unexpectded failure: (%d): %s", rsp.statusCode, rsp.body)
|
||||
}
|
||||
|
||||
err = json.Unmarshal(rsp.body, &sbList)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(sbList) == 0 {
|
||||
t.Fatalf("Empty response body")
|
||||
}
|
||||
if sbList[0].ID != sid2 {
|
||||
t.Fatalf("Incongruent resource found: %v", sbList[0])
|
||||
}
|
||||
|
||||
// Query sandbox by container id
|
||||
req, err = http.NewRequest("GET", "/sandboxes?container-id="+cid2, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
handleRequest(rsp, req)
|
||||
if rsp.statusCode != http.StatusOK {
|
||||
t.Fatalf("Unexpectded failure: (%d): %s", rsp.statusCode, rsp.body)
|
||||
}
|
||||
|
||||
err = json.Unmarshal(rsp.body, &sbList)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(sbList) == 0 {
|
||||
t.Fatalf("Empty response body")
|
||||
}
|
||||
if sbList[0].ContainerID != cid2 {
|
||||
t.Fatalf("Incongruent resource found: %v", sbList[0])
|
||||
}
|
||||
|
||||
// Query sandbox by partial container id
|
||||
req, err = http.NewRequest("GET", "/sandboxes?partial-container-id="+cpid1, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
handleRequest(rsp, req)
|
||||
if rsp.statusCode != http.StatusOK {
|
||||
t.Fatalf("Unexpectded failure: (%d): %s", rsp.statusCode, rsp.body)
|
||||
}
|
||||
|
||||
err = json.Unmarshal(rsp.body, &sbList)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(sbList) == 0 {
|
||||
t.Fatalf("Empty response body")
|
||||
}
|
||||
if sbList[0].ContainerID != cid1 {
|
||||
t.Fatalf("Incongruent resource found: %v", sbList[0])
|
||||
}
|
||||
}
|
||||
|
||||
type bre struct{}
|
||||
|
|
|
@ -21,9 +21,11 @@ type endpointResource struct {
|
|||
Network string `json:"network"`
|
||||
}
|
||||
|
||||
// containerResource is the body of "get service backend" response message
|
||||
type containerResource struct {
|
||||
ID string `json:"id"`
|
||||
// sandboxResource is the body of "get service backend" response message
|
||||
type sandboxResource struct {
|
||||
ID string `json:"id"`
|
||||
Key string `json:"key"`
|
||||
ContainerID string `json:"container_id"`
|
||||
// will add more fields once labels change is in
|
||||
}
|
||||
|
||||
|
@ -45,17 +47,21 @@ type endpointCreate struct {
|
|||
PortMapping []types.PortBinding `json:"port_mapping"`
|
||||
}
|
||||
|
||||
// sandboxCreate is the expected body of the "create sandbox" http request message
|
||||
type sandboxCreate struct {
|
||||
ContainerID string `json:"container_id"`
|
||||
HostName string `json:"host_name"`
|
||||
DomainName string `json:"domain_name"`
|
||||
HostsPath string `json:"hosts_path"`
|
||||
ResolvConfPath string `json:"resolv_conf_path"`
|
||||
DNS []string `json:"dns"`
|
||||
ExtraHosts []extraHost `json:"extra_hosts"`
|
||||
UseDefaultSandbox bool `json:"use_default_sandbox"`
|
||||
}
|
||||
|
||||
// endpointJoin represents the expected body of the "join endpoint" or "leave endpoint" http request messages
|
||||
type endpointJoin struct {
|
||||
ContainerID string `json:"container_id"`
|
||||
HostName string `json:"host_name"`
|
||||
DomainName string `json:"domain_name"`
|
||||
HostsPath string `json:"hosts_path"`
|
||||
ResolvConfPath string `json:"resolv_conf_path"`
|
||||
DNS []string `json:"dns"`
|
||||
ExtraHosts []endpointExtraHost `json:"extra_hosts"`
|
||||
ParentUpdates []endpointParentUpdate `json:"parent_updates"`
|
||||
UseDefaultSandbox bool `json:"use_default_sandbox"`
|
||||
SandboxID string `json:"sandbox_id"`
|
||||
}
|
||||
|
||||
// servicePublish represents the body of the "publish service" http request message
|
||||
|
@ -66,16 +72,8 @@ type servicePublish struct {
|
|||
PortMapping []types.PortBinding `json:"port_mapping"`
|
||||
}
|
||||
|
||||
// EndpointExtraHost represents the extra host object
|
||||
type endpointExtraHost struct {
|
||||
// extraHost represents the extra host object
|
||||
type extraHost struct {
|
||||
Name string `json:"name"`
|
||||
Address string `json:"address"`
|
||||
}
|
||||
|
||||
// EndpointParentUpdate is the object carrying the information about the
|
||||
// endpoint parent that needs to be updated
|
||||
type endpointParentUpdate struct {
|
||||
EndpointID string `json:"endpoint_id"`
|
||||
Name string `json:"name"`
|
||||
Address string `json:"address"`
|
||||
}
|
||||
|
|
|
@ -26,12 +26,13 @@ func TestMain(m *testing.M) {
|
|||
}
|
||||
|
||||
var callbackFunc func(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, http.Header, int, error)
|
||||
var mockNwJSON, mockNwListJSON, mockServiceJSON, mockServiceListJSON []byte
|
||||
var mockNwJSON, mockNwListJSON, mockServiceJSON, mockServiceListJSON, mockSbJSON, mockSbListJSON []byte
|
||||
var mockNwName = "test"
|
||||
var mockNwID = "2a3456789"
|
||||
var mockServiceName = "testSrv"
|
||||
var mockServiceID = "2a3456789"
|
||||
var mockContainerID = "2a3456789"
|
||||
var mockSandboxID = "2b3456789"
|
||||
|
||||
func setupMockHTTPCallback() {
|
||||
var list []networkResource
|
||||
|
@ -46,6 +47,12 @@ func setupMockHTTPCallback() {
|
|||
srvList = append(srvList, ep)
|
||||
mockServiceListJSON, _ = json.Marshal(srvList)
|
||||
|
||||
var sbxList []sandboxResource
|
||||
sb := sandboxResource{ID: mockSandboxID, ContainerID: mockContainerID}
|
||||
mockSbJSON, _ = json.Marshal(sb)
|
||||
sbxList = append(sbxList, sb)
|
||||
mockSbListJSON, _ = json.Marshal(sbxList)
|
||||
|
||||
dummyHTTPHdr := http.Header{}
|
||||
|
||||
callbackFunc = func(method, path string, data interface{}, headers map[string][]string) (io.ReadCloser, http.Header, int, error) {
|
||||
|
@ -78,6 +85,8 @@ func setupMockHTTPCallback() {
|
|||
rsp = string(mockServiceJSON)
|
||||
} else if strings.Contains(path, "containers") {
|
||||
return nopCloser{bytes.NewBufferString("")}, dummyHTTPHdr, 400, fmt.Errorf("Bad Request")
|
||||
} else if strings.Contains(path, fmt.Sprintf("sandboxes?container-id=%s", mockContainerID)) {
|
||||
rsp = string(mockSbListJSON)
|
||||
}
|
||||
case "POST":
|
||||
var data []byte
|
||||
|
@ -86,7 +95,7 @@ func setupMockHTTPCallback() {
|
|||
} else if strings.HasSuffix(path, "services") {
|
||||
data, _ = json.Marshal(mockServiceID)
|
||||
} else if strings.HasSuffix(path, "backend") {
|
||||
data, _ = json.Marshal(mockContainerID)
|
||||
data, _ = json.Marshal(mockSandboxID)
|
||||
}
|
||||
rsp = string(data)
|
||||
case "PUT":
|
||||
|
|
|
@ -114,6 +114,25 @@ func lookupContainerID(cli *NetworkCli, cnNameID string) (string, error) {
|
|||
return "", fmt.Errorf("Cannot find container ID in json response")
|
||||
}
|
||||
|
||||
func lookupSandboxID(cli *NetworkCli, containerID string) (string, error) {
|
||||
obj, _, err := readBody(cli.call("GET", fmt.Sprintf("/sandboxes?container-id=%s", containerID), nil, nil))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var sandboxList []sandboxResource
|
||||
err = json.Unmarshal(obj, &sandboxList)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if len(sandboxList) == 0 {
|
||||
return "", fmt.Errorf("cannot find sandbox for container: %s", containerID)
|
||||
}
|
||||
|
||||
return sandboxList[0].ID, nil
|
||||
}
|
||||
|
||||
// CmdService handles the service UI
|
||||
func (cli *NetworkCli) CmdService(chain string, args ...string) error {
|
||||
cmd := cli.Subcmd(chain, "service", "COMMAND [OPTIONS] [arg...]", serviceUsage(chain), false)
|
||||
|
@ -249,7 +268,7 @@ func getBackendID(cli *NetworkCli, servID string) (string, error) {
|
|||
)
|
||||
|
||||
if obj, _, err = readBody(cli.call("GET", "/services/"+servID+"/backend", nil, nil)); err == nil {
|
||||
var bkl []backendResource
|
||||
var bkl []sandboxResource
|
||||
if err := json.NewDecoder(bytes.NewReader(obj)).Decode(&bkl); err == nil {
|
||||
if len(bkl) > 0 {
|
||||
bk = bkl[0].ID
|
||||
|
@ -310,13 +329,18 @@ func (cli *NetworkCli) CmdServiceAttach(chain string, args ...string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
sandboxID, err := lookupSandboxID(cli, containerID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sn, nn := parseServiceName(cmd.Arg(1))
|
||||
serviceID, err := lookupServiceID(cli, nn, sn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nc := serviceAttach{ContainerID: containerID}
|
||||
nc := serviceAttach{SandboxID: sandboxID}
|
||||
|
||||
_, _, err = readBody(cli.call("POST", "/services/"+serviceID+"/backend", nc, nil))
|
||||
|
||||
|
|
|
@ -21,9 +21,11 @@ type serviceResource struct {
|
|||
Network string `json:"network"`
|
||||
}
|
||||
|
||||
// backendResource is the body of "get service backend" response message
|
||||
type backendResource struct {
|
||||
ID string `json:"id"`
|
||||
// sandboxResource is the body of "get service backend" response message
|
||||
type sandboxResource struct {
|
||||
ID string `json:"id"`
|
||||
Key string `json:"key"`
|
||||
ContainerID string `json:"container_id"`
|
||||
}
|
||||
|
||||
/***********
|
||||
|
@ -45,29 +47,32 @@ type serviceCreate struct {
|
|||
PortMapping []types.PortBinding `json:"port_mapping"`
|
||||
}
|
||||
|
||||
// serviceAttach represents the expected body of the "attach/detach backend to/from service" http request messages
|
||||
// serviceAttach represents the expected body of the "attach/detach sandbox to/from service" http request messages
|
||||
type serviceAttach struct {
|
||||
ContainerID string `json:"container_id"`
|
||||
HostName string `json:"host_name"`
|
||||
DomainName string `json:"domain_name"`
|
||||
HostsPath string `json:"hosts_path"`
|
||||
ResolvConfPath string `json:"resolv_conf_path"`
|
||||
DNS []string `json:"dns"`
|
||||
ExtraHosts []serviceExtraHost `json:"extra_hosts"`
|
||||
ParentUpdates []serviceParentUpdate `json:"parent_updates"`
|
||||
UseDefaultSandbox bool `json:"use_default_sandbox"`
|
||||
SandboxID string `json:"sandbox_id"`
|
||||
}
|
||||
|
||||
// serviceExtraHost represents the extra host object
|
||||
type serviceExtraHost struct {
|
||||
type sandboxCreate struct {
|
||||
ContainerID string `json:"container_id"`
|
||||
HostName string `json:"host_name"`
|
||||
DomainName string `json:"domain_name"`
|
||||
HostsPath string `json:"hosts_path"`
|
||||
ResolvConfPath string `json:"resolv_conf_path"`
|
||||
DNS []string `json:"dns"`
|
||||
ExtraHosts []extraHost `json:"extra_hosts"`
|
||||
UseDefaultSandbox bool `json:"use_default_sandbox"`
|
||||
}
|
||||
|
||||
// extraHost represents the extra host object
|
||||
type extraHost struct {
|
||||
Name string `json:"name"`
|
||||
Address string `json:"address"`
|
||||
}
|
||||
|
||||
// EndpointParentUpdate is the object carrying the information about the
|
||||
// endpoint parent that needs to be updated
|
||||
type serviceParentUpdate struct {
|
||||
EndpointID string `json:"service_id"`
|
||||
Name string `json:"name"`
|
||||
Address string `json:"address"`
|
||||
// sandboxParentUpdate is the object carrying the information about the
|
||||
// sanbox parent that needs to be updated
|
||||
type sandboxParentUpdate struct {
|
||||
ContainerID string `json:"container_id"`
|
||||
Name string `json:"name"`
|
||||
Address string `json:"address"`
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ import (
|
|||
"github.com/docker/libnetwork/driverapi"
|
||||
"github.com/docker/libnetwork/drivers/overlay"
|
||||
"github.com/docker/libnetwork/netlabel"
|
||||
"github.com/docker/libnetwork/types"
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
|
@ -68,14 +67,6 @@ func (ep *endpoint) AddStaticRoute(destination *net.IPNet, routeType int,
|
|||
return nil
|
||||
}
|
||||
|
||||
func (ep *endpoint) SetHostsPath(string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ep *endpoint) SetResolvConfPath(string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
if reexec.Init() {
|
||||
return
|
||||
|
@ -103,20 +94,20 @@ func main() {
|
|||
|
||||
r.d.Config(opt)
|
||||
|
||||
if err := r.d.CreateNetwork(types.UUID("testnetwork"),
|
||||
if err := r.d.CreateNetwork("testnetwork",
|
||||
map[string]interface{}{}); err != nil {
|
||||
fmt.Printf("Failed to create network in the driver: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
ep := &endpoint{}
|
||||
if err := r.d.CreateEndpoint(types.UUID("testnetwork"), types.UUID("testep"),
|
||||
if err := r.d.CreateEndpoint("testnetwork", "testep",
|
||||
ep, map[string]interface{}{}); err != nil {
|
||||
fmt.Printf("Failed to create endpoint in the driver: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if err := r.d.Join(types.UUID("testnetwork"), types.UUID("testep"),
|
||||
if err := r.d.Join("testnetwork", "testep",
|
||||
"", ep, map[string]interface{}{}); err != nil {
|
||||
fmt.Printf("Failed to join an endpoint in the driver: %v\n", err)
|
||||
os.Exit(1)
|
||||
|
@ -141,7 +132,7 @@ func main() {
|
|||
for {
|
||||
select {
|
||||
case <-sigCh:
|
||||
r.d.Leave(types.UUID("testnetwork"), types.UUID("testep"))
|
||||
r.d.Leave("testnetwork", "testep")
|
||||
overlay.Fini(r.d)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ func main() {
|
|||
}
|
||||
|
||||
// Create a network for containers to join.
|
||||
// NewNetwork accepts Variadic optional arguments that libnetwork and Drivers can make of
|
||||
// NewNetwork accepts Variadic optional arguments that libnetwork and Drivers can use.
|
||||
network, err := controller.NewNetwork(networkType, "network1")
|
||||
if err != nil {
|
||||
return
|
||||
|
@ -43,12 +43,14 @@ func main() {
|
|||
return
|
||||
}
|
||||
|
||||
// A container can join the endpoint by providing the container ID to the join
|
||||
// api.
|
||||
// Join accepts Variadic arguments which will be made use of by libnetwork and Drivers
|
||||
err = ep.Join("container1",
|
||||
libnetwork.JoinOptionHostname("test"),
|
||||
libnetwork.JoinOptionDomainname("docker.io"))
|
||||
// Create the sandbox for the containr.
|
||||
sbx, err := controller.NewSandbox("container1",
|
||||
libnetwork.OptionHostname("test"),
|
||||
libnetwork.OptionDomainname("docker.io"))
|
||||
|
||||
// A sandbox can join the endpoint via the join api.
|
||||
// Join accepts Variadic arguments which libnetwork and Drivers can use.
|
||||
err = ep.Join(sbx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@ create network namespaces and allocate interfaces for containers to use.
|
|||
package libnetwork
|
||||
|
||||
import (
|
||||
"container/heap"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
|
@ -58,7 +59,7 @@ import (
|
|||
"github.com/docker/libnetwork/driverapi"
|
||||
"github.com/docker/libnetwork/hostdiscovery"
|
||||
"github.com/docker/libnetwork/netlabel"
|
||||
"github.com/docker/libnetwork/sandbox"
|
||||
"github.com/docker/libnetwork/osl"
|
||||
"github.com/docker/libnetwork/types"
|
||||
)
|
||||
|
||||
|
@ -87,8 +88,17 @@ type NetworkController interface {
|
|||
// NetworkByID returns the Network which has the passed id. If not found, the error ErrNoSuchNetwork is returned.
|
||||
NetworkByID(id string) (Network, error)
|
||||
|
||||
// LeaveAll accepts a container id and attempts to leave all endpoints that the container has joined
|
||||
LeaveAll(id string) error
|
||||
// NewSandbox cretes a new network sandbox for the passed container id
|
||||
NewSandbox(containerID string, options ...SandboxOption) (Sandbox, error)
|
||||
|
||||
// Sandboxes returns the list of Sandbox(s) managed by this controller.
|
||||
Sandboxes() []Sandbox
|
||||
|
||||
// WlakSandboxes uses the provided function to walk the Sandbox(s) managed by this controller.
|
||||
WalkSandboxes(walker SandboxWalker)
|
||||
|
||||
// SandboxByID returns the Sandbox which has the passed id. If not found, a types.NotFoundError is returned.
|
||||
SandboxByID(id string) (Sandbox, error)
|
||||
|
||||
// GC triggers immediate garbage collection of resources which are garbage collected.
|
||||
GC()
|
||||
|
@ -98,15 +108,19 @@ type NetworkController interface {
|
|||
// When the function returns true, the walk will stop.
|
||||
type NetworkWalker func(nw Network) bool
|
||||
|
||||
// SandboxWalker is a client provided function which will be used to walk the Sandboxes.
|
||||
// When the function returns true, the walk will stop.
|
||||
type SandboxWalker func(sb Sandbox) bool
|
||||
|
||||
type driverData struct {
|
||||
driver driverapi.Driver
|
||||
capability driverapi.Capability
|
||||
}
|
||||
|
||||
type driverTable map[string]*driverData
|
||||
type networkTable map[types.UUID]*network
|
||||
type endpointTable map[types.UUID]*endpoint
|
||||
type sandboxTable map[string]*sandboxData
|
||||
type networkTable map[string]*network
|
||||
type endpointTable map[string]*endpoint
|
||||
type sandboxTable map[string]*sandbox
|
||||
|
||||
type controller struct {
|
||||
networks networkTable
|
||||
|
@ -250,7 +264,7 @@ func (c *controller) NewNetwork(networkType, name string, options ...NetworkOpti
|
|||
network := &network{
|
||||
name: name,
|
||||
networkType: networkType,
|
||||
id: types.UUID(stringid.GenerateRandomID()),
|
||||
id: stringid.GenerateRandomID(),
|
||||
ctrlr: c,
|
||||
endpoints: endpointTable{},
|
||||
}
|
||||
|
@ -356,12 +370,130 @@ func (c *controller) NetworkByID(id string) (Network, error) {
|
|||
}
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
if n, ok := c.networks[types.UUID(id)]; ok {
|
||||
if n, ok := c.networks[id]; ok {
|
||||
return n, nil
|
||||
}
|
||||
return nil, ErrNoSuchNetwork(id)
|
||||
}
|
||||
|
||||
// NewSandbox creates a new sandbox for the passed container id
|
||||
func (c *controller) NewSandbox(containerID string, options ...SandboxOption) (Sandbox, error) {
|
||||
var err error
|
||||
|
||||
if containerID == "" {
|
||||
return nil, types.BadRequestErrorf("invalid container ID")
|
||||
}
|
||||
|
||||
var existing Sandbox
|
||||
look := SandboxContainerWalker(&existing, containerID)
|
||||
c.WalkSandboxes(look)
|
||||
if existing != nil {
|
||||
return nil, types.BadRequestErrorf("container %s is already present: %v", containerID, existing)
|
||||
}
|
||||
|
||||
// Create sandbox and process options first. Key generation depends on an option
|
||||
sb := &sandbox{
|
||||
id: stringid.GenerateRandomID(),
|
||||
containerID: containerID,
|
||||
endpoints: epHeap{},
|
||||
epPriority: map[string]int{},
|
||||
config: containerConfig{},
|
||||
controller: c,
|
||||
}
|
||||
// This sandbox may be using an existing osl sandbox, sharing it with another sandbox
|
||||
var peerSb Sandbox
|
||||
c.WalkSandboxes(SandboxKeyWalker(&peerSb, sb.Key()))
|
||||
if peerSb != nil {
|
||||
sb.osSbox = peerSb.(*sandbox).osSbox
|
||||
}
|
||||
|
||||
heap.Init(&sb.endpoints)
|
||||
|
||||
sb.processOptions(options...)
|
||||
|
||||
err = sb.buildHostsFile()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = sb.updateParentHosts()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = sb.setupDNS()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if sb.osSbox == nil {
|
||||
if sb.osSbox, err = osl.NewSandbox(sb.Key(), !sb.config.useDefaultSandBox); err != nil {
|
||||
return nil, fmt.Errorf("failed to create new osl sandbox: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
c.Lock()
|
||||
c.sandboxes[sb.id] = sb
|
||||
c.Unlock()
|
||||
|
||||
return sb, nil
|
||||
}
|
||||
|
||||
func (c *controller) Sandboxes() []Sandbox {
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
|
||||
list := make([]Sandbox, 0, len(c.sandboxes))
|
||||
for _, s := range c.sandboxes {
|
||||
list = append(list, s)
|
||||
}
|
||||
|
||||
return list
|
||||
}
|
||||
|
||||
func (c *controller) WalkSandboxes(walker SandboxWalker) {
|
||||
for _, sb := range c.Sandboxes() {
|
||||
if walker(sb) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *controller) SandboxByID(id string) (Sandbox, error) {
|
||||
if id == "" {
|
||||
return nil, ErrInvalidID(id)
|
||||
}
|
||||
c.Lock()
|
||||
s, ok := c.sandboxes[id]
|
||||
c.Unlock()
|
||||
if !ok {
|
||||
return nil, types.NotFoundErrorf("sandbox %s not found", id)
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// SandboxContainerWalker returns a Sandbox Walker function which looks for an existing Sandbox with the passed containerID
|
||||
func SandboxContainerWalker(out *Sandbox, containerID string) SandboxWalker {
|
||||
return func(sb Sandbox) bool {
|
||||
if sb.ContainerID() == containerID {
|
||||
*out = sb
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// SandboxKeyWalker returns a Sandbox Walker function which looks for an existing Sandbox with the passed key
|
||||
func SandboxKeyWalker(out *Sandbox, key string) SandboxWalker {
|
||||
return func(sb Sandbox) bool {
|
||||
if sb.Key() == key {
|
||||
*out = sb
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (c *controller) loadDriver(networkType string) (*driverData, error) {
|
||||
// Plugins pkg performs lazy loading of plugins that acts as remote drivers.
|
||||
// As per the design, this Get call will result in remote driver discovery if there is a corresponding plugin available.
|
||||
|
@ -395,5 +527,5 @@ func (c *controller) isDriverGlobalScoped(networkType string) (bool, error) {
|
|||
}
|
||||
|
||||
func (c *controller) GC() {
|
||||
sandbox.GC()
|
||||
osl.GC()
|
||||
}
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
package driverapi
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/docker/libnetwork/types"
|
||||
)
|
||||
import "net"
|
||||
|
||||
// NetworkPluginEndpointType represents the Endpoint Type used by Plugin system
|
||||
const NetworkPluginEndpointType = "NetworkDriver"
|
||||
|
@ -17,31 +13,31 @@ type Driver interface {
|
|||
// CreateNetwork invokes the driver method to create a network passing
|
||||
// the network id and network specific config. The config mechanism will
|
||||
// eventually be replaced with labels which are yet to be introduced.
|
||||
CreateNetwork(nid types.UUID, options map[string]interface{}) error
|
||||
CreateNetwork(nid string, options map[string]interface{}) error
|
||||
|
||||
// DeleteNetwork invokes the driver method to delete network passing
|
||||
// the network id.
|
||||
DeleteNetwork(nid types.UUID) error
|
||||
DeleteNetwork(nid string) error
|
||||
|
||||
// CreateEndpoint invokes the driver method to create an endpoint
|
||||
// passing the network id, endpoint id endpoint information and driver
|
||||
// specific config. The endpoint information can be either consumed by
|
||||
// the driver or populated by the driver. The config mechanism will
|
||||
// eventually be replaced with labels which are yet to be introduced.
|
||||
CreateEndpoint(nid, eid types.UUID, epInfo EndpointInfo, options map[string]interface{}) error
|
||||
CreateEndpoint(nid, eid string, epInfo EndpointInfo, options map[string]interface{}) error
|
||||
|
||||
// DeleteEndpoint invokes the driver method to delete an endpoint
|
||||
// passing the network id and endpoint id.
|
||||
DeleteEndpoint(nid, eid types.UUID) error
|
||||
DeleteEndpoint(nid, eid string) error
|
||||
|
||||
// EndpointOperInfo retrieves from the driver the operational data related to the specified endpoint
|
||||
EndpointOperInfo(nid, eid types.UUID) (map[string]interface{}, error)
|
||||
EndpointOperInfo(nid, eid string) (map[string]interface{}, error)
|
||||
|
||||
// Join method is invoked when a Sandbox is attached to an endpoint.
|
||||
Join(nid, eid types.UUID, sboxKey string, jinfo JoinInfo, options map[string]interface{}) error
|
||||
Join(nid, eid string, sboxKey string, jinfo JoinInfo, options map[string]interface{}) error
|
||||
|
||||
// Leave method is invoked when a Sandbox detaches from an endpoint.
|
||||
Leave(nid, eid types.UUID) error
|
||||
Leave(nid, eid string) error
|
||||
|
||||
// Type returns the the type of this driver, the network type this driver manages
|
||||
Type() string
|
||||
|
@ -107,12 +103,6 @@ type JoinInfo interface {
|
|||
// AddStaticRoute adds a routes to the sandbox.
|
||||
// It may be used in addtion to or instead of a default gateway (as above).
|
||||
AddStaticRoute(destination *net.IPNet, routeType int, nextHop net.IP, interfaceID int) error
|
||||
|
||||
// SetHostsPath sets the overriding /etc/hosts path to use for the container.
|
||||
SetHostsPath(string) error
|
||||
|
||||
// SetResolvConfPath sets the overriding /etc/resolv.conf path to use for the container.
|
||||
SetResolvConfPath(string) error
|
||||
}
|
||||
|
||||
// DriverCallback provides a Callback interface for Drivers into LibNetwork
|
||||
|
|
|
@ -75,7 +75,7 @@ type containerConfiguration struct {
|
|||
}
|
||||
|
||||
type bridgeEndpoint struct {
|
||||
id types.UUID
|
||||
id string
|
||||
srcName string
|
||||
addr *net.IPNet
|
||||
addrv6 *net.IPNet
|
||||
|
@ -86,10 +86,10 @@ type bridgeEndpoint struct {
|
|||
}
|
||||
|
||||
type bridgeNetwork struct {
|
||||
id types.UUID
|
||||
id string
|
||||
bridge *bridgeInterface // The bridge's L3 interface
|
||||
config *networkConfiguration
|
||||
endpoints map[types.UUID]*bridgeEndpoint // key: endpoint id
|
||||
endpoints map[string]*bridgeEndpoint // key: endpoint id
|
||||
portMapper *portmapper.PortMapper
|
||||
driver *driver // The network's driver
|
||||
sync.Mutex
|
||||
|
@ -100,7 +100,7 @@ type driver struct {
|
|||
network *bridgeNetwork
|
||||
natChain *iptables.ChainInfo
|
||||
filterChain *iptables.ChainInfo
|
||||
networks map[types.UUID]*bridgeNetwork
|
||||
networks map[string]*bridgeNetwork
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
|
@ -110,7 +110,7 @@ func init() {
|
|||
|
||||
// New constructs a new bridge driver
|
||||
func newDriver() driverapi.Driver {
|
||||
return &driver{networks: map[types.UUID]*bridgeNetwork{}}
|
||||
return &driver{networks: map[string]*bridgeNetwork{}}
|
||||
}
|
||||
|
||||
// Init registers a new instance of bridge driver
|
||||
|
@ -346,7 +346,7 @@ func (n *bridgeNetwork) getNetworkBridgeName() string {
|
|||
return config.BridgeName
|
||||
}
|
||||
|
||||
func (n *bridgeNetwork) getEndpoint(eid types.UUID) (*bridgeEndpoint, error) {
|
||||
func (n *bridgeNetwork) getEndpoint(eid string) (*bridgeEndpoint, error) {
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
|
||||
|
@ -394,7 +394,7 @@ func (n *bridgeNetwork) isolateNetwork(others []*bridgeNetwork, enable bool) err
|
|||
}
|
||||
|
||||
// Checks whether this network's configuration for the network with this id conflicts with any of the passed networks
|
||||
func (c *networkConfiguration) conflictsWithNetworks(id types.UUID, others []*bridgeNetwork) error {
|
||||
func (c *networkConfiguration) conflictsWithNetworks(id string, others []*bridgeNetwork) error {
|
||||
for _, nw := range others {
|
||||
|
||||
nw.Lock()
|
||||
|
@ -475,7 +475,7 @@ func (d *driver) Config(option map[string]interface{}) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) getNetwork(id types.UUID) (*bridgeNetwork, error) {
|
||||
func (d *driver) getNetwork(id string) (*bridgeNetwork, error) {
|
||||
d.Lock()
|
||||
defer d.Unlock()
|
||||
|
||||
|
@ -567,7 +567,7 @@ func (d *driver) getNetworks() []*bridgeNetwork {
|
|||
}
|
||||
|
||||
// Create a new network using bridge plugin
|
||||
func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) error {
|
||||
func (d *driver) CreateNetwork(id string, option map[string]interface{}) error {
|
||||
var err error
|
||||
|
||||
// Sanity checks
|
||||
|
@ -596,7 +596,7 @@ func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) err
|
|||
// Create and set network handler in driver
|
||||
network := &bridgeNetwork{
|
||||
id: id,
|
||||
endpoints: make(map[types.UUID]*bridgeEndpoint),
|
||||
endpoints: make(map[string]*bridgeEndpoint),
|
||||
config: config,
|
||||
portMapper: portmapper.New(),
|
||||
driver: d,
|
||||
|
@ -719,7 +719,7 @@ func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) err
|
|||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) DeleteNetwork(nid types.UUID) error {
|
||||
func (d *driver) DeleteNetwork(nid string) error {
|
||||
var err error
|
||||
|
||||
// Get network handler and remove it from driver
|
||||
|
@ -843,7 +843,7 @@ func setHairpinMode(link netlink.Link, enable bool) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error {
|
||||
func (d *driver) CreateEndpoint(nid, eid string, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error {
|
||||
var (
|
||||
ipv6Addr *net.IPNet
|
||||
err error
|
||||
|
@ -927,13 +927,13 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn
|
|||
LinkAttrs: netlink.LinkAttrs{Name: hostIfName, TxQLen: 0},
|
||||
PeerName: containerIfName}
|
||||
if err = netlink.LinkAdd(veth); err != nil {
|
||||
return err
|
||||
return types.InternalErrorf("failed to add the host (%s) <=> sandbox (%s) pair interfaces: %v", hostIfName, containerIfName, err)
|
||||
}
|
||||
|
||||
// Get the host side pipe interface handler
|
||||
host, err := netlink.LinkByName(hostIfName)
|
||||
if err != nil {
|
||||
return err
|
||||
return types.InternalErrorf("failed to find host side interface %s: %v", hostIfName, err)
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
|
@ -944,7 +944,7 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn
|
|||
// Get the sandbox side pipe interface handler
|
||||
sbox, err := netlink.LinkByName(containerIfName)
|
||||
if err != nil {
|
||||
return err
|
||||
return types.InternalErrorf("failed to find sandbox side interface %s: %v", containerIfName, err)
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
|
@ -960,11 +960,11 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn
|
|||
if config.Mtu != 0 {
|
||||
err = netlink.LinkSetMTU(host, config.Mtu)
|
||||
if err != nil {
|
||||
return err
|
||||
return types.InternalErrorf("failed to set MTU on host interface %s: %v", hostIfName, err)
|
||||
}
|
||||
err = netlink.LinkSetMTU(sbox, config.Mtu)
|
||||
if err != nil {
|
||||
return err
|
||||
return types.InternalErrorf("failed to set MTU on sandbox interface %s: %v", containerIfName, err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1054,7 +1054,7 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn
|
|||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) DeleteEndpoint(nid, eid types.UUID) error {
|
||||
func (d *driver) DeleteEndpoint(nid, eid string) error {
|
||||
var err error
|
||||
|
||||
// Get the network handler and make sure it exists
|
||||
|
@ -1138,7 +1138,7 @@ func (d *driver) DeleteEndpoint(nid, eid types.UUID) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{}, error) {
|
||||
func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) {
|
||||
// Get the network handler and make sure it exists
|
||||
d.Lock()
|
||||
n, ok := d.networks[nid]
|
||||
|
@ -1195,7 +1195,7 @@ func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{},
|
|||
}
|
||||
|
||||
// Join method is invoked when a Sandbox is attached to an endpoint.
|
||||
func (d *driver) Join(nid, eid types.UUID, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
|
||||
func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
|
||||
network, err := d.getNetwork(nid)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -1238,7 +1238,7 @@ func (d *driver) Join(nid, eid types.UUID, sboxKey string, jinfo driverapi.JoinI
|
|||
}
|
||||
|
||||
// Leave method is invoked when a Sandbox detaches from an endpoint.
|
||||
func (d *driver) Leave(nid, eid types.UUID) error {
|
||||
func (d *driver) Leave(nid, eid string) error {
|
||||
network, err := d.getNetwork(nid)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -1282,7 +1282,7 @@ func (d *driver) link(network *bridgeNetwork, endpoint *bridgeEndpoint, options
|
|||
if endpoint.config != nil && endpoint.config.ExposedPorts != nil {
|
||||
for _, p := range cc.ParentEndpoints {
|
||||
var parentEndpoint *bridgeEndpoint
|
||||
parentEndpoint, err = network.getEndpoint(types.UUID(p))
|
||||
parentEndpoint, err = network.getEndpoint(p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -1312,7 +1312,7 @@ func (d *driver) link(network *bridgeNetwork, endpoint *bridgeEndpoint, options
|
|||
|
||||
for _, c := range cc.ChildEndpoints {
|
||||
var childEndpoint *bridgeEndpoint
|
||||
childEndpoint, err = network.getEndpoint(types.UUID(c))
|
||||
childEndpoint, err = network.getEndpoint(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -176,7 +176,7 @@ func TestCreateMultipleNetworks(t *testing.T) {
|
|||
verifyV4INCEntries(dd.networks, 0, t)
|
||||
}
|
||||
|
||||
func verifyV4INCEntries(networks map[types.UUID]*bridgeNetwork, numEntries int, t *testing.T) {
|
||||
func verifyV4INCEntries(networks map[string]*bridgeNetwork, numEntries int, t *testing.T) {
|
||||
out, err := iptables.Raw("-L", "FORWARD")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -268,16 +268,6 @@ func (te *testEndpoint) SetGatewayIPv6(gw6 net.IP) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (te *testEndpoint) SetHostsPath(path string) error {
|
||||
te.hostsPath = path
|
||||
return nil
|
||||
}
|
||||
|
||||
func (te *testEndpoint) SetResolvConfPath(path string) error {
|
||||
te.resolvConfPath = path
|
||||
return nil
|
||||
}
|
||||
|
||||
func (te *testEndpoint) AddStaticRoute(destination *net.IPNet, routeType int, nextHop net.IP, interfaceID int) error {
|
||||
te.routes = append(te.routes, types.StaticRoute{Destination: destination, RouteType: routeType, NextHop: nextHop, InterfaceID: interfaceID})
|
||||
return nil
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
const networkType = "host"
|
||||
|
||||
type driver struct {
|
||||
network types.UUID
|
||||
network string
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,7 @@ func (d *driver) Config(option map[string]interface{}) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) error {
|
||||
func (d *driver) CreateNetwork(id string, option map[string]interface{}) error {
|
||||
d.Lock()
|
||||
defer d.Unlock()
|
||||
|
||||
|
@ -39,33 +39,29 @@ func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) err
|
|||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) DeleteNetwork(nid types.UUID) error {
|
||||
func (d *driver) DeleteNetwork(nid string) error {
|
||||
return types.ForbiddenErrorf("network of type \"%s\" cannot be deleted", networkType)
|
||||
}
|
||||
|
||||
func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error {
|
||||
func (d *driver) CreateEndpoint(nid, eid string, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) DeleteEndpoint(nid, eid types.UUID) error {
|
||||
func (d *driver) DeleteEndpoint(nid, eid string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{}, error) {
|
||||
func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) {
|
||||
return make(map[string]interface{}, 0), nil
|
||||
}
|
||||
|
||||
// Join method is invoked when a Sandbox is attached to an endpoint.
|
||||
func (d *driver) Join(nid, eid types.UUID, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
|
||||
if err := jinfo.SetHostsPath("/etc/hosts"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return jinfo.SetResolvConfPath("/etc/resolv.conf")
|
||||
func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Leave method is invoked when a Sandbox detaches from an endpoint.
|
||||
func (d *driver) Leave(nid, eid types.UUID) error {
|
||||
func (d *driver) Leave(nid, eid string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
const networkType = "null"
|
||||
|
||||
type driver struct {
|
||||
network types.UUID
|
||||
network string
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,7 @@ func (d *driver) Config(option map[string]interface{}) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) error {
|
||||
func (d *driver) CreateNetwork(id string, option map[string]interface{}) error {
|
||||
d.Lock()
|
||||
defer d.Unlock()
|
||||
|
||||
|
@ -39,29 +39,29 @@ func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) err
|
|||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) DeleteNetwork(nid types.UUID) error {
|
||||
func (d *driver) DeleteNetwork(nid string) error {
|
||||
return types.ForbiddenErrorf("network of type \"%s\" cannot be deleted", networkType)
|
||||
}
|
||||
|
||||
func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error {
|
||||
func (d *driver) CreateEndpoint(nid, eid string, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) DeleteEndpoint(nid, eid types.UUID) error {
|
||||
func (d *driver) DeleteEndpoint(nid, eid string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{}, error) {
|
||||
func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) {
|
||||
return make(map[string]interface{}, 0), nil
|
||||
}
|
||||
|
||||
// Join method is invoked when a Sandbox is attached to an endpoint.
|
||||
func (d *driver) Join(nid, eid types.UUID, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
|
||||
func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Leave method is invoked when a Sandbox detaches from an endpoint.
|
||||
func (d *driver) Leave(nid, eid types.UUID) error {
|
||||
func (d *driver) Leave(nid, eid string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -4,12 +4,11 @@ import (
|
|||
"fmt"
|
||||
|
||||
"github.com/docker/libnetwork/driverapi"
|
||||
"github.com/docker/libnetwork/types"
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
// Join method is invoked when a Sandbox is attached to an endpoint.
|
||||
func (d *driver) Join(nid, eid types.UUID, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
|
||||
func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
|
||||
if err := validateID(nid, eid); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -77,7 +76,7 @@ func (d *driver) Join(nid, eid types.UUID, sboxKey string, jinfo driverapi.JoinI
|
|||
}
|
||||
|
||||
// Leave method is invoked when a Sandbox detaches from an endpoint.
|
||||
func (d *driver) Leave(nid, eid types.UUID) error {
|
||||
func (d *driver) Leave(nid, eid string) error {
|
||||
if err := validateID(nid, eid); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -7,18 +7,17 @@ import (
|
|||
|
||||
"github.com/docker/libnetwork/driverapi"
|
||||
"github.com/docker/libnetwork/netutils"
|
||||
"github.com/docker/libnetwork/types"
|
||||
)
|
||||
|
||||
type endpointTable map[types.UUID]*endpoint
|
||||
type endpointTable map[string]*endpoint
|
||||
|
||||
type endpoint struct {
|
||||
id types.UUID
|
||||
id string
|
||||
mac net.HardwareAddr
|
||||
addr *net.IPNet
|
||||
}
|
||||
|
||||
func (n *network) endpoint(eid types.UUID) *endpoint {
|
||||
func (n *network) endpoint(eid string) *endpoint {
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
|
||||
|
@ -31,13 +30,13 @@ func (n *network) addEndpoint(ep *endpoint) {
|
|||
n.Unlock()
|
||||
}
|
||||
|
||||
func (n *network) deleteEndpoint(eid types.UUID) {
|
||||
func (n *network) deleteEndpoint(eid string) {
|
||||
n.Lock()
|
||||
delete(n.endpoints, eid)
|
||||
n.Unlock()
|
||||
}
|
||||
|
||||
func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointInfo,
|
||||
func (d *driver) CreateEndpoint(nid, eid string, epInfo driverapi.EndpointInfo,
|
||||
epOptions map[string]interface{}) error {
|
||||
if err := validateID(nid, eid); err != nil {
|
||||
return err
|
||||
|
@ -85,7 +84,7 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn
|
|||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) DeleteEndpoint(nid, eid types.UUID) error {
|
||||
func (d *driver) DeleteEndpoint(nid, eid string) error {
|
||||
if err := validateID(nid, eid); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -105,6 +104,6 @@ func (d *driver) DeleteEndpoint(nid, eid types.UUID) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{}, error) {
|
||||
func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) {
|
||||
return make(map[string]interface{}, 0), nil
|
||||
}
|
||||
|
|
|
@ -10,20 +10,19 @@ import (
|
|||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/libnetwork/datastore"
|
||||
"github.com/docker/libnetwork/ipallocator"
|
||||
"github.com/docker/libnetwork/sandbox"
|
||||
"github.com/docker/libnetwork/types"
|
||||
"github.com/docker/libnetwork/osl"
|
||||
"github.com/vishvananda/netlink"
|
||||
"github.com/vishvananda/netlink/nl"
|
||||
)
|
||||
|
||||
type networkTable map[types.UUID]*network
|
||||
type networkTable map[string]*network
|
||||
|
||||
type network struct {
|
||||
id types.UUID
|
||||
id string
|
||||
vni uint32
|
||||
dbIndex uint64
|
||||
dbExists bool
|
||||
sbox sandbox.Sandbox
|
||||
sbox osl.Sandbox
|
||||
endpoints endpointTable
|
||||
ipAllocator *ipallocator.IPAllocator
|
||||
gw net.IP
|
||||
|
@ -36,7 +35,7 @@ type network struct {
|
|||
sync.Mutex
|
||||
}
|
||||
|
||||
func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) error {
|
||||
func (d *driver) CreateNetwork(id string, option map[string]interface{}) error {
|
||||
if id == "" {
|
||||
return fmt.Errorf("invalid network id")
|
||||
}
|
||||
|
@ -59,7 +58,7 @@ func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) err
|
|||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) DeleteNetwork(nid types.UUID) error {
|
||||
func (d *driver) DeleteNetwork(nid string) error {
|
||||
if nid == "" {
|
||||
return fmt.Errorf("invalid network id")
|
||||
}
|
||||
|
@ -140,8 +139,8 @@ func (n *network) initSandbox() error {
|
|||
n.initEpoch++
|
||||
n.Unlock()
|
||||
|
||||
sbox, err := sandbox.NewSandbox(
|
||||
sandbox.GenerateKey(fmt.Sprintf("%d-", n.initEpoch)+string(n.id)), true)
|
||||
sbox, err := osl.NewSandbox(
|
||||
osl.GenerateKey(fmt.Sprintf("%d-", n.initEpoch)+n.id), true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not create network sandbox: %v", err)
|
||||
}
|
||||
|
@ -216,7 +215,7 @@ func (n *network) watchMiss(nlSock *nl.NetlinkSocket) {
|
|||
continue
|
||||
}
|
||||
|
||||
if err := n.driver.peerAdd(n.id, types.UUID("dummy"), neigh.IP, mac, vtep, true); err != nil {
|
||||
if err := n.driver.peerAdd(n.id, "dummy", neigh.IP, mac, vtep, true); err != nil {
|
||||
logrus.Errorf("could not add neighbor entry for missed peer: %v", err)
|
||||
}
|
||||
}
|
||||
|
@ -229,27 +228,27 @@ func (d *driver) addNetwork(n *network) {
|
|||
d.Unlock()
|
||||
}
|
||||
|
||||
func (d *driver) deleteNetwork(nid types.UUID) {
|
||||
func (d *driver) deleteNetwork(nid string) {
|
||||
d.Lock()
|
||||
delete(d.networks, nid)
|
||||
d.Unlock()
|
||||
}
|
||||
|
||||
func (d *driver) network(nid types.UUID) *network {
|
||||
func (d *driver) network(nid string) *network {
|
||||
d.Lock()
|
||||
defer d.Unlock()
|
||||
|
||||
return d.networks[nid]
|
||||
}
|
||||
|
||||
func (n *network) sandbox() sandbox.Sandbox {
|
||||
func (n *network) sandbox() osl.Sandbox {
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
|
||||
return n.sbox
|
||||
}
|
||||
|
||||
func (n *network) setSandbox(sbox sandbox.Sandbox) {
|
||||
func (n *network) setSandbox(sbox osl.Sandbox) {
|
||||
n.Lock()
|
||||
n.sbox = sbox
|
||||
n.Unlock()
|
||||
|
@ -269,7 +268,7 @@ func (n *network) setVxlanID(vni uint32) {
|
|||
}
|
||||
|
||||
func (n *network) Key() []string {
|
||||
return []string{"overlay", "network", string(n.id)}
|
||||
return []string{"overlay", "network", n.id}
|
||||
}
|
||||
|
||||
func (n *network) KeyPrefix() []string {
|
||||
|
|
|
@ -7,14 +7,13 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/libnetwork/types"
|
||||
"github.com/hashicorp/serf/serf"
|
||||
)
|
||||
|
||||
type ovNotify struct {
|
||||
action string
|
||||
eid types.UUID
|
||||
nid types.UUID
|
||||
eid string
|
||||
nid string
|
||||
}
|
||||
|
||||
type logWriter struct{}
|
||||
|
@ -150,12 +149,12 @@ func (d *driver) processEvent(u serf.UserEvent) {
|
|||
|
||||
switch action {
|
||||
case "join":
|
||||
if err := d.peerAdd(types.UUID(nid), types.UUID(eid), net.ParseIP(ipStr), mac,
|
||||
if err := d.peerAdd(nid, eid, net.ParseIP(ipStr), mac,
|
||||
net.ParseIP(vtepStr), true); err != nil {
|
||||
fmt.Printf("Peer add failed in the driver: %v\n", err)
|
||||
}
|
||||
case "leave":
|
||||
if err := d.peerDelete(types.UUID(nid), types.UUID(eid), net.ParseIP(ipStr), mac,
|
||||
if err := d.peerDelete(nid, eid, net.ParseIP(ipStr), mac,
|
||||
net.ParseIP(vtepStr), true); err != nil {
|
||||
fmt.Printf("Peer delete failed in the driver: %v\n", err)
|
||||
}
|
||||
|
@ -171,7 +170,7 @@ func (d *driver) processQuery(q *serf.Query) {
|
|||
fmt.Printf("Failed to scan query payload string: %v\n", err)
|
||||
}
|
||||
|
||||
peerMac, vtep, err := d.peerDbSearch(types.UUID(nid), net.ParseIP(ipStr))
|
||||
peerMac, vtep, err := d.peerDbSearch(nid, net.ParseIP(ipStr))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -179,7 +178,7 @@ func (d *driver) processQuery(q *serf.Query) {
|
|||
q.Respond([]byte(fmt.Sprintf("%s %s", peerMac.String(), vtep.String())))
|
||||
}
|
||||
|
||||
func (d *driver) resolvePeer(nid types.UUID, peerIP net.IP) (net.HardwareAddr, net.IP, error) {
|
||||
func (d *driver) resolvePeer(nid string, peerIP net.IP) (net.HardwareAddr, net.IP, error) {
|
||||
qPayload := fmt.Sprintf("%s %s", string(nid), peerIP.String())
|
||||
resp, err := d.serfInstance.Query("peerlookup", []byte(qPayload), nil)
|
||||
if err != nil {
|
||||
|
|
|
@ -4,12 +4,11 @@ import (
|
|||
"fmt"
|
||||
|
||||
"github.com/docker/libnetwork/netutils"
|
||||
"github.com/docker/libnetwork/types"
|
||||
"github.com/vishvananda/netlink"
|
||||
"github.com/vishvananda/netlink/nl"
|
||||
)
|
||||
|
||||
func validateID(nid, eid types.UUID) error {
|
||||
func validateID(nid, eid string) error {
|
||||
if nid == "" {
|
||||
return fmt.Errorf("invalid network id")
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@ import (
|
|||
"github.com/docker/libnetwork/driverapi"
|
||||
"github.com/docker/libnetwork/idm"
|
||||
"github.com/docker/libnetwork/netlabel"
|
||||
"github.com/docker/libnetwork/types"
|
||||
"github.com/hashicorp/serf/serf"
|
||||
)
|
||||
|
||||
|
@ -77,7 +76,7 @@ func Init(dc driverapi.DriverCallback) error {
|
|||
return dc.RegisterDriver(networkType, &driver{
|
||||
networks: networkTable{},
|
||||
peerDb: peerNetworkMap{
|
||||
mp: map[types.UUID]peerMap{},
|
||||
mp: map[string]peerMap{},
|
||||
},
|
||||
}, c)
|
||||
}
|
||||
|
|
|
@ -5,8 +5,6 @@ import (
|
|||
"net"
|
||||
"sync"
|
||||
"syscall"
|
||||
|
||||
"github.com/docker/libnetwork/types"
|
||||
)
|
||||
|
||||
type peerKey struct {
|
||||
|
@ -15,7 +13,7 @@ type peerKey struct {
|
|||
}
|
||||
|
||||
type peerEntry struct {
|
||||
eid types.UUID
|
||||
eid string
|
||||
vtep net.IP
|
||||
inSandbox bool
|
||||
isLocal bool
|
||||
|
@ -27,7 +25,7 @@ type peerMap struct {
|
|||
}
|
||||
|
||||
type peerNetworkMap struct {
|
||||
mp map[types.UUID]peerMap
|
||||
mp map[string]peerMap
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
|
@ -58,7 +56,7 @@ func (pKey *peerKey) Scan(state fmt.ScanState, verb rune) error {
|
|||
|
||||
var peerDbWg sync.WaitGroup
|
||||
|
||||
func (d *driver) peerDbWalk(nid types.UUID, f func(*peerKey, *peerEntry) bool) error {
|
||||
func (d *driver) peerDbWalk(nid string, f func(*peerKey, *peerEntry) bool) error {
|
||||
d.peerDb.Lock()
|
||||
pMap, ok := d.peerDb.mp[nid]
|
||||
if !ok {
|
||||
|
@ -84,7 +82,7 @@ func (d *driver) peerDbWalk(nid types.UUID, f func(*peerKey, *peerEntry) bool) e
|
|||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) peerDbSearch(nid types.UUID, peerIP net.IP) (net.HardwareAddr, net.IP, error) {
|
||||
func (d *driver) peerDbSearch(nid string, peerIP net.IP) (net.HardwareAddr, net.IP, error) {
|
||||
var (
|
||||
peerMac net.HardwareAddr
|
||||
vtep net.IP
|
||||
|
@ -113,7 +111,7 @@ func (d *driver) peerDbSearch(nid types.UUID, peerIP net.IP) (net.HardwareAddr,
|
|||
return peerMac, vtep, nil
|
||||
}
|
||||
|
||||
func (d *driver) peerDbAdd(nid, eid types.UUID, peerIP net.IP,
|
||||
func (d *driver) peerDbAdd(nid, eid string, peerIP net.IP,
|
||||
peerMac net.HardwareAddr, vtep net.IP, isLocal bool) {
|
||||
|
||||
peerDbWg.Wait()
|
||||
|
@ -145,7 +143,7 @@ func (d *driver) peerDbAdd(nid, eid types.UUID, peerIP net.IP,
|
|||
pMap.Unlock()
|
||||
}
|
||||
|
||||
func (d *driver) peerDbDelete(nid, eid types.UUID, peerIP net.IP,
|
||||
func (d *driver) peerDbDelete(nid, eid string, peerIP net.IP,
|
||||
peerMac net.HardwareAddr, vtep net.IP) {
|
||||
peerDbWg.Wait()
|
||||
|
||||
|
@ -167,7 +165,7 @@ func (d *driver) peerDbDelete(nid, eid types.UUID, peerIP net.IP,
|
|||
pMap.Unlock()
|
||||
}
|
||||
|
||||
func (d *driver) peerDbUpdateSandbox(nid types.UUID) {
|
||||
func (d *driver) peerDbUpdateSandbox(nid string) {
|
||||
d.peerDb.Lock()
|
||||
pMap, ok := d.peerDb.mp[nid]
|
||||
if !ok {
|
||||
|
@ -214,7 +212,7 @@ func (d *driver) peerDbUpdateSandbox(nid types.UUID) {
|
|||
peerDbWg.Done()
|
||||
}
|
||||
|
||||
func (d *driver) peerAdd(nid, eid types.UUID, peerIP net.IP,
|
||||
func (d *driver) peerAdd(nid, eid string, peerIP net.IP,
|
||||
peerMac net.HardwareAddr, vtep net.IP, updateDb bool) error {
|
||||
|
||||
if err := validateID(nid, eid); err != nil {
|
||||
|
@ -249,7 +247,7 @@ func (d *driver) peerAdd(nid, eid types.UUID, peerIP net.IP,
|
|||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) peerDelete(nid, eid types.UUID, peerIP net.IP,
|
||||
func (d *driver) peerDelete(nid, eid string, peerIP net.IP,
|
||||
peerMac net.HardwareAddr, vtep net.IP, updateDb bool) error {
|
||||
|
||||
if err := validateID(nid, eid); err != nil {
|
||||
|
|
|
@ -127,8 +127,6 @@ type JoinResponse struct {
|
|||
InterfaceNames []*InterfaceName
|
||||
Gateway string
|
||||
GatewayIPv6 string
|
||||
HostsPath string
|
||||
ResolvConfPath string
|
||||
StaticRoutes []StaticRoute
|
||||
}
|
||||
|
||||
|
|
|
@ -57,20 +57,20 @@ func (d *driver) call(methodName string, arg interface{}, retVal maybeError) err
|
|||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) CreateNetwork(id types.UUID, options map[string]interface{}) error {
|
||||
func (d *driver) CreateNetwork(id string, options map[string]interface{}) error {
|
||||
create := &api.CreateNetworkRequest{
|
||||
NetworkID: string(id),
|
||||
NetworkID: id,
|
||||
Options: options,
|
||||
}
|
||||
return d.call("CreateNetwork", create, &api.CreateNetworkResponse{})
|
||||
}
|
||||
|
||||
func (d *driver) DeleteNetwork(nid types.UUID) error {
|
||||
delete := &api.DeleteNetworkRequest{NetworkID: string(nid)}
|
||||
func (d *driver) DeleteNetwork(nid string) error {
|
||||
delete := &api.DeleteNetworkRequest{NetworkID: nid}
|
||||
return d.call("DeleteNetwork", delete, &api.DeleteNetworkResponse{})
|
||||
}
|
||||
|
||||
func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error {
|
||||
func (d *driver) CreateEndpoint(nid, eid string, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error {
|
||||
if epInfo == nil {
|
||||
return fmt.Errorf("must not be called with nil EndpointInfo")
|
||||
}
|
||||
|
@ -87,8 +87,8 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn
|
|||
}
|
||||
}
|
||||
create := &api.CreateEndpointRequest{
|
||||
NetworkID: string(nid),
|
||||
EndpointID: string(eid),
|
||||
NetworkID: nid,
|
||||
EndpointID: eid,
|
||||
Interfaces: reqIfaces,
|
||||
Options: epOptions,
|
||||
}
|
||||
|
@ -129,18 +129,18 @@ func errorWithRollback(msg string, err error) error {
|
|||
return fmt.Errorf("%s; %s", msg, rollback)
|
||||
}
|
||||
|
||||
func (d *driver) DeleteEndpoint(nid, eid types.UUID) error {
|
||||
func (d *driver) DeleteEndpoint(nid, eid string) error {
|
||||
delete := &api.DeleteEndpointRequest{
|
||||
NetworkID: string(nid),
|
||||
EndpointID: string(eid),
|
||||
NetworkID: nid,
|
||||
EndpointID: eid,
|
||||
}
|
||||
return d.call("DeleteEndpoint", delete, &api.DeleteEndpointResponse{})
|
||||
}
|
||||
|
||||
func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{}, error) {
|
||||
func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) {
|
||||
info := &api.EndpointInfoRequest{
|
||||
NetworkID: string(nid),
|
||||
EndpointID: string(eid),
|
||||
NetworkID: nid,
|
||||
EndpointID: eid,
|
||||
}
|
||||
var res api.EndpointInfoResponse
|
||||
if err := d.call("EndpointOperInfo", info, &res); err != nil {
|
||||
|
@ -150,10 +150,10 @@ func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{},
|
|||
}
|
||||
|
||||
// Join method is invoked when a Sandbox is attached to an endpoint.
|
||||
func (d *driver) Join(nid, eid types.UUID, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
|
||||
func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
|
||||
join := &api.JoinRequest{
|
||||
NetworkID: string(nid),
|
||||
EndpointID: string(eid),
|
||||
NetworkID: nid,
|
||||
EndpointID: eid,
|
||||
SandboxKey: sboxKey,
|
||||
Options: options,
|
||||
}
|
||||
|
@ -209,20 +209,14 @@ func (d *driver) Join(nid, eid types.UUID, sboxKey string, jinfo driverapi.JoinI
|
|||
}
|
||||
}
|
||||
}
|
||||
if jinfo.SetHostsPath(res.HostsPath) != nil {
|
||||
return errorWithRollback(fmt.Sprintf("failed to set hosts path: %s", res.HostsPath), d.Leave(nid, eid))
|
||||
}
|
||||
if jinfo.SetResolvConfPath(res.ResolvConfPath) != nil {
|
||||
return errorWithRollback(fmt.Sprintf("failed to set resolv.conf path: %s", res.ResolvConfPath), d.Leave(nid, eid))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Leave method is invoked when a Sandbox detaches from an endpoint.
|
||||
func (d *driver) Leave(nid, eid types.UUID) error {
|
||||
func (d *driver) Leave(nid, eid string) error {
|
||||
leave := &api.LeaveRequest{
|
||||
NetworkID: string(nid),
|
||||
EndpointID: string(eid),
|
||||
NetworkID: nid,
|
||||
EndpointID: eid,
|
||||
}
|
||||
return d.call("Leave", leave, &api.LeaveResponse{})
|
||||
}
|
||||
|
|
|
@ -138,20 +138,6 @@ func (test *testEndpoint) SetGatewayIPv6(ipv6 net.IP) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (test *testEndpoint) SetHostsPath(p string) error {
|
||||
if p != test.hostsPath {
|
||||
test.t.Fatalf(`Wrong HostsPath; expected "%s", got "%s"`, test.hostsPath, p)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (test *testEndpoint) SetResolvConfPath(p string) error {
|
||||
if p != test.resolvConfPath {
|
||||
test.t.Fatalf(`Wrong ResolvConfPath; expected "%s", got "%s"`, test.resolvConfPath, p)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (test *testEndpoint) SetNames(src string, dst string) error {
|
||||
if test.src != src {
|
||||
test.t.Fatalf(`Wrong SrcName; expected "%s", got "%s"`, test.src, src)
|
||||
|
@ -282,13 +268,13 @@ func TestRemoteDriver(t *testing.T) {
|
|||
t.Fatal("Driver type does not match that given")
|
||||
}
|
||||
|
||||
netID := types.UUID("dummy-network")
|
||||
netID := "dummy-network"
|
||||
err = driver.CreateNetwork(netID, map[string]interface{}{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
endID := types.UUID("dummy-endpoint")
|
||||
endID := "dummy-endpoint"
|
||||
err = driver.CreateEndpoint(netID, endID, ep, map[string]interface{}{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -345,7 +331,7 @@ func TestDriverError(t *testing.T) {
|
|||
|
||||
driver := newDriver(plugin, p.Client)
|
||||
|
||||
if err := driver.CreateEndpoint(types.UUID("dummy"), types.UUID("dummy"), &testEndpoint{t: t}, map[string]interface{}{}); err == nil {
|
||||
if err := driver.CreateEndpoint("dummy", "dummy", &testEndpoint{t: t}, map[string]interface{}{}); err == nil {
|
||||
t.Fatalf("Expected error from driver")
|
||||
}
|
||||
}
|
||||
|
@ -379,7 +365,7 @@ func TestMissingValues(t *testing.T) {
|
|||
}
|
||||
driver := newDriver(plugin, p.Client)
|
||||
|
||||
if err := driver.CreateEndpoint(types.UUID("dummy"), types.UUID("dummy"), ep, map[string]interface{}{}); err != nil {
|
||||
if err := driver.CreateEndpoint("dummy", "dummy", ep, map[string]interface{}{}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
@ -427,7 +413,7 @@ func TestRollback(t *testing.T) {
|
|||
|
||||
ep := &rollbackEndpoint{}
|
||||
|
||||
if err := driver.CreateEndpoint(types.UUID("dummy"), types.UUID("dummy"), ep, map[string]interface{}{}); err == nil {
|
||||
if err := driver.CreateEndpoint("dummy", "dummy", ep, map[string]interface{}{}); err == nil {
|
||||
t.Fatalf("Expected error from driver")
|
||||
}
|
||||
if !rolledback {
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
package windows
|
||||
|
||||
import (
|
||||
"github.com/docker/libnetwork/driverapi"
|
||||
"github.com/docker/libnetwork/types"
|
||||
)
|
||||
import "github.com/docker/libnetwork/driverapi"
|
||||
|
||||
const networkType = "windows"
|
||||
|
||||
|
@ -23,33 +20,33 @@ func (d *driver) Config(option map[string]interface{}) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) error {
|
||||
func (d *driver) CreateNetwork(id string, option map[string]interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) DeleteNetwork(nid types.UUID) error {
|
||||
func (d *driver) DeleteNetwork(nid string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error {
|
||||
func (d *driver) CreateEndpoint(nid, eid string, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) DeleteEndpoint(nid, eid types.UUID) error {
|
||||
func (d *driver) DeleteEndpoint(nid, eid string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{}, error) {
|
||||
func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) {
|
||||
return make(map[string]interface{}, 0), nil
|
||||
}
|
||||
|
||||
// Join method is invoked when a Sandbox is attached to an endpoint.
|
||||
func (d *driver) Join(nid, eid types.UUID, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
|
||||
func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Leave method is invoked when a Sandbox detaches from an endpoint.
|
||||
func (d *driver) Leave(nid, eid types.UUID) error {
|
||||
func (d *driver) Leave(nid, eid string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -1,22 +1,14 @@
|
|||
package libnetwork
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"net"
|
||||
"sync"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/libnetwork/datastore"
|
||||
"github.com/docker/libnetwork/etchosts"
|
||||
"github.com/docker/libnetwork/netlabel"
|
||||
"github.com/docker/libnetwork/resolvconf"
|
||||
"github.com/docker/libnetwork/sandbox"
|
||||
"github.com/docker/libnetwork/types"
|
||||
)
|
||||
|
||||
|
@ -31,14 +23,12 @@ type Endpoint interface {
|
|||
// Network returns the name of the network to which this endpoint is attached.
|
||||
Network() string
|
||||
|
||||
// Join creates a new sandbox for the given container ID and populates the
|
||||
// network resources allocated for the endpoint and joins the sandbox to
|
||||
// the endpoint.
|
||||
Join(containerID string, options ...EndpointOption) error
|
||||
// Join joins the sandbox to the endpoint and populates into the sandbox
|
||||
// the network resources allocated for the endpoint.
|
||||
Join(sandbox Sandbox, options ...EndpointOption) error
|
||||
|
||||
// Leave removes the sandbox associated with container ID and detaches
|
||||
// the network resources populated in the sandbox
|
||||
Leave(containerID string, options ...EndpointOption) error
|
||||
// Leave detaches the network resources populated in the sandbox.
|
||||
Leave(sandbox Sandbox, options ...EndpointOption) error
|
||||
|
||||
// Return certain operational data belonging to this endpoint
|
||||
Info() EndpointInfo
|
||||
|
@ -46,14 +36,8 @@ type Endpoint interface {
|
|||
// DriverInfo returns a collection of driver operational data related to this endpoint retrieved from the driver
|
||||
DriverInfo() (map[string]interface{}, error)
|
||||
|
||||
// ContainerInfo returns the info available at the endpoint about the attached container
|
||||
ContainerInfo() ContainerInfo
|
||||
|
||||
// Delete and detaches this endpoint from the network.
|
||||
Delete() error
|
||||
|
||||
// Retrieve the interfaces' statistics from the sandbox
|
||||
Statistics() (map[string]*sandbox.InterfaceStatistics, error)
|
||||
}
|
||||
|
||||
// EndpointOption is a option setter function type used to pass varios options to Network
|
||||
|
@ -61,68 +45,13 @@ type Endpoint interface {
|
|||
// provided by libnetwork, they look like <Create|Join|Leave>Option[...](...)
|
||||
type EndpointOption func(ep *endpoint)
|
||||
|
||||
// ContainerData is a set of data returned when a container joins an endpoint.
|
||||
type ContainerData struct {
|
||||
SandboxKey string
|
||||
}
|
||||
|
||||
// These are the container configs used to customize container /etc/hosts file.
|
||||
type hostsPathConfig struct {
|
||||
hostName string
|
||||
domainName string
|
||||
hostsPath string
|
||||
extraHosts []extraHost
|
||||
parentUpdates []parentUpdate
|
||||
}
|
||||
|
||||
// These are the container configs used to customize container /etc/resolv.conf file.
|
||||
type resolvConfPathConfig struct {
|
||||
resolvConfPath string
|
||||
dnsList []string
|
||||
dnsSearchList []string
|
||||
}
|
||||
|
||||
type containerConfig struct {
|
||||
hostsPathConfig
|
||||
resolvConfPathConfig
|
||||
generic map[string]interface{}
|
||||
useDefaultSandBox bool
|
||||
prio int // higher the value, more the priority
|
||||
}
|
||||
|
||||
type extraHost struct {
|
||||
name string
|
||||
IP string
|
||||
}
|
||||
|
||||
type parentUpdate struct {
|
||||
eid string
|
||||
name string
|
||||
ip string
|
||||
}
|
||||
|
||||
type containerInfo struct {
|
||||
id string
|
||||
config containerConfig
|
||||
data ContainerData
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
func (ci *containerInfo) ID() string {
|
||||
return ci.id
|
||||
}
|
||||
|
||||
func (ci *containerInfo) Labels() map[string]interface{} {
|
||||
return ci.config.generic
|
||||
}
|
||||
|
||||
type endpoint struct {
|
||||
name string
|
||||
id types.UUID
|
||||
id string
|
||||
network *network
|
||||
iFaces []*endpointInterface
|
||||
joinInfo *endpointJoinInfo
|
||||
container *containerInfo
|
||||
sandboxID string
|
||||
exposedPorts []types.TransportPort
|
||||
generic map[string]interface{}
|
||||
joinLeaveDone chan struct{}
|
||||
|
@ -131,39 +60,17 @@ type endpoint struct {
|
|||
sync.Mutex
|
||||
}
|
||||
|
||||
func (ci *containerInfo) MarshalJSON() ([]byte, error) {
|
||||
ci.Lock()
|
||||
defer ci.Unlock()
|
||||
|
||||
// We are just interested in the container ID. This can be expanded to include all of containerInfo if there is a need
|
||||
return json.Marshal(ci.id)
|
||||
}
|
||||
|
||||
func (ci *containerInfo) UnmarshalJSON(b []byte) (err error) {
|
||||
ci.Lock()
|
||||
defer ci.Unlock()
|
||||
|
||||
var id string
|
||||
if err := json.Unmarshal(b, &id); err != nil {
|
||||
return err
|
||||
}
|
||||
ci.id = id
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ep *endpoint) MarshalJSON() ([]byte, error) {
|
||||
ep.Lock()
|
||||
defer ep.Unlock()
|
||||
|
||||
epMap := make(map[string]interface{})
|
||||
epMap["name"] = ep.name
|
||||
epMap["id"] = string(ep.id)
|
||||
epMap["id"] = ep.id
|
||||
epMap["ep_iface"] = ep.iFaces
|
||||
epMap["exposed_ports"] = ep.exposedPorts
|
||||
epMap["generic"] = ep.generic
|
||||
if ep.container != nil {
|
||||
epMap["container"] = ep.container
|
||||
}
|
||||
epMap["sandbox"] = ep.sandboxID
|
||||
return json.Marshal(epMap)
|
||||
}
|
||||
|
||||
|
@ -176,7 +83,7 @@ func (ep *endpoint) UnmarshalJSON(b []byte) (err error) {
|
|||
return err
|
||||
}
|
||||
ep.name = epMap["name"].(string)
|
||||
ep.id = types.UUID(epMap["id"].(string))
|
||||
ep.id = epMap["id"].(string)
|
||||
|
||||
ib, _ := json.Marshal(epMap["ep_iface"])
|
||||
var ifaces []endpointInterface
|
||||
|
@ -191,13 +98,8 @@ func (ep *endpoint) UnmarshalJSON(b []byte) (err error) {
|
|||
json.Unmarshal(tb, &tPorts)
|
||||
ep.exposedPorts = tPorts
|
||||
|
||||
epc, ok := epMap["container"]
|
||||
if ok {
|
||||
cb, _ := json.Marshal(epc)
|
||||
var cInfo containerInfo
|
||||
json.Unmarshal(cb, &cInfo)
|
||||
ep.container = &cInfo
|
||||
}
|
||||
cb, _ := json.Marshal(epMap["sandbox"])
|
||||
json.Unmarshal(cb, &ep.sandboxID)
|
||||
|
||||
if epMap["generic"] != nil {
|
||||
ep.generic = epMap["generic"].(map[string]interface{})
|
||||
|
@ -205,13 +107,11 @@ func (ep *endpoint) UnmarshalJSON(b []byte) (err error) {
|
|||
return nil
|
||||
}
|
||||
|
||||
const defaultPrefix = "/var/lib/docker/network/files"
|
||||
|
||||
func (ep *endpoint) ID() string {
|
||||
ep.Lock()
|
||||
defer ep.Unlock()
|
||||
|
||||
return string(ep.id)
|
||||
return ep.id
|
||||
}
|
||||
|
||||
func (ep *endpoint) Name() string {
|
||||
|
@ -222,36 +122,27 @@ func (ep *endpoint) Name() string {
|
|||
}
|
||||
|
||||
func (ep *endpoint) Network() string {
|
||||
ep.Lock()
|
||||
defer ep.Unlock()
|
||||
|
||||
return ep.network.name
|
||||
return ep.getNetwork().name
|
||||
}
|
||||
|
||||
// endpoint Key structure : endpoint/network-id/endpoint-id
|
||||
func (ep *endpoint) Key() []string {
|
||||
ep.Lock()
|
||||
n := ep.network
|
||||
defer ep.Unlock()
|
||||
return []string{datastore.EndpointKeyPrefix, string(n.id), string(ep.id)}
|
||||
return []string{datastore.EndpointKeyPrefix, ep.getNetwork().id, ep.id}
|
||||
}
|
||||
|
||||
func (ep *endpoint) KeyPrefix() []string {
|
||||
ep.Lock()
|
||||
n := ep.network
|
||||
defer ep.Unlock()
|
||||
return []string{datastore.EndpointKeyPrefix, string(n.id)}
|
||||
return []string{datastore.EndpointKeyPrefix, ep.getNetwork().id}
|
||||
}
|
||||
|
||||
func (ep *endpoint) networkIDFromKey(key []string) (types.UUID, error) {
|
||||
func (ep *endpoint) networkIDFromKey(key []string) (string, error) {
|
||||
// endpoint Key structure : endpoint/network-id/endpoint-id
|
||||
// it's an invalid key if the key doesn't have all the 3 key elements above
|
||||
if key == nil || len(key) < 3 || key[0] != datastore.EndpointKeyPrefix {
|
||||
return types.UUID(""), fmt.Errorf("invalid endpoint key : %v", key)
|
||||
return "", fmt.Errorf("invalid endpoint key : %v", key)
|
||||
}
|
||||
|
||||
// network-id is placed at index=1. pls refer to endpoint.Key() method
|
||||
return types.UUID(key[1]), nil
|
||||
return key[1], nil
|
||||
}
|
||||
|
||||
func (ep *endpoint) Value() []byte {
|
||||
|
@ -296,27 +187,6 @@ func (ep *endpoint) processOptions(options ...EndpointOption) {
|
|||
}
|
||||
}
|
||||
|
||||
func createBasePath(dir string) error {
|
||||
return os.MkdirAll(dir, 0644)
|
||||
}
|
||||
|
||||
func createFile(path string) error {
|
||||
var f *os.File
|
||||
|
||||
dir, _ := filepath.Split(path)
|
||||
err := createBasePath(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f, err = os.Create(path)
|
||||
if err == nil {
|
||||
f.Close()
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// joinLeaveStart waits to ensure there are no joins or leaves in progress and
|
||||
// marks this join/leave in progress without race
|
||||
func (ep *endpoint) joinLeaveStart() {
|
||||
|
@ -349,44 +219,36 @@ func (ep *endpoint) joinLeaveEnd() {
|
|||
}
|
||||
}
|
||||
|
||||
func (ep *endpoint) Join(containerID string, options ...EndpointOption) error {
|
||||
func (ep *endpoint) Join(sbox Sandbox, options ...EndpointOption) error {
|
||||
var err error
|
||||
|
||||
if containerID == "" {
|
||||
return InvalidContainerIDError(containerID)
|
||||
if sbox == nil {
|
||||
return types.BadRequestErrorf("endpoint cannot be joined by nil container")
|
||||
}
|
||||
|
||||
sb, ok := sbox.(*sandbox)
|
||||
if !ok {
|
||||
return types.BadRequestErrorf("not a valid Sandbox interface")
|
||||
}
|
||||
|
||||
ep.joinLeaveStart()
|
||||
defer func() {
|
||||
ep.joinLeaveEnd()
|
||||
}()
|
||||
defer ep.joinLeaveEnd()
|
||||
|
||||
ep.Lock()
|
||||
if ep.container != nil {
|
||||
if ep.sandboxID != "" {
|
||||
ep.Unlock()
|
||||
return ErrInvalidJoin{}
|
||||
return types.ForbiddenErrorf("a sandbox has already joined the endpoint")
|
||||
}
|
||||
|
||||
ep.container = &containerInfo{
|
||||
id: containerID,
|
||||
config: containerConfig{
|
||||
hostsPathConfig: hostsPathConfig{
|
||||
extraHosts: []extraHost{},
|
||||
parentUpdates: []parentUpdate{},
|
||||
},
|
||||
}}
|
||||
|
||||
ep.sandboxID = sbox.ID()
|
||||
ep.joinInfo = &endpointJoinInfo{}
|
||||
|
||||
container := ep.container
|
||||
network := ep.network
|
||||
epid := ep.id
|
||||
|
||||
ep.Unlock()
|
||||
defer func() {
|
||||
if err != nil {
|
||||
ep.Lock()
|
||||
ep.container = nil
|
||||
ep.sandboxID = ""
|
||||
ep.Unlock()
|
||||
}
|
||||
}()
|
||||
|
@ -394,17 +256,11 @@ func (ep *endpoint) Join(containerID string, options ...EndpointOption) error {
|
|||
network.Lock()
|
||||
driver := network.driver
|
||||
nid := network.id
|
||||
ctrlr := network.ctrlr
|
||||
network.Unlock()
|
||||
|
||||
ep.processOptions(options...)
|
||||
|
||||
sboxKey := sandbox.GenerateKey(containerID)
|
||||
if container.config.useDefaultSandBox {
|
||||
sboxKey = sandbox.GenerateKey("default")
|
||||
}
|
||||
|
||||
err = driver.Join(nid, epid, sboxKey, ep, container.config.generic)
|
||||
err = driver.Join(nid, epid, sbox.Key(), ep, sbox.Labels())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -417,36 +273,26 @@ func (ep *endpoint) Join(containerID string, options ...EndpointOption) error {
|
|||
}
|
||||
}()
|
||||
|
||||
err = ep.buildHostsFiles()
|
||||
if err != nil {
|
||||
address := ""
|
||||
if ip := ep.getFirstInterfaceAddress(); ip != nil {
|
||||
address = ip.String()
|
||||
}
|
||||
if err = sb.updateHostsFile(address, network.getSvcRecords()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = ep.updateParentHosts()
|
||||
if err != nil {
|
||||
if err = sb.updateDNS(ep.getNetwork().enableIPv6); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = ep.setupDNS()
|
||||
if err != nil {
|
||||
if err = network.ctrlr.updateEndpointToStore(ep); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sb, err := ctrlr.sandboxAdd(sboxKey, !container.config.useDefaultSandBox, ep)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed sandbox add: %v", err)
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
ctrlr.sandboxRm(sboxKey, ep)
|
||||
}
|
||||
}()
|
||||
|
||||
if err := network.ctrlr.updateEndpointToStore(ep); err != nil {
|
||||
if err = sb.populateNetworkResources(ep); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
container.data.SandboxKey = sb.Key()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -463,49 +309,54 @@ func (ep *endpoint) hasInterface(iName string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (ep *endpoint) Leave(containerID string, options ...EndpointOption) error {
|
||||
var err error
|
||||
|
||||
func (ep *endpoint) Leave(sbox Sandbox, options ...EndpointOption) error {
|
||||
ep.joinLeaveStart()
|
||||
defer ep.joinLeaveEnd()
|
||||
|
||||
if sbox == nil || sbox.ID() == "" || sbox.Key() == "" {
|
||||
return types.BadRequestErrorf("invalid Sandbox passed to enpoint leave: %v", sbox)
|
||||
}
|
||||
|
||||
sb, ok := sbox.(*sandbox)
|
||||
if !ok {
|
||||
return types.BadRequestErrorf("not a valid Sandbox interface")
|
||||
}
|
||||
|
||||
ep.Lock()
|
||||
sid := ep.sandboxID
|
||||
ep.Unlock()
|
||||
|
||||
if sid == "" {
|
||||
return types.ForbiddenErrorf("cannot leave endpoint with no attached sandbox")
|
||||
}
|
||||
if sid != sbox.ID() {
|
||||
return types.ForbiddenErrorf("unexpected sandbox ID in leave request. Expected %s. Got %s", ep.sandboxID, sbox.ID())
|
||||
}
|
||||
|
||||
ep.processOptions(options...)
|
||||
|
||||
ep.Lock()
|
||||
container := ep.container
|
||||
ep.sandboxID = ""
|
||||
n := ep.network
|
||||
|
||||
if container == nil || container.id == "" || container.data.SandboxKey == "" ||
|
||||
containerID == "" || container.id != containerID {
|
||||
if container == nil {
|
||||
err = ErrNoContainer{}
|
||||
} else {
|
||||
err = InvalidContainerIDError(containerID)
|
||||
}
|
||||
|
||||
ep.Unlock()
|
||||
return err
|
||||
}
|
||||
ep.container = nil
|
||||
ep.Unlock()
|
||||
|
||||
n.Lock()
|
||||
driver := n.driver
|
||||
ctrlr := n.ctrlr
|
||||
c := n.ctrlr
|
||||
d := n.driver
|
||||
n.Unlock()
|
||||
|
||||
if err := ctrlr.updateEndpointToStore(ep); err != nil {
|
||||
if err := c.updateEndpointToStore(ep); err != nil {
|
||||
ep.Lock()
|
||||
ep.container = container
|
||||
ep.sandboxID = sid
|
||||
ep.Unlock()
|
||||
return err
|
||||
}
|
||||
|
||||
err = driver.Leave(n.id, ep.id)
|
||||
if err := d.Leave(n.id, ep.id); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctrlr.sandboxRm(container.data.SandboxKey, ep)
|
||||
|
||||
return err
|
||||
return sb.clearNetworkResources(ep)
|
||||
}
|
||||
|
||||
func (ep *endpoint) Delete() error {
|
||||
|
@ -514,9 +365,9 @@ func (ep *endpoint) Delete() error {
|
|||
epid := ep.id
|
||||
name := ep.name
|
||||
n := ep.network
|
||||
if ep.container != nil {
|
||||
if ep.sandboxID != "" {
|
||||
ep.Unlock()
|
||||
return &ActiveContainerError{name: name, id: string(epid)}
|
||||
return &ActiveContainerError{name: name, id: epid}
|
||||
}
|
||||
n.Lock()
|
||||
ctrlr := n.ctrlr
|
||||
|
@ -556,33 +407,6 @@ func (ep *endpoint) Delete() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (ep *endpoint) Statistics() (map[string]*sandbox.InterfaceStatistics, error) {
|
||||
m := make(map[string]*sandbox.InterfaceStatistics)
|
||||
|
||||
ep.Lock()
|
||||
n := ep.network
|
||||
skey := ep.container.data.SandboxKey
|
||||
ep.Unlock()
|
||||
|
||||
n.Lock()
|
||||
c := n.ctrlr
|
||||
n.Unlock()
|
||||
|
||||
sbox := c.sandboxGet(skey)
|
||||
if sbox == nil {
|
||||
return m, nil
|
||||
}
|
||||
|
||||
var err error
|
||||
for _, i := range sbox.Info().Interfaces() {
|
||||
if m[i.DstName()], err = i.Statistics(); err != nil {
|
||||
return m, err
|
||||
}
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (ep *endpoint) deleteEndpoint() error {
|
||||
ep.Lock()
|
||||
n := ep.network
|
||||
|
@ -616,260 +440,36 @@ func (ep *endpoint) deleteEndpoint() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (ep *endpoint) addHostEntries(recs []etchosts.Record) {
|
||||
func (ep *endpoint) getNetwork() *network {
|
||||
ep.Lock()
|
||||
container := ep.container
|
||||
ep.Unlock()
|
||||
|
||||
if container == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := etchosts.Add(container.config.hostsPath, recs); err != nil {
|
||||
log.Warnf("Failed adding service host entries to the running container: %v", err)
|
||||
}
|
||||
defer ep.Unlock()
|
||||
return ep.network
|
||||
}
|
||||
|
||||
func (ep *endpoint) deleteHostEntries(recs []etchosts.Record) {
|
||||
func (ep *endpoint) getSandbox() (*sandbox, bool) {
|
||||
ep.Lock()
|
||||
container := ep.container
|
||||
c := ep.network.getController()
|
||||
sid := ep.sandboxID
|
||||
ep.Unlock()
|
||||
|
||||
if container == nil {
|
||||
return
|
||||
}
|
||||
c.Lock()
|
||||
ps, ok := c.sandboxes[sid]
|
||||
c.Unlock()
|
||||
|
||||
if err := etchosts.Delete(container.config.hostsPath, recs); err != nil {
|
||||
log.Warnf("Failed deleting service host entries to the running container: %v", err)
|
||||
}
|
||||
return ps, ok
|
||||
}
|
||||
|
||||
func (ep *endpoint) buildHostsFiles() error {
|
||||
var extraContent []etchosts.Record
|
||||
|
||||
func (ep *endpoint) getFirstInterfaceAddress() net.IP {
|
||||
ep.Lock()
|
||||
container := ep.container
|
||||
joinInfo := ep.joinInfo
|
||||
ifaces := ep.iFaces
|
||||
n := ep.network
|
||||
ep.Unlock()
|
||||
defer ep.Unlock()
|
||||
|
||||
if container == nil {
|
||||
return ErrNoContainer{}
|
||||
}
|
||||
|
||||
if container.config.hostsPath == "" {
|
||||
container.config.hostsPath = defaultPrefix + "/" + container.id + "/hosts"
|
||||
}
|
||||
|
||||
dir, _ := filepath.Split(container.config.hostsPath)
|
||||
err := createBasePath(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if joinInfo != nil && joinInfo.hostsPath != "" {
|
||||
content, err := ioutil.ReadFile(joinInfo.hostsPath)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
return ioutil.WriteFile(container.config.hostsPath, content, 0644)
|
||||
}
|
||||
}
|
||||
|
||||
for _, extraHost := range container.config.extraHosts {
|
||||
extraContent = append(extraContent,
|
||||
etchosts.Record{Hosts: extraHost.name, IP: extraHost.IP})
|
||||
}
|
||||
|
||||
extraContent = append(extraContent, n.getSvcRecords()...)
|
||||
|
||||
IP := ""
|
||||
if len(ifaces) != 0 && ifaces[0] != nil {
|
||||
IP = ifaces[0].addr.IP.String()
|
||||
}
|
||||
|
||||
return etchosts.Build(container.config.hostsPath, IP, container.config.hostName,
|
||||
container.config.domainName, extraContent)
|
||||
}
|
||||
|
||||
func (ep *endpoint) updateParentHosts() error {
|
||||
ep.Lock()
|
||||
container := ep.container
|
||||
network := ep.network
|
||||
ep.Unlock()
|
||||
|
||||
if container == nil {
|
||||
return ErrNoContainer{}
|
||||
}
|
||||
|
||||
for _, update := range container.config.parentUpdates {
|
||||
network.Lock()
|
||||
pep, ok := network.endpoints[types.UUID(update.eid)]
|
||||
if !ok {
|
||||
network.Unlock()
|
||||
continue
|
||||
}
|
||||
network.Unlock()
|
||||
|
||||
pep.Lock()
|
||||
pContainer := pep.container
|
||||
pep.Unlock()
|
||||
|
||||
if pContainer != nil {
|
||||
if err := etchosts.Update(pContainer.config.hostsPath, update.ip, update.name); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(ep.iFaces) != 0 && ep.iFaces[0] != nil {
|
||||
return ep.iFaces[0].addr.IP
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ep *endpoint) updateDNS(resolvConf []byte) error {
|
||||
ep.Lock()
|
||||
container := ep.container
|
||||
network := ep.network
|
||||
ep.Unlock()
|
||||
|
||||
if container == nil {
|
||||
return ErrNoContainer{}
|
||||
}
|
||||
|
||||
oldHash := []byte{}
|
||||
hashFile := container.config.resolvConfPath + ".hash"
|
||||
|
||||
resolvBytes, err := ioutil.ReadFile(container.config.resolvConfPath)
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
oldHash, err = ioutil.ReadFile(hashFile)
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
oldHash = []byte{}
|
||||
}
|
||||
}
|
||||
|
||||
curHash, err := ioutils.HashData(bytes.NewReader(resolvBytes))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if string(oldHash) != "" && curHash != string(oldHash) {
|
||||
// Seems the user has changed the container resolv.conf since the last time
|
||||
// we checked so return without doing anything.
|
||||
return nil
|
||||
}
|
||||
|
||||
// replace any localhost/127.* and remove IPv6 nameservers if IPv6 disabled.
|
||||
resolvConf, _ = resolvconf.FilterResolvDNS(resolvConf, network.enableIPv6)
|
||||
|
||||
newHash, err := ioutils.HashData(bytes.NewReader(resolvConf))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// for atomic updates to these files, use temporary files with os.Rename:
|
||||
dir := path.Dir(container.config.resolvConfPath)
|
||||
tmpHashFile, err := ioutil.TempFile(dir, "hash")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tmpResolvFile, err := ioutil.TempFile(dir, "resolv")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Change the perms to 0644 since ioutil.TempFile creates it by default as 0600
|
||||
if err := os.Chmod(tmpResolvFile.Name(), 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// write the updates to the temp files
|
||||
if err = ioutil.WriteFile(tmpHashFile.Name(), []byte(newHash), 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = ioutil.WriteFile(tmpResolvFile.Name(), resolvConf, 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// rename the temp files for atomic replace
|
||||
if err = os.Rename(tmpHashFile.Name(), hashFile); err != nil {
|
||||
return err
|
||||
}
|
||||
return os.Rename(tmpResolvFile.Name(), container.config.resolvConfPath)
|
||||
}
|
||||
|
||||
func copyFile(src, dst string) error {
|
||||
sBytes, err := ioutil.ReadFile(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return ioutil.WriteFile(dst, sBytes, 0644)
|
||||
}
|
||||
|
||||
func (ep *endpoint) setupDNS() error {
|
||||
ep.Lock()
|
||||
container := ep.container
|
||||
joinInfo := ep.joinInfo
|
||||
ep.Unlock()
|
||||
|
||||
if container == nil {
|
||||
return ErrNoContainer{}
|
||||
}
|
||||
|
||||
if container.config.resolvConfPath == "" {
|
||||
container.config.resolvConfPath = defaultPrefix + "/" + container.id + "/resolv.conf"
|
||||
}
|
||||
|
||||
dir, _ := filepath.Split(container.config.resolvConfPath)
|
||||
err := createBasePath(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if joinInfo.resolvConfPath != "" {
|
||||
if err := copyFile(joinInfo.resolvConfPath, container.config.resolvConfPath); err != nil {
|
||||
return fmt.Errorf("could not copy source resolv.conf file %s to %s: %v", joinInfo.resolvConfPath, container.config.resolvConfPath, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
resolvConf, err := resolvconf.Get()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(container.config.dnsList) > 0 ||
|
||||
len(container.config.dnsSearchList) > 0 {
|
||||
var (
|
||||
dnsList = resolvconf.GetNameservers(resolvConf)
|
||||
dnsSearchList = resolvconf.GetSearchDomains(resolvConf)
|
||||
)
|
||||
|
||||
if len(container.config.dnsList) > 0 {
|
||||
dnsList = container.config.dnsList
|
||||
}
|
||||
|
||||
if len(container.config.dnsSearchList) > 0 {
|
||||
dnsSearchList = container.config.dnsSearchList
|
||||
}
|
||||
|
||||
return resolvconf.Build(container.config.resolvConfPath, dnsList, dnsSearchList)
|
||||
}
|
||||
|
||||
return ep.updateDNS(resolvConf)
|
||||
}
|
||||
|
||||
// EndpointOptionGeneric function returns an option setter for a Generic option defined
|
||||
// in a Dictionary of Key-Value pair
|
||||
func EndpointOptionGeneric(generic map[string]interface{}) EndpointOption {
|
||||
|
@ -880,86 +480,6 @@ func EndpointOptionGeneric(generic map[string]interface{}) EndpointOption {
|
|||
}
|
||||
}
|
||||
|
||||
// JoinOptionPriority function returns an option setter for priority option to
|
||||
// be passed to endpoint Join method.
|
||||
func JoinOptionPriority(prio int) EndpointOption {
|
||||
return func(ep *endpoint) {
|
||||
ep.container.config.prio = prio
|
||||
}
|
||||
}
|
||||
|
||||
// JoinOptionHostname function returns an option setter for hostname option to
|
||||
// be passed to endpoint Join method.
|
||||
func JoinOptionHostname(name string) EndpointOption {
|
||||
return func(ep *endpoint) {
|
||||
ep.container.config.hostName = name
|
||||
}
|
||||
}
|
||||
|
||||
// JoinOptionDomainname function returns an option setter for domainname option to
|
||||
// be passed to endpoint Join method.
|
||||
func JoinOptionDomainname(name string) EndpointOption {
|
||||
return func(ep *endpoint) {
|
||||
ep.container.config.domainName = name
|
||||
}
|
||||
}
|
||||
|
||||
// JoinOptionHostsPath function returns an option setter for hostspath option to
|
||||
// be passed to endpoint Join method.
|
||||
func JoinOptionHostsPath(path string) EndpointOption {
|
||||
return func(ep *endpoint) {
|
||||
ep.container.config.hostsPath = path
|
||||
}
|
||||
}
|
||||
|
||||
// JoinOptionExtraHost function returns an option setter for extra /etc/hosts options
|
||||
// which is a name and IP as strings.
|
||||
func JoinOptionExtraHost(name string, IP string) EndpointOption {
|
||||
return func(ep *endpoint) {
|
||||
ep.container.config.extraHosts = append(ep.container.config.extraHosts, extraHost{name: name, IP: IP})
|
||||
}
|
||||
}
|
||||
|
||||
// JoinOptionParentUpdate function returns an option setter for parent container
|
||||
// which needs to update the IP address for the linked container.
|
||||
func JoinOptionParentUpdate(eid string, name, ip string) EndpointOption {
|
||||
return func(ep *endpoint) {
|
||||
ep.container.config.parentUpdates = append(ep.container.config.parentUpdates, parentUpdate{eid: eid, name: name, ip: ip})
|
||||
}
|
||||
}
|
||||
|
||||
// JoinOptionResolvConfPath function returns an option setter for resolvconfpath option to
|
||||
// be passed to endpoint Join method.
|
||||
func JoinOptionResolvConfPath(path string) EndpointOption {
|
||||
return func(ep *endpoint) {
|
||||
ep.container.config.resolvConfPath = path
|
||||
}
|
||||
}
|
||||
|
||||
// JoinOptionDNS function returns an option setter for dns entry option to
|
||||
// be passed to endpoint Join method.
|
||||
func JoinOptionDNS(dns string) EndpointOption {
|
||||
return func(ep *endpoint) {
|
||||
ep.container.config.dnsList = append(ep.container.config.dnsList, dns)
|
||||
}
|
||||
}
|
||||
|
||||
// JoinOptionDNSSearch function returns an option setter for dns search entry option to
|
||||
// be passed to endpoint Join method.
|
||||
func JoinOptionDNSSearch(search string) EndpointOption {
|
||||
return func(ep *endpoint) {
|
||||
ep.container.config.dnsSearchList = append(ep.container.config.dnsSearchList, search)
|
||||
}
|
||||
}
|
||||
|
||||
// JoinOptionUseDefaultSandbox function returns an option setter for using default sandbox to
|
||||
// be passed to endpoint Join method.
|
||||
func JoinOptionUseDefaultSandbox() EndpointOption {
|
||||
return func(ep *endpoint) {
|
||||
ep.container.config.useDefaultSandBox = true
|
||||
}
|
||||
}
|
||||
|
||||
// CreateOptionExposedPorts function returns an option setter for the container exposed
|
||||
// ports option to be passed to network.CreateEndpoint() method.
|
||||
func CreateOptionExposedPorts(exposedPorts []types.TransportPort) EndpointOption {
|
||||
|
@ -984,11 +504,19 @@ func CreateOptionPortMapping(portBindings []types.PortBinding) EndpointOption {
|
|||
}
|
||||
}
|
||||
|
||||
// JoinOptionGeneric function returns an option setter for Generic configuration
|
||||
// that is not managed by libNetwork but can be used by the Drivers during the call to
|
||||
// endpoint join method. Container Labels are a good example.
|
||||
func JoinOptionGeneric(generic map[string]interface{}) EndpointOption {
|
||||
// JoinOptionPriority function returns an option setter for priority option to
|
||||
// be passed to the endpoint.Join() method.
|
||||
func JoinOptionPriority(ep Endpoint, prio int) EndpointOption {
|
||||
return func(ep *endpoint) {
|
||||
ep.container.config.generic = generic
|
||||
// ep lock already acquired
|
||||
c := ep.network.getController()
|
||||
c.Lock()
|
||||
sb, ok := c.sandboxes[ep.sandboxID]
|
||||
c.Unlock()
|
||||
if !ok {
|
||||
log.Errorf("Could not set endpoint priority value during Join to endpoint %s: No sandbox id present in endpoint", ep.id)
|
||||
return
|
||||
}
|
||||
sb.epPriority[ep.id] = prio
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,10 +22,8 @@ type EndpointInfo interface {
|
|||
// This will only return a valid value if a container has joined the endpoint.
|
||||
GatewayIPv6() net.IP
|
||||
|
||||
// SandboxKey returns the sanbox key for the container which has joined
|
||||
// the endpoint. If there is no container joined then this will return an
|
||||
// empty string.
|
||||
SandboxKey() string
|
||||
// Sandbox returns the attached sandbox if there, nil otherwise.
|
||||
Sandbox() Sandbox
|
||||
}
|
||||
|
||||
// InterfaceInfo provides an interface to retrieve interface addresses bound to the endpoint.
|
||||
|
@ -40,14 +38,6 @@ type InterfaceInfo interface {
|
|||
AddressIPv6() net.IPNet
|
||||
}
|
||||
|
||||
// ContainerInfo provides an interface to retrieve the info about the container attached to the endpoint
|
||||
type ContainerInfo interface {
|
||||
// ID returns the ID of the container
|
||||
ID() string
|
||||
// Labels returns the container's labels
|
||||
Labels() map[string]interface{}
|
||||
}
|
||||
|
||||
type endpointInterface struct {
|
||||
id int
|
||||
mac net.HardwareAddr
|
||||
|
@ -115,23 +105,9 @@ func (epi *endpointInterface) UnmarshalJSON(b []byte) (err error) {
|
|||
}
|
||||
|
||||
type endpointJoinInfo struct {
|
||||
gw net.IP
|
||||
gw6 net.IP
|
||||
hostsPath string
|
||||
resolvConfPath string
|
||||
StaticRoutes []*types.StaticRoute
|
||||
}
|
||||
|
||||
func (ep *endpoint) ContainerInfo() ContainerInfo {
|
||||
ep.Lock()
|
||||
ci := ep.container
|
||||
defer ep.Unlock()
|
||||
|
||||
// Need this since we return the interface
|
||||
if ci == nil {
|
||||
return nil
|
||||
}
|
||||
return ci
|
||||
gw net.IP
|
||||
gw6 net.IP
|
||||
StaticRoutes []*types.StaticRoute
|
||||
}
|
||||
|
||||
func (ep *endpoint) Info() EndpointInfo {
|
||||
|
@ -257,15 +233,12 @@ func (ep *endpoint) addInterfaceRoute(route *types.StaticRoute) error {
|
|||
route.InterfaceID)
|
||||
}
|
||||
|
||||
func (ep *endpoint) SandboxKey() string {
|
||||
ep.Lock()
|
||||
defer ep.Unlock()
|
||||
|
||||
if ep.container == nil {
|
||||
return ""
|
||||
func (ep *endpoint) Sandbox() Sandbox {
|
||||
cnt, ok := ep.getSandbox()
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
return ep.container.data.SandboxKey
|
||||
return cnt
|
||||
}
|
||||
|
||||
func (ep *endpoint) Gateway() net.IP {
|
||||
|
@ -305,19 +278,3 @@ func (ep *endpoint) SetGatewayIPv6(gw6 net.IP) error {
|
|||
ep.joinInfo.gw6 = types.GetIPCopy(gw6)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ep *endpoint) SetHostsPath(path string) error {
|
||||
ep.Lock()
|
||||
defer ep.Unlock()
|
||||
|
||||
ep.joinInfo.hostsPath = path
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ep *endpoint) SetResolvConfPath(path string) error {
|
||||
ep.Lock()
|
||||
defer ep.Unlock()
|
||||
|
||||
ep.joinInfo.resolvConfPath = path
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import (
|
|||
"github.com/docker/libnetwork/netlabel"
|
||||
"github.com/docker/libnetwork/netutils"
|
||||
"github.com/docker/libnetwork/options"
|
||||
"github.com/docker/libnetwork/osl"
|
||||
"github.com/docker/libnetwork/types"
|
||||
"github.com/vishvananda/netlink"
|
||||
"github.com/vishvananda/netns"
|
||||
|
@ -98,6 +99,14 @@ func getPortMapping() []types.PortBinding {
|
|||
}
|
||||
|
||||
func TestNull(t *testing.T) {
|
||||
cnt, err := controller.NewSandbox("null_container",
|
||||
libnetwork.OptionHostname("test"),
|
||||
libnetwork.OptionDomainname("docker.io"),
|
||||
libnetwork.OptionExtraHost("web", "192.168.0.1"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
network, err := createTestNetwork("null", "testnull", options.Generic{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -108,15 +117,12 @@ func TestNull(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = ep.Join("null_container",
|
||||
libnetwork.JoinOptionHostname("test"),
|
||||
libnetwork.JoinOptionDomainname("docker.io"),
|
||||
libnetwork.JoinOptionExtraHost("web", "192.168.0.1"))
|
||||
err = ep.Join(cnt)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = ep.Leave("null_container")
|
||||
err = ep.Leave(cnt)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -125,6 +131,10 @@ func TestNull(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := cnt.Delete(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// host type is special network. Cannot be removed.
|
||||
err = network.Delete()
|
||||
if err == nil {
|
||||
|
@ -136,6 +146,34 @@ func TestNull(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestHost(t *testing.T) {
|
||||
sbx1, err := controller.NewSandbox("host_c1",
|
||||
libnetwork.OptionHostname("test1"),
|
||||
libnetwork.OptionDomainname("docker.io"),
|
||||
libnetwork.OptionExtraHost("web", "192.168.0.1"),
|
||||
libnetwork.OptionUseDefaultSandbox())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := sbx1.Delete(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
sbx2, err := controller.NewSandbox("host_c2",
|
||||
libnetwork.OptionHostname("test2"),
|
||||
libnetwork.OptionDomainname("docker.io"),
|
||||
libnetwork.OptionExtraHost("web", "192.168.0.1"),
|
||||
libnetwork.OptionUseDefaultSandbox())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := sbx2.Delete(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
network, err := createTestNetwork("host", "testhost", options.Generic{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -146,12 +184,7 @@ func TestHost(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = ep1.Join("host_container1",
|
||||
libnetwork.JoinOptionHostname("test1"),
|
||||
libnetwork.JoinOptionDomainname("docker.io"),
|
||||
libnetwork.JoinOptionExtraHost("web", "192.168.0.1"),
|
||||
libnetwork.JoinOptionUseDefaultSandbox())
|
||||
if err != nil {
|
||||
if err := ep1.Join(sbx1); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -160,22 +193,15 @@ func TestHost(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = ep2.Join("host_container2",
|
||||
libnetwork.JoinOptionHostname("test2"),
|
||||
libnetwork.JoinOptionDomainname("docker.io"),
|
||||
libnetwork.JoinOptionExtraHost("web", "192.168.0.1"),
|
||||
libnetwork.JoinOptionUseDefaultSandbox())
|
||||
if err != nil {
|
||||
if err := ep2.Join(sbx2); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = ep1.Leave("host_container1")
|
||||
if err != nil {
|
||||
if err := ep1.Leave(sbx1); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = ep2.Leave("host_container2")
|
||||
if err != nil {
|
||||
if err := ep2.Leave(sbx2); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -188,22 +214,30 @@ func TestHost(t *testing.T) {
|
|||
}
|
||||
|
||||
// Try to create another host endpoint and join/leave that.
|
||||
cnt3, err := controller.NewSandbox("host_c3",
|
||||
libnetwork.OptionHostname("test3"),
|
||||
libnetwork.OptionDomainname("docker.io"),
|
||||
libnetwork.OptionExtraHost("web", "192.168.0.1"),
|
||||
libnetwork.OptionUseDefaultSandbox())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := cnt3.Delete(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
ep3, err := network.CreateEndpoint("testep3")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = ep3.Join("host_container3",
|
||||
libnetwork.JoinOptionHostname("test3"),
|
||||
libnetwork.JoinOptionDomainname("docker.io"),
|
||||
libnetwork.JoinOptionExtraHost("web", "192.168.0.1"),
|
||||
libnetwork.JoinOptionUseDefaultSandbox())
|
||||
if err != nil {
|
||||
if err := ep3.Join(sbx2); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = ep3.Leave("host_container3")
|
||||
if err != nil {
|
||||
if err := ep3.Leave(sbx2); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -926,7 +960,7 @@ func TestNetworkQuery(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
const containerID = "valid_container"
|
||||
const containerID = "valid_c"
|
||||
|
||||
func checkSandbox(t *testing.T, info libnetwork.EndpointInfo) {
|
||||
origns, err := netns.Get()
|
||||
|
@ -935,7 +969,7 @@ func checkSandbox(t *testing.T, info libnetwork.EndpointInfo) {
|
|||
}
|
||||
defer origns.Close()
|
||||
|
||||
key := info.SandboxKey()
|
||||
key := info.Sandbox().Key()
|
||||
f, err := os.OpenFile(key, os.O_RDONLY, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to open network namespace path %q: %v", key, err)
|
||||
|
@ -995,7 +1029,6 @@ func TestEndpointJoin(t *testing.T) {
|
|||
|
||||
// Validate if ep.Info() only gives me IP address info and not names and gateway during CreateEndpoint()
|
||||
info := ep1.Info()
|
||||
|
||||
for _, iface := range info.InterfaceList() {
|
||||
if iface.Address().IP.To4() == nil {
|
||||
t.Fatalf("Invalid IP address returned: %v", iface.Address())
|
||||
|
@ -1006,22 +1039,48 @@ func TestEndpointJoin(t *testing.T) {
|
|||
t.Fatalf("Expected empty gateway for an empty endpoint. Instead found a gateway: %v", info.Gateway())
|
||||
}
|
||||
|
||||
if info.SandboxKey() != "" {
|
||||
t.Fatalf("Expected an empty sandbox key for an empty endpoint. Instead found a non-empty sandbox key: %s", info.SandboxKey())
|
||||
if info.Sandbox() != nil {
|
||||
t.Fatalf("Expected an empty sandbox key for an empty endpoint. Instead found a non-empty sandbox key: %s", info.Sandbox().Key())
|
||||
}
|
||||
|
||||
defer controller.LeaveAll(containerID)
|
||||
// test invalid joins
|
||||
err = ep1.Join(nil)
|
||||
if err == nil {
|
||||
t.Fatalf("Expected to fail join with nil Sandbox")
|
||||
}
|
||||
if _, ok := err.(types.BadRequestError); !ok {
|
||||
t.Fatalf("Unexpected error type returned: %T", err)
|
||||
}
|
||||
|
||||
err = ep1.Join(containerID,
|
||||
libnetwork.JoinOptionHostname("test"),
|
||||
libnetwork.JoinOptionDomainname("docker.io"),
|
||||
libnetwork.JoinOptionExtraHost("web", "192.168.0.1"))
|
||||
fsbx := &fakeSandbox{}
|
||||
if err = ep1.Join(fsbx); err == nil {
|
||||
t.Fatalf("Expected to fail join with invalid Sandbox")
|
||||
}
|
||||
if _, ok := err.(types.BadRequestError); !ok {
|
||||
t.Fatalf("Unexpected error type returned: %T", err)
|
||||
}
|
||||
|
||||
sb, err := controller.NewSandbox(containerID,
|
||||
libnetwork.OptionHostname("test"),
|
||||
libnetwork.OptionDomainname("docker.io"),
|
||||
libnetwork.OptionExtraHost("web", "192.168.0.1"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := sb.Delete(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
err = ep1.Join(sb)
|
||||
runtime.LockOSThread()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
err = ep1.Leave(containerID)
|
||||
err = ep1.Leave(sb)
|
||||
runtime.LockOSThread()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -1034,17 +1093,17 @@ func TestEndpointJoin(t *testing.T) {
|
|||
t.Fatalf("Expected a valid gateway for a joined endpoint. Instead found an invalid gateway: %v", info.Gateway())
|
||||
}
|
||||
|
||||
if info.SandboxKey() == "" {
|
||||
if info.Sandbox() == nil {
|
||||
t.Fatalf("Expected an non-empty sandbox key for a joined endpoint. Instead found a empty sandbox key")
|
||||
}
|
||||
|
||||
// Check endpoint provided container information
|
||||
if ep1.ContainerInfo().ID() != containerID {
|
||||
t.Fatalf("Endpoint ContainerInfo returned unexpected id: %s", ep1.ContainerInfo().ID())
|
||||
if ep1.Info().Sandbox().Key() != sb.Key() {
|
||||
t.Fatalf("Endpoint Info returned unexpected sandbox key: %s", sb.Key())
|
||||
}
|
||||
|
||||
// Attempt retrieval of endpoint interfaces statistics
|
||||
stats, err := ep1.Statistics()
|
||||
stats, err := sb.Statistics()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -1079,65 +1138,50 @@ func TestEndpointJoin(t *testing.T) {
|
|||
}
|
||||
}()
|
||||
|
||||
err = ep2.Join(containerID)
|
||||
err = ep2.Join(sb)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runtime.LockOSThread()
|
||||
defer func() {
|
||||
err = ep2.Leave(containerID)
|
||||
err = ep2.Leave(sb)
|
||||
runtime.LockOSThread()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
if ep1.ContainerInfo().ID() != ep2.ContainerInfo().ID() {
|
||||
t.Fatalf("ep1 and ep2 returned different container info")
|
||||
if ep1.Info().Sandbox().Key() != ep2.Info().Sandbox().Key() {
|
||||
t.Fatalf("ep1 and ep2 returned different container sandbox key")
|
||||
}
|
||||
|
||||
checkSandbox(t, info)
|
||||
|
||||
}
|
||||
|
||||
func TestEndpointJoinInvalidContainerId(t *testing.T) {
|
||||
if !netutils.IsRunningInContainer() {
|
||||
defer netutils.SetupTestNetNS(t)()
|
||||
}
|
||||
type fakeSandbox struct{}
|
||||
|
||||
n, err := createTestNetwork(bridgeNetType, "testnetwork", options.Generic{
|
||||
netlabel.GenericData: options.Generic{
|
||||
"BridgeName": "testnetwork",
|
||||
"AllowNonDefaultBridge": true,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := n.Delete(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
func (f *fakeSandbox) ID() string {
|
||||
return "fake sandbox"
|
||||
}
|
||||
|
||||
ep, err := n.CreateEndpoint("ep1")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := ep.Delete(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
func (f *fakeSandbox) ContainerID() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
err = ep.Join("")
|
||||
if err == nil {
|
||||
t.Fatal("Expected to fail join with empty container id string")
|
||||
}
|
||||
func (f *fakeSandbox) Key() string {
|
||||
return "fake key"
|
||||
}
|
||||
|
||||
if _, ok := err.(libnetwork.InvalidContainerIDError); !ok {
|
||||
t.Fatalf("Failed for unexpected reason: %v", err)
|
||||
}
|
||||
func (f *fakeSandbox) Labels() map[string]interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakeSandbox) Statistics() (map[string]*osl.InterfaceStatistics, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (f *fakeSandbox) Delete() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestEndpointDeleteWithActiveContainer(t *testing.T) {
|
||||
|
@ -1171,18 +1215,23 @@ func TestEndpointDeleteWithActiveContainer(t *testing.T) {
|
|||
}
|
||||
}()
|
||||
|
||||
defer controller.LeaveAll(containerID)
|
||||
cnt, err := controller.NewSandbox(containerID,
|
||||
libnetwork.OptionHostname("test"),
|
||||
libnetwork.OptionDomainname("docker.io"),
|
||||
libnetwork.OptionExtraHost("web", "192.168.0.1"))
|
||||
defer func() {
|
||||
if err := cnt.Delete(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
err = ep.Join(containerID,
|
||||
libnetwork.JoinOptionHostname("test"),
|
||||
libnetwork.JoinOptionDomainname("docker.io"),
|
||||
libnetwork.JoinOptionExtraHost("web", "192.168.0.1"))
|
||||
err = ep.Join(cnt)
|
||||
runtime.LockOSThread()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
err = ep.Leave(containerID)
|
||||
err = ep.Leave(cnt)
|
||||
runtime.LockOSThread()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -1204,9 +1253,9 @@ func TestEndpointMultipleJoins(t *testing.T) {
|
|||
defer netutils.SetupTestNetNS(t)()
|
||||
}
|
||||
|
||||
n, err := createTestNetwork(bridgeNetType, "testnetwork", options.Generic{
|
||||
n, err := createTestNetwork(bridgeNetType, "testmultiple", options.Generic{
|
||||
netlabel.GenericData: options.Generic{
|
||||
"BridgeName": "testnetwork",
|
||||
"BridgeName": "testmultiple",
|
||||
"AllowNonDefaultBridge": true,
|
||||
},
|
||||
})
|
||||
|
@ -1229,32 +1278,46 @@ func TestEndpointMultipleJoins(t *testing.T) {
|
|||
}
|
||||
}()
|
||||
|
||||
defer controller.LeaveAll(containerID)
|
||||
sbx1, err := controller.NewSandbox(containerID,
|
||||
libnetwork.OptionHostname("test"),
|
||||
libnetwork.OptionDomainname("docker.io"),
|
||||
libnetwork.OptionExtraHost("web", "192.168.0.1"))
|
||||
defer func() {
|
||||
if err := sbx1.Delete(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
err = ep.Join(containerID,
|
||||
libnetwork.JoinOptionHostname("test"),
|
||||
libnetwork.JoinOptionDomainname("docker.io"),
|
||||
libnetwork.JoinOptionExtraHost("web", "192.168.0.1"))
|
||||
sbx2, err := controller.NewSandbox("c2")
|
||||
defer func() {
|
||||
if err := sbx2.Delete(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runtime.LockOSThread()
|
||||
}()
|
||||
|
||||
err = ep.Join(sbx1)
|
||||
runtime.LockOSThread()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
err = ep.Leave(containerID)
|
||||
err = ep.Leave(sbx1)
|
||||
runtime.LockOSThread()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
err = ep.Join("container2")
|
||||
err = ep.Join(sbx2)
|
||||
if err == nil {
|
||||
t.Fatal("Expected to fail multiple joins for the same endpoint")
|
||||
}
|
||||
|
||||
if _, ok := err.(libnetwork.ErrInvalidJoin); !ok {
|
||||
t.Fatalf("Failed for unexpected reason: %v", err)
|
||||
if _, ok := err.(types.ForbiddenError); !ok {
|
||||
t.Fatalf("Failed with unexpected error type: %T. Desc: %s", err, err.Error())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestLeaveAll(t *testing.T) {
|
||||
|
@ -1272,6 +1335,7 @@ func TestLeaveAll(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
// If this goes through, it means cnt.Delete() effectively detached from all the endpoints
|
||||
if err := n.Delete(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -1297,32 +1361,30 @@ func TestLeaveAll(t *testing.T) {
|
|||
}
|
||||
}()
|
||||
|
||||
err = ep1.Join("leaveall")
|
||||
cnt, err := controller.NewSandbox("leaveall")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = ep1.Join(cnt)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to join ep1: %v", err)
|
||||
}
|
||||
runtime.LockOSThread()
|
||||
|
||||
err = ep2.Join("leaveall")
|
||||
err = ep2.Join(cnt)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to join ep2: %v", err)
|
||||
}
|
||||
runtime.LockOSThread()
|
||||
|
||||
err = ep1.Leave("leaveall")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to leave ep1: %v", err)
|
||||
}
|
||||
runtime.LockOSThread()
|
||||
|
||||
err = controller.LeaveAll("leaveall")
|
||||
err = cnt.Delete()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runtime.LockOSThread()
|
||||
}
|
||||
|
||||
func TestEndpointInvalidLeave(t *testing.T) {
|
||||
func TestontainerInvalidLeave(t *testing.T) {
|
||||
if !netutils.IsRunningInContainer() {
|
||||
defer netutils.SetupTestNetNS(t)()
|
||||
}
|
||||
|
@ -1352,51 +1414,40 @@ func TestEndpointInvalidLeave(t *testing.T) {
|
|||
}
|
||||
}()
|
||||
|
||||
err = ep.Leave(containerID)
|
||||
if err == nil {
|
||||
t.Fatal("Expected to fail leave from an endpoint which has no active join")
|
||||
}
|
||||
|
||||
if _, ok := err.(libnetwork.InvalidContainerIDError); !ok {
|
||||
if _, ok := err.(libnetwork.ErrNoContainer); !ok {
|
||||
t.Fatalf("Failed for unexpected reason: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
defer controller.LeaveAll(containerID)
|
||||
|
||||
err = ep.Join(containerID,
|
||||
libnetwork.JoinOptionHostname("test"),
|
||||
libnetwork.JoinOptionDomainname("docker.io"),
|
||||
libnetwork.JoinOptionExtraHost("web", "192.168.0.1"))
|
||||
runtime.LockOSThread()
|
||||
cnt, err := controller.NewSandbox(containerID,
|
||||
libnetwork.OptionHostname("test"),
|
||||
libnetwork.OptionDomainname("docker.io"),
|
||||
libnetwork.OptionExtraHost("web", "192.168.0.1"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
err = ep.Leave(containerID)
|
||||
runtime.LockOSThread()
|
||||
if err != nil {
|
||||
if err := cnt.Delete(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
err = ep.Leave("")
|
||||
err = ep.Leave(cnt)
|
||||
if err == nil {
|
||||
t.Fatal("Expected to fail leave with empty container id")
|
||||
t.Fatal("Expected to fail leave from an endpoint which has no active join")
|
||||
}
|
||||
if _, ok := err.(types.ForbiddenError); !ok {
|
||||
t.Fatalf("Failed with unexpected error type: %T. Desc: %s", err, err.Error())
|
||||
}
|
||||
|
||||
if _, ok := err.(libnetwork.InvalidContainerIDError); !ok {
|
||||
t.Fatalf("Failed for unexpected reason: %v", err)
|
||||
if err := ep.Leave(nil); err == nil {
|
||||
t.Fatalf("Expected to fail leave nil Sandbox")
|
||||
}
|
||||
if _, ok := err.(types.BadRequestError); !ok {
|
||||
t.Fatalf("Unexpected error type returned: %T", err)
|
||||
}
|
||||
|
||||
err = ep.Leave("container2")
|
||||
if err == nil {
|
||||
t.Fatal("Expected to fail leave with wrong container id")
|
||||
fsbx := &fakeSandbox{}
|
||||
if err = ep.Leave(fsbx); err == nil {
|
||||
t.Fatalf("Expected to fail leave with invalid Sandbox")
|
||||
}
|
||||
|
||||
if _, ok := err.(libnetwork.InvalidContainerIDError); !ok {
|
||||
t.Fatalf("Failed for unexpected reason: %v", err)
|
||||
if _, ok := err.(types.BadRequestError); !ok {
|
||||
t.Fatalf("Unexpected error type returned: %T", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1430,23 +1481,6 @@ func TestEndpointUpdateParent(t *testing.T) {
|
|||
}
|
||||
}()
|
||||
|
||||
defer controller.LeaveAll(containerID)
|
||||
err = ep1.Join(containerID,
|
||||
libnetwork.JoinOptionHostname("test1"),
|
||||
libnetwork.JoinOptionDomainname("docker.io"),
|
||||
libnetwork.JoinOptionExtraHost("web", "192.168.0.1"))
|
||||
runtime.LockOSThread()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
err = ep1.Leave(containerID)
|
||||
runtime.LockOSThread()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
ep2, err := n.CreateEndpoint("ep2")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -1457,23 +1491,50 @@ func TestEndpointUpdateParent(t *testing.T) {
|
|||
}
|
||||
}()
|
||||
|
||||
defer controller.LeaveAll("container2")
|
||||
err = ep2.Join("container2",
|
||||
libnetwork.JoinOptionHostname("test2"),
|
||||
libnetwork.JoinOptionDomainname("docker.io"),
|
||||
libnetwork.JoinOptionHostsPath("/var/lib/docker/test_network/container2/hosts"),
|
||||
libnetwork.JoinOptionParentUpdate(ep1.ID(), "web", "192.168.0.2"))
|
||||
sbx1, err := controller.NewSandbox(containerID,
|
||||
libnetwork.OptionHostname("test"),
|
||||
libnetwork.OptionDomainname("docker.io"),
|
||||
libnetwork.OptionExtraHost("web", "192.168.0.1"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := sbx1.Delete(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
sbx2, err := controller.NewSandbox("c2",
|
||||
libnetwork.OptionHostname("test2"),
|
||||
libnetwork.OptionDomainname("docker.io"),
|
||||
libnetwork.OptionHostsPath("/var/lib/docker/test_network/container2/hosts"),
|
||||
libnetwork.OptionExtraHost("web", "192.168.0.2"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := sbx2.Delete(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
err = ep1.Join(sbx1)
|
||||
runtime.LockOSThread()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = ep2.Leave("container2")
|
||||
err = ep2.Join(sbx2)
|
||||
runtime.LockOSThread()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = ep2.Leave(sbx2)
|
||||
runtime.LockOSThread()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnableIPv6(t *testing.T) {
|
||||
|
@ -1481,7 +1542,7 @@ func TestEnableIPv6(t *testing.T) {
|
|||
defer netutils.SetupTestNetNS(t)()
|
||||
}
|
||||
|
||||
tmpResolvConf := []byte("search pommesfrites.fr\nnameserver 12.34.56.78\nnameserver 2001:4860:4860::8888")
|
||||
tmpResolvConf := []byte("search pommesfrites.fr\nnameserver 12.34.56.78\nnameserver 2001:4860:4860::8888\n")
|
||||
//take a copy of resolv.conf for restoring after test completes
|
||||
resolvConfSystem, err := ioutil.ReadFile("/etc/resolv.conf")
|
||||
if err != nil {
|
||||
|
@ -1536,15 +1597,22 @@ func TestEnableIPv6(t *testing.T) {
|
|||
resolvConfPath := "/tmp/libnetwork_test/resolv.conf"
|
||||
defer os.Remove(resolvConfPath)
|
||||
|
||||
defer controller.LeaveAll(containerID)
|
||||
err = ep1.Join(containerID,
|
||||
libnetwork.JoinOptionResolvConfPath(resolvConfPath))
|
||||
runtime.LockOSThread()
|
||||
sb, err := controller.NewSandbox(containerID, libnetwork.OptionResolvConfPath(resolvConfPath))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
err = ep1.Leave(containerID)
|
||||
if err := sb.Delete(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
err = ep1.Join(sb)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
err = ep1.Leave(sb)
|
||||
runtime.LockOSThread()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -1557,7 +1625,7 @@ func TestEnableIPv6(t *testing.T) {
|
|||
}
|
||||
|
||||
if !bytes.Equal(content, tmpResolvConf) {
|
||||
t.Fatalf("Expected %s, Got %s", string(tmpResolvConf), string(content))
|
||||
t.Fatalf("Expected:\n%s\nGot:\n%s", string(tmpResolvConf), string(content))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
@ -1570,7 +1638,7 @@ func TestResolvConfHost(t *testing.T) {
|
|||
defer netutils.SetupTestNetNS(t)()
|
||||
}
|
||||
|
||||
tmpResolvConf := []byte("search localhost.net\nnameserver 127.0.0.1\nnameserver 2001:4860:4860::8888")
|
||||
tmpResolvConf := []byte("search localhost.net\nnameserver 127.0.0.1\nnameserver 2001:4860:4860::8888\n")
|
||||
|
||||
//take a copy of resolv.conf for restoring after test completes
|
||||
resolvConfSystem, err := ioutil.ReadFile("/etc/resolv.conf")
|
||||
|
@ -1601,13 +1669,24 @@ func TestResolvConfHost(t *testing.T) {
|
|||
resolvConfPath := "/tmp/libnetwork_test/resolv.conf"
|
||||
defer os.Remove(resolvConfPath)
|
||||
|
||||
err = ep1.Join(containerID,
|
||||
libnetwork.JoinOptionResolvConfPath(resolvConfPath))
|
||||
sb, err := controller.NewSandbox(containerID,
|
||||
libnetwork.OptionResolvConfPath(resolvConfPath),
|
||||
libnetwork.OptionOriginResolvConfPath("/etc/resolv.conf"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
err = ep1.Leave(containerID)
|
||||
if err := sb.Delete(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
err = ep1.Join(sb)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
err = ep1.Leave(sb)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -1629,7 +1708,7 @@ func TestResolvConfHost(t *testing.T) {
|
|||
}
|
||||
|
||||
if !bytes.Equal(content, tmpResolvConf) {
|
||||
t.Fatalf("Expected %s, Got %s", string(tmpResolvConf), string(content))
|
||||
t.Fatalf("Expected:\n%s\nGot:\n%s", string(tmpResolvConf), string(content))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1638,9 +1717,9 @@ func TestResolvConf(t *testing.T) {
|
|||
defer netutils.SetupTestNetNS(t)()
|
||||
}
|
||||
|
||||
tmpResolvConf1 := []byte("search pommesfrites.fr\nnameserver 12.34.56.78\nnameserver 2001:4860:4860::8888")
|
||||
tmpResolvConf1 := []byte("search pommesfrites.fr\nnameserver 12.34.56.78\nnameserver 2001:4860:4860::8888\n")
|
||||
expectedResolvConf1 := []byte("search pommesfrites.fr\nnameserver 12.34.56.78\n")
|
||||
tmpResolvConf2 := []byte("search pommesfrites.fr\nnameserver 112.34.56.78\nnameserver 2001:4860:4860::8888")
|
||||
tmpResolvConf2 := []byte("search pommesfrites.fr\nnameserver 112.34.56.78\nnameserver 2001:4860:4860::8888\n")
|
||||
expectedResolvConf2 := []byte("search pommesfrites.fr\nnameserver 112.34.56.78\n")
|
||||
tmpResolvConf3 := []byte("search pommesfrites.fr\nnameserver 113.34.56.78\n")
|
||||
|
||||
|
@ -1672,12 +1751,12 @@ func TestResolvConf(t *testing.T) {
|
|||
}
|
||||
}()
|
||||
|
||||
ep1, err := n.CreateEndpoint("ep1")
|
||||
ep, err := n.CreateEndpoint("ep")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := ep1.Delete(); err != nil {
|
||||
if err := ep.Delete(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
@ -1689,21 +1768,22 @@ func TestResolvConf(t *testing.T) {
|
|||
resolvConfPath := "/tmp/libnetwork_test/resolv.conf"
|
||||
defer os.Remove(resolvConfPath)
|
||||
|
||||
defer controller.LeaveAll(containerID)
|
||||
err = ep1.Join(containerID,
|
||||
libnetwork.JoinOptionResolvConfPath(resolvConfPath))
|
||||
runtime.LockOSThread()
|
||||
sb1, err := controller.NewSandbox(containerID, libnetwork.OptionResolvConfPath(resolvConfPath))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
err = ep1.Leave(containerID)
|
||||
runtime.LockOSThread()
|
||||
if err != nil {
|
||||
if err := sb1.Delete(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
err = ep.Join(sb1)
|
||||
runtime.LockOSThread()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
finfo, err := os.Stat(resolvConfPath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -1720,10 +1800,11 @@ func TestResolvConf(t *testing.T) {
|
|||
}
|
||||
|
||||
if !bytes.Equal(content, expectedResolvConf1) {
|
||||
t.Fatalf("Expected %s, Got %s", string(expectedResolvConf1), string(content))
|
||||
fmt.Printf("\n%v\n%v\n", expectedResolvConf1, content)
|
||||
t.Fatalf("Expected:\n%s\nGot:\n%s", string(expectedResolvConf1), string(content))
|
||||
}
|
||||
|
||||
err = ep1.Leave(containerID)
|
||||
err = ep.Leave(sb1)
|
||||
runtime.LockOSThread()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -1733,8 +1814,17 @@ func TestResolvConf(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = ep1.Join(containerID,
|
||||
libnetwork.JoinOptionResolvConfPath(resolvConfPath))
|
||||
sb2, err := controller.NewSandbox(containerID+"_2", libnetwork.OptionResolvConfPath(resolvConfPath))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := sb2.Delete(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
err = ep.Join(sb2)
|
||||
runtime.LockOSThread()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -1746,21 +1836,20 @@ func TestResolvConf(t *testing.T) {
|
|||
}
|
||||
|
||||
if !bytes.Equal(content, expectedResolvConf2) {
|
||||
t.Fatalf("Expected %s, Got %s", string(expectedResolvConf2), string(content))
|
||||
t.Fatalf("Expected:\n%s\nGot:\n%s", string(expectedResolvConf2), string(content))
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(resolvConfPath, tmpResolvConf3, 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = ep1.Leave(containerID)
|
||||
err = ep.Leave(sb2)
|
||||
runtime.LockOSThread()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = ep1.Join(containerID,
|
||||
libnetwork.JoinOptionResolvConfPath(resolvConfPath))
|
||||
err = ep.Join(sb2)
|
||||
runtime.LockOSThread()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -1772,7 +1861,7 @@ func TestResolvConf(t *testing.T) {
|
|||
}
|
||||
|
||||
if !bytes.Equal(content, tmpResolvConf3) {
|
||||
t.Fatalf("Expected %s, Got %s", string(tmpResolvConf3), string(content))
|
||||
t.Fatalf("Expected:\n%s\nGot:\n%s", string(tmpResolvConf3), string(content))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1886,6 +1975,7 @@ var (
|
|||
done = make(chan chan struct{}, numThreads-1)
|
||||
origns = netns.None()
|
||||
testns = netns.None()
|
||||
sboxes = make([]libnetwork.Sandbox, numThreads)
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -1945,6 +2035,15 @@ func createGlobalInstance(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if sboxes[first-1], err = controller.NewSandbox(fmt.Sprintf("%drace", first), libnetwork.OptionUseDefaultSandbox()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for thd := first + 1; thd <= last; thd++ {
|
||||
if sboxes[thd-1], err = controller.NewSandbox(fmt.Sprintf("%drace", thd)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func debugf(format string, a ...interface{}) (int, error) {
|
||||
|
@ -1955,42 +2054,49 @@ func debugf(format string, a ...interface{}) (int, error) {
|
|||
return 0, nil
|
||||
}
|
||||
|
||||
func parallelJoin(t *testing.T, ep libnetwork.Endpoint, thrNumber int) {
|
||||
func parallelJoin(t *testing.T, rc libnetwork.Sandbox, ep libnetwork.Endpoint, thrNumber int) {
|
||||
debugf("J%d.", thrNumber)
|
||||
var err error
|
||||
if thrNumber == first {
|
||||
err = ep.Join(fmt.Sprintf("%drace", thrNumber), libnetwork.JoinOptionUseDefaultSandbox())
|
||||
} else {
|
||||
err = ep.Join(fmt.Sprintf("%drace", thrNumber))
|
||||
}
|
||||
|
||||
sb := sboxes[thrNumber-1]
|
||||
err = ep.Join(sb)
|
||||
|
||||
runtime.LockOSThread()
|
||||
if err != nil {
|
||||
if _, ok := err.(libnetwork.ErrNoContainer); !ok {
|
||||
if _, ok := err.(libnetwork.ErrInvalidJoin); !ok {
|
||||
t.Fatalf("thread %d: %v", thrNumber, err)
|
||||
}
|
||||
if _, ok := err.(types.ForbiddenError); !ok {
|
||||
t.Fatalf("thread %d: %v", thrNumber, err)
|
||||
}
|
||||
debugf("JE%d(%v).", thrNumber, err)
|
||||
}
|
||||
debugf("JD%d.", thrNumber)
|
||||
}
|
||||
|
||||
func parallelLeave(t *testing.T, ep libnetwork.Endpoint, thrNumber int) {
|
||||
func parallelLeave(t *testing.T, rc libnetwork.Sandbox, ep libnetwork.Endpoint, thrNumber int) {
|
||||
debugf("L%d.", thrNumber)
|
||||
var err error
|
||||
|
||||
cid := fmt.Sprintf("%drace", thrNumber)
|
||||
sb := sboxes[thrNumber-1]
|
||||
|
||||
if thrNumber == first {
|
||||
err = ep.Leave(fmt.Sprintf("%drace", thrNumber))
|
||||
err = ep.Leave(sb)
|
||||
} else {
|
||||
err = controller.LeaveAll(fmt.Sprintf("%drace", thrNumber))
|
||||
err = sb.Delete()
|
||||
// re add sandbox
|
||||
defer func() {
|
||||
if err == nil {
|
||||
var e error
|
||||
if sboxes[thrNumber-1], e = controller.NewSandbox(cid); e != nil {
|
||||
t.Fatalf("Failed to recreate sandbox %s: %v", cid, e)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
runtime.LockOSThread()
|
||||
if err != nil {
|
||||
if _, ok := err.(libnetwork.ErrNoContainer); !ok {
|
||||
if _, ok := err.(libnetwork.ErrInvalidJoin); !ok {
|
||||
t.Fatalf("thread %d: %v", thrNumber, err)
|
||||
}
|
||||
if _, ok := err.(types.ForbiddenError); !ok {
|
||||
t.Fatalf("thread %d: %v", thrNumber, err)
|
||||
}
|
||||
debugf("LE%d(%v).", thrNumber, err)
|
||||
}
|
||||
|
@ -1998,7 +2104,11 @@ func parallelLeave(t *testing.T, ep libnetwork.Endpoint, thrNumber int) {
|
|||
}
|
||||
|
||||
func runParallelTests(t *testing.T, thrNumber int) {
|
||||
var err error
|
||||
var (
|
||||
ep libnetwork.Endpoint
|
||||
sb libnetwork.Sandbox
|
||||
err error
|
||||
)
|
||||
|
||||
t.Parallel()
|
||||
|
||||
|
@ -2046,7 +2156,7 @@ func runParallelTests(t *testing.T, thrNumber int) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
if net1 == nil {
|
||||
t.Fatal("Could not find network1")
|
||||
t.Fatal("Could not find testhost")
|
||||
}
|
||||
|
||||
net2, err := controller.NetworkByName("network2")
|
||||
|
@ -2059,9 +2169,6 @@ func runParallelTests(t *testing.T, thrNumber int) {
|
|||
|
||||
epName := fmt.Sprintf("pep%d", thrNumber)
|
||||
|
||||
//var err error
|
||||
var ep libnetwork.Endpoint
|
||||
|
||||
if thrNumber == first {
|
||||
ep, err = net1.EndpointByName(epName)
|
||||
} else {
|
||||
|
@ -2075,9 +2182,15 @@ func runParallelTests(t *testing.T, thrNumber int) {
|
|||
t.Fatal("Got nil ep with no error")
|
||||
}
|
||||
|
||||
cid := fmt.Sprintf("%drace", thrNumber)
|
||||
controller.WalkSandboxes(libnetwork.SandboxContainerWalker(&sb, cid))
|
||||
if sb == nil {
|
||||
t.Fatalf("Got nil sandbox for container: %s", cid)
|
||||
}
|
||||
|
||||
for i := 0; i < iterCnt; i++ {
|
||||
parallelJoin(t, ep, thrNumber)
|
||||
parallelLeave(t, ep, thrNumber)
|
||||
parallelJoin(t, sb, ep, thrNumber)
|
||||
parallelLeave(t, sb, ep, thrNumber)
|
||||
}
|
||||
|
||||
debugf("\n")
|
||||
|
@ -2095,6 +2208,15 @@ func runParallelTests(t *testing.T, thrNumber int) {
|
|||
}
|
||||
|
||||
testns.Close()
|
||||
err = sb.Delete()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ep.Delete()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := net2.Delete(); err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
|
@ -59,7 +59,7 @@ type network struct {
|
|||
ctrlr *controller
|
||||
name string
|
||||
networkType string
|
||||
id types.UUID
|
||||
id string
|
||||
driver driverapi.Driver
|
||||
enableIPv6 bool
|
||||
endpointCnt uint64
|
||||
|
@ -83,7 +83,7 @@ func (n *network) ID() string {
|
|||
n.Lock()
|
||||
defer n.Unlock()
|
||||
|
||||
return string(n.id)
|
||||
return n.id
|
||||
}
|
||||
|
||||
func (n *network) Type() string {
|
||||
|
@ -100,7 +100,7 @@ func (n *network) Type() string {
|
|||
func (n *network) Key() []string {
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
return []string{datastore.NetworkKeyPrefix, string(n.id)}
|
||||
return []string{datastore.NetworkKeyPrefix, n.id}
|
||||
}
|
||||
|
||||
func (n *network) KeyPrefix() []string {
|
||||
|
@ -162,7 +162,7 @@ func (n *network) DecEndpointCnt() {
|
|||
func (n *network) MarshalJSON() ([]byte, error) {
|
||||
netMap := make(map[string]interface{})
|
||||
netMap["name"] = n.name
|
||||
netMap["id"] = string(n.id)
|
||||
netMap["id"] = n.id
|
||||
netMap["networkType"] = n.networkType
|
||||
netMap["endpointCnt"] = n.endpointCnt
|
||||
netMap["enableIPv6"] = n.enableIPv6
|
||||
|
@ -177,7 +177,7 @@ func (n *network) UnmarshalJSON(b []byte) (err error) {
|
|||
return err
|
||||
}
|
||||
n.name = netMap["name"].(string)
|
||||
n.id = types.UUID(netMap["id"].(string))
|
||||
n.id = netMap["id"].(string)
|
||||
n.networkType = netMap["networkType"].(string)
|
||||
n.endpointCnt = uint64(netMap["endpointCnt"].(float64))
|
||||
n.enableIPv6 = netMap["enableIPv6"].(bool)
|
||||
|
@ -223,12 +223,12 @@ func (n *network) Delete() error {
|
|||
ctrlr.Unlock()
|
||||
|
||||
if !ok {
|
||||
return &UnknownNetworkError{name: n.name, id: string(n.id)}
|
||||
return &UnknownNetworkError{name: n.name, id: n.id}
|
||||
}
|
||||
|
||||
numEps := n.EndpointCnt()
|
||||
if numEps != 0 {
|
||||
return &ActiveEndpointsError{name: n.name, id: string(n.id)}
|
||||
return &ActiveEndpointsError{name: n.name, id: n.id}
|
||||
}
|
||||
|
||||
// deleteNetworkFromStore performs an atomic delete operation and the network.endpointCnt field will help
|
||||
|
@ -287,7 +287,7 @@ func (n *network) addEndpoint(ep *endpoint) error {
|
|||
|
||||
err = d.CreateEndpoint(n.id, ep.id, ep, ep.generic)
|
||||
if err != nil {
|
||||
return err
|
||||
return types.InternalErrorf("failed to create endpoint %s on network %s: %v", ep.Name(), n.Name(), err)
|
||||
}
|
||||
|
||||
n.updateSvcRecord(ep, true)
|
||||
|
@ -307,7 +307,7 @@ func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoi
|
|||
ep := &endpoint{name: name,
|
||||
iFaces: []*endpointInterface{},
|
||||
generic: make(map[string]interface{})}
|
||||
ep.id = types.UUID(stringid.GenerateRandomID())
|
||||
ep.id = stringid.GenerateRandomID()
|
||||
ep.network = n
|
||||
ep.processOptions(options...)
|
||||
|
||||
|
@ -393,7 +393,7 @@ func (n *network) EndpointByID(id string) (Endpoint, error) {
|
|||
}
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
if e, ok := n.endpoints[types.UUID(id)]; ok {
|
||||
if e, ok := n.endpoints[id]; ok {
|
||||
return e, nil
|
||||
}
|
||||
return nil, ErrNoSuchEndpoint(id)
|
||||
|
@ -435,22 +435,19 @@ func (n *network) updateSvcRecord(ep *endpoint, isAdd bool) {
|
|||
return
|
||||
}
|
||||
|
||||
var epList []*endpoint
|
||||
var sbList []*sandbox
|
||||
n.WalkEndpoints(func(e Endpoint) bool {
|
||||
cEp := e.(*endpoint)
|
||||
cEp.Lock()
|
||||
if cEp.container != nil {
|
||||
epList = append(epList, cEp)
|
||||
if sb, hasSandbox := e.(*endpoint).getSandbox(); hasSandbox {
|
||||
sbList = append(sbList, sb)
|
||||
}
|
||||
cEp.Unlock()
|
||||
return false
|
||||
})
|
||||
|
||||
for _, cEp := range epList {
|
||||
for _, sb := range sbList {
|
||||
if isAdd {
|
||||
cEp.addHostEntries(recs)
|
||||
sb.addHostsEntries(recs)
|
||||
} else {
|
||||
cEp.deleteHostEntries(recs)
|
||||
sb.deleteHostsEntries(recs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -469,3 +466,9 @@ func (n *network) getSvcRecords() []etchosts.Record {
|
|||
|
||||
return recs
|
||||
}
|
||||
|
||||
func (n *network) getController() *controller {
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
return n.ctrlr
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package sandbox
|
||||
package osl
|
||||
|
||||
// IfaceOption is a function option type to set interface options
|
||||
type IfaceOption func()
|
|
@ -1,4 +1,4 @@
|
|||
package sandbox
|
||||
package osl
|
||||
|
||||
import (
|
||||
"fmt"
|
|
@ -1,4 +1,4 @@
|
|||
package sandbox
|
||||
package osl
|
||||
|
||||
// IfaceOption is a function option type to set interface options
|
||||
type IfaceOption func()
|
|
@ -1,4 +1,4 @@
|
|||
package sandbox
|
||||
package osl
|
||||
|
||||
import (
|
||||
"fmt"
|
|
@ -1,6 +1,6 @@
|
|||
// +build !linux,!windows,!freebsd
|
||||
|
||||
package sandbox
|
||||
package osl
|
||||
|
||||
// GC triggers garbage collection of namespace path right away
|
||||
// and waits for it.
|
|
@ -1,4 +1,4 @@
|
|||
package sandbox
|
||||
package osl
|
||||
|
||||
// GenerateKey generates a sandbox key based on the passed
|
||||
// container id.
|
|
@ -1,4 +1,4 @@
|
|||
package sandbox
|
||||
package osl
|
||||
|
||||
// NeighOption is a function option type to set neighbor options
|
||||
type NeighOption func()
|
|
@ -1,4 +1,4 @@
|
|||
package sandbox
|
||||
package osl
|
||||
|
||||
import (
|
||||
"bytes"
|
|
@ -1,4 +1,4 @@
|
|||
package sandbox
|
||||
package osl
|
||||
|
||||
// NeighOption is a function option type to set neighbor options
|
||||
type NeighOption func()
|
|
@ -1,4 +1,4 @@
|
|||
package sandbox
|
||||
package osl
|
||||
|
||||
import "net"
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package sandbox
|
||||
package osl
|
||||
|
||||
import (
|
||||
"fmt"
|
|
@ -1,4 +1,5 @@
|
|||
package sandbox
|
||||
// Package osl describes structures and interfaces which abstract os entities
|
||||
package osl
|
||||
|
||||
import (
|
||||
"fmt"
|
|
@ -1,4 +1,4 @@
|
|||
package sandbox
|
||||
package osl
|
||||
|
||||
// GenerateKey generates a sandbox key based on the passed
|
||||
// container id.
|
|
@ -1,4 +1,4 @@
|
|||
package sandbox
|
||||
package osl
|
||||
|
||||
import (
|
||||
"net"
|
|
@ -1,4 +1,4 @@
|
|||
package sandbox
|
||||
package osl
|
||||
|
||||
import (
|
||||
"os"
|
|
@ -1,6 +1,6 @@
|
|||
// +build !linux,!windows,!freebsd
|
||||
|
||||
package sandbox
|
||||
package osl
|
||||
|
||||
import "errors"
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
// +build !linux
|
||||
|
||||
package sandbox
|
||||
package osl
|
||||
|
||||
import (
|
||||
"errors"
|
|
@ -168,20 +168,25 @@ func GetSearchDomains(resolvConf []byte) []string {
|
|||
// Build writes a configuration file to path containing a "nameserver" entry
|
||||
// for every element in dns, and a "search" entry for every element in
|
||||
// dnsSearch.
|
||||
func Build(path string, dns, dnsSearch []string) error {
|
||||
func Build(path string, dns, dnsSearch []string) (string, error) {
|
||||
content := bytes.NewBuffer(nil)
|
||||
for _, dns := range dns {
|
||||
if _, err := content.WriteString("nameserver " + dns + "\n"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(dnsSearch) > 0 {
|
||||
if searchString := strings.Join(dnsSearch, " "); strings.Trim(searchString, " ") != "." {
|
||||
if _, err := content.WriteString("search " + searchString + "\n"); err != nil {
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, dns := range dns {
|
||||
if _, err := content.WriteString("nameserver " + dns + "\n"); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
return ioutil.WriteFile(path, content.Bytes(), 0644)
|
||||
hash, err := ioutils.HashData(bytes.NewReader(content.Bytes()))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return hash, ioutil.WriteFile(path, content.Bytes(), 0644)
|
||||
}
|
||||
|
|
|
@ -119,7 +119,7 @@ func TestBuild(t *testing.T) {
|
|||
}
|
||||
defer os.Remove(file.Name())
|
||||
|
||||
err = Build(file.Name(), []string{"ns1", "ns2", "ns3"}, []string{"search1"})
|
||||
_, err = Build(file.Name(), []string{"ns1", "ns2", "ns3"}, []string{"search1"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -129,7 +129,7 @@ func TestBuild(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if expected := "nameserver ns1\nnameserver ns2\nnameserver ns3\nsearch search1\n"; !bytes.Contains(content, []byte(expected)) {
|
||||
if expected := "search search1\nnameserver ns1\nnameserver ns2\nnameserver ns3\n"; !bytes.Contains(content, []byte(expected)) {
|
||||
t.Fatalf("Expected to find '%s' got '%s'", expected, content)
|
||||
}
|
||||
}
|
||||
|
@ -141,7 +141,7 @@ func TestBuildWithZeroLengthDomainSearch(t *testing.T) {
|
|||
}
|
||||
defer os.Remove(file.Name())
|
||||
|
||||
err = Build(file.Name(), []string{"ns1", "ns2", "ns3"}, []string{"."})
|
||||
_, err = Build(file.Name(), []string{"ns1", "ns2", "ns3"}, []string{"."})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
662
libnetwork/sandbox.go
Normal file
662
libnetwork/sandbox.go
Normal file
|
@ -0,0 +1,662 @@
|
|||
package libnetwork
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"container/heap"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"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)
|
||||
// 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
|
||||
}
|
||||
|
||||
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 {
|
||||
sb.Lock()
|
||||
c := sb.controller
|
||||
eps := make([]*endpoint, len(sb.endpoints))
|
||||
for i, ep := range sb.endpoints {
|
||||
eps[i] = ep
|
||||
}
|
||||
sb.Unlock()
|
||||
|
||||
// Detach from all containers
|
||||
for _, ep := range eps {
|
||||
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) 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) 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 {
|
||||
// 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 {
|
||||
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
|
||||
}
|
||||
|
||||
resolvConf, err := resolvconf.Get()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dnsList := resolvconf.GetNameservers(resolvConf)
|
||||
dnsSearchList := resolvconf.GetSearchDomains(resolvConf)
|
||||
|
||||
if len(sb.config.dnsList) > 0 || len(sb.config.dnsSearchList) > 0 {
|
||||
if len(sb.config.dnsList) > 0 {
|
||||
dnsList = sb.config.dnsList
|
||||
}
|
||||
if len(sb.config.dnsSearchList) > 0 {
|
||||
dnsSearchList = sb.config.dnsSearchList
|
||||
}
|
||||
}
|
||||
|
||||
hash, err := resolvconf.Build(sb.config.resolvConfPath, dnsList, dnsSearchList)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// write hash
|
||||
if err := ioutil.WriteFile(sb.config.resolvConfHashFile, []byte(hash), filePerm); err != nil {
|
||||
return types.InternalErrorf("failed to write resol.conf hash file when setting up dns for sandbox %s: %v", sb.ID(), err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sb *sandbox) updateDNS(ipv6Enabled bool) error {
|
||||
var oldHash []byte
|
||||
hashFile := sb.config.resolvConfHashFile
|
||||
|
||||
resolvConf, err := ioutil.ReadFile(sb.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(resolvConf))
|
||||
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.
|
||||
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.
|
||||
resolvConf, _ = resolvconf.FilterResolvDNS(resolvConf, ipv6Enabled)
|
||||
|
||||
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(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(newHash), filePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = ioutil.WriteFile(tmpResolvFile.Name(), resolvConf, 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)
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
219
libnetwork/sandbox_test.go
Normal file
219
libnetwork/sandbox_test.go
Normal file
|
@ -0,0 +1,219 @@
|
|||
package libnetwork
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/docker/libnetwork/netlabel"
|
||||
"github.com/docker/libnetwork/netutils"
|
||||
"github.com/docker/libnetwork/options"
|
||||
"github.com/docker/libnetwork/osl"
|
||||
)
|
||||
|
||||
func createEmptyCtrlr() *controller {
|
||||
return &controller{sandboxes: sandboxTable{}}
|
||||
}
|
||||
|
||||
func createEmptyEndpoint() *endpoint {
|
||||
return &endpoint{
|
||||
joinInfo: &endpointJoinInfo{},
|
||||
iFaces: []*endpointInterface{},
|
||||
}
|
||||
}
|
||||
|
||||
func getTestEnv(t *testing.T) (NetworkController, Network, Network) {
|
||||
c, err := New()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
option := options.Generic{
|
||||
"EnableIPForwarding": true,
|
||||
}
|
||||
genericOption := make(map[string]interface{})
|
||||
genericOption[netlabel.GenericData] = option
|
||||
if err := c.ConfigureNetworkDriver("bridge", genericOption); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
netType := "bridge"
|
||||
name1 := "test_nw_1"
|
||||
netOption1 := options.Generic{
|
||||
netlabel.GenericData: options.Generic{
|
||||
"BridgeName": name1,
|
||||
"AllowNonDefaultBridge": true,
|
||||
},
|
||||
}
|
||||
n1, err := c.NewNetwork(netType, name1, NetworkOptionGeneric(netOption1))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
name2 := "test_nw_2"
|
||||
netOption2 := options.Generic{
|
||||
netlabel.GenericData: options.Generic{
|
||||
"BridgeName": name2,
|
||||
"AllowNonDefaultBridge": true,
|
||||
},
|
||||
}
|
||||
n2, err := c.NewNetwork(netType, name2, NetworkOptionGeneric(netOption2))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
return c, n1, n2
|
||||
}
|
||||
|
||||
func TestSandboxAddEmpty(t *testing.T) {
|
||||
ctrlr := createEmptyCtrlr()
|
||||
|
||||
sbx, err := ctrlr.NewSandbox("sandbox0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := sbx.Delete(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(ctrlr.sandboxes) != 0 {
|
||||
t.Fatalf("controller sandboxes is not empty. len = %d", len(ctrlr.sandboxes))
|
||||
}
|
||||
|
||||
osl.GC()
|
||||
}
|
||||
|
||||
func TestSandboxAddMultiPrio(t *testing.T) {
|
||||
if !netutils.IsRunningInContainer() {
|
||||
defer netutils.SetupTestNetNS(t)()
|
||||
}
|
||||
|
||||
c, nw, _ := getTestEnv(t)
|
||||
ctrlr := c.(*controller)
|
||||
|
||||
sbx, err := ctrlr.NewSandbox("sandbox1")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sid := sbx.ID()
|
||||
|
||||
ep1, err := nw.CreateEndpoint("ep1")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ep2, err := nw.CreateEndpoint("ep2")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ep3, err := nw.CreateEndpoint("ep3")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := ep1.Join(sbx, JoinOptionPriority(ep1, 1)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := ep2.Join(sbx, JoinOptionPriority(ep2, 2)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := ep3.Join(sbx, JoinOptionPriority(ep3, 3)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ctrlr.sandboxes[sid].endpoints[0] != ep3 {
|
||||
t.Fatal("Expected ep3 to be at the top of the heap. But did not find ep3 at the top of the heap")
|
||||
}
|
||||
|
||||
if err := ep3.Leave(sbx); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if ctrlr.sandboxes[sid].endpoints[0] != ep2 {
|
||||
t.Fatal("Expected ep2 to be at the top of the heap after removing ep3. But did not find ep2 at the top of the heap")
|
||||
}
|
||||
|
||||
if err := ep2.Leave(sbx); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if ctrlr.sandboxes[sid].endpoints[0] != ep1 {
|
||||
t.Fatal("Expected ep1 to be at the top of the heap after removing ep2. But did not find ep1 at the top of the heap")
|
||||
}
|
||||
|
||||
// Re-add ep3 back
|
||||
if err := ep3.Join(sbx, JoinOptionPriority(ep3, 3)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ctrlr.sandboxes[sid].endpoints[0] != ep3 {
|
||||
t.Fatal("Expected ep3 to be at the top of the heap after adding ep3 back. But did not find ep3 at the top of the heap")
|
||||
}
|
||||
|
||||
if err := sbx.Delete(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(ctrlr.sandboxes) != 0 {
|
||||
t.Fatalf("controller sandboxes is not empty. len = %d", len(ctrlr.sandboxes))
|
||||
}
|
||||
|
||||
osl.GC()
|
||||
}
|
||||
|
||||
func TestSandboxAddSamePrio(t *testing.T) {
|
||||
if !netutils.IsRunningInContainer() {
|
||||
defer netutils.SetupTestNetNS(t)()
|
||||
}
|
||||
|
||||
c, nw1, nw2 := getTestEnv(t)
|
||||
|
||||
ctrlr := c.(*controller)
|
||||
|
||||
sbx, err := ctrlr.NewSandbox("sandbox1")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sid := sbx.ID()
|
||||
|
||||
ep1, err := nw1.CreateEndpoint("ep1")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ep2, err := nw2.CreateEndpoint("ep2")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := ep1.Join(sbx); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := ep2.Join(sbx); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ctrlr.sandboxes[sid].endpoints[0] != ep1 {
|
||||
t.Fatal("Expected ep1 to be at the top of the heap. But did not find ep1 at the top of the heap")
|
||||
}
|
||||
|
||||
if err := ep1.Leave(sbx); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ctrlr.sandboxes[sid].endpoints[0] != ep2 {
|
||||
t.Fatal("Expected ep2 to be at the top of the heap after removing ep3. But did not find ep2 at the top of the heap")
|
||||
}
|
||||
|
||||
if err := ep2.Leave(sbx); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := sbx.Delete(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(ctrlr.sandboxes) != 0 {
|
||||
t.Fatalf("controller containers is not empty. len = %d", len(ctrlr.sandboxes))
|
||||
}
|
||||
|
||||
osl.GC()
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -1,141 +0,0 @@
|
|||
package libnetwork
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/docker/libnetwork/sandbox"
|
||||
)
|
||||
|
||||
func createEmptyCtrlr() *controller {
|
||||
return &controller{sandboxes: sandboxTable{}}
|
||||
}
|
||||
|
||||
func createEmptyEndpoint() *endpoint {
|
||||
return &endpoint{
|
||||
container: &containerInfo{},
|
||||
joinInfo: &endpointJoinInfo{},
|
||||
iFaces: []*endpointInterface{},
|
||||
}
|
||||
}
|
||||
|
||||
func TestSandboxAddEmpty(t *testing.T) {
|
||||
ctrlr := createEmptyCtrlr()
|
||||
ep := createEmptyEndpoint()
|
||||
|
||||
if _, err := ctrlr.sandboxAdd(sandbox.GenerateKey("sandbox1"), true, ep); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ctrlr.sandboxRm(sandbox.GenerateKey("sandbox1"), ep)
|
||||
|
||||
ctrlr.LeaveAll("sandbox1")
|
||||
if len(ctrlr.sandboxes) != 0 {
|
||||
t.Fatalf("controller sandboxes is not empty. len = %d", len(ctrlr.sandboxes))
|
||||
}
|
||||
|
||||
sandbox.GC()
|
||||
}
|
||||
|
||||
func TestSandboxAddMultiPrio(t *testing.T) {
|
||||
ctrlr := createEmptyCtrlr()
|
||||
ep1 := createEmptyEndpoint()
|
||||
ep2 := createEmptyEndpoint()
|
||||
ep3 := createEmptyEndpoint()
|
||||
|
||||
ep1.container.config.prio = 1
|
||||
ep2.container.config.prio = 2
|
||||
ep3.container.config.prio = 3
|
||||
|
||||
sKey := sandbox.GenerateKey("sandbox1")
|
||||
|
||||
if _, err := ctrlr.sandboxAdd(sKey, true, ep1); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := ctrlr.sandboxAdd(sKey, true, ep2); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := ctrlr.sandboxAdd(sKey, true, ep3); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ctrlr.sandboxes[sKey].endpoints[0] != ep3 {
|
||||
t.Fatal("Expected ep3 to be at the top of the heap. But did not find ep3 at the top of the heap")
|
||||
}
|
||||
|
||||
ctrlr.sandboxRm(sKey, ep3)
|
||||
|
||||
if ctrlr.sandboxes[sKey].endpoints[0] != ep2 {
|
||||
t.Fatal("Expected ep2 to be at the top of the heap after removing ep3. But did not find ep2 at the top of the heap")
|
||||
}
|
||||
|
||||
ctrlr.sandboxRm(sKey, ep2)
|
||||
|
||||
if ctrlr.sandboxes[sKey].endpoints[0] != ep1 {
|
||||
t.Fatal("Expected ep1 to be at the top of the heap after removing ep2. But did not find ep1 at the top of the heap")
|
||||
}
|
||||
|
||||
// Re-add ep3 back
|
||||
if _, err := ctrlr.sandboxAdd(sKey, true, ep3); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ctrlr.sandboxes[sKey].endpoints[0] != ep3 {
|
||||
t.Fatal("Expected ep3 to be at the top of the heap after adding ep3 back. But did not find ep3 at the top of the heap")
|
||||
}
|
||||
|
||||
ctrlr.sandboxRm(sKey, ep3)
|
||||
ctrlr.sandboxRm(sKey, ep1)
|
||||
|
||||
if err := ctrlr.LeaveAll("sandbox1"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(ctrlr.sandboxes) != 0 {
|
||||
t.Fatalf("controller sandboxes is not empty. len = %d", len(ctrlr.sandboxes))
|
||||
}
|
||||
|
||||
sandbox.GC()
|
||||
}
|
||||
|
||||
func TestSandboxAddSamePrio(t *testing.T) {
|
||||
ctrlr := createEmptyCtrlr()
|
||||
ep1 := createEmptyEndpoint()
|
||||
ep2 := createEmptyEndpoint()
|
||||
|
||||
ep1.network = &network{name: "aaa"}
|
||||
ep2.network = &network{name: "bbb"}
|
||||
|
||||
sKey := sandbox.GenerateKey("sandbox1")
|
||||
|
||||
if _, err := ctrlr.sandboxAdd(sKey, true, ep1); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := ctrlr.sandboxAdd(sKey, true, ep2); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ctrlr.sandboxes[sKey].endpoints[0] != ep1 {
|
||||
t.Fatal("Expected ep1 to be at the top of the heap. But did not find ep1 at the top of the heap")
|
||||
}
|
||||
|
||||
ctrlr.sandboxRm(sKey, ep1)
|
||||
|
||||
if ctrlr.sandboxes[sKey].endpoints[0] != ep2 {
|
||||
t.Fatal("Expected ep2 to be at the top of the heap after removing ep3. But did not find ep2 at the top of the heap")
|
||||
}
|
||||
|
||||
ctrlr.sandboxRm(sKey, ep2)
|
||||
|
||||
if err := ctrlr.LeaveAll("sandbox1"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(ctrlr.sandboxes) != 0 {
|
||||
t.Fatalf("controller sandboxes is not empty. len = %d", len(ctrlr.sandboxes))
|
||||
}
|
||||
|
||||
sandbox.GC()
|
||||
}
|
|
@ -7,7 +7,6 @@ import (
|
|||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/docker/libkv/store"
|
||||
"github.com/docker/libnetwork/datastore"
|
||||
"github.com/docker/libnetwork/types"
|
||||
)
|
||||
|
||||
func (c *controller) validateDatastoreConfig() bool {
|
||||
|
@ -91,7 +90,7 @@ func (c *controller) deleteNetworkFromStore(n *network) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (c *controller) getNetworkFromStore(nid types.UUID) (*network, error) {
|
||||
func (c *controller) getNetworkFromStore(nid string) (*network, error) {
|
||||
n := network{id: nid}
|
||||
if err := c.store.GetObject(datastore.Key(n.Key()...), &n); err != nil {
|
||||
return nil, err
|
||||
|
@ -105,7 +104,7 @@ func (c *controller) newEndpointFromStore(key string, ep *endpoint) error {
|
|||
id := ep.id
|
||||
ep.Unlock()
|
||||
|
||||
_, err := n.EndpointByID(string(id))
|
||||
_, err := n.EndpointByID(id)
|
||||
if err != nil {
|
||||
if _, ok := err.(ErrNoSuchEndpoint); ok {
|
||||
return n.addEndpoint(ep)
|
||||
|
@ -134,7 +133,7 @@ func (c *controller) updateEndpointToStore(ep *endpoint) error {
|
|||
return cs.PutObjectAtomic(ep)
|
||||
}
|
||||
|
||||
func (c *controller) getEndpointFromStore(eid types.UUID) (*endpoint, error) {
|
||||
func (c *controller) getEndpointFromStore(eid string) (*endpoint, error) {
|
||||
ep := endpoint{id: eid}
|
||||
if err := c.store.GetObject(datastore.Key(ep.Key()...), &ep); err != nil {
|
||||
return nil, err
|
||||
|
@ -346,7 +345,7 @@ func (c *controller) processEndpointUpdate(ep *endpoint) bool {
|
|||
if !ok {
|
||||
return true
|
||||
}
|
||||
existing, _ := n.EndpointByID(string(ep.id))
|
||||
existing, _ := n.EndpointByID(ep.id)
|
||||
if existing == nil {
|
||||
return true
|
||||
}
|
||||
|
@ -357,13 +356,7 @@ func (c *controller) processEndpointUpdate(ep *endpoint) bool {
|
|||
// Can't use SetIndex() because ee is locked.
|
||||
ee.dbIndex = ep.Index()
|
||||
ee.dbExists = true
|
||||
if ee.container != nil && ep.container != nil {
|
||||
// we care only about the container id
|
||||
ee.container.id = ep.container.id
|
||||
} else {
|
||||
// we still care only about the container id, but this is a short-cut to communicate join or leave operation
|
||||
ee.container = ep.container
|
||||
}
|
||||
ee.sandboxID = ep.sandboxID
|
||||
}
|
||||
ee.Unlock()
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue