|
@@ -63,8 +63,15 @@ func (daemon *Daemon) ContainerRm(job *engine.Job) error {
|
|
|
return fmt.Errorf("Conflict, You cannot remove a running container. Stop the container before attempting removal or use -f")
|
|
|
}
|
|
|
}
|
|
|
- if err := daemon.Rm(container); err != nil {
|
|
|
- return fmt.Errorf("Cannot destroy container %s: %s", name, err)
|
|
|
+
|
|
|
+ if forceRemove {
|
|
|
+ if err := daemon.ForceRm(container); err != nil {
|
|
|
+ logrus.Errorf("Cannot destroy container %s: %v", name, err)
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if err := daemon.Rm(container); err != nil {
|
|
|
+ return fmt.Errorf("Cannot destroy container %s: %v", name, err)
|
|
|
+ }
|
|
|
}
|
|
|
container.LogEvent("destroy")
|
|
|
if removeVolume {
|
|
@@ -83,8 +90,16 @@ func (daemon *Daemon) DeleteVolumes(volumeIDs map[string]struct{}) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+func (daemon *Daemon) Rm(container *Container) (err error) {
|
|
|
+ return daemon.commonRm(container, false)
|
|
|
+}
|
|
|
+
|
|
|
+func (daemon *Daemon) ForceRm(container *Container) (err error) {
|
|
|
+ return daemon.commonRm(container, true)
|
|
|
+}
|
|
|
+
|
|
|
// Destroy unregisters a container from the daemon and cleanly removes its contents from the filesystem.
|
|
|
-func (daemon *Daemon) Rm(container *Container) error {
|
|
|
+func (daemon *Daemon) commonRm(container *Container, forceRemove bool) (err error) {
|
|
|
if container == nil {
|
|
|
return fmt.Errorf("The given container is <nil>")
|
|
|
}
|
|
@@ -94,19 +109,40 @@ func (daemon *Daemon) Rm(container *Container) error {
|
|
|
return fmt.Errorf("Container %v not found - maybe it was already destroyed?", container.ID)
|
|
|
}
|
|
|
|
|
|
- if err := container.Stop(3); err != nil {
|
|
|
+ // Container state RemovalInProgress should be used to avoid races.
|
|
|
+ if err = container.SetRemovalInProgress(); err != nil {
|
|
|
+ return fmt.Errorf("Failed to set container state to RemovalInProgress: %s", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ defer container.ResetRemovalInProgress()
|
|
|
+
|
|
|
+ if err = container.Stop(3); err != nil {
|
|
|
return err
|
|
|
}
|
|
|
|
|
|
- // Deregister the container before removing its directory, to avoid race conditions
|
|
|
- daemon.idIndex.Delete(container.ID)
|
|
|
- daemon.containers.Delete(container.ID)
|
|
|
+ // Mark container dead. We don't want anybody to be restarting it.
|
|
|
+ container.SetDead()
|
|
|
+
|
|
|
+ // Save container state to disk. So that if error happens before
|
|
|
+ // container meta file got removed from disk, then a restart of
|
|
|
+ // docker should not make a dead container alive.
|
|
|
+ container.ToDisk()
|
|
|
+
|
|
|
+ // If force removal is required, delete container from various
|
|
|
+ // indexes even if removal failed.
|
|
|
+ defer func() {
|
|
|
+ if err != nil && forceRemove {
|
|
|
+ daemon.idIndex.Delete(container.ID)
|
|
|
+ daemon.containers.Delete(container.ID)
|
|
|
+ }
|
|
|
+ }()
|
|
|
+
|
|
|
container.derefVolumes()
|
|
|
if _, err := daemon.containerGraph.Purge(container.ID); err != nil {
|
|
|
logrus.Debugf("Unable to remove container from link graph: %s", err)
|
|
|
}
|
|
|
|
|
|
- if err := daemon.driver.Remove(container.ID); err != nil {
|
|
|
+ if err = daemon.driver.Remove(container.ID); err != nil {
|
|
|
return fmt.Errorf("Driver %s failed to remove root filesystem %s: %s", daemon.driver, container.ID, err)
|
|
|
}
|
|
|
|
|
@@ -115,15 +151,17 @@ func (daemon *Daemon) Rm(container *Container) error {
|
|
|
return fmt.Errorf("Driver %s failed to remove init filesystem %s: %s", daemon.driver, initID, err)
|
|
|
}
|
|
|
|
|
|
- if err := os.RemoveAll(container.root); err != nil {
|
|
|
+ if err = os.RemoveAll(container.root); err != nil {
|
|
|
return fmt.Errorf("Unable to remove filesystem for %v: %v", container.ID, err)
|
|
|
}
|
|
|
|
|
|
- if err := daemon.execDriver.Clean(container.ID); err != nil {
|
|
|
+ if err = daemon.execDriver.Clean(container.ID); err != nil {
|
|
|
return fmt.Errorf("Unable to remove execdriver data for %s: %s", container.ID, err)
|
|
|
}
|
|
|
|
|
|
selinuxFreeLxcContexts(container.ProcessLabel)
|
|
|
+ daemon.idIndex.Delete(container.ID)
|
|
|
+ daemon.containers.Delete(container.ID)
|
|
|
|
|
|
return nil
|
|
|
}
|