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, }