From 27159ce6bac4308b5fba311258fab8e852667787 Mon Sep 17 00:00:00 2001 From: Sven Dowideit Date: Sat, 16 Nov 2013 20:15:04 +1000 Subject: [PATCH 1/3] expunge the word 'Resource' in reference to a file/dir in a CONTAINER - that way users don't wonder how its different from a Path --- api.go | 2 +- commands.go | 4 ++-- docs/sources/commandline/cli.rst | 7 ++++++- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/api.go b/api.go index dbaa2ae7de..c4d0f79503 100644 --- a/api.go +++ b/api.go @@ -978,7 +978,7 @@ func postContainersCopy(srv *Server, version float64, w http.ResponseWriter, r * } if copyData.Resource == "" { - return fmt.Errorf("Resource cannot be empty") + return fmt.Errorf("Path cannot be empty") } if copyData.Resource[0] == '/' { copyData.Resource = copyData.Resource[1:] diff --git a/commands.go b/commands.go index 710a311c08..1f780925ad 100644 --- a/commands.go +++ b/commands.go @@ -1924,7 +1924,7 @@ func (cli *DockerCli) CmdRun(args ...string) error { } func (cli *DockerCli) CmdCp(args ...string) error { - cmd := Subcmd("cp", "CONTAINER:RESOURCE HOSTPATH", "Copy files/folders from the RESOURCE to the HOSTPATH") + cmd := Subcmd("cp", "CONTAINER:PATH HOSTPATH", "Copy files/folders from the PATH to the HOSTPATH") if err := cmd.Parse(args); err != nil { return nil } @@ -1938,7 +1938,7 @@ func (cli *DockerCli) CmdCp(args ...string) error { info := strings.Split(cmd.Arg(0), ":") if len(info) != 2 { - return fmt.Errorf("Error: Resource not specified") + return fmt.Errorf("Error: Path not specified") } copyData.Resource = info[1] diff --git a/docs/sources/commandline/cli.rst b/docs/sources/commandline/cli.rst index 37f371baad..91f92248ba 100644 --- a/docs/sources/commandline/cli.rst +++ b/docs/sources/commandline/cli.rst @@ -219,10 +219,15 @@ Full -run example :: - Usage: docker cp CONTAINER:RESOURCE HOSTPATH + Usage: docker cp CONTAINER:PATH HOSTPATH Copy files/folders from the containers filesystem to the host path. Paths are relative to the root of the filesystem. + +.. code-block:: bash + + $ sudo docker cp 7bb0e258aefe:/etc/debian_version . + $ sudo docker cp blue_frog:/etc/hosts . .. _cli_diff: From 152459b7272daa30ab5207b512f5319fdc4ff491 Mon Sep 17 00:00:00 2001 From: Sven Dowideit Date: Sat, 16 Nov 2013 20:45:30 +1000 Subject: [PATCH 2/3] add some common examples for docker images, and tell the user what -a filters out --- commands.go | 2 +- docs/sources/commandline/cli.rst | 44 ++++++++++++++++++++++++++++---- 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/commands.go b/commands.go index 710a311c08..e130711dde 100644 --- a/commands.go +++ b/commands.go @@ -1073,7 +1073,7 @@ func (cli *DockerCli) CmdPull(args ...string) error { func (cli *DockerCli) CmdImages(args ...string) error { cmd := Subcmd("images", "[OPTIONS] [NAME]", "List images") quiet := cmd.Bool("q", false, "only show numeric IDs") - all := cmd.Bool("a", false, "show all images") + all := cmd.Bool("a", false, "show all images (by default filter out the intermediate images used to build)") noTrunc := cmd.Bool("notrunc", false, "Don't truncate output") flViz := cmd.Bool("viz", false, "output graph in graphviz format") flTree := cmd.Bool("tree", false, "output graph in tree format") diff --git a/docs/sources/commandline/cli.rst b/docs/sources/commandline/cli.rst index 37f371baad..d6ad116313 100644 --- a/docs/sources/commandline/cli.rst +++ b/docs/sources/commandline/cli.rst @@ -334,18 +334,52 @@ Show events in the past from a specified time List images - -a=false: show all images + -a=false: show all images (by default filter out the intermediate images used to build) -notrunc=false: Don't truncate output -q=false: only show numeric IDs -tree=false: output graph in tree format -viz=false: output graph in graphviz format + +Listing the most recently created images +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: bash + + $ sudo docker images | head + REPOSITORY TAG IMAGE ID CREATED SIZE + 77af4d6b9913 19 hours ago 30.53 MB (virtual 1.089 GB) + committest latest b6fa739cedf5 19 hours ago 30.53 MB (virtual 1.089 GB) + 78a85c484f71 19 hours ago 30.53 MB (virtual 1.089 GB) + docker latest 30557a29d5ab 20 hours ago 30.53 MB (virtual 1.089 GB) + 0124422dd9f9 20 hours ago 30.53 MB (virtual 1.089 GB) + 18ad6fad3402 22 hours ago 23.68 MB (virtual 1.082 GB) + f9f1e26352f0 23 hours ago 30.46 MB (virtual 1.089 GB) + tryout latest 2629d1fa0b81 23 hours ago 16.4 kB (virtual 131.5 MB) + 5ed6274db6ce 24 hours ago 30.44 MB (virtual 1.089 GB) + +Listing the full length image IDs +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: bash + + $ sudo docker images -notrunc | head + REPOSITORY TAG IMAGE ID CREATED SIZE + 77af4d6b9913e693e8d0b4b294fa62ade6054e6b2f1ffb617ac955dd63fb0182 19 hours ago 30.53 MB (virtual 1.089 GB) + committest latest b6fa739cedf5ea12a620a439402b6004d057da800f91c7524b5086a5e4749c9f 19 hours ago 30.53 MB (virtual 1.089 GB) + 78a85c484f71509adeaace20e72e941f6bdd2b25b4c75da8693efd9f61a37921 19 hours ago 30.53 MB (virtual 1.089 GB) + docker latest 30557a29d5abc51e5f1d5b472e79b7e296f595abcf19fe6b9199dbbc809c6ff4 20 hours ago 30.53 MB (virtual 1.089 GB) + 0124422dd9f9cf7ef15c0617cda3931ee68346455441d66ab8bdc5b05e9fdce5 20 hours ago 30.53 MB (virtual 1.089 GB) + 18ad6fad340262ac2a636efd98a6d1f0ea775ae3d45240d3418466495a19a81b 22 hours ago 23.68 MB (virtual 1.082 GB) + f9f1e26352f0a3ba6a0ff68167559f64f3e21ff7ada60366e2d44a04befd1d3a 23 hours ago 30.46 MB (virtual 1.089 GB) + tryout latest 2629d1fa0b81b222fca63371ca16cbf6a0772d07759ff80e8d1369b926940074 23 hours ago 16.4 kB (virtual 131.5 MB) + 5ed6274db6ceb2397844896966ea239290555e74ef307030ebb01ff91b1914df 24 hours ago 30.44 MB (virtual 1.089 GB) Displaying images visually ~~~~~~~~~~~~~~~~~~~~~~~~~~ -:: +.. code-block:: bash - sudo docker images -viz | dot -Tpng -o docker.png + $ sudo docker images -viz | dot -Tpng -o docker.png .. image:: docker_images.gif :alt: Example inheritance graph of Docker images. @@ -354,9 +388,9 @@ Displaying images visually Displaying image hierarchy ~~~~~~~~~~~~~~~~~~~~~~~~~~ -:: +.. code-block:: bash - sudo docker images -tree + $ sudo docker images -tree |─8dbd9e392a96 Size: 131.5 MB (virtual 131.5 MB) Tags: ubuntu:12.04,ubuntu:latest,ubuntu:precise └─27cf78414709 Size: 180.1 MB (virtual 180.1 MB) From fd7ab143bf1ecfbf20df90edd876f73dc28c264d Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Wed, 20 Nov 2013 17:28:19 -0800 Subject: [PATCH 3/3] Allow images to be saved and loaded by id and repository --- api.go | 12 +--- commands.go | 13 ++--- server.go | 163 ++++++++++++++++++++++++++++++++-------------------- 3 files changed, 108 insertions(+), 80 deletions(-) diff --git a/api.go b/api.go index 3bbcdfd43d..1104b787b8 100644 --- a/api.go +++ b/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 { diff --git a/commands.go b/commands.go index 752ed82906..3b56f74e5d 100644 --- a/commands.go +++ b/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 } diff --git a/server.go b/server.go index 4cc808bb52..39c6dfdc6d 100644 --- a/server.go +++ b/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 }