|
@@ -197,6 +197,185 @@ func (srv *Server) ContainerExport(name string, out io.Writer) error {
|
|
|
return fmt.Errorf("No such container: %s", name)
|
|
|
}
|
|
|
|
|
|
+// ImageExport exports all images with the given tag. All versions
|
|
|
+// containing the same tag are exported. The resulting output is an
|
|
|
+// uncompressed tar ball.
|
|
|
+// name is the set of tags to export.
|
|
|
+// out is the writer where the images are written to.
|
|
|
+func (srv *Server) ImageExport(name string, out io.Writer) error {
|
|
|
+ // get image json
|
|
|
+ tempdir, err := ioutil.TempDir("", "docker-export-")
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ defer os.RemoveAll(tempdir)
|
|
|
+
|
|
|
+ utils.Debugf("Serializing %s", name)
|
|
|
+
|
|
|
+ rootRepo := srv.runtime.repositories.Repositories[name]
|
|
|
+ for _, rootImage := range rootRepo {
|
|
|
+ image, _ := srv.ImageInspect(rootImage)
|
|
|
+ for i := image; i != nil; {
|
|
|
+ // temporary directory
|
|
|
+ tmpImageDir := path.Join(tempdir, i.ID)
|
|
|
+ if err := os.Mkdir(tmpImageDir, os.ModeDir); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ defer os.RemoveAll(tmpImageDir)
|
|
|
+
|
|
|
+ var version = "1.0"
|
|
|
+ var versionBuf = []byte(version)
|
|
|
+
|
|
|
+ if err := ioutil.WriteFile(path.Join(tmpImageDir, "VERSION"), versionBuf, os.ModeAppend); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ // serialize json
|
|
|
+ b, err := json.Marshal(i)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ if err := ioutil.WriteFile(path.Join(tmpImageDir, "json"), b, os.ModeAppend); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ // serialize filesystem
|
|
|
+ fs, err := archive.Tar(path.Join(srv.runtime.graph.Root, i.ID, "layer"), archive.Uncompressed)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ fsTar, err := os.Create(path.Join(tmpImageDir, "layer.tar"))
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ if _, err = io.Copy(fsTar, fs); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ fsTar.Close()
|
|
|
+
|
|
|
+ // find parent
|
|
|
+ if i.Parent != "" {
|
|
|
+ i, err = srv.ImageInspect(i.Parent)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ i = nil
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // write repositories
|
|
|
+ rootRepoMap := map[string]Repository{}
|
|
|
+ rootRepoMap[name] = rootRepo
|
|
|
+ rootRepoJson, _ := json.Marshal(rootRepoMap)
|
|
|
+
|
|
|
+ if err := ioutil.WriteFile(path.Join(tempdir, "repositories"), rootRepoJson, os.ModeAppend); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ fs, err := archive.Tar(tempdir, archive.Uncompressed)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ if _, err := io.Copy(out, fs); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+// Loads a set of images into the repository. This is the complementary of ImageExport.
|
|
|
+// The input stream is an uncompressed tar ball containing images and metadata.
|
|
|
+func (srv *Server) ImageLoad(in io.Reader) error {
|
|
|
+ tmpImageDir, err := ioutil.TempDir("", "docker-import-")
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ defer os.RemoveAll(tmpImageDir)
|
|
|
+
|
|
|
+ var (
|
|
|
+ repoTarFile = path.Join(tmpImageDir, "repo.tar")
|
|
|
+ repoDir = path.Join(tmpImageDir, "repo")
|
|
|
+ )
|
|
|
+
|
|
|
+ tarFile, err := os.Create(repoTarFile)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ if _, err := io.Copy(tarFile, in); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ tarFile.Close()
|
|
|
+
|
|
|
+ repoFile, err := os.Open(repoTarFile)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ if err := os.Mkdir(repoDir, os.ModeDir); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ if err := archive.Untar(repoFile, repoDir); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ repositoriesJson, err := ioutil.ReadFile(path.Join(tmpImageDir, "repo", "repositories"))
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ repositories := map[string]Repository{}
|
|
|
+ if err := json.Unmarshal(repositoriesJson, &repositories); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ for imageName, tagMap := range repositories {
|
|
|
+ for tag, address := range tagMap {
|
|
|
+ if err := srv.recursiveLoad(address, tmpImageDir); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ if err := srv.runtime.repositories.Set(imageName, tag, address, true); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+func (srv *Server) recursiveLoad(address, tmpImageDir string) error {
|
|
|
+ if _, err := srv.ImageInspect(address); err != nil {
|
|
|
+ utils.Debugf("Loading %s", address)
|
|
|
+
|
|
|
+ imageJson, err := ioutil.ReadFile(path.Join(tmpImageDir, "repo", address, "json"))
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ utils.Debugf("Error reading json", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ layer, err := os.Open(path.Join(tmpImageDir, "repo", address, "layer.tar"))
|
|
|
+ if err != nil {
|
|
|
+ utils.Debugf("Error reading embedded tar", err)
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ img, err := NewImgJSON(imageJson)
|
|
|
+ if err != nil {
|
|
|
+ utils.Debugf("Error unmarshalling json", err)
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ if img.Parent != "" {
|
|
|
+ if !srv.runtime.graph.Exists(img.Parent) {
|
|
|
+ if err := srv.recursiveLoad(img.Parent, tmpImageDir); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if err := srv.runtime.graph.Register(imageJson, layer, img); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ }
|
|
|
+ utils.Debugf("Completed processing %s", address)
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
func (srv *Server) ImagesSearch(term string) ([]registry.SearchResult, error) {
|
|
|
r, err := registry.NewRegistry(srv.runtime.config.Root, nil, srv.HTTPRequestFactory(nil))
|
|
|
if err != nil {
|