فهرست منبع

Allow images to be saved and loaded by id and repository

Michael Crosby 11 سال پیش
والد
کامیت
fd7ab143bf
3فایلهای تغییر یافته به همراه107 افزوده شده و 79 حذف شده
  1. 2 10
      api.go
  2. 6 7
      commands.go
  3. 99 62
      server.go

+ 2 - 10
api.go

@@ -539,19 +539,11 @@ func getImagesGet(srv *Server, version float64, w http.ResponseWriter, r *http.R
 	if version > 1.0 {
 		w.Header().Set("Content-Type", "application/x-tar")
 	}
-	err := srv.ImageExport(name, w)
-	if err != nil {
-		return err
-	}
-	return nil
+	return srv.ImageExport(name, w)
 }
 
 func postImagesLoad(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
-	err := srv.ImageLoad(r.Body)
-	if err != nil {
-		return err
-	}
-	return nil
+	return srv.ImageLoad(r.Body)
 }
 
 func postContainersCreate(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {

+ 6 - 7
commands.go

@@ -1969,8 +1969,7 @@ func (cli *DockerCli) CmdCp(args ...string) error {
 func (cli *DockerCli) CmdSave(args ...string) error {
 	cmd := Subcmd("save", "IMAGE DESTINATION", "Save an image to a tar archive")
 	if err := cmd.Parse(args); err != nil {
-		cmd.Usage()
-		return nil
+		return err
 	}
 
 	if cmd.NArg() != 1 {
@@ -1979,7 +1978,6 @@ func (cli *DockerCli) CmdSave(args ...string) error {
 	}
 
 	image := cmd.Arg(0)
-
 	if err := cli.stream("GET", "/images/"+image+"/get", nil, cli.out, nil); err != nil {
 		return err
 	}
@@ -1988,17 +1986,18 @@ func (cli *DockerCli) CmdSave(args ...string) error {
 
 func (cli *DockerCli) CmdLoad(args ...string) error {
 	cmd := Subcmd("load", "SOURCE", "Load an image from a tar archive")
+	if err := cmd.Parse(args); err != nil {
+		return err
+	}
 
 	if cmd.NArg() != 0 {
 		cmd.Usage()
 		return nil
 	}
 
-	err := cli.stream("POST", "/images/load", cli.in, cli.out, nil)
-	if err != nil {
-		fmt.Println("Send failed", err)
+	if err := cli.stream("POST", "/images/load", cli.in, cli.out, nil); err != nil {
+		return err
 	}
-
 	return nil
 }
 

+ 99 - 62
server.go

@@ -212,67 +212,38 @@ func (srv *Server) ImageExport(name string, out io.Writer) error {
 
 	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)
+	rootRepo, err := srv.runtime.repositories.Get(name)
+	if err != nil {
+		return err
+	}
+	if rootRepo != nil {
+		for _, id := range rootRepo {
+			image, err := srv.ImageInspect(id)
 			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 {
+			if err := srv.exportImage(image, tempdir); 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)
+		// 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
+		if err := ioutil.WriteFile(path.Join(tempdir, "repositories"), rootRepoJson, os.ModeAppend); err != nil {
+			return err
+		}
+	} else {
+		image, err := srv.ImageInspect(name)
+		if err != nil {
+			return err
+		}
+		if err := srv.exportImage(image, tempdir); err != nil {
+			return err
+		}
 	}
 
 	fs, err := archive.Tar(tempdir, archive.Uncompressed)
@@ -286,6 +257,58 @@ func (srv *Server) ImageExport(name string, out io.Writer) error {
 	return nil
 }
 
+func (srv *Server) exportImage(image *Image, tempdir string) error {
+	for i := image; i != nil; {
+		// temporary directory
+		tmpImageDir := path.Join(tempdir, i.ID)
+		if err := os.Mkdir(tmpImageDir, os.ModeDir); err != nil {
+			return err
+		}
+
+		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
+		}
+	}
+	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 {
@@ -319,25 +342,38 @@ func (srv *Server) ImageLoad(in io.Reader) error {
 	if err := archive.Untar(repoFile, repoDir); err != nil {
 		return err
 	}
-	repositoriesJson, err := ioutil.ReadFile(path.Join(tmpImageDir, "repo", "repositories"))
+
+	dirs, err := ioutil.ReadDir(repoDir)
 	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 {
+	for _, d := range dirs {
+		if d.IsDir() {
+			if err := srv.recursiveLoad(d.Name(), tmpImageDir); err != nil {
 				return err
 			}
-			if err := srv.runtime.repositories.Set(imageName, tag, address, true); err != nil {
-				return err
+		}
+	}
+
+	repositoriesJson, err := ioutil.ReadFile(path.Join(tmpImageDir, "repo", "repositories"))
+	if err == nil {
+		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.runtime.repositories.Set(imageName, tag, address, true); err != nil {
+					return err
+				}
 			}
 		}
+	} else if !os.IsNotExist(err) {
+		return err
 	}
+
 	return nil
 }
 
@@ -373,6 +409,7 @@ func (srv *Server) recursiveLoad(address, tmpImageDir string) error {
 		}
 	}
 	utils.Debugf("Completed processing %s", address)
+
 	return nil
 }