github.com/rawahars/moby@v24.0.4+incompatible/daemon/delete.go (about) 1 package daemon // import "github.com/docker/docker/daemon" 2 3 import ( 4 "context" 5 "fmt" 6 "os" 7 "path" 8 "strings" 9 "time" 10 11 "github.com/containerd/containerd/leases" 12 "github.com/docker/docker/api/types" 13 containertypes "github.com/docker/docker/api/types/container" 14 "github.com/docker/docker/container" 15 "github.com/docker/docker/errdefs" 16 "github.com/docker/docker/pkg/containerfs" 17 "github.com/opencontainers/selinux/go-selinux" 18 "github.com/pkg/errors" 19 "github.com/sirupsen/logrus" 20 ) 21 22 // ContainerRm removes the container id from the filesystem. An error 23 // is returned if the container is not found, or if the remove 24 // fails. If the remove succeeds, the container name is released, and 25 // network links are removed. 26 func (daemon *Daemon) ContainerRm(name string, config *types.ContainerRmConfig) error { 27 start := time.Now() 28 ctr, err := daemon.GetContainer(name) 29 if err != nil { 30 return err 31 } 32 33 // Container state RemovalInProgress should be used to avoid races. 34 if inProgress := ctr.SetRemovalInProgress(); inProgress { 35 err := fmt.Errorf("removal of container %s is already in progress", name) 36 return errdefs.Conflict(err) 37 } 38 defer ctr.ResetRemovalInProgress() 39 40 // check if container wasn't deregistered by previous rm since Get 41 if c := daemon.containers.Get(ctr.ID); c == nil { 42 return nil 43 } 44 45 if config.RemoveLink { 46 return daemon.rmLink(ctr, name) 47 } 48 49 err = daemon.cleanupContainer(ctr, *config) 50 containerActions.WithValues("delete").UpdateSince(start) 51 52 return err 53 } 54 55 func (daemon *Daemon) rmLink(container *container.Container, name string) error { 56 if name[0] != '/' { 57 name = "/" + name 58 } 59 parent, n := path.Split(name) 60 if parent == "/" { 61 return fmt.Errorf("Conflict, cannot remove the default link name of the container") 62 } 63 64 parent = strings.TrimSuffix(parent, "/") 65 pe, err := daemon.containersReplica.Snapshot().GetID(parent) 66 if err != nil { 67 return fmt.Errorf("Cannot get parent %s for link name %s", parent, name) 68 } 69 70 daemon.releaseName(name) 71 parentContainer, _ := daemon.GetContainer(pe) 72 if parentContainer != nil { 73 daemon.linkIndex.unlink(name, container, parentContainer) 74 if err := daemon.updateNetwork(parentContainer); err != nil { 75 logrus.Debugf("Could not update network to remove link %s: %v", n, err) 76 } 77 } 78 return nil 79 } 80 81 // cleanupContainer unregisters a container from the daemon, stops stats 82 // collection and cleanly removes contents and metadata from the filesystem. 83 func (daemon *Daemon) cleanupContainer(container *container.Container, config types.ContainerRmConfig) error { 84 if container.IsRunning() { 85 if !config.ForceRemove { 86 state := container.StateString() 87 procedure := "Stop the container before attempting removal or force remove" 88 if state == "paused" { 89 procedure = "Unpause and then " + strings.ToLower(procedure) 90 } 91 err := fmt.Errorf("You cannot remove a %s container %s. %s", state, container.ID, procedure) 92 return errdefs.Conflict(err) 93 } 94 if err := daemon.Kill(container); err != nil { 95 return fmt.Errorf("Could not kill running container %s, cannot remove - %v", container.ID, err) 96 } 97 } 98 99 // stop collection of stats for the container regardless 100 // if stats are currently getting collected. 101 daemon.statsCollector.StopCollection(container) 102 103 // stopTimeout is the number of seconds to wait for the container to stop 104 // gracefully before forcibly killing it. 105 // 106 // Why 3 seconds? The timeout specified here was originally added in commit 107 // 1615bb08c7c3fc6c4b22db0a633edda516f97cf0, which added a custom timeout to 108 // some commands, but lacking an option for a timeout on "docker rm", was 109 // hardcoded to 10 seconds. Commit 28fd289b448164b77affd8103c0d96fd8110daf9 110 // later on updated this to 3 seconds (but no background on that change). 111 // 112 // If you arrived here and know the answer, you earned yourself a picture 113 // of a cute animal of your own choosing. 114 var stopTimeout = 3 115 if err := daemon.containerStop(context.TODO(), container, containertypes.StopOptions{Timeout: &stopTimeout}); err != nil { 116 return err 117 } 118 119 // Mark container dead. We don't want anybody to be restarting it. 120 container.Lock() 121 container.Dead = true 122 123 // Save container state to disk. So that if error happens before 124 // container meta file got removed from disk, then a restart of 125 // docker should not make a dead container alive. 126 if err := container.CheckpointTo(daemon.containersReplica); err != nil && !os.IsNotExist(err) { 127 logrus.Errorf("Error saving dying container to disk: %v", err) 128 } 129 container.Unlock() 130 131 // When container creation fails and `RWLayer` has not been created yet, we 132 // do not call `ReleaseRWLayer` 133 if container.RWLayer != nil { 134 if err := daemon.imageService.ReleaseLayer(container.RWLayer); err != nil { 135 err = errors.Wrapf(err, "container %s", container.ID) 136 container.SetRemovalError(err) 137 return err 138 } 139 container.RWLayer = nil 140 } else { 141 if daemon.UsesSnapshotter() { 142 ls := daemon.containerdCli.LeasesService() 143 lease := leases.Lease{ 144 ID: container.ID, 145 } 146 if err := ls.Delete(context.Background(), lease, leases.SynchronousDelete); err != nil { 147 container.SetRemovalError(err) 148 return err 149 } 150 } 151 } 152 153 // Hold the container lock while deleting the container root directory 154 // so that other goroutines don't attempt to concurrently open files 155 // within it. Having any file open on Windows (without the 156 // FILE_SHARE_DELETE flag) will block it from being deleted. 157 container.Lock() 158 err := containerfs.EnsureRemoveAll(container.Root) 159 container.Unlock() 160 if err != nil { 161 err = errors.Wrapf(err, "unable to remove filesystem for %s", container.ID) 162 container.SetRemovalError(err) 163 return err 164 } 165 166 linkNames := daemon.linkIndex.delete(container) 167 selinux.ReleaseLabel(container.ProcessLabel) 168 daemon.containers.Delete(container.ID) 169 daemon.containersReplica.Delete(container) 170 if err := daemon.removeMountPoints(container, config.RemoveVolume); err != nil { 171 logrus.Error(err) 172 } 173 for _, name := range linkNames { 174 daemon.releaseName(name) 175 } 176 container.SetRemoved() 177 stateCtr.del(container.ID) 178 179 daemon.LogContainerEvent(container, "destroy") 180 return nil 181 }