Merge pull request #502 from mavenugo/sbox_uns

Support to provide external key to sandbox
This commit is contained in:
Jana Radhakrishnan 2015-09-09 21:39:48 -07:00
commit 0e00550af4
9 changed files with 250 additions and 27 deletions

View File

@ -249,6 +249,9 @@ func (sc *sandboxCreate) parseOptions() []libnetwork.SandboxOption {
if sc.UseDefaultSandbox {
setFctList = append(setFctList, libnetwork.OptionUseDefaultSandbox())
}
if sc.UseExternalKey {
setFctList = append(setFctList, libnetwork.OptionUseExternalKey())
}
if sc.DNS != nil {
for _, d := range sc.DNS {
setFctList = append(setFctList, libnetwork.OptionDNS(d))

View File

@ -57,6 +57,7 @@ type sandboxCreate struct {
DNS []string `json:"dns"`
ExtraHosts []extraHost `json:"extra_hosts"`
UseDefaultSandbox bool `json:"use_default_sandbox"`
UseExternalKey bool `json:"use_external_key"`
}
// endpointJoin represents the expected body of the "join endpoint" or "leave endpoint" http request messages

View File

@ -414,7 +414,7 @@ func (c *controller) NewSandbox(containerID string, options ...SandboxOption) (S
return nil, err
}
if sb.osSbox == nil {
if sb.osSbox == nil && !sb.config.useExternalKey {
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)
}

View File

@ -1,6 +1,7 @@
package libnetwork
import (
"container/heap"
"encoding/json"
"fmt"
"net"
@ -289,10 +290,25 @@ func (ep *endpoint) Join(sbox Sandbox, options ...EndpointOption) error {
return err
}
sb.Lock()
heap.Push(&sb.endpoints, ep)
sb.Unlock()
defer func() {
if err != nil {
for i, e := range sb.getConnectedEndpoints() {
if e == ep {
sb.Lock()
heap.Remove(&sb.endpoints, i)
sb.Unlock()
return
}
}
}
}()
if err = sb.populateNetworkResources(ep); err != nil {
return err
}
return nil
}

View File

@ -1188,6 +1188,117 @@ func (f *fakeSandbox) Delete() error {
return nil
}
func (f *fakeSandbox) SetKey(key string) error {
return nil
}
func TestExternalKey(t *testing.T) {
if !netutils.IsRunningInContainer() {
defer osl.SetupTestOSContext(t)()
}
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)
}
}()
ep, err := n.CreateEndpoint("ep1")
if err != nil {
t.Fatal(err)
}
defer func() {
err = ep.Delete()
if err != nil {
t.Fatal(err)
}
}()
ep2, err := n.CreateEndpoint("ep2")
if err != nil {
t.Fatal(err)
}
defer func() {
err = ep2.Delete()
if err != nil {
t.Fatal(err)
}
}()
cnt, err := controller.NewSandbox(containerID,
libnetwork.OptionHostname("test"),
libnetwork.OptionDomainname("docker.io"),
libnetwork.OptionUseExternalKey(),
libnetwork.OptionExtraHost("web", "192.168.0.1"))
defer func() {
if err := cnt.Delete(); err != nil {
t.Fatal(err)
}
}()
// Join endpoint to sandbox before SetKey
err = ep.Join(cnt)
runtime.LockOSThread()
if err != nil {
t.Fatal(err)
}
defer func() {
err = ep.Leave(cnt)
runtime.LockOSThread()
if err != nil {
t.Fatal(err)
}
}()
sbox := ep.Info().Sandbox()
if sbox == nil {
t.Fatalf("Expected to have a valid Sandbox")
}
// Setting an non-existing key (namespace) must fail
if err := sbox.SetKey("this-must-fail"); err == nil {
t.Fatalf("Setkey must fail if the corresponding namespace is not created")
}
// Create a new OS sandbox using the osl API before using it in SetKey
if _, err := osl.NewSandbox("ValidKey", true); err != nil {
t.Fatalf("Failed to create new osl sandbox")
}
if err := sbox.SetKey("ValidKey"); err != nil {
t.Fatalf("Setkey failed with %v", err)
}
// Join endpoint to sandbox after SetKey
err = ep2.Join(sbox)
if err != nil {
t.Fatal(err)
}
runtime.LockOSThread()
defer func() {
err = ep2.Leave(sbox)
runtime.LockOSThread()
if err != nil {
t.Fatal(err)
}
}()
if ep.Info().Sandbox().Key() != ep2.Info().Sandbox().Key() {
t.Fatalf("ep1 and ep2 returned different container sandbox key")
}
checkSandbox(t, ep.Info())
}
func TestEndpointDeleteWithActiveContainer(t *testing.T) {
if !testutils.IsRunningInContainer() {
defer testutils.SetupTestOSContext(t)()

View File

@ -157,16 +157,38 @@ func (n *networkNamespace) NeighborOptions() NeighborOptionSetter {
return n
}
func mountNetworkNamespace(basePath string, lnPath string) error {
if err := syscall.Mount(basePath, lnPath, "bind", syscall.MS_BIND, ""); err != nil {
return err
}
if err := loopbackUp(); err != nil {
return err
}
return nil
}
// GetSandboxForExternalKey returns sandbox object for the supplied path
func GetSandboxForExternalKey(basePath string, key string) (Sandbox, error) {
var err error
if err = createNamespaceFile(key); err != nil {
return nil, err
}
n := &networkNamespace{path: basePath}
n.InvokeFunc(func() {
err = mountNetworkNamespace(basePath, key)
})
if err != nil {
return nil, err
}
return &networkNamespace{path: key}, nil
}
func reexecCreateNamespace() {
if len(os.Args) < 2 {
log.Fatal("no namespace path provided")
}
if err := syscall.Mount("/proc/self/ns/net", os.Args[1], "bind", syscall.MS_BIND, ""); err != nil {
log.Fatal(err)
}
if err := loopbackUp(); err != nil {
if err := mountNetworkNamespace("/proc/self/ns/net", os.Args[1]); err != nil {
log.Fatal(err)
}
}

View File

@ -6,3 +6,7 @@ package osl
// and waits for it.
func GC() {
}
func GetSandboxForExternalKey(path string, key string) (Sandbox, error) {
return nil, nil
}

View File

@ -19,6 +19,10 @@ func NewSandbox(key string, osCreate bool) (Sandbox, error) {
return nil, nil
}
func GetSandboxForExternalKey(path string, key string) (Sandbox, error) {
return nil, nil
}
// GC triggers garbage collection of namespace path right away
// and waits for it.
func GC() {

View File

@ -32,6 +32,8 @@ type Sandbox interface {
// Refresh leaves all the endpoints, resets and re-apply the options,
// re-joins all the endpoints without destroying the osl sandbox
Refresh(options ...SandboxOption) error
// SetKey updates the Sandbox Key
SetKey(key string) error
// Delete destroys this container after detaching it from all connected endpoints.
Delete() error
}
@ -102,6 +104,7 @@ type containerConfig struct {
resolvConfPathConfig
generic map[string]interface{}
useDefaultSandBox bool
useExternalKey bool
prio int // higher the value, more the priority
}
@ -241,8 +244,14 @@ func (sb *sandbox) getConnectedEndpoints() []*endpoint {
}
func (sb *sandbox) updateGateway(ep *endpoint) error {
sb.osSbox.UnsetGateway()
sb.osSbox.UnsetGatewayIPv6()
sb.Lock()
osSbox := sb.osSbox
sb.Unlock()
if osSbox == nil {
return nil
}
osSbox.UnsetGateway()
osSbox.UnsetGatewayIPv6()
if ep == nil {
return nil
@ -252,18 +261,60 @@ func (sb *sandbox) updateGateway(ep *endpoint) error {
joinInfo := ep.joinInfo
ep.Unlock()
if err := sb.osSbox.SetGateway(joinInfo.gw); err != nil {
if err := 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 {
if err := osSbox.SetGatewayIPv6(joinInfo.gw6); err != nil {
return fmt.Errorf("failed to set IPv6 gateway while updating gateway: %v", err)
}
return nil
}
func (sb *sandbox) SetKey(basePath string) error {
var err error
if basePath == "" {
return types.BadRequestErrorf("invalid sandbox key")
}
sb.Lock()
if sb.osSbox != nil {
sb.Unlock()
return types.ForbiddenErrorf("failed to set sandbox key : already assigned")
}
sb.Unlock()
osSbox, err := osl.GetSandboxForExternalKey(basePath, sb.Key())
if err != nil {
return err
}
sb.Lock()
sb.osSbox = osSbox
sb.Unlock()
defer func() {
if err != nil {
sb.Lock()
sb.osSbox = nil
sb.Unlock()
}
}()
for _, ep := range sb.getConnectedEndpoints() {
if err = sb.populateNetworkResources(ep); err != nil {
return err
}
}
return nil
}
func (sb *sandbox) populateNetworkResources(ep *endpoint) error {
sb.Lock()
if sb.osSbox == nil {
sb.Unlock()
return nil
}
sb.Unlock()
ep.Lock()
joinInfo := ep.joinInfo
ifaces := ep.iFaces
@ -292,7 +343,6 @@ func (sb *sandbox) populateNetworkResources(ep *endpoint) error {
}
sb.Lock()
heap.Push(&sb.endpoints, ep)
highEp := sb.endpoints[0]
sb.Unlock()
if ep == highEp {
@ -305,24 +355,28 @@ func (sb *sandbox) populateNetworkResources(ep *endpoint) error {
}
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)
sb.Lock()
osSbox := sb.osSbox
sb.Unlock()
if osSbox != nil {
for _, i := range 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()
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)
// Remove non-interface routes.
for _, r := range joinInfo.StaticRoutes {
if err := osSbox.RemoveStaticRoute(r); err != nil {
log.Debugf("Remove route failed: %v", err)
}
}
}
@ -670,6 +724,14 @@ func OptionUseDefaultSandbox() SandboxOption {
}
}
// OptionUseExternalKey function returns an option setter for using provided namespace
// instead of creating one.
func OptionUseExternalKey() SandboxOption {
return func(sb *sandbox) {
sb.config.useExternalKey = 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.