cri-o/cmd/kpod/pull.go
Daniel J Walsh 04e96d05fc validateFlags command line options to make sure the user entered a value
When a user enters a CLI with a StringFlags or StringSliceFlags and does not add
a value the CLI mistakently takes the next option and uses it as a value.

This usually ends up with an error like not enough options or others.  Some times
it could also succeed, with weird results.  This patch looks for any values that
begin with a "-" and return an error.

Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2017-10-04 09:36:29 +00:00

163 lines
4.5 KiB
Go

package main
import (
"os"
"fmt"
"github.com/containers/image/docker/reference"
"github.com/containers/image/pkg/sysregistries"
"github.com/containers/image/transports/alltransports"
"github.com/containers/image/types"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
)
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",
},
cli.StringFlag{
Name: "signature-policy",
Usage: "`pathname` of signature policy file (not usually used)",
Hidden: true,
},
}
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: "",
}
)
// struct for when a user passes a short or incomplete
// image name
type imagePullStruct struct {
imageName string
tag string
registry string
hasRegistry bool
transport string
}
func (ips imagePullStruct) returnFQName() string {
return fmt.Sprintf("%s%s/%s:%s", ips.transport, ips.registry, ips.imageName, ips.tag)
}
func getRegistriesToTry(image string) ([]string, error) {
var registries []string
var imageError = fmt.Sprintf("unable to parse '%s'\n", image)
imgRef, err := reference.Parse(image)
if err != nil {
return nil, errors.Wrapf(err, imageError)
}
tagged, isTagged := imgRef.(reference.NamedTagged)
tag := "latest"
if isTagged {
tag = tagged.Tag()
}
hasDomain := true
registry := reference.Domain(imgRef.(reference.Named))
if registry == "" {
hasDomain = false
}
imageName := reference.Path(imgRef.(reference.Named))
pImage := imagePullStruct{
imageName,
tag,
registry,
hasDomain,
"docker://",
}
if pImage.hasRegistry {
// If input has a registry, we have to assume they included an image
// name but maybe not a tag
pullRef, err := alltransports.ParseImageName(pImage.returnFQName())
if err != nil {
return nil, errors.Errorf(imageError)
}
registries = append(registries, pullRef.DockerReference().String())
} else {
// No registry means we check the globals registries configuration file
// and assemble a list of candidate sources to try
registryConfigPath := ""
envOverride := os.Getenv("REGISTRIES_CONFIG_PATH")
if len(envOverride) > 0 {
registryConfigPath = envOverride
}
searchRegistries, err := sysregistries.GetRegistries(&types.SystemContext{SystemRegistriesConfPath: registryConfigPath})
if err != nil {
fmt.Println(err)
return nil, errors.Errorf("unable to parse the registries.conf file and"+
" the image name '%s' is incomplete.", imageName)
}
for _, searchRegistry := range searchRegistries {
pImage.registry = searchRegistry
pullRef, err := alltransports.ParseImageName(pImage.returnFQName())
if err != nil {
return nil, errors.Errorf("unable to parse '%s'", pImage.returnFQName())
}
registries = append(registries, pullRef.DockerReference().String())
}
}
return registries, nil
}
// 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 {
var fqRegistries []string
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
}
if err := validateFlags(c, pullFlags); err != nil {
return err
}
image := args[0]
srcRef, err := alltransports.ParseImageName(image)
if err != nil {
fqRegistries, err = getRegistriesToTry(image)
if err != nil {
fmt.Println(err)
}
} else {
fqRegistries = append(fqRegistries, srcRef.DockerReference().String())
}
runtime, err := getRuntime(c)
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
defer runtime.Shutdown(false)
if err != nil {
return errors.Wrapf(err, "could not create runtime")
}
for _, fqname := range fqRegistries {
fmt.Printf("Trying to pull %s...", fqname)
if err := runtime.PullImage(fqname, c.Bool("all-tags"), c.String("signature-policy"), os.Stdout); err != nil {
fmt.Printf(" Failed\n")
} else {
return nil
}
}
return errors.Errorf("error pulling image from %q", image)
}