load.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. // +build linux
  2. package graph
  3. import (
  4. "encoding/json"
  5. "io"
  6. "io/ioutil"
  7. "os"
  8. "path"
  9. "github.com/Sirupsen/logrus"
  10. "github.com/docker/docker/image"
  11. "github.com/docker/docker/pkg/archive"
  12. "github.com/docker/docker/pkg/chrootarchive"
  13. )
  14. // Loads a set of images into the repository. This is the complementary of ImageExport.
  15. // The input stream is an uncompressed tar ball containing images and metadata.
  16. func (s *TagStore) Load(inTar io.ReadCloser, outStream io.Writer) error {
  17. tmpImageDir, err := ioutil.TempDir("", "docker-import-")
  18. if err != nil {
  19. return err
  20. }
  21. defer os.RemoveAll(tmpImageDir)
  22. var (
  23. repoDir = path.Join(tmpImageDir, "repo")
  24. )
  25. if err := os.Mkdir(repoDir, os.ModeDir); err != nil {
  26. return err
  27. }
  28. images, err := s.graph.Map()
  29. if err != nil {
  30. return err
  31. }
  32. excludes := make([]string, len(images))
  33. i := 0
  34. for k := range images {
  35. excludes[i] = k
  36. i++
  37. }
  38. if err := chrootarchive.Untar(inTar, repoDir, &archive.TarOptions{ExcludePatterns: excludes}); err != nil {
  39. return err
  40. }
  41. dirs, err := ioutil.ReadDir(repoDir)
  42. if err != nil {
  43. return err
  44. }
  45. for _, d := range dirs {
  46. if d.IsDir() {
  47. if err := s.recursiveLoad(d.Name(), tmpImageDir); err != nil {
  48. return err
  49. }
  50. }
  51. }
  52. reposJSONFile, err := os.Open(path.Join(tmpImageDir, "repo", "repositories"))
  53. if err != nil {
  54. if !os.IsNotExist(err) {
  55. return err
  56. }
  57. return nil
  58. }
  59. defer reposJSONFile.Close()
  60. repositories := map[string]Repository{}
  61. if err := json.NewDecoder(reposJSONFile).Decode(&repositories); err != nil {
  62. return err
  63. }
  64. for imageName, tagMap := range repositories {
  65. for tag, address := range tagMap {
  66. if err := s.SetLoad(imageName, tag, address, true, outStream); err != nil {
  67. return err
  68. }
  69. }
  70. }
  71. return nil
  72. }
  73. func (s *TagStore) recursiveLoad(address, tmpImageDir string) error {
  74. if _, err := s.LookupImage(address); err != nil {
  75. logrus.Debugf("Loading %s", address)
  76. imageJson, err := ioutil.ReadFile(path.Join(tmpImageDir, "repo", address, "json"))
  77. if err != nil {
  78. logrus.Debugf("Error reading json", err)
  79. return err
  80. }
  81. layer, err := os.Open(path.Join(tmpImageDir, "repo", address, "layer.tar"))
  82. if err != nil {
  83. logrus.Debugf("Error reading embedded tar", err)
  84. return err
  85. }
  86. img, err := image.NewImgJSON(imageJson)
  87. if err != nil {
  88. logrus.Debugf("Error unmarshalling json", err)
  89. return err
  90. }
  91. if err := image.ValidateID(img.ID); err != nil {
  92. logrus.Debugf("Error validating ID: %s", err)
  93. return err
  94. }
  95. // ensure no two downloads of the same layer happen at the same time
  96. if c, err := s.poolAdd("pull", "layer:"+img.ID); err != nil {
  97. if c != nil {
  98. logrus.Debugf("Image (id: %s) load is already running, waiting: %v", img.ID, err)
  99. <-c
  100. return nil
  101. }
  102. return err
  103. }
  104. defer s.poolRemove("pull", "layer:"+img.ID)
  105. if img.Parent != "" {
  106. if !s.graph.Exists(img.Parent) {
  107. if err := s.recursiveLoad(img.Parent, tmpImageDir); err != nil {
  108. return err
  109. }
  110. }
  111. }
  112. if err := s.graph.Register(img, layer); err != nil {
  113. return err
  114. }
  115. }
  116. logrus.Debugf("Completed processing %s", address)
  117. return nil
  118. }