Merge pull request #502 from mavenugo/sbox_uns
Support to provide external key to sandbox
This commit is contained in:
commit
0e00550af4
|
@ -249,6 +249,9 @@ func (sc *sandboxCreate) parseOptions() []libnetwork.SandboxOption {
|
||||||
if sc.UseDefaultSandbox {
|
if sc.UseDefaultSandbox {
|
||||||
setFctList = append(setFctList, libnetwork.OptionUseDefaultSandbox())
|
setFctList = append(setFctList, libnetwork.OptionUseDefaultSandbox())
|
||||||
}
|
}
|
||||||
|
if sc.UseExternalKey {
|
||||||
|
setFctList = append(setFctList, libnetwork.OptionUseExternalKey())
|
||||||
|
}
|
||||||
if sc.DNS != nil {
|
if sc.DNS != nil {
|
||||||
for _, d := range sc.DNS {
|
for _, d := range sc.DNS {
|
||||||
setFctList = append(setFctList, libnetwork.OptionDNS(d))
|
setFctList = append(setFctList, libnetwork.OptionDNS(d))
|
||||||
|
|
|
@ -57,6 +57,7 @@ type sandboxCreate struct {
|
||||||
DNS []string `json:"dns"`
|
DNS []string `json:"dns"`
|
||||||
ExtraHosts []extraHost `json:"extra_hosts"`
|
ExtraHosts []extraHost `json:"extra_hosts"`
|
||||||
UseDefaultSandbox bool `json:"use_default_sandbox"`
|
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
|
// endpointJoin represents the expected body of the "join endpoint" or "leave endpoint" http request messages
|
||||||
|
|
|
@ -414,7 +414,7 @@ func (c *controller) NewSandbox(containerID string, options ...SandboxOption) (S
|
||||||
return nil, err
|
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 {
|
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)
|
return nil, fmt.Errorf("failed to create new osl sandbox: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package libnetwork
|
package libnetwork
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"container/heap"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
@ -289,10 +290,25 @@ func (ep *endpoint) Join(sbox Sandbox, options ...EndpointOption) error {
|
||||||
return err
|
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 {
|
if err = sb.populateNetworkResources(ep); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1188,6 +1188,117 @@ func (f *fakeSandbox) Delete() error {
|
||||||
return nil
|
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) {
|
func TestEndpointDeleteWithActiveContainer(t *testing.T) {
|
||||||
if !testutils.IsRunningInContainer() {
|
if !testutils.IsRunningInContainer() {
|
||||||
defer testutils.SetupTestOSContext(t)()
|
defer testutils.SetupTestOSContext(t)()
|
||||||
|
|
|
@ -157,16 +157,38 @@ func (n *networkNamespace) NeighborOptions() NeighborOptionSetter {
|
||||||
return n
|
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() {
|
func reexecCreateNamespace() {
|
||||||
if len(os.Args) < 2 {
|
if len(os.Args) < 2 {
|
||||||
log.Fatal("no namespace path provided")
|
log.Fatal("no namespace path provided")
|
||||||
}
|
}
|
||||||
|
if err := mountNetworkNamespace("/proc/self/ns/net", os.Args[1]); err != nil {
|
||||||
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 {
|
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,3 +6,7 @@ package osl
|
||||||
// and waits for it.
|
// and waits for it.
|
||||||
func GC() {
|
func GC() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetSandboxForExternalKey(path string, key string) (Sandbox, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
|
@ -19,6 +19,10 @@ func NewSandbox(key string, osCreate bool) (Sandbox, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetSandboxForExternalKey(path string, key string) (Sandbox, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
// GC triggers garbage collection of namespace path right away
|
// GC triggers garbage collection of namespace path right away
|
||||||
// and waits for it.
|
// and waits for it.
|
||||||
func GC() {
|
func GC() {
|
||||||
|
|
|
@ -32,6 +32,8 @@ type Sandbox interface {
|
||||||
// Refresh leaves all the endpoints, resets and re-apply the options,
|
// Refresh leaves all the endpoints, resets and re-apply the options,
|
||||||
// re-joins all the endpoints without destroying the osl sandbox
|
// re-joins all the endpoints without destroying the osl sandbox
|
||||||
Refresh(options ...SandboxOption) error
|
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 destroys this container after detaching it from all connected endpoints.
|
||||||
Delete() error
|
Delete() error
|
||||||
}
|
}
|
||||||
|
@ -102,6 +104,7 @@ type containerConfig struct {
|
||||||
resolvConfPathConfig
|
resolvConfPathConfig
|
||||||
generic map[string]interface{}
|
generic map[string]interface{}
|
||||||
useDefaultSandBox bool
|
useDefaultSandBox bool
|
||||||
|
useExternalKey bool
|
||||||
prio int // higher the value, more the priority
|
prio int // higher the value, more the priority
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,8 +244,14 @@ func (sb *sandbox) getConnectedEndpoints() []*endpoint {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sb *sandbox) updateGateway(ep *endpoint) error {
|
func (sb *sandbox) updateGateway(ep *endpoint) error {
|
||||||
sb.osSbox.UnsetGateway()
|
sb.Lock()
|
||||||
sb.osSbox.UnsetGatewayIPv6()
|
osSbox := sb.osSbox
|
||||||
|
sb.Unlock()
|
||||||
|
if osSbox == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
osSbox.UnsetGateway()
|
||||||
|
osSbox.UnsetGatewayIPv6()
|
||||||
|
|
||||||
if ep == nil {
|
if ep == nil {
|
||||||
return nil
|
return nil
|
||||||
|
@ -252,18 +261,60 @@ func (sb *sandbox) updateGateway(ep *endpoint) error {
|
||||||
joinInfo := ep.joinInfo
|
joinInfo := ep.joinInfo
|
||||||
ep.Unlock()
|
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)
|
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 fmt.Errorf("failed to set IPv6 gateway while updating gateway: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
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 {
|
func (sb *sandbox) populateNetworkResources(ep *endpoint) error {
|
||||||
|
sb.Lock()
|
||||||
|
if sb.osSbox == nil {
|
||||||
|
sb.Unlock()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
sb.Unlock()
|
||||||
|
|
||||||
ep.Lock()
|
ep.Lock()
|
||||||
joinInfo := ep.joinInfo
|
joinInfo := ep.joinInfo
|
||||||
ifaces := ep.iFaces
|
ifaces := ep.iFaces
|
||||||
|
@ -292,7 +343,6 @@ func (sb *sandbox) populateNetworkResources(ep *endpoint) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
sb.Lock()
|
sb.Lock()
|
||||||
heap.Push(&sb.endpoints, ep)
|
|
||||||
highEp := sb.endpoints[0]
|
highEp := sb.endpoints[0]
|
||||||
sb.Unlock()
|
sb.Unlock()
|
||||||
if ep == highEp {
|
if ep == highEp {
|
||||||
|
@ -305,24 +355,28 @@ func (sb *sandbox) populateNetworkResources(ep *endpoint) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sb *sandbox) clearNetworkResources(ep *endpoint) error {
|
func (sb *sandbox) clearNetworkResources(ep *endpoint) error {
|
||||||
|
sb.Lock()
|
||||||
for _, i := range sb.osSbox.Info().Interfaces() {
|
osSbox := sb.osSbox
|
||||||
// Only remove the interfaces owned by this endpoint from the sandbox.
|
sb.Unlock()
|
||||||
if ep.hasInterface(i.SrcName()) {
|
if osSbox != nil {
|
||||||
if err := i.Remove(); err != nil {
|
for _, i := range osSbox.Info().Interfaces() {
|
||||||
log.Debugf("Remove interface failed: %v", err)
|
// 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()
|
ep.Lock()
|
||||||
joinInfo := ep.joinInfo
|
joinInfo := ep.joinInfo
|
||||||
ep.Unlock()
|
ep.Unlock()
|
||||||
|
|
||||||
// Remove non-interface routes.
|
// Remove non-interface routes.
|
||||||
for _, r := range joinInfo.StaticRoutes {
|
for _, r := range joinInfo.StaticRoutes {
|
||||||
if err := sb.osSbox.RemoveStaticRoute(r); err != nil {
|
if err := osSbox.RemoveStaticRoute(r); err != nil {
|
||||||
log.Debugf("Remove route failed: %v", err)
|
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
|
// 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
|
// 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.
|
// net container creation method. Container Labels are a good example.
|
||||||
|
|
Loading…
Reference in New Issue