2017-06-30 19:10:57 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2017-09-06 14:28:59 +00:00
|
|
|
"os"
|
|
|
|
|
2017-08-31 13:04:02 +00:00
|
|
|
"fmt"
|
2017-09-09 11:14:40 +00:00
|
|
|
|
2017-08-31 13:04:02 +00:00
|
|
|
"github.com/containers/image/docker/reference"
|
|
|
|
"github.com/containers/image/pkg/sysregistries"
|
|
|
|
"github.com/containers/image/transports/alltransports"
|
|
|
|
"github.com/containers/image/types"
|
2017-06-30 19:10:57 +00:00
|
|
|
"github.com/pkg/errors"
|
2017-08-05 11:40:46 +00:00
|
|
|
"github.com/sirupsen/logrus"
|
2017-06-30 19:10:57 +00:00
|
|
|
"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",
|
|
|
|
},
|
2017-09-09 11:14:40 +00:00
|
|
|
cli.StringFlag{
|
|
|
|
Name: "signature-policy",
|
|
|
|
Usage: "`pathname` of signature policy file (not usually used)",
|
|
|
|
Hidden: true,
|
|
|
|
},
|
2017-06-30 19:10:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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: "",
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
2017-08-31 13:04:02 +00:00
|
|
|
// 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
|
|
|
|
}
|
|
|
|
|
2017-06-30 19:10:57 +00:00
|
|
|
// 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 {
|
2017-08-31 13:04:02 +00:00
|
|
|
var fqRegistries []string
|
|
|
|
|
2017-06-30 19:10:57 +00:00
|
|
|
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]
|
2017-08-31 13:04:02 +00:00
|
|
|
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())
|
|
|
|
}
|
2017-09-06 14:28:59 +00:00
|
|
|
runtime, err := getRuntime(c)
|
2017-09-09 11:14:40 +00:00
|
|
|
if err != nil {
|
|
|
|
return errors.Wrapf(err, "could not get runtime")
|
|
|
|
}
|
2017-08-31 13:04:02 +00:00
|
|
|
defer runtime.Shutdown(false)
|
|
|
|
|
2017-06-30 19:10:57 +00:00
|
|
|
if err != nil {
|
2017-09-06 14:28:59 +00:00
|
|
|
return errors.Wrapf(err, "could not create runtime")
|
2017-06-30 19:10:57 +00:00
|
|
|
}
|
2017-08-31 13:04:02 +00:00
|
|
|
for _, fqname := range fqRegistries {
|
|
|
|
fmt.Printf("Trying to pull %s...", fqname)
|
2017-09-09 11:14:40 +00:00
|
|
|
if err := runtime.PullImage(fqname, c.Bool("all-tags"), c.String("signature-policy"), os.Stdout); err != nil {
|
2017-08-31 13:04:02 +00:00
|
|
|
fmt.Printf(" Failed\n")
|
|
|
|
} else {
|
|
|
|
return nil
|
|
|
|
}
|
2017-06-30 19:10:57 +00:00
|
|
|
}
|
2017-08-31 13:04:02 +00:00
|
|
|
return errors.Errorf("error pulling image from %q", image)
|
2017-06-30 19:10:57 +00:00
|
|
|
}
|