github.com/mforkel/docker-ce-i386@v17.12.1-ce-rc2+incompatible/components/engine/daemon/delete.go (about) 1 package daemon 2 3 import ( 4 "fmt" 5 "os" 6 "path" 7 "strings" 8 "time" 9 10 "github.com/docker/docker/api/types" 11 "github.com/docker/docker/container" 12 "github.com/docker/docker/layer" 13 "github.com/docker/docker/pkg/system" 14 "github.com/docker/docker/volume" 15 volumestore "github.com/docker/docker/volume/store" 16 "github.com/pkg/errors" 17 "github.com/sirupsen/logrus" 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 stateConflictError{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.containersReplica.Snapshot().GetID(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 stateConflictError{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.Lock() 107 container.Dead = true 108 109 // Save container state to disk. So that if error happens before 110 // container meta file got removed from disk, then a restart of 111 // docker should not make a dead container alive. 112 if err := container.CheckpointTo(daemon.containersReplica); err != nil && !os.IsNotExist(err) { 113 logrus.Errorf("Error saving dying container to disk: %v", err) 114 } 115 container.Unlock() 116 117 // When container creation fails and `RWLayer` has not been created yet, we 118 // do not call `ReleaseRWLayer` 119 if container.RWLayer != nil { 120 metadata, err := daemon.stores[container.OS].layerStore.ReleaseRWLayer(container.RWLayer) 121 layer.LogReleaseMetadata(metadata) 122 if err != nil && err != layer.ErrMountDoesNotExist && !os.IsNotExist(errors.Cause(err)) { 123 e := errors.Wrapf(err, "driver %q failed to remove root filesystem for %s", daemon.GraphDriverName(container.OS), container.ID) 124 container.SetRemovalError(e) 125 return e 126 } 127 container.RWLayer = nil 128 } 129 130 if err := system.EnsureRemoveAll(container.Root); err != nil { 131 e := errors.Wrapf(err, "unable to remove filesystem for %s", container.ID) 132 container.SetRemovalError(e) 133 return e 134 } 135 136 linkNames := daemon.linkIndex.delete(container) 137 selinuxFreeLxcContexts(container.ProcessLabel) 138 daemon.idIndex.Delete(container.ID) 139 daemon.containers.Delete(container.ID) 140 daemon.containersReplica.Delete(container) 141 if e := daemon.removeMountPoints(container, removeVolume); e != nil { 142 logrus.Error(e) 143 } 144 for _, name := range linkNames { 145 daemon.releaseName(name) 146 } 147 container.SetRemoved() 148 stateCtr.del(container.ID) 149 150 daemon.LogContainerEvent(container, "destroy") 151 return nil 152 } 153 154 // VolumeRm removes the volume with the given name. 155 // If the volume is referenced by a container it is not removed 156 // This is called directly from the Engine API 157 func (daemon *Daemon) VolumeRm(name string, force bool) error { 158 v, err := daemon.volumes.Get(name) 159 if err != nil { 160 if force && volumestore.IsNotExist(err) { 161 return nil 162 } 163 return err 164 } 165 166 err = daemon.volumeRm(v) 167 if err != nil && volumestore.IsInUse(err) { 168 return stateConflictError{err} 169 } 170 171 if err == nil || force { 172 daemon.volumes.Purge(name) 173 return nil 174 } 175 return err 176 } 177 178 func (daemon *Daemon) volumeRm(v volume.Volume) error { 179 if err := daemon.volumes.Remove(v); err != nil { 180 return errors.Wrap(err, "unable to remove volume") 181 } 182 daemon.LogVolumeEvent(v.Name(), "destroy", map[string]string{"driver": v.DriverName()}) 183 return nil 184 }