github.com/openshift/moby-moby@v1.13.2-0.20170601211448-f5ec1e2936dc/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 apierrors "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 "github.com/pkg/errors" 17 ) 18 19 // ContainerRm removes the container id from the filesystem. An error 20 // is returned if the container is not found, or if the remove 21 // fails. If the remove succeeds, the container name is released, and 22 // network links are removed. 23 func (daemon *Daemon) ContainerRm(name string, config *types.ContainerRmConfig) error { 24 start := time.Now() 25 container, err := daemon.GetContainer(name) 26 if err != nil { 27 return err 28 } 29 30 // Container state RemovalInProgress should be used to avoid races. 31 if inProgress := container.SetRemovalInProgress(); inProgress { 32 err := fmt.Errorf("removal of container %s is already in progress", name) 33 return apierrors.NewBadRequestError(err) 34 } 35 defer container.ResetRemovalInProgress() 36 37 // check if container wasn't deregistered by previous rm since Get 38 if c := daemon.containers.Get(container.ID); c == nil { 39 return nil 40 } 41 42 if config.RemoveLink { 43 return daemon.rmLink(container, name) 44 } 45 46 err = daemon.cleanupContainer(container, config.ForceRemove, config.RemoveVolume) 47 containerActions.WithValues("delete").UpdateSince(start) 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, removeVolume 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 apierrors.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 && !os.IsNotExist(err) { 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 if e := daemon.removeMountPoints(container, removeVolume); e != nil { 119 logrus.Error(e) 120 } 121 daemon.LogContainerEvent(container, "destroy") 122 } 123 }() 124 125 if err = os.RemoveAll(container.Root); err != nil { 126 return fmt.Errorf("Unable to remove filesystem for %v: %v", container.ID, err) 127 } 128 129 // When container creation fails and `RWLayer` has not been created yet, we 130 // do not call `ReleaseRWLayer` 131 if container.RWLayer != nil { 132 metadata, err := daemon.layerStore.ReleaseRWLayer(container.RWLayer) 133 layer.LogReleaseMetadata(metadata) 134 if err != nil && err != layer.ErrMountDoesNotExist { 135 return fmt.Errorf("Driver %s failed to remove root filesystem %s: %s", daemon.GraphDriverName(), container.ID, err) 136 } 137 } 138 139 return nil 140 } 141 142 // VolumeRm removes the volume with the given name. 143 // If the volume is referenced by a container it is not removed 144 // This is called directly from the Engine API 145 func (daemon *Daemon) VolumeRm(name string, force bool) error { 146 err := daemon.volumeRm(name) 147 if err != nil && volumestore.IsInUse(err) { 148 return apierrors.NewRequestConflictError(err) 149 } 150 if err == nil || force { 151 daemon.volumes.Purge(name) 152 return nil 153 } 154 return err 155 } 156 157 func (daemon *Daemon) volumeRm(name string) error { 158 v, err := daemon.volumes.Get(name) 159 if err != nil { 160 return err 161 } 162 163 if err := daemon.volumes.Remove(v); err != nil { 164 return errors.Wrap(err, "unable to remove volume") 165 } 166 daemon.LogVolumeEvent(v.Name(), "destroy", map[string]string{"driver": v.DriverName()}) 167 return nil 168 }