Refactor image commands to make use of the new trust struct for trusted pull

Signed-off-by: Daniel Nephin <dnephin@docker.com>
This commit is contained in:
Daniel Nephin 2017-09-26 12:53:21 -04:00
parent d956386b2d
commit 4203b49431
9 changed files with 139 additions and 129 deletions

View File

@ -6,8 +6,8 @@ import (
"github.com/docker/cli/cli" "github.com/docker/cli/cli"
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/trust"
"github.com/docker/distribution/reference" "github.com/docker/distribution/reference"
"github.com/docker/docker/registry"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"golang.org/x/net/context" "golang.org/x/net/context"
@ -40,11 +40,14 @@ func NewPullCommand(dockerCli command.Cli) *cobra.Command {
return cmd return cmd
} }
func runPull(dockerCli command.Cli, opts pullOptions) error { func runPull(cli command.Cli, opts pullOptions) error {
distributionRef, err := reference.ParseNormalizedNamed(opts.remote) ctx := context.Background()
imgRefAndAuth, err := trust.GetImageReferencesAndAuth(ctx, AuthResolver(cli), opts.remote)
if err != nil { if err != nil {
return err return err
} }
distributionRef := imgRefAndAuth.Reference()
if opts.all && !reference.IsNameOnly(distributionRef) { if opts.all && !reference.IsNameOnly(distributionRef) {
return errors.New("tag can't be used with --all-tags/-a") return errors.New("tag can't be used with --all-tags/-a")
} }
@ -52,27 +55,16 @@ func runPull(dockerCli command.Cli, opts pullOptions) error {
if !opts.all && reference.IsNameOnly(distributionRef) { if !opts.all && reference.IsNameOnly(distributionRef) {
distributionRef = reference.TagNameOnly(distributionRef) distributionRef = reference.TagNameOnly(distributionRef)
if tagged, ok := distributionRef.(reference.Tagged); ok { if tagged, ok := distributionRef.(reference.Tagged); ok {
fmt.Fprintf(dockerCli.Out(), "Using default tag: %s\n", tagged.Tag()) fmt.Fprintf(cli.Out(), "Using default tag: %s\n", tagged.Tag())
} }
} }
// Resolve the Repository name from fqn to RepositoryInfo
repoInfo, err := registry.ParseRepositoryInfo(distributionRef)
if err != nil {
return err
}
ctx := context.Background()
authConfig := command.ResolveAuthConfig(ctx, dockerCli, repoInfo.Index)
requestPrivilege := command.RegistryAuthenticationPrivilegedFunc(dockerCli, repoInfo.Index, "pull")
// Check if reference has a digest // Check if reference has a digest
_, isCanonical := distributionRef.(reference.Canonical) _, isCanonical := distributionRef.(reference.Canonical)
if command.IsTrusted() && !isCanonical { if command.IsTrusted() && !isCanonical {
err = trustedPull(ctx, dockerCli, repoInfo, distributionRef, authConfig, requestPrivilege) err = trustedPull(ctx, cli, imgRefAndAuth)
} else { } else {
err = imagePullPrivileged(ctx, dockerCli, authConfig, reference.FamiliarString(distributionRef), requestPrivilege, opts.all) err = imagePullPrivileged(ctx, cli, imgRefAndAuth, opts.all)
} }
if err != nil { if err != nil {
if strings.Contains(err.Error(), "when fetching 'plugin'") { if strings.Contains(err.Error(), "when fetching 'plugin'") {
@ -80,6 +72,5 @@ func runPull(dockerCli command.Cli, opts pullOptions) error {
} }
return err return err
} }
return nil return nil
} }

View File

@ -32,11 +32,6 @@ func TestNewPullCommandErrors(t *testing.T) {
expectedError: "tag can't be used with --all-tags/-a", expectedError: "tag can't be used with --all-tags/-a",
args: []string{"--all-tags", "image:tag"}, args: []string{"--all-tags", "image:tag"},
}, },
{
name: "pull-error",
args: []string{"--disable-content-trust=false", "image:tag"},
expectedError: "you are not authorized to perform this operation: server returned 401.",
},
} }
for _, tc := range testCases { for _, tc := range testCases {
cli := test.NewFakeCli(&fakeClient{}) cli := test.NewFakeCli(&fakeClient{})

View File

@ -11,11 +11,12 @@ import (
"github.com/docker/cli/cli/trust" "github.com/docker/cli/cli/trust"
"github.com/docker/distribution/reference" "github.com/docker/distribution/reference"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
registrytypes "github.com/docker/docker/api/types/registry"
"github.com/docker/docker/pkg/jsonmessage" "github.com/docker/docker/pkg/jsonmessage"
"github.com/docker/docker/registry" "github.com/docker/docker/registry"
"github.com/docker/notary/client" "github.com/docker/notary/client"
"github.com/docker/notary/tuf/data" "github.com/docker/notary/tuf/data"
"github.com/opencontainers/go-digest" digest "github.com/opencontainers/go-digest"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"golang.org/x/net/context" "golang.org/x/net/context"
@ -181,57 +182,13 @@ func imagePushPrivileged(ctx context.Context, cli command.Cli, authConfig types.
} }
// trustedPull handles content trust pulling of an image // trustedPull handles content trust pulling of an image
func trustedPull(ctx context.Context, cli command.Cli, repoInfo *registry.RepositoryInfo, ref reference.Named, authConfig types.AuthConfig, requestPrivilege types.RequestPrivilegeFunc) error { func trustedPull(ctx context.Context, cli command.Cli, imgRefAndAuth trust.ImageRefAndAuth) error {
var refs []target refs, err := getTrustedPullTargets(cli, imgRefAndAuth)
notaryRepo, err := trust.GetNotaryRepository(cli.In(), cli.Out(), command.UserAgent(), repoInfo, &authConfig, "pull")
if err != nil {
fmt.Fprintf(cli.Out(), "Error establishing connection to trust repository: %s\n", err)
return err
}
if tagged, isTagged := ref.(reference.NamedTagged); !isTagged {
// List all targets
targets, err := notaryRepo.ListTargets(trust.ReleasesRole, data.CanonicalTargetsRole)
if err != nil {
return trust.NotaryError(ref.Name(), err)
}
for _, tgt := range targets {
t, err := convertTarget(tgt.Target)
if err != nil {
fmt.Fprintf(cli.Out(), "Skipping target for %q\n", reference.FamiliarName(ref))
continue
}
// Only list tags in the top level targets role or the releases delegation role - ignore
// all other delegation roles
if tgt.Role != trust.ReleasesRole && tgt.Role != data.CanonicalTargetsRole {
continue
}
refs = append(refs, t)
}
if len(refs) == 0 {
return trust.NotaryError(ref.Name(), errors.Errorf("No trusted tags for %s", ref.Name()))
}
} else {
t, err := notaryRepo.GetTargetByName(tagged.Tag(), trust.ReleasesRole, data.CanonicalTargetsRole)
if err != nil {
return trust.NotaryError(ref.Name(), err)
}
// Only get the tag if it's in the top level targets role or the releases delegation role
// ignore it if it's in any other delegation roles
if t.Role != trust.ReleasesRole && t.Role != data.CanonicalTargetsRole {
return trust.NotaryError(ref.Name(), errors.Errorf("No trust data for %s", tagged.Tag()))
}
logrus.Debugf("retrieving target for %s role\n", t.Role)
r, err := convertTarget(t.Target)
if err != nil { if err != nil {
return err return err
}
refs = append(refs, r)
} }
ref := imgRefAndAuth.Reference()
for i, r := range refs { for i, r := range refs {
displayTag := r.name displayTag := r.name
if displayTag != "" { if displayTag != "" {
@ -243,7 +200,7 @@ func trustedPull(ctx context.Context, cli command.Cli, repoInfo *registry.Reposi
if err != nil { if err != nil {
return err return err
} }
if err := imagePullPrivileged(ctx, cli, authConfig, reference.FamiliarString(trustedRef), requestPrivilege, false); err != nil { if err := imagePullPrivileged(ctx, cli, imgRefAndAuth, false); err != nil {
return err return err
} }
@ -259,13 +216,65 @@ func trustedPull(ctx context.Context, cli command.Cli, repoInfo *registry.Reposi
return nil return nil
} }
// imagePullPrivileged pulls the image and displays it to the output func getTrustedPullTargets(cli command.Cli, imgRefAndAuth trust.ImageRefAndAuth) ([]target, error) {
func imagePullPrivileged(ctx context.Context, cli command.Cli, authConfig types.AuthConfig, ref string, requestPrivilege types.RequestPrivilegeFunc, all bool) error { notaryRepo, err := cli.NotaryClient(imgRefAndAuth, trust.ActionsPullOnly)
if err != nil {
fmt.Fprintf(cli.Out(), "Error establishing connection to trust repository: %s\n", err)
return nil, err
}
encodedAuth, err := command.EncodeAuthToBase64(authConfig) ref := imgRefAndAuth.Reference()
tagged, isTagged := ref.(reference.NamedTagged)
if !isTagged {
// List all targets
targets, err := notaryRepo.ListTargets(trust.ReleasesRole, data.CanonicalTargetsRole)
if err != nil {
return nil, trust.NotaryError(ref.Name(), err)
}
var refs []target
for _, tgt := range targets {
t, err := convertTarget(tgt.Target)
if err != nil {
fmt.Fprintf(cli.Out(), "Skipping target for %q\n", reference.FamiliarName(ref))
continue
}
// Only list tags in the top level targets role or the releases delegation role - ignore
// all other delegation roles
if tgt.Role != trust.ReleasesRole && tgt.Role != data.CanonicalTargetsRole {
continue
}
refs = append(refs, t)
}
if len(refs) == 0 {
return nil, trust.NotaryError(ref.Name(), errors.Errorf("No trusted tags for %s", ref.Name()))
}
return refs, nil
}
t, err := notaryRepo.GetTargetByName(tagged.Tag(), trust.ReleasesRole, data.CanonicalTargetsRole)
if err != nil {
return nil, trust.NotaryError(ref.Name(), err)
}
// Only get the tag if it's in the top level targets role or the releases delegation role
// ignore it if it's in any other delegation roles
if t.Role != trust.ReleasesRole && t.Role != data.CanonicalTargetsRole {
return nil, trust.NotaryError(ref.Name(), errors.Errorf("No trust data for %s", tagged.Tag()))
}
logrus.Debugf("retrieving target for %s role\n", t.Role)
r, err := convertTarget(t.Target)
return []target{r}, err
}
// imagePullPrivileged pulls the image and displays it to the output
func imagePullPrivileged(ctx context.Context, cli command.Cli, imgRefAndAuth trust.ImageRefAndAuth, all bool) error {
ref := reference.FamiliarString(imgRefAndAuth.Reference())
encodedAuth, err := command.EncodeAuthToBase64(*imgRefAndAuth.AuthConfig())
if err != nil { if err != nil {
return err return err
} }
requestPrivilege := command.RegistryAuthenticationPrivilegedFunc(cli, imgRefAndAuth.RepoInfo().Index, "pull")
options := types.ImagePullOptions{ options := types.ImagePullOptions{
RegistryAuth: encodedAuth, RegistryAuth: encodedAuth,
PrivilegeFunc: requestPrivilege, PrivilegeFunc: requestPrivilege,
@ -346,3 +355,10 @@ func TagTrusted(ctx context.Context, cli command.Cli, trustedRef reference.Canon
return cli.Client().ImageTag(ctx, trustedFamiliarRef, familiarRef) return cli.Client().ImageTag(ctx, trustedFamiliarRef, familiarRef)
} }
// AuthResolver returns an auth resolver function from a command.Cli
func AuthResolver(cli command.Cli) func(ctx context.Context, index *registrytypes.IndexInfo) types.AuthConfig {
return func(ctx context.Context, index *registrytypes.IndexInfo) types.AuthConfig {
return command.ResolveAuthConfig(ctx, cli, index)
}
}

View File

@ -5,15 +5,13 @@ import (
"fmt" "fmt"
"os" "os"
"github.com/docker/docker/api/types" "github.com/docker/cli/cli"
registrytypes "github.com/docker/docker/api/types/registry" "github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/image"
"github.com/docker/cli/cli/trust"
"github.com/docker/notary/client" "github.com/docker/notary/client"
"github.com/docker/notary/tuf/data" "github.com/docker/notary/tuf/data"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/trust"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -38,10 +36,7 @@ func newRevokeCommand(dockerCli command.Cli) *cobra.Command {
func revokeTrust(cli command.Cli, remote string, options revokeOptions) error { func revokeTrust(cli command.Cli, remote string, options revokeOptions) error {
ctx := context.Background() ctx := context.Background()
authResolver := func(ctx context.Context, index *registrytypes.IndexInfo) types.AuthConfig { imgRefAndAuth, err := trust.GetImageReferencesAndAuth(ctx, image.AuthResolver(cli), remote)
return command.ResolveAuthConfig(ctx, cli, index)
}
imgRefAndAuth, err := trust.GetImageReferencesAndAuth(ctx, authResolver, remote)
if err != nil { if err != nil {
return err return err
} }
@ -57,7 +52,7 @@ func revokeTrust(cli command.Cli, remote string, options revokeOptions) error {
} }
} }
notaryRepo, err := cli.NotaryClient(*imgRefAndAuth, trust.ActionsPushAndPull) notaryRepo, err := cli.NotaryClient(imgRefAndAuth, trust.ActionsPushAndPull)
if err != nil { if err != nil {
return err return err
} }

View File

@ -3,6 +3,7 @@ package trust
import ( import (
"context" "context"
"fmt" "fmt"
"io"
"path" "path"
"sort" "sort"
"strings" "strings"
@ -11,8 +12,6 @@ import (
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/image" "github.com/docker/cli/cli/command/image"
"github.com/docker/cli/cli/trust" "github.com/docker/cli/cli/trust"
"github.com/docker/docker/api/types"
registrytypes "github.com/docker/docker/api/types/registry"
"github.com/docker/notary/client" "github.com/docker/notary/client"
"github.com/docker/notary/tuf/data" "github.com/docker/notary/tuf/data"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -25,30 +24,23 @@ func newSignCommand(dockerCli command.Cli) *cobra.Command {
Short: "Sign an image", Short: "Sign an image",
Args: cli.ExactArgs(1), Args: cli.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return signImage(dockerCli, args[0]) return runSignImage(dockerCli, args[0])
}, },
} }
return cmd return cmd
} }
func signImage(cli command.Cli, imageName string) error { func runSignImage(cli command.Cli, imageName string) error {
ctx := context.Background() ctx := context.Background()
authResolver := func(ctx context.Context, index *registrytypes.IndexInfo) types.AuthConfig { imgRefAndAuth, err := trust.GetImageReferencesAndAuth(ctx, image.AuthResolver(cli), imageName)
return command.ResolveAuthConfig(ctx, cli, index)
}
imgRefAndAuth, err := trust.GetImageReferencesAndAuth(ctx, authResolver, imageName)
if err != nil { if err != nil {
return err return err
} }
tag := imgRefAndAuth.Tag() if err := validateTag(imgRefAndAuth); err != nil {
if tag == "" { return err
if imgRefAndAuth.Digest() != "" {
return fmt.Errorf("cannot use a digest reference for IMAGE:TAG")
}
return fmt.Errorf("No tag specified for %s", imageName)
} }
notaryRepo, err := cli.NotaryClient(*imgRefAndAuth, trust.ActionsPushAndPull) notaryRepo, err := cli.NotaryClient(imgRefAndAuth, trust.ActionsPushAndPull)
if err != nil { if err != nil {
return trust.NotaryError(imgRefAndAuth.Reference().Name(), err) return trust.NotaryError(imgRefAndAuth.Reference().Name(), err)
} }
@ -78,7 +70,7 @@ func signImage(cli command.Cli, imageName string) error {
} }
} }
requestPrivilege := command.RegistryAuthenticationPrivilegedFunc(cli, imgRefAndAuth.RepoInfo().Index, "push") requestPrivilege := command.RegistryAuthenticationPrivilegedFunc(cli, imgRefAndAuth.RepoInfo().Index, "push")
target, err := createTarget(notaryRepo, tag) target, err := createTarget(notaryRepo, imgRefAndAuth.Tag())
if err != nil { if err != nil {
switch err := err.(type) { switch err := err.(type) {
case client.ErrNoSuchTarget, client.ErrRepositoryNotExist: case client.ErrNoSuchTarget, client.ErrRepositoryNotExist:
@ -91,21 +83,36 @@ func signImage(cli command.Cli, imageName string) error {
return err return err
} }
} }
return signAndPublishToTarget(cli.Out(), imgRefAndAuth, notaryRepo, target)
}
fmt.Fprintf(cli.Out(), "Signing and pushing trust metadata for %s\n", imageName) func signAndPublishToTarget(out io.Writer, imgRefAndAuth trust.ImageRefAndAuth, notaryRepo client.Repository, target client.Target) error {
tag := imgRefAndAuth.Tag()
fmt.Fprintf(out, "Signing and pushing trust metadata for %s\n", imgRefAndAuth.Name())
existingSigInfo, err := getExistingSignatureInfoForReleasedTag(notaryRepo, tag) existingSigInfo, err := getExistingSignatureInfoForReleasedTag(notaryRepo, tag)
if err != nil { if err != nil {
return err return err
} }
err = image.AddTargetToAllSignableRoles(notaryRepo, &target) err = image.AddTargetToAllSignableRoles(notaryRepo, &target)
if err == nil { if err == nil {
prettyPrintExistingSignatureInfo(cli, existingSigInfo) prettyPrintExistingSignatureInfo(out, existingSigInfo)
err = notaryRepo.Publish() err = notaryRepo.Publish()
} }
if err != nil { if err != nil {
return errors.Wrapf(err, "failed to sign %q:%s", imgRefAndAuth.RepoInfo().Name.Name(), tag) return errors.Wrapf(err, "failed to sign %q:%s", imgRefAndAuth.RepoInfo().Name.Name(), tag)
} }
fmt.Fprintf(cli.Out(), "Successfully signed %q:%s\n", imgRefAndAuth.RepoInfo().Name.Name(), tag) fmt.Fprintf(out, "Successfully signed %q:%s\n", imgRefAndAuth.RepoInfo().Name.Name(), tag)
return nil
}
func validateTag(imgRefAndAuth trust.ImageRefAndAuth) error {
tag := imgRefAndAuth.Tag()
if tag == "" {
if imgRefAndAuth.Digest() != "" {
return fmt.Errorf("cannot use a digest reference for IMAGE:TAG")
}
return fmt.Errorf("No tag specified for %s", imgRefAndAuth.Name())
}
return nil return nil
} }
@ -154,10 +161,10 @@ func getExistingSignatureInfoForReleasedTag(notaryRepo client.Repository, tag st
return releasedTargetInfoList[0], nil return releasedTargetInfoList[0], nil
} }
func prettyPrintExistingSignatureInfo(cli command.Cli, existingSigInfo trustTagRow) { func prettyPrintExistingSignatureInfo(out io.Writer, existingSigInfo trustTagRow) {
sort.Strings(existingSigInfo.Signers) sort.Strings(existingSigInfo.Signers)
joinedSigners := strings.Join(existingSigInfo.Signers, ", ") joinedSigners := strings.Join(existingSigInfo.Signers, ", ")
fmt.Fprintf(cli.Out(), "Existing signatures for tag %s digest %s from:\n%s\n", existingSigInfo.TagName, existingSigInfo.HashHex, joinedSigners) fmt.Fprintf(out, "Existing signatures for tag %s digest %s from:\n%s\n", existingSigInfo.TagName, existingSigInfo.HashHex, joinedSigners)
} }
func initNotaryRepoWithSigners(notaryRepo client.Repository, newSigner data.RoleName) error { func initNotaryRepoWithSigners(notaryRepo client.Repository, newSigner data.RoleName) error {

View File

@ -6,6 +6,8 @@ import (
"os" "os"
"testing" "testing"
"bytes"
"github.com/docker/cli/cli/config" "github.com/docker/cli/cli/config"
"github.com/docker/cli/cli/trust" "github.com/docker/cli/cli/trust"
"github.com/docker/cli/internal/test" "github.com/docker/cli/internal/test"
@ -264,13 +266,12 @@ func TestGetExistingSignatureInfoForReleasedTag(t *testing.T) {
} }
func TestPrettyPrintExistingSignatureInfo(t *testing.T) { func TestPrettyPrintExistingSignatureInfo(t *testing.T) {
fakeCli := test.NewFakeCli(&fakeClient{}) buf := bytes.NewBuffer(nil)
signers := []string{"Bob", "Alice", "Carol"} signers := []string{"Bob", "Alice", "Carol"}
existingSig := trustTagRow{trustTagKey{"tagName", "abc123"}, signers} existingSig := trustTagRow{trustTagKey{"tagName", "abc123"}, signers}
prettyPrintExistingSignatureInfo(fakeCli, existingSig) prettyPrintExistingSignatureInfo(buf, existingSig)
assert.Contains(t, fakeCli.OutBuffer().String(), "Existing signatures for tag tagName digest abc123 from:\nAlice, Bob, Carol") assert.Contains(t, buf.String(), "Existing signatures for tag tagName digest abc123 from:\nAlice, Bob, Carol")
} }
func TestSignCommandChangeListIsCleanedOnError(t *testing.T) { func TestSignCommandChangeListIsCleanedOnError(t *testing.T) {

View File

@ -11,9 +11,8 @@ import (
"github.com/docker/cli/cli" "github.com/docker/cli/cli"
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/formatter" "github.com/docker/cli/cli/command/formatter"
"github.com/docker/cli/cli/command/image"
"github.com/docker/cli/cli/trust" "github.com/docker/cli/cli/trust"
"github.com/docker/docker/api/types"
registrytypes "github.com/docker/docker/api/types/registry"
"github.com/docker/notary" "github.com/docker/notary"
"github.com/docker/notary/client" "github.com/docker/notary/client"
"github.com/docker/notary/tuf/data" "github.com/docker/notary/tuf/data"
@ -61,15 +60,12 @@ func newViewCommand(dockerCli command.Cli) *cobra.Command {
func lookupTrustInfo(cli command.Cli, remote string) error { func lookupTrustInfo(cli command.Cli, remote string) error {
ctx := context.Background() ctx := context.Background()
authResolver := func(ctx context.Context, index *registrytypes.IndexInfo) types.AuthConfig { imgRefAndAuth, err := trust.GetImageReferencesAndAuth(ctx, image.AuthResolver(cli), remote)
return command.ResolveAuthConfig(ctx, cli, index)
}
imgRefAndAuth, err := trust.GetImageReferencesAndAuth(ctx, authResolver, remote)
if err != nil { if err != nil {
return err return err
} }
tag := imgRefAndAuth.Tag() tag := imgRefAndAuth.Tag()
notaryRepo, err := cli.NotaryClient(*imgRefAndAuth, trust.ActionsPullOnly) notaryRepo, err := cli.NotaryClient(imgRefAndAuth, trust.ActionsPullOnly)
if err != nil { if err != nil {
return trust.NotaryError(imgRefAndAuth.Reference().Name(), err) return trust.NotaryError(imgRefAndAuth.Reference().Name(), err)
} }

View File

@ -1,7 +1,6 @@
package trust package trust
import ( import (
"context"
"encoding/json" "encoding/json"
"io" "io"
"net" "net"
@ -32,6 +31,7 @@ import (
digest "github.com/opencontainers/go-digest" digest "github.com/opencontainers/go-digest"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"golang.org/x/net/context"
) )
var ( var (
@ -288,6 +288,7 @@ func GetSignableRoles(repo client.Repository, target *client.Target) ([]data.Rol
// ImageRefAndAuth contains all reference information and the auth config for an image request // ImageRefAndAuth contains all reference information and the auth config for an image request
type ImageRefAndAuth struct { type ImageRefAndAuth struct {
original string
authConfig *types.AuthConfig authConfig *types.AuthConfig
reference reference.Named reference reference.Named
repoInfo *registry.RepositoryInfo repoInfo *registry.RepositoryInfo
@ -295,27 +296,29 @@ type ImageRefAndAuth struct {
digest digest.Digest digest digest.Digest
} }
// NewImageRefAndAuth creates a new ImageRefAndAuth struct
func NewImageRefAndAuth(authConfig *types.AuthConfig, reference reference.Named, repoInfo *registry.RepositoryInfo, tag string, digest digest.Digest) *ImageRefAndAuth {
return &ImageRefAndAuth{authConfig, reference, repoInfo, tag, digest}
}
// GetImageReferencesAndAuth retrieves the necessary reference and auth information for an image name // GetImageReferencesAndAuth retrieves the necessary reference and auth information for an image name
// as a ImageRefAndAuth struct // as a ImageRefAndAuth struct
func GetImageReferencesAndAuth(ctx context.Context, authResolver func(ctx context.Context, index *registrytypes.IndexInfo) types.AuthConfig, imgName string) (*ImageRefAndAuth, error) { func GetImageReferencesAndAuth(ctx context.Context, authResolver func(ctx context.Context, index *registrytypes.IndexInfo) types.AuthConfig, imgName string) (ImageRefAndAuth, error) {
ref, err := reference.ParseNormalizedNamed(imgName) ref, err := reference.ParseNormalizedNamed(imgName)
if err != nil { if err != nil {
return nil, err return ImageRefAndAuth{}, err
} }
// Resolve the Repository name from fqn to RepositoryInfo // Resolve the Repository name from fqn to RepositoryInfo
repoInfo, err := registry.ParseRepositoryInfo(ref) repoInfo, err := registry.ParseRepositoryInfo(ref)
if err != nil { if err != nil {
return nil, err return ImageRefAndAuth{}, err
} }
authConfig := authResolver(ctx, repoInfo.Index) authConfig := authResolver(ctx, repoInfo.Index)
return NewImageRefAndAuth(&authConfig, ref, repoInfo, getTag(ref), getDigest(ref)), nil return ImageRefAndAuth{
original: imgName,
authConfig: &authConfig,
reference: ref,
repoInfo: repoInfo,
tag: getTag(ref),
digest: getDigest(ref),
}, nil
} }
func getTag(ref reference.Named) string { func getTag(ref reference.Named) string {
@ -364,3 +367,9 @@ func (imgRefAuth *ImageRefAndAuth) Tag() string {
func (imgRefAuth *ImageRefAndAuth) Digest() digest.Digest { func (imgRefAuth *ImageRefAndAuth) Digest() digest.Digest {
return imgRefAuth.digest return imgRefAuth.digest
} }
// Name returns the image name used to initialize the ImageRefAndAuth
func (imgRefAuth *ImageRefAndAuth) Name() string {
return imgRefAuth.original
}

View File

@ -26,6 +26,6 @@
"vet" "vet"
], ],
"Cyclo": 19, "Cyclo": 16,
"LineLength": 200 "LineLength": 200
} }