|
@@ -66,6 +66,7 @@ type sandbox struct {
|
|
|
joinLeaveDone chan struct{}
|
|
|
dbIndex uint64
|
|
|
dbExists bool
|
|
|
+ inDelete bool
|
|
|
sync.Mutex
|
|
|
}
|
|
|
|
|
@@ -146,6 +147,22 @@ func (sb *sandbox) Statistics() (map[string]*types.InterfaceStatistics, error) {
|
|
|
}
|
|
|
|
|
|
func (sb *sandbox) Delete() error {
|
|
|
+ sb.Lock()
|
|
|
+ if sb.inDelete {
|
|
|
+ sb.Unlock()
|
|
|
+ return types.ForbiddenErrorf("another sandbox delete in progress")
|
|
|
+ }
|
|
|
+ // Set the inDelete flag. This will ensure that we don't
|
|
|
+ // update the store until we have completed all the endpoint
|
|
|
+ // leaves and deletes. And when endpoint leaves and deletes
|
|
|
+ // are completed then we can finally delete the sandbox object
|
|
|
+ // altogether from the data store. If the daemon exits
|
|
|
+ // ungracefully in the middle of a sandbox delete this way we
|
|
|
+ // will have all the references to the endpoints in the
|
|
|
+ // sandbox so that we can clean them up when we restart
|
|
|
+ sb.inDelete = true
|
|
|
+ sb.Unlock()
|
|
|
+
|
|
|
c := sb.controller
|
|
|
|
|
|
// Detach from all endpoints
|
|
@@ -355,6 +372,10 @@ func releaseOSSboxResources(osSbox osl.Sandbox, ep *endpoint) {
|
|
|
joinInfo := ep.joinInfo
|
|
|
ep.Unlock()
|
|
|
|
|
|
+ if joinInfo == nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
// Remove non-interface routes.
|
|
|
for _, r := range joinInfo.StaticRoutes {
|
|
|
if err := osSbox.RemoveStaticRoute(r); err != nil {
|
|
@@ -386,6 +407,7 @@ func (sb *sandbox) populateNetworkResources(ep *endpoint) error {
|
|
|
sb.Unlock()
|
|
|
return nil
|
|
|
}
|
|
|
+ inDelete := sb.inDelete
|
|
|
sb.Unlock()
|
|
|
|
|
|
ep.Lock()
|
|
@@ -425,7 +447,16 @@ func (sb *sandbox) populateNetworkResources(ep *endpoint) error {
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- return sb.storeUpdate()
|
|
|
+
|
|
|
+ // Only update the store if we did not come here as part of
|
|
|
+ // sandbox delete. If we came here as part of delete then do
|
|
|
+ // not bother updating the store. The sandbox object will be
|
|
|
+ // deleted anyway
|
|
|
+ if !inDelete {
|
|
|
+ return sb.storeUpdate()
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
}
|
|
|
|
|
|
func (sb *sandbox) clearNetworkResources(origEp *endpoint) error {
|
|
@@ -437,6 +468,7 @@ func (sb *sandbox) clearNetworkResources(origEp *endpoint) error {
|
|
|
|
|
|
sb.Lock()
|
|
|
osSbox := sb.osSbox
|
|
|
+ inDelete := sb.inDelete
|
|
|
sb.Unlock()
|
|
|
if osSbox != nil {
|
|
|
releaseOSSboxResources(osSbox, ep)
|
|
@@ -480,7 +512,15 @@ func (sb *sandbox) clearNetworkResources(origEp *endpoint) error {
|
|
|
sb.updateGateway(gwepAfter)
|
|
|
}
|
|
|
|
|
|
- return sb.storeUpdate()
|
|
|
+ // Only update the store if we did not come here as part of
|
|
|
+ // sandbox delete. If we came here as part of delete then do
|
|
|
+ // not bother updating the store. The sandbox object will be
|
|
|
+ // deleted anyway
|
|
|
+ if !inDelete {
|
|
|
+ return sb.storeUpdate()
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
}
|
|
|
|
|
|
const (
|