moby/daemon/delete.go
Tibor Vass b08f071e18 Revert "Merge pull request #16228 from duglin/ContextualizeEvents"
Although having a request ID available throughout the codebase is very
valuable, the impact of requiring a Context as an argument to every
function in the codepath of an API request, is too significant and was
not properly understood at the time of the review.

Furthermore, mixing API-layer code with non-API-layer code makes the
latter usable only by API-layer code (one that has a notion of Context).

This reverts commit de41640435, reversing
changes made to 7daeecd42d.

Signed-off-by: Tibor Vass <tibor@docker.com>

Conflicts:
	api/server/container.go
	builder/internals.go
	daemon/container_unix.go
	daemon/create.go
2015-09-29 14:26:51 -04:00

164 lines
4.5 KiB
Go

package daemon
import (
"fmt"
"os"
"path"
"github.com/Sirupsen/logrus"
derr "github.com/docker/docker/errors"
"github.com/docker/docker/volume/store"
)
// ContainerRmConfig is a holder for passing in runtime config.
type ContainerRmConfig struct {
ForceRemove, RemoveVolume, RemoveLink bool
}
// ContainerRm removes the container id from the filesystem. An error
// is returned if the container is not found, or if the remove
// fails. If the remove succeeds, the container name is released, and
// network links are removed.
func (daemon *Daemon) ContainerRm(name string, config *ContainerRmConfig) error {
container, err := daemon.Get(name)
if err != nil {
return err
}
if config.RemoveLink {
name, err := GetFullContainerName(name)
if err != nil {
return err
}
parent, n := path.Split(name)
if parent == "/" {
return derr.ErrorCodeDefaultName
}
pe := daemon.containerGraph().Get(parent)
if pe == nil {
return derr.ErrorCodeNoParent.WithArgs(parent, name)
}
if err := daemon.containerGraph().Delete(name); err != nil {
return err
}
parentContainer, _ := daemon.Get(pe.ID())
if parentContainer != nil {
if err := parentContainer.updateNetwork(); err != nil {
logrus.Debugf("Could not update network to remove link %s: %v", n, err)
}
}
return nil
}
if err := daemon.rm(container, config.ForceRemove); err != nil {
// return derr.ErrorCodeCantDestroy.WithArgs(name, utils.GetErrorMessage(err))
return err
}
if err := container.removeMountPoints(config.RemoveVolume); err != nil {
logrus.Error(err)
}
return nil
}
// Destroy unregisters a container from the daemon and cleanly removes its contents from the filesystem.
func (daemon *Daemon) rm(container *Container, forceRemove bool) (err error) {
if container.IsRunning() {
if !forceRemove {
return derr.ErrorCodeRmRunning
}
if err := container.Kill(); err != nil {
return derr.ErrorCodeRmFailed.WithArgs(err)
}
}
// stop collection of stats for the container regardless
// if stats are currently getting collected.
daemon.statsCollector.stopCollection(container)
element := daemon.containers.Get(container.ID)
if element == nil {
return derr.ErrorCodeRmNotFound.WithArgs(container.ID)
}
// Container state RemovalInProgress should be used to avoid races.
if err = container.setRemovalInProgress(); err != nil {
return derr.ErrorCodeRmState.WithArgs(err)
}
defer container.resetRemovalInProgress()
if err = container.Stop(3); err != nil {
return err
}
// 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.
if err := container.toDiskLocking(); err != nil {
logrus.Errorf("Error saving dying container to disk: %v", err)
}
// 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)
os.RemoveAll(container.root)
container.logEvent("destroy")
}
}()
if _, err := daemon.containerGraphDB.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 {
return derr.ErrorCodeRmDriverFS.WithArgs(daemon.driver, container.ID, err)
}
initID := fmt.Sprintf("%s-init", container.ID)
if err := daemon.driver.Remove(initID); err != nil {
return derr.ErrorCodeRmInit.WithArgs(daemon.driver, initID, err)
}
if err = os.RemoveAll(container.root); err != nil {
return derr.ErrorCodeRmFS.WithArgs(container.ID, err)
}
if err = daemon.execDriver.Clean(container.ID); err != nil {
return derr.ErrorCodeRmExecDriver.WithArgs(container.ID, err)
}
selinuxFreeLxcContexts(container.ProcessLabel)
daemon.idIndex.Delete(container.ID)
daemon.containers.Delete(container.ID)
container.logEvent("destroy")
return nil
}
// VolumeRm removes the volume with the given name.
// If the volume is referenced by a container it is not removed
// This is called directly from the remote API
func (daemon *Daemon) VolumeRm(name string) error {
v, err := daemon.volumes.Get(name)
if err != nil {
return err
}
if err := daemon.volumes.Remove(v); err != nil {
if err == store.ErrVolumeInUse {
return derr.ErrorCodeRmVolumeInUse.WithArgs(err)
}
return derr.ErrorCodeRmVolume.WithArgs(name, err)
}
return nil
}