delete.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. package daemon
  2. import (
  3. "fmt"
  4. "log"
  5. "os"
  6. "path"
  7. "path/filepath"
  8. "strings"
  9. "github.com/docker/docker/engine"
  10. "github.com/docker/docker/utils"
  11. )
  12. // FIXME: rename to ContainerRemove for consistency with the CLI command.
  13. func (daemon *Daemon) ContainerDestroy(job *engine.Job) engine.Status {
  14. if len(job.Args) != 1 {
  15. return job.Errorf("Not enough arguments. Usage: %s CONTAINER\n", job.Name)
  16. }
  17. name := job.Args[0]
  18. removeVolume := job.GetenvBool("removeVolume")
  19. removeLink := job.GetenvBool("removeLink")
  20. forceRemove := job.GetenvBool("forceRemove")
  21. container := daemon.Get(name)
  22. if removeLink {
  23. if container == nil {
  24. return job.Errorf("No such link: %s", name)
  25. }
  26. name, err := GetFullContainerName(name)
  27. if err != nil {
  28. job.Error(err)
  29. }
  30. parent, n := path.Split(name)
  31. if parent == "/" {
  32. return job.Errorf("Conflict, cannot remove the default name of the container")
  33. }
  34. pe := daemon.ContainerGraph().Get(parent)
  35. if pe == nil {
  36. return job.Errorf("Cannot get parent %s for name %s", parent, name)
  37. }
  38. parentContainer := daemon.Get(pe.ID())
  39. if parentContainer != nil {
  40. parentContainer.DisableLink(n)
  41. }
  42. if err := daemon.ContainerGraph().Delete(name); err != nil {
  43. return job.Error(err)
  44. }
  45. return engine.StatusOK
  46. }
  47. if container != nil {
  48. if container.State.IsRunning() {
  49. if forceRemove {
  50. if err := container.Kill(); err != nil {
  51. return job.Errorf("Could not kill running container, cannot remove - %v", err)
  52. }
  53. } else {
  54. return job.Errorf("You cannot remove a running container. Stop the container before attempting removal or use -f")
  55. }
  56. }
  57. if err := daemon.Destroy(container); err != nil {
  58. return job.Errorf("Cannot destroy container %s: %s", name, err)
  59. }
  60. container.LogEvent("destroy")
  61. if removeVolume {
  62. var (
  63. volumes = make(map[string]struct{})
  64. binds = make(map[string]struct{})
  65. usedVolumes = make(map[string]*Container)
  66. )
  67. // the volume id is always the base of the path
  68. getVolumeId := func(p string) string {
  69. return filepath.Base(strings.TrimSuffix(p, "/layer"))
  70. }
  71. // populate bind map so that they can be skipped and not removed
  72. for _, bind := range container.HostConfig().Binds {
  73. source := strings.Split(bind, ":")[0]
  74. // TODO: refactor all volume stuff, all of it
  75. // it is very important that we eval the link or comparing the keys to container.Volumes will not work
  76. //
  77. // eval symlink can fail, ref #5244 if we receive an is not exist error we can ignore it
  78. p, err := filepath.EvalSymlinks(source)
  79. if err != nil && !os.IsNotExist(err) {
  80. return job.Error(err)
  81. }
  82. if p != "" {
  83. source = p
  84. }
  85. binds[source] = struct{}{}
  86. }
  87. // Store all the deleted containers volumes
  88. for _, volumeId := range container.Volumes {
  89. // Skip the volumes mounted from external
  90. // bind mounts here will will be evaluated for a symlink
  91. if _, exists := binds[volumeId]; exists {
  92. continue
  93. }
  94. volumeId = getVolumeId(volumeId)
  95. volumes[volumeId] = struct{}{}
  96. }
  97. // Retrieve all volumes from all remaining containers
  98. for _, container := range daemon.List() {
  99. for _, containerVolumeId := range container.Volumes {
  100. containerVolumeId = getVolumeId(containerVolumeId)
  101. usedVolumes[containerVolumeId] = container
  102. }
  103. }
  104. for volumeId := range volumes {
  105. // If the requested volu
  106. if c, exists := usedVolumes[volumeId]; exists {
  107. log.Printf("The volume %s is used by the container %s. Impossible to remove it. Skipping.\n", volumeId, c.ID)
  108. continue
  109. }
  110. if err := daemon.Volumes().Delete(volumeId); err != nil {
  111. return job.Errorf("Error calling volumes.Delete(%q): %v", volumeId, err)
  112. }
  113. }
  114. }
  115. } else {
  116. return job.Errorf("No such container: %s", name)
  117. }
  118. return engine.StatusOK
  119. }
  120. // Destroy unregisters a container from the daemon and cleanly removes its contents from the filesystem.
  121. // FIXME: rename to Rm for consistency with the CLI command
  122. func (daemon *Daemon) Destroy(container *Container) error {
  123. if container == nil {
  124. return fmt.Errorf("The given container is <nil>")
  125. }
  126. element := daemon.containers.Get(container.ID)
  127. if element == nil {
  128. return fmt.Errorf("Container %v not found - maybe it was already destroyed?", container.ID)
  129. }
  130. if err := container.Stop(3); err != nil {
  131. return err
  132. }
  133. // Deregister the container before removing its directory, to avoid race conditions
  134. daemon.idIndex.Delete(container.ID)
  135. daemon.containers.Delete(container.ID)
  136. if _, err := daemon.containerGraph.Purge(container.ID); err != nil {
  137. utils.Debugf("Unable to remove container from link graph: %s", err)
  138. }
  139. if err := daemon.driver.Remove(container.ID); err != nil {
  140. return fmt.Errorf("Driver %s failed to remove root filesystem %s: %s", daemon.driver, container.ID, err)
  141. }
  142. initID := fmt.Sprintf("%s-init", container.ID)
  143. if err := daemon.driver.Remove(initID); err != nil {
  144. return fmt.Errorf("Driver %s failed to remove init filesystem %s: %s", daemon.driver, initID, err)
  145. }
  146. if err := os.RemoveAll(container.root); err != nil {
  147. return fmt.Errorf("Unable to remove filesystem for %v: %v", container.ID, err)
  148. }
  149. selinuxFreeLxcContexts(container.ProcessLabel)
  150. return nil
  151. }