From 670302e66b25061be8e7317d07c6507a167faecb Mon Sep 17 00:00:00 2001 From: Jana Radhakrishnan Date: Sun, 1 Nov 2015 23:03:26 -0800 Subject: [PATCH] Fix stale sandbox from store problem At times, when checkpointed sandbox from store cannot be cleaned up properly we still retain the sandbox in both the store and in memory. But this sandbox store may not contain important configuration information from docker. So when docker requests a new sandbox, instead of using it as is, reconcile the sandbox state from store with the the configuration information provided by docker. To do this mark the sandbox from store as stub and never reveal it to external searches. When docker requests a new sandbox, update the stub sandbox and clear the stub flag. Signed-off-by: Jana Radhakrishnan --- libnetwork/controller.go | 68 ++++++++++++++++++++++++++++++------- libnetwork/sandbox.go | 1 + libnetwork/sandbox_store.go | 1 + 3 files changed, 58 insertions(+), 12 deletions(-) diff --git a/libnetwork/controller.go b/libnetwork/controller.go index 3e9d8e9f03..a0cb4cb5d2 100644 --- a/libnetwork/controller.go +++ b/libnetwork/controller.go @@ -100,6 +100,9 @@ type NetworkController interface { // SandboxByID returns the Sandbox which has the passed id. If not found, a types.NotFoundError is returned. SandboxByID(id string) (Sandbox, error) + // SandboxDestroy destroys a sandbox given a container ID + SandboxDestroy(id string) error + // Stop network controller Stop() } @@ -478,21 +481,37 @@ func (c *controller) NewSandbox(containerID string, options ...SandboxOption) (S 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) + var sb *sandbox + c.Lock() + for _, s := range c.sandboxes { + if s.containerID == containerID { + // If not a stub, then we already have a complete sandbox. + if !s.isStub { + c.Unlock() + return nil, types.BadRequestErrorf("container %s is already present: %v", containerID, s) + } + + // We already have a stub sandbox from the + // store. Make use of it so that we don't lose + // the endpoints from store but reset the + // isStub flag. + sb = s + sb.isStub = false + break + } } + c.Unlock() // 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, + if sb == nil { + sb = &sandbox{ + id: stringid.GenerateRandomID(), + containerID: containerID, + endpoints: epHeap{}, + epPriority: map[string]int{}, + config: containerConfig{}, + controller: c, + } } heap.Init(&sb.endpoints) @@ -547,6 +566,11 @@ func (c *controller) Sandboxes() []Sandbox { list := make([]Sandbox, 0, len(c.sandboxes)) for _, s := range c.sandboxes { + // Hide stub sandboxes from libnetwork users + if s.isStub { + continue + } + list = append(list, s) } @@ -574,6 +598,26 @@ func (c *controller) SandboxByID(id string) (Sandbox, error) { return s, nil } +// SandboxDestroy destroys a sandbox given a container ID +func (c *controller) SandboxDestroy(id string) error { + var sb *sandbox + c.Lock() + for _, s := range c.sandboxes { + if s.containerID == id { + sb = s + break + } + } + c.Unlock() + + // It is not an error if sandbox is not available + if sb == nil { + return nil + } + + return sb.Delete() +} + // 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 { diff --git a/libnetwork/sandbox.go b/libnetwork/sandbox.go index d6d0ae43a5..41074641dc 100644 --- a/libnetwork/sandbox.go +++ b/libnetwork/sandbox.go @@ -68,6 +68,7 @@ type sandbox struct { joinLeaveDone chan struct{} dbIndex uint64 dbExists bool + isStub bool inDelete bool sync.Mutex } diff --git a/libnetwork/sandbox_store.go b/libnetwork/sandbox_store.go index cd61f696fe..efa33aae60 100644 --- a/libnetwork/sandbox_store.go +++ b/libnetwork/sandbox_store.go @@ -188,6 +188,7 @@ func (c *controller) sandboxCleanup() { endpoints: epHeap{}, epPriority: map[string]int{}, dbIndex: sbs.dbIndex, + isStub: true, dbExists: true, }