mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Support to provide external key to sandbox
Signed-off-by: Madhu Venugopal <madhu@docker.com>
This commit is contained in:
parent
aad77d46dd
commit
f59502e1bd
9 changed files with 250 additions and 27 deletions
|
@ -245,6 +245,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))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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 !netutils.IsRunningInContainer() {
|
||||
defer osl.SetupTestOSContext(t)()
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,3 +6,7 @@ package osl
|
|||
// and waits for it.
|
||||
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
|
||||
}
|
||||
|
||||
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() {
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in a new issue