04e96d05fc
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>
163 lines
4.5 KiB
Go
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)
|
|
}
|