graph_unix.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. // +build !windows
  2. package graph
  3. import (
  4. "compress/gzip"
  5. "encoding/json"
  6. "fmt"
  7. "io"
  8. "os"
  9. "path/filepath"
  10. "strings"
  11. "syscall"
  12. "github.com/Sirupsen/logrus"
  13. "github.com/docker/docker/image"
  14. "github.com/docker/docker/pkg/archive"
  15. "github.com/docker/docker/pkg/system"
  16. "github.com/vbatts/tar-split/tar/asm"
  17. "github.com/vbatts/tar-split/tar/storage"
  18. )
  19. // setupInitLayer populates a directory with mountpoints suitable
  20. // for bind-mounting dockerinit into the container. The mountpoint is simply an
  21. // empty file at /.dockerinit
  22. //
  23. // This extra layer is used by all containers as the top-most ro layer. It protects
  24. // the container from unwanted side-effects on the rw layer.
  25. func SetupInitLayer(initLayer string) error {
  26. for pth, typ := range map[string]string{
  27. "/dev/pts": "dir",
  28. "/dev/shm": "dir",
  29. "/proc": "dir",
  30. "/sys": "dir",
  31. "/.dockerinit": "file",
  32. "/.dockerenv": "file",
  33. "/etc/resolv.conf": "file",
  34. "/etc/hosts": "file",
  35. "/etc/hostname": "file",
  36. "/dev/console": "file",
  37. "/etc/mtab": "/proc/mounts",
  38. } {
  39. parts := strings.Split(pth, "/")
  40. prev := "/"
  41. for _, p := range parts[1:] {
  42. prev = filepath.Join(prev, p)
  43. syscall.Unlink(filepath.Join(initLayer, prev))
  44. }
  45. if _, err := os.Stat(filepath.Join(initLayer, pth)); err != nil {
  46. if os.IsNotExist(err) {
  47. if err := system.MkdirAll(filepath.Join(initLayer, filepath.Dir(pth)), 0755); err != nil {
  48. return err
  49. }
  50. switch typ {
  51. case "dir":
  52. if err := system.MkdirAll(filepath.Join(initLayer, pth), 0755); err != nil {
  53. return err
  54. }
  55. case "file":
  56. f, err := os.OpenFile(filepath.Join(initLayer, pth), os.O_CREATE, 0755)
  57. if err != nil {
  58. return err
  59. }
  60. f.Close()
  61. default:
  62. if err := os.Symlink(typ, filepath.Join(initLayer, pth)); err != nil {
  63. return err
  64. }
  65. }
  66. } else {
  67. return err
  68. }
  69. }
  70. }
  71. // Layer is ready to use, if it wasn't before.
  72. return nil
  73. }
  74. func createRootFilesystemInDriver(graph *Graph, img *image.Image, layerData archive.ArchiveReader) error {
  75. if err := graph.driver.Create(img.ID, img.Parent); err != nil {
  76. return fmt.Errorf("Driver %s failed to create image rootfs %s: %s", graph.driver, img.ID, err)
  77. }
  78. return nil
  79. }
  80. func (graph *Graph) restoreBaseImages() ([]string, error) {
  81. return nil, nil
  82. }
  83. // storeImage stores file system layer data for the given image to the
  84. // graph's storage driver. Image metadata is stored in a file
  85. // at the specified root directory.
  86. func (graph *Graph) storeImage(img *image.Image, layerData archive.ArchiveReader, root string) (err error) {
  87. // Store the layer. If layerData is not nil, unpack it into the new layer
  88. if layerData != nil {
  89. // this is saving the tar-split metadata
  90. mf, err := os.OpenFile(filepath.Join(root, tarDataFileName), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(0600))
  91. if err != nil {
  92. return err
  93. }
  94. defer mf.Close()
  95. mfz := gzip.NewWriter(mf)
  96. defer mfz.Close()
  97. metaPacker := storage.NewJSONPacker(mfz)
  98. inflatedLayerData, err := archive.DecompressStream(layerData)
  99. if err != nil {
  100. return err
  101. }
  102. // we're passing nil here for the file putter, because the ApplyDiff will
  103. // handle the extraction of the archive
  104. its, err := asm.NewInputTarStream(inflatedLayerData, metaPacker, nil)
  105. if err != nil {
  106. return err
  107. }
  108. if img.Size, err = graph.driver.ApplyDiff(img.ID, img.Parent, archive.ArchiveReader(its)); err != nil {
  109. return err
  110. }
  111. }
  112. if err := graph.saveSize(root, int(img.Size)); err != nil {
  113. return err
  114. }
  115. f, err := os.OpenFile(jsonPath(root), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(0600))
  116. if err != nil {
  117. return err
  118. }
  119. defer f.Close()
  120. return json.NewEncoder(f).Encode(img)
  121. }
  122. // TarLayer returns a tar archive of the image's filesystem layer.
  123. func (graph *Graph) TarLayer(img *image.Image) (arch archive.Archive, err error) {
  124. root := graph.imageRoot(img.ID)
  125. mFileName := filepath.Join(root, tarDataFileName)
  126. mf, err := os.Open(mFileName)
  127. if err != nil {
  128. if !os.IsNotExist(err) {
  129. logrus.Errorf("failed to open %q: %s", mFileName, err)
  130. }
  131. logrus.Debugf("[graph] TarLayer with traditional differ: %s", img.ID)
  132. return graph.driver.Diff(img.ID, img.Parent)
  133. }
  134. pR, pW := io.Pipe()
  135. // this will need to be in a goroutine, as we are returning the stream of a
  136. // tar archive, but can not close the metadata reader early (when this
  137. // function returns)...
  138. go func() {
  139. defer mf.Close()
  140. // let's reassemble!
  141. logrus.Debugf("[graph] TarLayer with reassembly: %s", img.ID)
  142. mfz, err := gzip.NewReader(mf)
  143. if err != nil {
  144. pW.CloseWithError(fmt.Errorf("[graph] error with %s: %s", mFileName, err))
  145. return
  146. }
  147. defer mfz.Close()
  148. // get our relative path to the container
  149. fsLayer, err := graph.driver.Get(img.ID, "")
  150. if err != nil {
  151. pW.CloseWithError(err)
  152. return
  153. }
  154. defer graph.driver.Put(img.ID)
  155. metaUnpacker := storage.NewJSONUnpacker(mfz)
  156. fileGetter := storage.NewPathFileGetter(fsLayer)
  157. logrus.Debugf("[graph] %s is at %q", img.ID, fsLayer)
  158. ots := asm.NewOutputTarStream(fileGetter, metaUnpacker)
  159. defer ots.Close()
  160. if _, err := io.Copy(pW, ots); err != nil {
  161. pW.CloseWithError(err)
  162. return
  163. }
  164. pW.Close()
  165. }()
  166. return pR, nil
  167. }