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