Add 'kpod pull' command
Signed-off-by: umohnani8 <umohnani@redhat.com>
This commit is contained in:
parent
e949508b17
commit
ac9b53266d
6 changed files with 262 additions and 2 deletions
|
@ -1,7 +1,11 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io"
|
||||||
|
|
||||||
|
cp "github.com/containers/image/copy"
|
||||||
is "github.com/containers/image/storage"
|
is "github.com/containers/image/storage"
|
||||||
|
"github.com/containers/image/types"
|
||||||
"github.com/containers/storage"
|
"github.com/containers/storage"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
|
@ -9,6 +13,11 @@ import (
|
||||||
|
|
||||||
func getStore(c *cli.Context) (storage.Store, error) {
|
func getStore(c *cli.Context) (storage.Store, error) {
|
||||||
options := storage.DefaultStoreOptions
|
options := storage.DefaultStoreOptions
|
||||||
|
if c.GlobalIsSet("root") || c.GlobalIsSet("runroot") {
|
||||||
|
options.GraphRoot = c.GlobalString("root")
|
||||||
|
options.RunRoot = c.GlobalString("runroot")
|
||||||
|
}
|
||||||
|
|
||||||
if c.GlobalIsSet("storage-driver") {
|
if c.GlobalIsSet("storage-driver") {
|
||||||
options.GraphDriverName = c.GlobalString("storage-driver")
|
options.GraphDriverName = c.GlobalString("storage-driver")
|
||||||
}
|
}
|
||||||
|
@ -43,5 +52,18 @@ func findImage(store storage.Store, image string) (*storage.Image, error) {
|
||||||
img = img2
|
img = img2
|
||||||
}
|
}
|
||||||
return img, nil
|
return img, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCopyOptions(reportWriter io.Writer) *cp.Options {
|
||||||
|
return &cp.Options{
|
||||||
|
ReportWriter: reportWriter,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSystemContext(signaturePolicyPath string) *types.SystemContext {
|
||||||
|
sc := &types.SystemContext{}
|
||||||
|
if signaturePolicyPath != "" {
|
||||||
|
sc.SignaturePolicyPath = signaturePolicyPath
|
||||||
|
}
|
||||||
|
return sc
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/containers/storage/pkg/reexec"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -11,6 +12,10 @@ import (
|
||||||
const Version string = "0.0.1"
|
const Version string = "0.0.1"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
if reexec.Init() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
app := cli.NewApp()
|
app := cli.NewApp()
|
||||||
app.Name = "kpod"
|
app.Name = "kpod"
|
||||||
app.Usage = "manage pods and images"
|
app.Usage = "manage pods and images"
|
||||||
|
@ -20,6 +25,25 @@ func main() {
|
||||||
launchCommand,
|
launchCommand,
|
||||||
tagCommand,
|
tagCommand,
|
||||||
versionCommand,
|
versionCommand,
|
||||||
|
pullCommand,
|
||||||
|
}
|
||||||
|
app.Flags = []cli.Flag{
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "root",
|
||||||
|
Usage: "path to the root directory in which data, including images, is stored",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "runroot",
|
||||||
|
Usage: "path to the 'run directory' where all state information is stored",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "storage-driver, s",
|
||||||
|
Usage: "select which storage driver is used to manage storage of images and containers (default is overlay2)",
|
||||||
|
},
|
||||||
|
cli.StringSliceFlag{
|
||||||
|
Name: "storage-opt",
|
||||||
|
Usage: "used to pass an option to the storage driver",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := app.Run(os.Args); err != nil {
|
if err := app.Run(os.Args); err != nil {
|
||||||
|
|
125
cmd/kpod/pull.go
Normal file
125
cmd/kpod/pull.go
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
cp "github.com/containers/image/copy"
|
||||||
|
"github.com/containers/image/docker/reference"
|
||||||
|
"github.com/containers/image/signature"
|
||||||
|
is "github.com/containers/image/storage"
|
||||||
|
"github.com/containers/image/transports/alltransports"
|
||||||
|
"github.com/containers/image/types"
|
||||||
|
"github.com/containers/storage"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/urfave/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// DefaultRegistry is a prefix that we apply to an image name
|
||||||
|
// to check docker hub first for the image
|
||||||
|
DefaultRegistry = "docker://"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
pullFlags = []cli.Flag{
|
||||||
|
cli.BoolFlag{
|
||||||
|
// all-tags is hidden since it has not been implemented yet
|
||||||
|
Name: "all-tags, a",
|
||||||
|
Hidden: true,
|
||||||
|
Usage: "Download all tagged images in the repository",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
pullDescription = "Pulls an image from a registry and stores it locally.\n" +
|
||||||
|
"An image can be pulled using its tag or digest. If a tag is not\n" +
|
||||||
|
"specified, the image with the 'latest' tag (if it exists) is pulled."
|
||||||
|
pullCommand = cli.Command{
|
||||||
|
Name: "pull",
|
||||||
|
Usage: "pull an image from a registry",
|
||||||
|
Description: pullDescription,
|
||||||
|
Flags: pullFlags,
|
||||||
|
Action: pullCmd,
|
||||||
|
ArgsUsage: "",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// pullCmd gets the data from the command line and calls pullImage
|
||||||
|
// to copy an image from a registry to a local machine
|
||||||
|
func pullCmd(c *cli.Context) error {
|
||||||
|
args := c.Args()
|
||||||
|
if len(args) == 0 {
|
||||||
|
logrus.Errorf("an image name must be specified")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if len(args) > 1 {
|
||||||
|
logrus.Errorf("too many arguments. Requires exactly 1")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
image := args[0]
|
||||||
|
|
||||||
|
store, err := getStore(c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
allTags := false
|
||||||
|
if c.IsSet("all-tags") {
|
||||||
|
allTags = c.Bool("all-tags")
|
||||||
|
}
|
||||||
|
|
||||||
|
systemContext := getSystemContext("")
|
||||||
|
|
||||||
|
err = pullImage(store, image, allTags, systemContext)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Errorf("error pulling image from %q: %v", image, err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// pullImage copies the image from the source to the destination
|
||||||
|
func pullImage(store storage.Store, imgName string, allTags bool, sc *types.SystemContext) error {
|
||||||
|
defaultName := DefaultRegistry + imgName
|
||||||
|
var fromName string
|
||||||
|
var tag string
|
||||||
|
|
||||||
|
srcRef, err := alltransports.ParseImageName(defaultName)
|
||||||
|
if err != nil {
|
||||||
|
srcRef2, err2 := alltransports.ParseImageName(imgName)
|
||||||
|
if err2 != nil {
|
||||||
|
return errors.Wrapf(err2, "error parsing image name %q", imgName)
|
||||||
|
}
|
||||||
|
srcRef = srcRef2
|
||||||
|
}
|
||||||
|
|
||||||
|
ref := srcRef.DockerReference()
|
||||||
|
if ref != nil {
|
||||||
|
imgName = srcRef.DockerReference().Name()
|
||||||
|
fromName = imgName
|
||||||
|
tagged, ok := srcRef.DockerReference().(reference.NamedTagged)
|
||||||
|
if ok {
|
||||||
|
imgName = imgName + ":" + tagged.Tag()
|
||||||
|
tag = tagged.Tag()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
destRef, err := is.Transport.ParseStoreReference(store, imgName)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "error parsing full image name %q", imgName)
|
||||||
|
}
|
||||||
|
|
||||||
|
policy, err := signature.DefaultPolicy(sc)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
policyContext, err := signature.NewPolicyContext(policy)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(tag + ": pulling from " + fromName)
|
||||||
|
|
||||||
|
return cp.Image(policyContext, destRef, srcRef, getCopyOptions(os.Stdout))
|
||||||
|
}
|
|
@ -33,7 +33,7 @@ _kpod_version() {
|
||||||
local boolean_options="
|
local boolean_options="
|
||||||
"
|
"
|
||||||
_complete_ "$options_with_args" "$boolean_options"
|
_complete_ "$options_with_args" "$boolean_options"
|
||||||
}
|
}
|
||||||
|
|
||||||
kpod_tag() {
|
kpod_tag() {
|
||||||
local options_with_args="
|
local options_with_args="
|
||||||
|
@ -43,6 +43,15 @@ kpod_tag() {
|
||||||
_complete_ "$options_with_args" "$boolean_options"
|
_complete_ "$options_with_args" "$boolean_options"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_kpod_pull() {
|
||||||
|
local options_with_args="
|
||||||
|
"
|
||||||
|
local boolean_options="
|
||||||
|
--all-tags -a
|
||||||
|
"
|
||||||
|
_complete_ "$options_with_args" "$boolean_options"
|
||||||
|
}
|
||||||
|
|
||||||
_kpod_kpod() {
|
_kpod_kpod() {
|
||||||
local options_with_args="
|
local options_with_args="
|
||||||
"
|
"
|
||||||
|
@ -54,6 +63,7 @@ _kpod_kpod() {
|
||||||
launch
|
launch
|
||||||
tag
|
tag
|
||||||
version
|
version
|
||||||
|
pull
|
||||||
"
|
"
|
||||||
|
|
||||||
case "$prev" in
|
case "$prev" in
|
||||||
|
|
39
docs/kpod-pull.1.md
Normal file
39
docs/kpod-pull.1.md
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
% kpod(8) # kpod-pull - Simple tool to pull an image from a registry
|
||||||
|
% Urvashi Mohnani
|
||||||
|
% JULY 2017
|
||||||
|
# NAME
|
||||||
|
kpod-pull - Pull an image from a registry
|
||||||
|
|
||||||
|
# SYNOPSIS
|
||||||
|
**kpod pull**
|
||||||
|
**NAME[:TAG|@DISGEST]**
|
||||||
|
[**--help**|**-h**]
|
||||||
|
|
||||||
|
# DESCRIPTION
|
||||||
|
Copies an image from a registry onto the local machine. **kpod pull** pulls an
|
||||||
|
image from Docker Hub if a registry is not specified in the command line argument.
|
||||||
|
If an image tag is not specified, **kpod pull** defaults to the image with the
|
||||||
|
**latest** tag (if it exists) and pulls it. **kpod pull** can also pull an image
|
||||||
|
using its digest **kpod pull [image]@[digest]**.
|
||||||
|
|
||||||
|
**kpod [GLOBAL OPTIONS]**
|
||||||
|
|
||||||
|
**kpod pull [GLOBAL OPTIONS]**
|
||||||
|
|
||||||
|
**kpod pull NAME[:TAG|@DIGEST] [GLOBAL OPTIONS]**
|
||||||
|
|
||||||
|
# GLOBAL OPTIONS
|
||||||
|
|
||||||
|
**--help, -h**
|
||||||
|
Print usage statement
|
||||||
|
|
||||||
|
# COMMANDS
|
||||||
|
|
||||||
|
## pull
|
||||||
|
Pull an image from a registry
|
||||||
|
|
||||||
|
# SEE ALSO
|
||||||
|
kpod(1), crio(8), crio.conf(5)
|
||||||
|
|
||||||
|
# HISTORY
|
||||||
|
July 2017, Originally compiled by Urvashi Mohnani <umohnani@redhat.com>
|
|
@ -2,8 +2,48 @@
|
||||||
|
|
||||||
load helpers
|
load helpers
|
||||||
|
|
||||||
|
ROOT="$TESTDIR/crio"
|
||||||
|
RUNROOT="$TESTDIR/crio-run"
|
||||||
|
KPOD_OPTIONS="--root $ROOT --runroot $RUNROOT --storage-driver vfs"
|
||||||
|
|
||||||
@test "kpod version test" {
|
@test "kpod version test" {
|
||||||
run ${KPOD_BINARY} version
|
run ${KPOD_BINARY} version
|
||||||
echo "$output"
|
echo "$output"
|
||||||
[ "$status" -eq 0 ]
|
[ "$status" -eq 0 ]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@test "kpod pull from docker with tag" {
|
||||||
|
run ${KPOD_BINARY} $KPOD_OPTIONS pull debian:6.0.10
|
||||||
|
echo "$output"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "kpod pull from docker without tag" {
|
||||||
|
run ${KPOD_BINARY} $KPOD_OPTIONS pull debian
|
||||||
|
echo "$output"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "kpod pull from a non-docker registry with tag" {
|
||||||
|
run ${KPOD_BINARY} $KPOD_OPTIONS pull registry.fedoraproject.org/fedora:rawhide
|
||||||
|
echo "$output"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "kpod pull from a non-docker registry without tag" {
|
||||||
|
run ${KPOD_BINARY} $KPOD_OPTIONS pull registry.fedoraproject.org/fedora
|
||||||
|
echo "$output"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "kpod pull using digest" {
|
||||||
|
run ${KPOD_BINARY} $KPOD_OPTIONS pull debian@sha256:7d067f77d2ae5a23fe6920f8fbc2936c4b0d417e9d01b26372561860750815f0
|
||||||
|
echo "$output"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "kpod pull from a non existent image" {
|
||||||
|
run ${KPOD_BINARY} $KPOD_OPTIONS pull umohnani/get-started
|
||||||
|
echo "$output"
|
||||||
|
[ "$status" -ne 0 ]
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue