Add authfile flag to pull and push

Push and pull can now access any cached registry credentials from the auth file

Signed-off-by: umohnani8 <umohnani@redhat.com>
This commit is contained in:
umohnani8 2017-10-13 17:04:57 -04:00
parent 0914a7a667
commit d855e2c8ad
13 changed files with 428 additions and 210 deletions

View file

@ -95,14 +95,19 @@ func loadCmd(c *cli.Context) error {
output = os.Stdout
}
options := libpod.CopyOptions{
SignaturePolicyPath: c.String("signature-policy"),
Writer: output,
}
src := libpod.DockerArchive + ":" + input
if err := runtime.PullImage(src, false, c.String("signature-policy"), output); err != nil {
if err := runtime.PullImage(src, options); err != nil {
src = libpod.OCIArchive + ":" + input
// generate full src name with specified image:tag
if image != "" {
src = src + ":" + image
}
if err := runtime.PullImage(src, false, "", output); err != nil {
if err := runtime.PullImage(src, options); err != nil {
return errors.Wrapf(err, "error pulling %q", src)
}
}

View file

@ -38,6 +38,9 @@ func logoutCmd(c *cli.Context) error {
if len(args) > 1 {
return errors.Errorf("too many arguments, logout takes only 1 argument")
}
if len(args) == 0 {
return errors.Errorf("registry must be given")
}
var server string
if len(args) == 1 {
server = args[0]

View file

@ -1,14 +1,14 @@
package main
import (
"fmt"
"os"
"fmt"
"golang.org/x/crypto/ssh/terminal"
"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/kubernetes-incubator/cri-o/libpod"
"github.com/kubernetes-incubator/cri-o/libpod/common"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
@ -16,16 +16,18 @@ import (
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)",
},
cli.StringFlag{
Name: "authfile",
Usage: "Path of the authentication file. Default is ${XDG_RUNTIME_DIR}/containers/auth.json",
},
cli.StringFlag{
Name: "creds",
Usage: "`credentials` (USERNAME:PASSWORD) to use for authenticating to a registry",
},
}
pullDescription = "Pulls an image from a registry and stores it locally.\n" +
@ -41,83 +43,14 @@ var (
}
)
// 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
runtime, err := getRuntime(c)
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
defer runtime.Shutdown(false)
args := c.Args()
if len(args) == 0 {
@ -132,31 +65,34 @@ func pullCmd(c *cli.Context) error {
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
var registryCreds *types.DockerAuthConfig
if c.String("creds") != "" {
creds, err := common.ParseRegistryCreds(c.String("creds"))
if err != nil {
if err == common.ErrNoPassword {
fmt.Print("Password: ")
password, err := terminal.ReadPassword(0)
if err != nil {
return errors.Wrapf(err, "could not read password from terminal")
}
creds.Password = string(password)
} else {
return err
}
}
registryCreds = creds
}
return errors.Errorf("error pulling image from %q", image)
options := libpod.CopyOptions{
SignaturePolicyPath: c.String("signature-policy"),
AuthFile: c.String("authfile"),
DockerRegistryOptions: common.DockerRegistryOptions{
DockerRegistryCreds: registryCreds,
},
Writer: os.Stdout,
}
return runtime.PullImage(image, options)
}

View file

@ -45,6 +45,10 @@ var (
Name: "quiet, q",
Usage: "don't output progress information when pushing images",
},
cli.StringFlag{
Name: "authfile",
Usage: "Path of the authentication file. Default is ${XDG_RUNTIME_DIR}/containers/auth.json",
},
}
pushDescription = fmt.Sprintf(`
Pushes an image to a specified location.
@ -120,7 +124,9 @@ func pushCmd(c *cli.Context) error {
RemoveSignatures: removeSignatures,
SignBy: signBy,
},
AuthFile: c.String("authfile"),
Writer: writer,
}
return runtime.PushImage(srcName, destName, options, writer)
return runtime.PushImage(srcName, destName, options)
}

View file

@ -83,13 +83,14 @@ func saveCmd(c *cli.Context) error {
saveOpts := libpod.CopyOptions{
SignaturePolicyPath: "",
Writer: writer,
}
// only one image is supported for now
// future pull requests will fix this
for _, image := range args {
dest := dst + ":" + image
if err := runtime.PushImage(image, dest, saveOpts, writer); err != nil {
if err := runtime.PushImage(image, dest, saveOpts); err != nil {
return errors.Wrapf(err, "unable to save %q", image)
}
}