diff options
-rw-r--r-- | cmd/kpod/load.go | 12 | ||||
-rw-r--r-- | cmd/kpod/save.go | 34 | ||||
-rw-r--r-- | completions/bash/kpod | 1 | ||||
-rw-r--r-- | docs/kpod-save.1.md | 47 | ||||
-rw-r--r-- | test/kpod_load.bats | 31 | ||||
-rw-r--r-- | test/kpod_save.bats | 14 |
6 files changed, 119 insertions, 20 deletions
diff --git a/cmd/kpod/load.go b/cmd/kpod/load.go index d29da0c06..5ae75a7a2 100644 --- a/cmd/kpod/load.go +++ b/cmd/kpod/load.go @@ -104,14 +104,18 @@ func loadCmd(c *cli.Context) error { src := libpod.DockerArchive + ":" + input imgName, err := runtime.PullImage(src, options) if err != nil { - src = libpod.OCIArchive + ":" + input // generate full src name with specified image:tag + fullSrc := libpod.OCIArchive + ":" + input if image != "" { - src = src + ":" + image + fullSrc = fullSrc + ":" + image } - imgName, err = runtime.PullImage(src, options) + imgName, err = runtime.PullImage(fullSrc, options) if err != nil { - return errors.Wrapf(err, "error pulling %q", src) + src = libpod.DirTransport + ":" + input + imgName, err = runtime.PullImage(src, options) + if err != nil { + return errors.Wrapf(err, "error pulling %q", src) + } } } fmt.Println("Loaded image: ", imgName) diff --git a/cmd/kpod/save.go b/cmd/kpod/save.go index 0f5fcfa4d..85a8c7930 100644 --- a/cmd/kpod/save.go +++ b/cmd/kpod/save.go @@ -3,15 +3,27 @@ package main import ( "io" "os" + "strings" + "github.com/containers/image/manifest" + imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" "github.com/projectatomic/libpod/libpod" "github.com/sirupsen/logrus" "github.com/urfave/cli" ) +const ( + ociManifestDir = "oci-dir" + v2s2ManifestDir = "docker-dir" +) + var ( saveFlags = []cli.Flag{ + cli.BoolFlag{ + Name: "compress", + Usage: "compress tarball image layers when saving to a directory using the 'dir' transport. (default is same compression type as source)", + }, cli.StringFlag{ Name: "output, o", Usage: "Write to a file, default is STDOUT", @@ -23,7 +35,7 @@ var ( }, cli.StringFlag{ Name: "format", - Usage: "Save image to oci-archive", + Usage: "Save image to oci-archive, oci-dir (directory with oci manifest type), docker-dir (directory with v2s2 manifest type)", }, } saveDescription = ` @@ -56,6 +68,10 @@ func saveCmd(c *cli.Context) error { } defer runtime.Shutdown(false) + if c.IsSet("compress") && (c.String("format") != ociManifestDir && c.String("format") != v2s2ManifestDir && c.String("format") == "") { + return errors.Errorf("--compress can only be set when --format is either 'oci-dir' or 'docker-dir'") + } + var writer io.Writer if !c.Bool("quiet") { writer = os.Stdout @@ -69,10 +85,16 @@ func saveCmd(c *cli.Context) error { } } - var dst string + var dst, manifestType string switch c.String("format") { case libpod.OCIArchive: dst = libpod.OCIArchive + ":" + output + case "oci-dir": + dst = libpod.DirTransport + ":" + output + manifestType = imgspecv1.MediaTypeImageManifest + case "docker-dir": + dst = libpod.DirTransport + ":" + output + manifestType = manifest.DockerV2Schema2MediaType case libpod.DockerArchive: fallthrough case "": @@ -84,12 +106,18 @@ func saveCmd(c *cli.Context) error { saveOpts := libpod.CopyOptions{ SignaturePolicyPath: "", Writer: writer, + ManifestMIMEType: manifestType, + ForceCompress: c.Bool("compress"), } // only one image is supported for now // future pull requests will fix this for _, image := range args { - dest := dst + ":" + image + dest := dst + // need dest to be in the format transport:path:reference for the following transports + if strings.Contains(dst, libpod.OCIArchive) || strings.Contains(dst, libpod.DockerArchive) { + dest = dst + ":" + image + } if err := runtime.PushImage(image, dest, saveOpts); err != nil { if err2 := os.Remove(output); err2 != nil { logrus.Errorf("error deleting %q: %v", output, err) diff --git a/completions/bash/kpod b/completions/bash/kpod index 417e9468d..3e291c526 100644 --- a/completions/bash/kpod +++ b/completions/bash/kpod @@ -1302,6 +1302,7 @@ _kpod_save() { --format " local boolean_options=" + --compress --quiet -q " _complete_ "$options_with_args" "$boolean_options" diff --git a/docs/kpod-save.1.md b/docs/kpod-save.1.md index dbcf96d04..ece4bea5e 100644 --- a/docs/kpod-save.1.md +++ b/docs/kpod-save.1.md @@ -14,10 +14,10 @@ kpod-save - Save an image to docker-archive or oci-archive [**--help**|**-h**] ## DESCRIPTION -**kpod save** saves an image to either **docker-archive** or **oci-archive** -on the local machine, default is **docker-archive**. -**kpod save** writes to STDOUT by default and can be redirected to a file using the **output** flag. -The **quiet** flag suppresses the output when set. +**kpod save** saves an image to either **docker-archive**, **oci-archive**, **oci-dir** (directory +with oci manifest type), or **docker-dir** (directory with v2s2 manifest type) on the local machine, +default is **docker-archive**. **kpod save** writes to STDOUT by default and can be redirected to a +file using the **output** flag. The **quiet** flag suppresses the output when set. **kpod [GLOBAL OPTIONS]** @@ -27,13 +27,20 @@ The **quiet** flag suppresses the output when set. ## OPTIONS +**--compress** + +Compress tarball image layers when pushing to a directory using the 'dir' transport. (default is same compression type, compressed or uncompressed, as source) +Note: This flag can only be set when using the **dir** transport i.e --format=oci-dir or --format-docker-dir + **--output, -o** Write to a file, default is STDOUT **--format** -Save image to **oci-archive** +Save image to **oci-archive**, **oci-dir** (directory with oci manifest type), or **docker-dir** (directory with v2s2 manifest type) ``` --format oci-archive +--format oci-dir +--format docker-dir ``` **--quiet, -q** @@ -53,6 +60,36 @@ Suppress the output # kpod save -o oci-alpine.tar --format oci-archive alpine ``` +``` +# kpod save --compress --format oci-dir -o alp-dir alpine +Getting image source signatures +Copying blob sha256:2fdfe1cd78c20d05774f0919be19bc1a3e4729bce219968e4188e7e0f1af679d + 1.97 MB / 1.97 MB [========================================================] 0s +Copying config sha256:501d1a8f0487e93128df34ea349795bc324d5e0c0d5112e08386a9dfaff620be + 584 B / 584 B [============================================================] 0s +Writing manifest to image destination +Storing signatures +``` + +``` +# kpod save --format docker-dir -o ubuntu-dir ubuntu +Getting image source signatures +Copying blob sha256:660c48dd555dcbfdfe19c80a30f557ac57a15f595250e67bfad1e5663c1725bb + 45.55 MB / 45.55 MB [======================================================] 8s +Copying blob sha256:4c7380416e7816a5ab1f840482c9c3ca8de58c6f3ee7f95e55ad299abbfe599f + 846 B / 846 B [============================================================] 0s +Copying blob sha256:421e436b5f80d876128b74139531693be9b4e59e4f1081c9a3c379c95094e375 + 620 B / 620 B [============================================================] 0s +Copying blob sha256:e4ce6c3651b3a090bb43688f512f687ea6e3e533132bcbc4a83fb97e7046cea3 + 849 B / 849 B [============================================================] 0s +Copying blob sha256:be588e74bd348ce48bb7161350f4b9d783c331f37a853a80b0b4abc0a33c569e + 169 B / 169 B [============================================================] 0s +Copying config sha256:20c44cd7596ff4807aef84273c99588d22749e2a7e15a7545ac96347baa65eda + 3.53 KB / 3.53 KB [========================================================] 0s +Writing manifest to image destination +Storing signatures +``` + ## SEE ALSO kpod(1), kpod-load(1), crio(8), crio.conf(5) diff --git a/test/kpod_load.bats b/test/kpod_load.bats index 7404cb76c..abbe8ee5d 100644 --- a/test/kpod_load.bats +++ b/test/kpod_load.bats @@ -10,10 +10,10 @@ function teardown() { cleanup_test } @test "kpod load input flag" { - run bash -c ${KPOD_BINARY} ${KPOD_OPTIONS} save -o alpine.tar $IMAGE + run bash -c ${KPOD_BINARY} ${KPOD_OPTIONS} save -o alpine.tar $ALPINE echo "$output" [ "$status" -eq 0 ] - run bash -c ${KPOD_BINARY} ${KPOD_OPTIONS} rmi $IMAGE + run bash -c ${KPOD_BINARY} ${KPOD_OPTIONS} rmi $ALPINE echo "$output" [ "$status" -eq 0 ] run bash -c ${KPOD_BINARY} ${KPOD_OPTIONS} load -i alpine.tar @@ -23,9 +23,9 @@ function teardown() { } @test "kpod load oci-archive image" { - run bash -c ${KPOD_BINARY} ${KPOD_OPTIONS} save -o alpine.tar --format oci-archive $IMAGE + run bash -c ${KPOD_BINARY} ${KPOD_OPTIONS} save -o alpine.tar --format oci-archive $ALPINE [ "$status" -eq 0 ] - run bash -c ${KPOD_BINARY} $KPOD_OPTIONS rmi $IMAGE + run bash -c ${KPOD_BINARY} $KPOD_OPTIONS rmi $ALPINE [ "$status" -eq 0 ] run bash -c ${KPOD_BINARY} ${KPOD_OPTIONS} load -i alpine.tar echo "$output" @@ -34,9 +34,9 @@ function teardown() { } @test "kpod load oci-archive image with signature-policy" { - run bash -c ${KPOD_BINARY} ${KPOD_OPTIONS} save -o alpine.tar --format oci-archive $IMAGE + run bash -c ${KPOD_BINARY} ${KPOD_OPTIONS} save -o alpine.tar --format oci-archive $ALPINE [ "$status" -eq 0 ] - run bash -c ${KPOD_BINARY} $KPOD_OPTIONS rmi $IMAGE + run bash -c ${KPOD_BINARY} $KPOD_OPTIONS rmi $ALPINE [ "$status" -eq 0 ] cp /etc/containers/policy.json /tmp run bash -c ${KPOD_BINARY} ${KPOD_OPTIONS} load --signature-policy /tmp/policy.json -i alpine.tar @@ -47,10 +47,10 @@ function teardown() { } @test "kpod load using quiet flag" { - run bash -c ${KPOD_BINARY} ${KPOD_OPTIONS} save -o alpine.tar $IMAGE + run bash -c ${KPOD_BINARY} ${KPOD_OPTIONS} save -o alpine.tar $ALPINE echo "$output" [ "$status" -eq 0 ] - run bash -c ${KPOD_BINARY} ${KPOD_OPTIONS} rmi $IMAGE + run bash -c ${KPOD_BINARY} ${KPOD_OPTIONS} rmi $ALPINE echo "$output" [ "$status" -eq 0 ] run bash -c ${KPOD_BINARY} ${KPOD_OPTIONS} load -q -i alpine.tar @@ -59,6 +59,21 @@ function teardown() { rm -f alpine.tar } +@test "kpod load directory" { + run bash -c ${KPOD_BINARY} ${KPOD_OPTIONS} save --format oci-dir -o alp-dir $ALPINE + echo "$output" + [ "$status" -eq 0 ] + run bash -c ${KPOD_BINARY} ${KPOD_OPTIONS} rmi $ALPINE + echo "$output" + [ "$status" -eq 0 ] + run bash -c ${KPOD_BINARY} ${KPOD_OPTIONS} load -i alp-dir + echo "$output" + [ "$status" -eq 0 ] + run bash -c ${KPOD_BINARY} ${KPOD_OPTIONS} rmi alp-dir + echo "$output" + [ "$status" -eq 0 ] +} + @test "kpod load non-existent file" { run ${KPOD_BINARY} ${KPOD_OPTIONS} load -i alpine.tar echo "$output" diff --git a/test/kpod_save.bats b/test/kpod_save.bats index 6da3279a2..56f23db91 100644 --- a/test/kpod_save.bats +++ b/test/kpod_save.bats @@ -42,3 +42,17 @@ function setup() { echo "$output" [ "$status" -ne 0 ] } + +@test "kpod save to directory wit oci format" { + run bash -c "${KPOD_BINARY} ${KPOD_OPTIONS} save --format oci-dir -o alp-dir $ALPINE" + echo "$output" + [ "$status" -eq 0 ] + rm -rf alp-dir +} + +@test "kpod save to directory wit v2s2 (docker) format" { + run bash -c "${KPOD_BINARY} ${KPOD_OPTIONS} save --format docker-dir -o alp-dir $ALPINE" + echo "$output" + [ "$status" -eq 0 ] + rm -rf alp-dir +} |