Merge pull request #2793 from crosbymichael/offline-ids
Allow images to be saved and loaded by id and repository
This commit is contained in:
commit
f20c738963
3 changed files with 108 additions and 80 deletions
12
api.go
12
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 {
|
||||
|
|
13
commands.go
13
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
|
||||
}
|
||||
|
||||
|
|
163
server.go
163
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 {
|
||||
if err := srv.exportImage(image, tempdir); 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)
|
||||
// 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 {
|
||||
return err
|
||||
}
|
||||
if err := srv.runtime.repositories.Set(imageName, tag, address, true); err != nil {
|
||||
for _, d := range dirs {
|
||||
if d.IsDir() {
|
||||
if err := srv.recursiveLoad(d.Name(), tmpImageDir); 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
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue