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