delete.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. package daemon
  2. import (
  3. "fmt"
  4. "os"
  5. "path"
  6. "github.com/docker/docker/context"
  7. "github.com/Sirupsen/logrus"
  8. derr "github.com/docker/docker/errors"
  9. "github.com/docker/docker/volume/store"
  10. )
  11. // ContainerRmConfig is a holder for passing in runtime config.
  12. type ContainerRmConfig struct {
  13. ForceRemove, RemoveVolume, RemoveLink bool
  14. }
  15. // ContainerRm removes the container id from the filesystem. An error
  16. // is returned if the container is not found, or if the remove
  17. // fails. If the remove succeeds, the container name is released, and
  18. // network links are removed.
  19. func (daemon *Daemon) ContainerRm(ctx context.Context, name string, config *ContainerRmConfig) error {
  20. container, err := daemon.Get(ctx, name)
  21. if err != nil {
  22. return err
  23. }
  24. if config.RemoveLink {
  25. name, err := GetFullContainerName(name)
  26. if err != nil {
  27. return err
  28. }
  29. parent, n := path.Split(name)
  30. if parent == "/" {
  31. return derr.ErrorCodeDefaultName
  32. }
  33. pe := daemon.containerGraph().Get(parent)
  34. if pe == nil {
  35. return derr.ErrorCodeNoParent.WithArgs(parent, name)
  36. }
  37. if err := daemon.containerGraph().Delete(name); err != nil {
  38. return err
  39. }
  40. parentContainer, _ := daemon.Get(ctx, pe.ID())
  41. if parentContainer != nil {
  42. if err := parentContainer.updateNetwork(ctx); err != nil {
  43. logrus.Debugf("Could not update network to remove link %s: %v", n, err)
  44. }
  45. }
  46. return nil
  47. }
  48. if err := daemon.rm(ctx, container, config.ForceRemove); err != nil {
  49. // return derr.ErrorCodeCantDestroy.WithArgs(name, utils.GetErrorMessage(err))
  50. return err
  51. }
  52. if err := container.removeMountPoints(config.RemoveVolume); err != nil {
  53. logrus.Error(err)
  54. }
  55. return nil
  56. }
  57. // Destroy unregisters a container from the daemon and cleanly removes its contents from the filesystem.
  58. func (daemon *Daemon) rm(ctx context.Context, container *Container, forceRemove bool) (err error) {
  59. if container.IsRunning() {
  60. if !forceRemove {
  61. return derr.ErrorCodeRmRunning
  62. }
  63. if err := container.Kill(ctx); err != nil {
  64. return derr.ErrorCodeRmFailed.WithArgs(err)
  65. }
  66. }
  67. // stop collection of stats for the container regardless
  68. // if stats are currently getting collected.
  69. daemon.statsCollector.stopCollection(container)
  70. element := daemon.containers.Get(container.ID)
  71. if element == nil {
  72. return derr.ErrorCodeRmNotFound.WithArgs(container.ID)
  73. }
  74. // Container state RemovalInProgress should be used to avoid races.
  75. if err = container.setRemovalInProgress(); err != nil {
  76. return derr.ErrorCodeRmState.WithArgs(err)
  77. }
  78. defer container.resetRemovalInProgress()
  79. if err = container.Stop(ctx, 3); err != nil {
  80. return err
  81. }
  82. // Mark container dead. We don't want anybody to be restarting it.
  83. container.setDead()
  84. // Save container state to disk. So that if error happens before
  85. // container meta file got removed from disk, then a restart of
  86. // docker should not make a dead container alive.
  87. if err := container.toDiskLocking(); err != nil {
  88. logrus.Errorf("Error saving dying container to disk: %v", err)
  89. }
  90. // If force removal is required, delete container from various
  91. // indexes even if removal failed.
  92. defer func() {
  93. if err != nil && forceRemove {
  94. daemon.idIndex.Delete(container.ID)
  95. daemon.containers.Delete(container.ID)
  96. os.RemoveAll(container.root)
  97. container.logEvent(ctx, "destroy")
  98. }
  99. }()
  100. if _, err := daemon.containerGraphDB.Purge(container.ID); err != nil {
  101. logrus.Debugf("Unable to remove container from link graph: %s", err)
  102. }
  103. if err = daemon.driver.Remove(container.ID); err != nil {
  104. return derr.ErrorCodeRmDriverFS.WithArgs(daemon.driver, container.ID, err)
  105. }
  106. initID := fmt.Sprintf("%s-init", container.ID)
  107. if err := daemon.driver.Remove(initID); err != nil {
  108. return derr.ErrorCodeRmInit.WithArgs(daemon.driver, initID, err)
  109. }
  110. if err = os.RemoveAll(container.root); err != nil {
  111. return derr.ErrorCodeRmFS.WithArgs(container.ID, err)
  112. }
  113. if err = daemon.execDriver.Clean(container.ID); err != nil {
  114. return derr.ErrorCodeRmExecDriver.WithArgs(container.ID, err)
  115. }
  116. selinuxFreeLxcContexts(container.ProcessLabel)
  117. daemon.idIndex.Delete(container.ID)
  118. daemon.containers.Delete(container.ID)
  119. container.logEvent(ctx, "destroy")
  120. return nil
  121. }
  122. // VolumeRm removes the volume with the given name.
  123. // If the volume is referenced by a container it is not removed
  124. // This is called directly from the remote API
  125. func (daemon *Daemon) VolumeRm(ctx context.Context, name string) error {
  126. v, err := daemon.volumes.Get(name)
  127. if err != nil {
  128. return err
  129. }
  130. if err := daemon.volumes.Remove(v); err != nil {
  131. if err == store.ErrVolumeInUse {
  132. return derr.ErrorCodeRmVolumeInUse.WithArgs(err)
  133. }
  134. return derr.ErrorCodeRmVolume.WithArgs(name, err)
  135. }
  136. return nil
  137. }