github.com/akerouanton/docker@v1.11.0-rc3/daemon/delete.go (about) 1 package daemon 2 3 import ( 4 "fmt" 5 "os" 6 "path" 7 "strings" 8 9 "github.com/Sirupsen/logrus" 10 "github.com/docker/docker/container" 11 "github.com/docker/docker/errors" 12 "github.com/docker/docker/layer" 13 volumestore "github.com/docker/docker/volume/store" 14 "github.com/docker/engine-api/types" 15 ) 16 17 // ContainerRm removes the container id from the filesystem. An error 18 // is returned if the container is not found, or if the remove 19 // fails. If the remove succeeds, the container name is released, and 20 // network links are removed. 21 func (daemon *Daemon) ContainerRm(name string, config *types.ContainerRmConfig) error { 22 container, err := daemon.GetContainer(name) 23 if err != nil { 24 return err 25 } 26 27 // Container state RemovalInProgress should be used to avoid races. 28 if inProgress := container.SetRemovalInProgress(); inProgress { 29 return nil 30 } 31 defer container.ResetRemovalInProgress() 32 33 // check if container wasn't deregistered by previous rm since Get 34 if c := daemon.containers.Get(container.ID); c == nil { 35 return nil 36 } 37 38 if config.RemoveLink { 39 return daemon.rmLink(container, name) 40 } 41 42 err = daemon.cleanupContainer(container, config.ForceRemove) 43 if err == nil || config.ForceRemove { 44 if e := daemon.removeMountPoints(container, config.RemoveVolume); e != nil { 45 logrus.Error(e) 46 } 47 } 48 49 return err 50 } 51 52 func (daemon *Daemon) rmLink(container *container.Container, name string) error { 53 if name[0] != '/' { 54 name = "/" + name 55 } 56 parent, n := path.Split(name) 57 if parent == "/" { 58 return fmt.Errorf("Conflict, cannot remove the default name of the container") 59 } 60 61 parent = strings.TrimSuffix(parent, "/") 62 pe, err := daemon.nameIndex.Get(parent) 63 if err != nil { 64 return fmt.Errorf("Cannot get parent %s for name %s", parent, name) 65 } 66 67 daemon.releaseName(name) 68 parentContainer, _ := daemon.GetContainer(pe) 69 if parentContainer != nil { 70 daemon.linkIndex.unlink(name, container, parentContainer) 71 if err := daemon.updateNetwork(parentContainer); err != nil { 72 logrus.Debugf("Could not update network to remove link %s: %v", n, err) 73 } 74 } 75 return nil 76 } 77 78 // cleanupContainer unregisters a container from the daemon, stops stats 79 // collection and cleanly removes contents and metadata from the filesystem. 80 func (daemon *Daemon) cleanupContainer(container *container.Container, forceRemove bool) (err error) { 81 if container.IsRunning() { 82 if !forceRemove { 83 err := fmt.Errorf("You cannot remove a running container %s. Stop the container before attempting removal or use -f", container.ID) 84 return errors.NewRequestConflictError(err) 85 } 86 if err := daemon.Kill(container); err != nil { 87 return fmt.Errorf("Could not kill running container %s, cannot remove - %v", container.ID, err) 88 } 89 } 90 91 // stop collection of stats for the container regardless 92 // if stats are currently getting collected. 93 daemon.statsCollector.stopCollection(container) 94 95 if err = daemon.containerStop(container, 3); err != nil { 96 return err 97 } 98 99 // Mark container dead. We don't want anybody to be restarting it. 100 container.SetDead() 101 102 // Save container state to disk. So that if error happens before 103 // container meta file got removed from disk, then a restart of 104 // docker should not make a dead container alive. 105 if err := container.ToDiskLocking(); err != nil { 106 logrus.Errorf("Error saving dying container to disk: %v", err) 107 } 108 109 // If force removal is required, delete container from various 110 // indexes even if removal failed. 111 defer func() { 112 if err == nil || forceRemove { 113 daemon.nameIndex.Delete(container.ID) 114 daemon.linkIndex.delete(container) 115 selinuxFreeLxcContexts(container.ProcessLabel) 116 daemon.idIndex.Delete(container.ID) 117 daemon.containers.Delete(container.ID) 118 daemon.LogContainerEvent(container, "destroy") 119 } 120 }() 121 122 if err = os.RemoveAll(container.Root); err != nil { 123 return fmt.Errorf("Unable to remove filesystem for %v: %v", container.ID, err) 124 } 125 126 metadata, err := daemon.layerStore.ReleaseRWLayer(container.RWLayer) 127 layer.LogReleaseMetadata(metadata) 128 if err != nil && err != layer.ErrMountDoesNotExist { 129 return fmt.Errorf("Driver %s failed to remove root filesystem %s: %s", daemon.GraphDriverName(), container.ID, err) 130 } 131 132 return nil 133 } 134 135 // VolumeRm removes the volume with the given name. 136 // If the volume is referenced by a container it is not removed 137 // This is called directly from the remote API 138 func (daemon *Daemon) VolumeRm(name string) error { 139 v, err := daemon.volumes.Get(name) 140 if err != nil { 141 return err 142 } 143 144 if err := daemon.volumes.Remove(v); err != nil { 145 if volumestore.IsInUse(err) { 146 err := fmt.Errorf("Unable to remove volume, volume still in use: %v", err) 147 return errors.NewRequestConflictError(err) 148 } 149 return fmt.Errorf("Error while removing volume %s: %v", name, err) 150 } 151 daemon.LogVolumeEvent(v.Name(), "destroy", map[string]string{"driver": v.DriverName()}) 152 return nil 153 }