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