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