github.com/mheon/docker@v0.11.2-0.20150922122814-44f47903a831/graph/export.go (about) 1 package graph 2 3 import ( 4 "encoding/json" 5 "io" 6 "io/ioutil" 7 "os" 8 "path/filepath" 9 10 "github.com/Sirupsen/logrus" 11 "github.com/docker/docker/pkg/archive" 12 "github.com/docker/docker/pkg/parsers" 13 "github.com/docker/docker/registry" 14 ) 15 16 // ImageExport exports list of images to a output stream specified in the 17 // config. The exported images are archived into a tar when written to the 18 // output stream. All images with the given tag and all versions containing the 19 // same tag are exported. names is the set of tags to export, and outStream 20 // is the writer which the images are written to. 21 func (s *TagStore) ImageExport(names []string, outStream io.Writer) error { 22 // get image json 23 tempdir, err := ioutil.TempDir("", "docker-export-") 24 if err != nil { 25 return err 26 } 27 defer os.RemoveAll(tempdir) 28 29 rootRepoMap := map[string]Repository{} 30 addKey := func(name string, tag string, id string) { 31 logrus.Debugf("add key [%s:%s]", name, tag) 32 if repo, ok := rootRepoMap[name]; !ok { 33 rootRepoMap[name] = Repository{tag: id} 34 } else { 35 repo[tag] = id 36 } 37 } 38 for _, name := range names { 39 name = registry.NormalizeLocalName(name) 40 logrus.Debugf("Serializing %s", name) 41 rootRepo := s.Repositories[name] 42 if rootRepo != nil { 43 // this is a base repo name, like 'busybox' 44 for tag, id := range rootRepo { 45 addKey(name, tag, id) 46 if err := s.exportImage(id, tempdir); err != nil { 47 return err 48 } 49 } 50 } else { 51 img, err := s.LookupImage(name) 52 if err != nil { 53 return err 54 } 55 56 if img != nil { 57 // This is a named image like 'busybox:latest' 58 repoName, repoTag := parsers.ParseRepositoryTag(name) 59 60 // check this length, because a lookup of a truncated has will not have a tag 61 // and will not need to be added to this map 62 if len(repoTag) > 0 { 63 addKey(repoName, repoTag, img.ID) 64 } 65 if err := s.exportImage(img.ID, tempdir); err != nil { 66 return err 67 } 68 69 } else { 70 // this must be an ID that didn't get looked up just right? 71 if err := s.exportImage(name, tempdir); err != nil { 72 return err 73 } 74 } 75 } 76 logrus.Debugf("End Serializing %s", name) 77 } 78 // write repositories, if there is something to write 79 if len(rootRepoMap) > 0 { 80 f, err := os.OpenFile(filepath.Join(tempdir, "repositories"), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644) 81 if err != nil { 82 f.Close() 83 return err 84 } 85 if err := json.NewEncoder(f).Encode(rootRepoMap); err != nil { 86 return err 87 } 88 if err := f.Close(); err != nil { 89 return err 90 } 91 } else { 92 logrus.Debugf("There were no repositories to write") 93 } 94 95 fs, err := archive.Tar(tempdir, archive.Uncompressed) 96 if err != nil { 97 return err 98 } 99 defer fs.Close() 100 101 if _, err := io.Copy(outStream, fs); err != nil { 102 return err 103 } 104 logrus.Debugf("End export image") 105 return nil 106 } 107 108 func (s *TagStore) exportImage(name, tempdir string) error { 109 for n := name; n != ""; { 110 // temporary directory 111 tmpImageDir := filepath.Join(tempdir, n) 112 if err := os.Mkdir(tmpImageDir, os.FileMode(0755)); err != nil { 113 if os.IsExist(err) { 114 return nil 115 } 116 return err 117 } 118 119 var version = "1.0" 120 var versionBuf = []byte(version) 121 122 if err := ioutil.WriteFile(filepath.Join(tmpImageDir, "VERSION"), versionBuf, os.FileMode(0644)); err != nil { 123 return err 124 } 125 126 // serialize json 127 json, err := os.Create(filepath.Join(tmpImageDir, "json")) 128 if err != nil { 129 return err 130 } 131 imageInspectRaw, err := s.lookupRaw(n) 132 if err != nil { 133 return err 134 } 135 written, err := json.Write(imageInspectRaw) 136 if err != nil { 137 return err 138 } 139 if written != len(imageInspectRaw) { 140 logrus.Warnf("%d byes should have been written instead %d have been written", written, len(imageInspectRaw)) 141 } 142 143 // serialize filesystem 144 fsTar, err := os.Create(filepath.Join(tmpImageDir, "layer.tar")) 145 if err != nil { 146 return err 147 } 148 if err := s.ImageTarLayer(n, fsTar); err != nil { 149 return err 150 } 151 152 // find parent 153 img, err := s.LookupImage(n) 154 if err != nil { 155 return err 156 } 157 n = img.Parent 158 } 159 return nil 160 }