volumes_unix.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. // +build !windows
  2. package daemon
  3. import (
  4. "io/ioutil"
  5. "os"
  6. "sort"
  7. "github.com/docker/docker/daemon/execdriver"
  8. "github.com/docker/docker/pkg/chrootarchive"
  9. "github.com/docker/docker/pkg/system"
  10. "github.com/docker/docker/volume"
  11. volumedrivers "github.com/docker/docker/volume/drivers"
  12. "github.com/docker/docker/volume/local"
  13. )
  14. // copyExistingContents copies from the source to the destination and
  15. // ensures the ownership is appropriately set.
  16. func copyExistingContents(source, destination string) error {
  17. volList, err := ioutil.ReadDir(source)
  18. if err != nil {
  19. return err
  20. }
  21. if len(volList) > 0 {
  22. srcList, err := ioutil.ReadDir(destination)
  23. if err != nil {
  24. return err
  25. }
  26. if len(srcList) == 0 {
  27. // If the source volume is empty copy files from the root into the volume
  28. if err := chrootarchive.CopyWithTar(source, destination); err != nil {
  29. return err
  30. }
  31. }
  32. }
  33. return copyOwnership(source, destination)
  34. }
  35. // copyOwnership copies the permissions and uid:gid of the source file
  36. // to the destination file
  37. func copyOwnership(source, destination string) error {
  38. stat, err := system.Stat(source)
  39. if err != nil {
  40. return err
  41. }
  42. if err := os.Chown(destination, int(stat.UID()), int(stat.GID())); err != nil {
  43. return err
  44. }
  45. return os.Chmod(destination, os.FileMode(stat.Mode()))
  46. }
  47. // setupMounts iterates through each of the mount points for a container and
  48. // calls Setup() on each. It also looks to see if is a network mount such as
  49. // /etc/resolv.conf, and if it is not, appends it to the array of mounts.
  50. func (daemon *Daemon) setupMounts(container *Container) ([]execdriver.Mount, error) {
  51. var mounts []execdriver.Mount
  52. for _, m := range container.MountPoints {
  53. path, err := m.Setup()
  54. if err != nil {
  55. return nil, err
  56. }
  57. if !container.trySetNetworkMount(m.Destination, path) {
  58. mounts = append(mounts, execdriver.Mount{
  59. Source: path,
  60. Destination: m.Destination,
  61. Writable: m.RW,
  62. })
  63. }
  64. }
  65. mounts = sortMounts(mounts)
  66. netMounts := container.networkMounts()
  67. // if we are going to mount any of the network files from container
  68. // metadata, the ownership must be set properly for potential container
  69. // remapped root (user namespaces)
  70. rootUID, rootGID := daemon.GetRemappedUIDGID()
  71. for _, mount := range netMounts {
  72. if err := os.Chown(mount.Source, rootUID, rootGID); err != nil {
  73. return nil, err
  74. }
  75. }
  76. return append(mounts, netMounts...), nil
  77. }
  78. // sortMounts sorts an array of mounts in lexicographic order. This ensure that
  79. // when mounting, the mounts don't shadow other mounts. For example, if mounting
  80. // /etc and /etc/resolv.conf, /etc/resolv.conf must not be mounted first.
  81. func sortMounts(m []execdriver.Mount) []execdriver.Mount {
  82. sort.Sort(mounts(m))
  83. return m
  84. }
  85. // migrateVolume links the contents of a volume created pre Docker 1.7
  86. // into the location expected by the local driver.
  87. // It creates a symlink from DOCKER_ROOT/vfs/dir/VOLUME_ID to DOCKER_ROOT/volumes/VOLUME_ID/_container_data.
  88. // It preserves the volume json configuration generated pre Docker 1.7 to be able to
  89. // downgrade from Docker 1.7 to Docker 1.6 without losing volume compatibility.
  90. func migrateVolume(id, vfs string) error {
  91. l, err := volumedrivers.Lookup(volume.DefaultDriverName)
  92. if err != nil {
  93. return err
  94. }
  95. newDataPath := l.(*local.Root).DataPath(id)
  96. fi, err := os.Stat(newDataPath)
  97. if err != nil && !os.IsNotExist(err) {
  98. return err
  99. }
  100. if fi != nil && fi.IsDir() {
  101. return nil
  102. }
  103. return os.Symlink(vfs, newDataPath)
  104. }
  105. // validVolumeLayout checks whether the volume directory layout
  106. // is valid to work with Docker post 1.7 or not.
  107. func validVolumeLayout(files []os.FileInfo) bool {
  108. if len(files) == 1 && files[0].Name() == local.VolumeDataPathName && files[0].IsDir() {
  109. return true
  110. }
  111. if len(files) != 2 {
  112. return false
  113. }
  114. for _, f := range files {
  115. if f.Name() == "config.json" ||
  116. (f.Name() == local.VolumeDataPathName && f.Mode()&os.ModeSymlink == os.ModeSymlink) {
  117. // Old volume configuration, we ignore it
  118. continue
  119. }
  120. return false
  121. }
  122. return true
  123. }
  124. // setBindModeIfNull is platform specific processing to ensure the
  125. // shared mode is set to 'z' if it is null. This is called in the case
  126. // of processing a named volume and not a typical bind.
  127. func setBindModeIfNull(bind *volume.MountPoint) *volume.MountPoint {
  128. if bind.Mode == "" {
  129. bind.Mode = "z"
  130. }
  131. return bind
  132. }