Merge pull request #678 from umohnani8/kpod_save
Add 'kpod save' command
This commit is contained in:
commit
d2a82a28c1
7 changed files with 214 additions and 0 deletions
|
@ -47,6 +47,7 @@ It is currently in active development in the Kubernetes community through the [d
|
||||||
| [kpod-pull(1)](/docs/kpod-pull.1.md) | Pull an image from a registry |
|
| [kpod-pull(1)](/docs/kpod-pull.1.md) | Pull an image from a registry |
|
||||||
| [kpod-push(1)](/docs/kpod-push.1.md) | Push an image to a specified destination |
|
| [kpod-push(1)](/docs/kpod-push.1.md) | Push an image to a specified destination |
|
||||||
| [kpod-rmi(1)](/docs/kpod-rmi.1.md) | Removes one or more images |
|
| [kpod-rmi(1)](/docs/kpod-rmi.1.md) | Removes one or more images |
|
||||||
|
| [kpod-save(1)](/docs/kpod-save.1.md) | Saves an image to an archive |
|
||||||
| [kpod-tag(1)](/docs/kpod-tag.1.md) | Add an additional name to a local image |
|
| [kpod-tag(1)](/docs/kpod-tag.1.md) | Add an additional name to a local image |
|
||||||
| [kpod-version(1)](/docs/kpod-version.1.md) | Display the Kpod Version Information |
|
| [kpod-version(1)](/docs/kpod-version.1.md) | Display the Kpod Version Information |
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@ func main() {
|
||||||
rmiCommand,
|
rmiCommand,
|
||||||
tagCommand,
|
tagCommand,
|
||||||
versionCommand,
|
versionCommand,
|
||||||
|
saveCommand,
|
||||||
}
|
}
|
||||||
app.Flags = []cli.Flag{
|
app.Flags = []cli.Flag{
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
|
|
96
cmd/kpod/save.go
Normal file
96
cmd/kpod/save.go
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/containers/storage"
|
||||||
|
libkpodimage "github.com/kubernetes-incubator/cri-o/libkpod/image"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/urfave/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
dockerArchive = "docker-archive:"
|
||||||
|
)
|
||||||
|
|
||||||
|
type saveOptions struct {
|
||||||
|
output string
|
||||||
|
quiet bool
|
||||||
|
images []string
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
saveFlags = []cli.Flag{
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "output, o",
|
||||||
|
Usage: "Write to a file, default is STDOUT",
|
||||||
|
Value: "/dev/stdout",
|
||||||
|
},
|
||||||
|
cli.BoolFlag{
|
||||||
|
Name: "quiet, q",
|
||||||
|
Usage: "Suppress the output",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
saveDescription = "Save an image to docker-archive on the local machine"
|
||||||
|
saveCommand = cli.Command{
|
||||||
|
Name: "save",
|
||||||
|
Usage: "Save image to an archive",
|
||||||
|
Description: saveDescription,
|
||||||
|
Flags: saveFlags,
|
||||||
|
Action: saveCmd,
|
||||||
|
ArgsUsage: "",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// saveCmd saves the image to either docker-archive or oci
|
||||||
|
func saveCmd(c *cli.Context) error {
|
||||||
|
args := c.Args()
|
||||||
|
if len(args) == 0 {
|
||||||
|
return errors.Errorf("need at least 1 argument")
|
||||||
|
}
|
||||||
|
|
||||||
|
store, err := getStore(c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
output := c.String("output")
|
||||||
|
quiet := c.Bool("quiet")
|
||||||
|
|
||||||
|
if output == "/dev/stdout" {
|
||||||
|
fi := os.Stdout
|
||||||
|
if logrus.IsTerminal(fi) {
|
||||||
|
return errors.Errorf("refusing to save to terminal. Use -o flag or redirect")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
opts := saveOptions{
|
||||||
|
output: output,
|
||||||
|
quiet: quiet,
|
||||||
|
images: args,
|
||||||
|
}
|
||||||
|
|
||||||
|
return saveImage(store, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
// saveImage pushes the image to docker-archive or oci by
|
||||||
|
// calling pushImageForSave
|
||||||
|
func saveImage(store storage.Store, opts saveOptions) error {
|
||||||
|
dst := dockerArchive + opts.output
|
||||||
|
|
||||||
|
pushOpts := libkpodimage.CopyOptions{
|
||||||
|
SignaturePolicyPath: "",
|
||||||
|
Store: store,
|
||||||
|
}
|
||||||
|
|
||||||
|
// only one image is supported for now
|
||||||
|
// future pull requests will fix this
|
||||||
|
for _, image := range opts.images {
|
||||||
|
dest := dst + ":" + image
|
||||||
|
if err := libkpodimage.PushImage(image, dest, pushOpts); err != nil {
|
||||||
|
return errors.Wrapf(err, "unable to save %q", image)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -130,6 +130,16 @@ _kpod_version() {
|
||||||
_complete_ "$options_with_args" "$boolean_options"
|
_complete_ "$options_with_args" "$boolean_options"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_kpod_save() {
|
||||||
|
local options_with_args="
|
||||||
|
--output -o
|
||||||
|
"
|
||||||
|
local boolean_options="
|
||||||
|
--quiet -q
|
||||||
|
"
|
||||||
|
_complete_ "$options_with_args" "$boolean_options"
|
||||||
|
}
|
||||||
|
|
||||||
_complete_() {
|
_complete_() {
|
||||||
local options_with_args=$1
|
local options_with_args=$1
|
||||||
local boolean_options="$2 -h --help"
|
local boolean_options="$2 -h --help"
|
||||||
|
|
51
docs/kpod-save.1.md
Normal file
51
docs/kpod-save.1.md
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
% kpod(1) kpod-save - Simple tool to save an image to an archive
|
||||||
|
% Urvashi Mohnani
|
||||||
|
# kpod-save "1" "July 2017" "kpod"
|
||||||
|
|
||||||
|
## NAME
|
||||||
|
kpod-save - save an image to docker-archive or oci
|
||||||
|
|
||||||
|
## SYNOPSIS
|
||||||
|
**kpod save**
|
||||||
|
**NAME[:TAG]**
|
||||||
|
[**--help**|**-h**]
|
||||||
|
|
||||||
|
## DESCRIPTION
|
||||||
|
**kpod save** saves an image to either **docker-archive** on the loacl machine.
|
||||||
|
**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]**
|
||||||
|
|
||||||
|
**kpod save [GLOBAL OPTIONS]**
|
||||||
|
|
||||||
|
**kpod save [OPTIONS] NAME[:TAG] [GLOBAL OPTIONS]**
|
||||||
|
|
||||||
|
## OPTIONS
|
||||||
|
|
||||||
|
**--output, -o**
|
||||||
|
Write to a file, default is STDOUT
|
||||||
|
|
||||||
|
**--quiet, -q**
|
||||||
|
Suppress the output
|
||||||
|
|
||||||
|
## GLOBAL OPTIONS
|
||||||
|
|
||||||
|
**--help, -h**
|
||||||
|
Print usage statement
|
||||||
|
|
||||||
|
## EXAMPLES
|
||||||
|
|
||||||
|
```
|
||||||
|
# kpod save --quiet -o alpine.tar alpine:2.6
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
# kpod save > alpine-all.tar alpine
|
||||||
|
```
|
||||||
|
|
||||||
|
## SEE ALSO
|
||||||
|
kpod(1), kpod-load(1), crio(8), crio.conf(5)
|
||||||
|
|
||||||
|
## HISTORY
|
||||||
|
July 2017, Originally compiled by Urvashi Mohnani <umohnani@redhat.com>
|
|
@ -115,6 +115,7 @@ function teardown() {
|
||||||
|
|
||||||
@test "kpod history json flag" {
|
@test "kpod history json flag" {
|
||||||
run ${KPOD_BINARY} ${KPOD_OPTIONS} pull $IMAGE
|
run ${KPOD_BINARY} ${KPOD_OPTIONS} pull $IMAGE
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
run bash -c "${KPOD_BINARY} ${KPOD_OPTIONS} history --json $IMAGE | python -m json.tool"
|
run bash -c "${KPOD_BINARY} ${KPOD_OPTIONS} history --json $IMAGE | python -m json.tool"
|
||||||
echo "$output"
|
echo "$output"
|
||||||
[ "$status" -eq 0 ]
|
[ "$status" -eq 0 ]
|
||||||
|
|
54
test/kpod_save.bats
Normal file
54
test/kpod_save.bats
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
#!/usr/bin/env bats
|
||||||
|
|
||||||
|
load helpers
|
||||||
|
|
||||||
|
IMAGE="alpine:latest"
|
||||||
|
ROOT="$TESTDIR/crio"
|
||||||
|
RUNROOT="$TESTDIR/crio-run"
|
||||||
|
KPOD_OPTIONS="--root $ROOT --runroot $RUNROOT --storage-driver vfs"
|
||||||
|
|
||||||
|
function teardown() {
|
||||||
|
cleanup_test
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "kpod save output flag" {
|
||||||
|
run ${KPOD_BINARY} ${KPOD_OPTIONS} pull $IMAGE
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
run ${KPOD_BINARY} ${KPOD_OPTIONS} save -o alpine.tar $IMAGE
|
||||||
|
echo "$output"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
run ${KPOD_BINARY} ${KPOD_OPTIONS} rmi $IMAGE
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
rm -f alpine.tar
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "kpod save using stdout" {
|
||||||
|
run ${KPOD_BINARY} ${KPOD_OPTIONS} pull $IMAGE
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
run ${KPOD_BINARY} ${KPOD_OPTIONS} save > alpine.tar $IMAGE
|
||||||
|
echo "$output"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
run ${KPOD_BINARY} ${KPOD_OPTIONS} rmi $IMAGE
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
rm -f alpine.tar
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "kpod save quiet flag" {
|
||||||
|
run ${KPOD_BINARY} ${KPOD_OPTIONS} pull $IMAGE
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
run ${KPOD_BINARY} ${KPOD_OPTIONS} save -q -o alpine.tar $IMAGE
|
||||||
|
echo "$output"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
run ${KPOD_BINARY} ${KPOD_OPTIONS} rmi $IMAGE
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
rm -f alpine.tar
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "kpod save non-existent image" {
|
||||||
|
run ${KPOD_BINARY} ${KPOD_OPTIONS} save -o alpine.tar $IMAGE
|
||||||
|
echo "$output"
|
||||||
|
[ "$status" -ne 0 ]
|
||||||
|
}
|
Loading…
Reference in a new issue