Remove use of forked reference package for cli

Use resolving to repo info as the split point between the
legitimate reference package and forked reference package.

Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)
This commit is contained in:
Derek McGowan 2017-01-11 13:54:52 -08:00
parent ca5bd1c106
commit bbc4ac69fa
11 changed files with 119 additions and 124 deletions

View File

@ -5,6 +5,7 @@ import (
"io" "io"
"os" "os"
"github.com/docker/distribution/reference"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/container"
networktypes "github.com/docker/docker/api/types/network" networktypes "github.com/docker/docker/api/types/network"
@ -13,8 +14,6 @@ import (
"github.com/docker/docker/cli/command/image" "github.com/docker/docker/cli/command/image"
apiclient "github.com/docker/docker/client" apiclient "github.com/docker/docker/client"
"github.com/docker/docker/pkg/jsonmessage" "github.com/docker/docker/pkg/jsonmessage"
// FIXME migrate to docker/distribution/reference
"github.com/docker/docker/reference"
"github.com/docker/docker/registry" "github.com/docker/docker/registry"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/pflag" "github.com/spf13/pflag"
@ -72,7 +71,7 @@ func runCreate(dockerCli *command.DockerCli, flags *pflag.FlagSet, opts *createO
} }
func pullImage(ctx context.Context, dockerCli *command.DockerCli, image string, out io.Writer) error { func pullImage(ctx context.Context, dockerCli *command.DockerCli, image string, out io.Writer) error {
ref, err := reference.ParseNamed(image) ref, err := reference.ParseNormalizedNamed(image)
if err != nil { if err != nil {
return err return err
} }
@ -150,7 +149,12 @@ func newCIDFile(path string) (*cidFile, error) {
func createContainer(ctx context.Context, dockerCli *command.DockerCli, config *container.Config, hostConfig *container.HostConfig, networkingConfig *networktypes.NetworkingConfig, cidfile, name string) (*container.ContainerCreateCreatedBody, error) { func createContainer(ctx context.Context, dockerCli *command.DockerCli, config *container.Config, hostConfig *container.HostConfig, networkingConfig *networktypes.NetworkingConfig, cidfile, name string) (*container.ContainerCreateCreatedBody, error) {
stderr := dockerCli.Err() stderr := dockerCli.Err()
var containerIDFile *cidFile var (
containerIDFile *cidFile
trustedRef reference.Canonical
namedRef reference.Named
)
if cidfile != "" { if cidfile != "" {
var err error var err error
if containerIDFile, err = newCIDFile(cidfile); err != nil { if containerIDFile, err = newCIDFile(cidfile); err != nil {
@ -159,21 +163,24 @@ func createContainer(ctx context.Context, dockerCli *command.DockerCli, config *
defer containerIDFile.Close() defer containerIDFile.Close()
} }
var trustedRef reference.Canonical ref, err := reference.ParseAnyReference(config.Image)
_, ref, err := reference.ParseIDOrReference(config.Image)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if ref != nil { if named, ok := ref.(reference.Named); ok {
ref = reference.WithDefaultTag(ref) if reference.IsNameOnly(named) {
namedRef = reference.EnsureTagged(named)
} else {
namedRef = named
}
if ref, ok := ref.(reference.NamedTagged); ok && command.IsTrusted() { if taggedRef, ok := namedRef.(reference.NamedTagged); ok && command.IsTrusted() {
var err error var err error
trustedRef, err = image.TrustedReference(ctx, dockerCli, ref, nil) trustedRef, err = image.TrustedReference(ctx, dockerCli, taggedRef, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.Image = trustedRef.String() config.Image = reference.FamiliarString(trustedRef)
} }
} }
@ -182,15 +189,15 @@ func createContainer(ctx context.Context, dockerCli *command.DockerCli, config *
//if image not found try to pull it //if image not found try to pull it
if err != nil { if err != nil {
if apiclient.IsErrImageNotFound(err) && ref != nil { if apiclient.IsErrImageNotFound(err) && namedRef != nil {
fmt.Fprintf(stderr, "Unable to find image '%s' locally\n", ref.String()) fmt.Fprintf(stderr, "Unable to find image '%s' locally\n", reference.FamiliarString(namedRef))
// we don't want to write to stdout anything apart from container.ID // we don't want to write to stdout anything apart from container.ID
if err = pullImage(ctx, dockerCli, config.Image, stderr); err != nil { if err = pullImage(ctx, dockerCli, config.Image, stderr); err != nil {
return nil, err return nil, err
} }
if ref, ok := ref.(reference.NamedTagged); ok && trustedRef != nil { if taggedRef, ok := namedRef.(reference.NamedTagged); ok && trustedRef != nil {
if err := image.TagTrusted(ctx, dockerCli, trustedRef, ref); err != nil { if err := image.TagTrusted(ctx, dockerCli, trustedRef, taggedRef); err != nil {
return nil, err return nil, err
} }
} }

View File

@ -4,9 +4,9 @@ import (
"fmt" "fmt"
"time" "time"
"github.com/docker/distribution/reference"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"github.com/docker/docker/pkg/stringid" "github.com/docker/docker/pkg/stringid"
"github.com/docker/docker/reference"
units "github.com/docker/go-units" units "github.com/docker/go-units"
) )
@ -95,21 +95,23 @@ func imageFormat(ctx ImageContext, images []types.ImageSummary, format func(subC
repoDigests := map[string][]string{} repoDigests := map[string][]string{}
for _, refString := range append(image.RepoTags) { for _, refString := range append(image.RepoTags) {
ref, err := reference.ParseNamed(refString) ref, err := reference.ParseNormalizedNamed(refString)
if err != nil { if err != nil {
continue continue
} }
if nt, ok := ref.(reference.NamedTagged); ok { if nt, ok := ref.(reference.NamedTagged); ok {
repoTags[ref.Name()] = append(repoTags[ref.Name()], nt.Tag()) familiarRef := reference.FamiliarName(ref)
repoTags[familiarRef] = append(repoTags[familiarRef], nt.Tag())
} }
} }
for _, refString := range append(image.RepoDigests) { for _, refString := range append(image.RepoDigests) {
ref, err := reference.ParseNamed(refString) ref, err := reference.ParseNormalizedNamed(refString)
if err != nil { if err != nil {
continue continue
} }
if c, ok := ref.(reference.Canonical); ok { if c, ok := ref.(reference.Canonical); ok {
repoDigests[ref.Name()] = append(repoDigests[ref.Name()], c.Digest().String()) familiarRef := reference.FamiliarName(ref)
repoDigests[familiarRef] = append(repoDigests[familiarRef], c.Digest().String())
} }
} }

View File

@ -11,6 +11,7 @@ import (
"regexp" "regexp"
"runtime" "runtime"
"github.com/docker/distribution/reference"
"github.com/docker/docker/api" "github.com/docker/docker/api"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/container"
@ -25,7 +26,6 @@ import (
"github.com/docker/docker/pkg/progress" "github.com/docker/docker/pkg/progress"
"github.com/docker/docker/pkg/streamformatter" "github.com/docker/docker/pkg/streamformatter"
"github.com/docker/docker/pkg/urlutil" "github.com/docker/docker/pkg/urlutil"
"github.com/docker/docker/reference"
runconfigopts "github.com/docker/docker/runconfig/opts" runconfigopts "github.com/docker/docker/runconfig/opts"
units "github.com/docker/go-units" units "github.com/docker/go-units"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -360,7 +360,7 @@ type translatorFunc func(context.Context, reference.NamedTagged) (reference.Cano
// validateTag checks if the given image name can be resolved. // validateTag checks if the given image name can be resolved.
func validateTag(rawRepo string) (string, error) { func validateTag(rawRepo string) (string, error) {
_, err := reference.ParseNamed(rawRepo) _, err := reference.ParseNormalizedNamed(rawRepo)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -392,18 +392,21 @@ func rewriteDockerfileFrom(ctx context.Context, dockerfile io.Reader, translator
matches := dockerfileFromLinePattern.FindStringSubmatch(line) matches := dockerfileFromLinePattern.FindStringSubmatch(line)
if matches != nil && matches[1] != api.NoBaseImageSpecifier { if matches != nil && matches[1] != api.NoBaseImageSpecifier {
// Replace the line with a resolved "FROM repo@digest" // Replace the line with a resolved "FROM repo@digest"
ref, err := reference.ParseNamed(matches[1]) var ref reference.Named
ref, err = reference.ParseNormalizedNamed(matches[1])
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
ref = reference.WithDefaultTag(ref) if reference.IsNameOnly(ref) {
ref = reference.EnsureTagged(ref)
}
if ref, ok := ref.(reference.NamedTagged); ok && command.IsTrusted() { if ref, ok := ref.(reference.NamedTagged); ok && command.IsTrusted() {
trustedRef, err := translator(ctx, ref) trustedRef, err := translator(ctx, ref)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
line = dockerfileFromLinePattern.ReplaceAllLiteralString(line, fmt.Sprintf("FROM %s", trustedRef.String())) line = dockerfileFromLinePattern.ReplaceAllLiteralString(line, fmt.Sprintf("FROM %s", reference.FamiliarString(trustedRef)))
resolvedTags = append(resolvedTags, &resolvedTag{ resolvedTags = append(resolvedTags, &resolvedTag{
digestRef: trustedRef, digestRef: trustedRef,
tagRef: ref, tagRef: ref,

View File

@ -7,9 +7,9 @@ import (
"golang.org/x/net/context" "golang.org/x/net/context"
"github.com/docker/distribution/reference"
"github.com/docker/docker/cli" "github.com/docker/docker/cli"
"github.com/docker/docker/cli/command" "github.com/docker/docker/cli/command"
"github.com/docker/docker/reference"
"github.com/docker/docker/registry" "github.com/docker/docker/registry"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -42,7 +42,8 @@ func NewPullCommand(dockerCli *command.DockerCli) *cobra.Command {
} }
func runPull(dockerCli *command.DockerCli, opts pullOptions) error { func runPull(dockerCli *command.DockerCli, opts pullOptions) error {
distributionRef, err := reference.ParseNamed(opts.remote) var distributionRef reference.Named
distributionRef, err := reference.ParseNormalizedNamed(opts.remote)
if err != nil { if err != nil {
return err return err
} }
@ -51,8 +52,9 @@ func runPull(dockerCli *command.DockerCli, opts pullOptions) error {
} }
if !opts.all && reference.IsNameOnly(distributionRef) { if !opts.all && reference.IsNameOnly(distributionRef) {
distributionRef = reference.WithDefaultTag(distributionRef) taggedRef := reference.EnsureTagged(distributionRef)
fmt.Fprintf(dockerCli.Out(), "Using default tag: %s\n", reference.DefaultTag) fmt.Fprintf(dockerCli.Out(), "Using default tag: %s\n", taggedRef.Tag())
distributionRef = taggedRef
} }
// Resolve the Repository name from fqn to RepositoryInfo // Resolve the Repository name from fqn to RepositoryInfo
@ -71,7 +73,7 @@ func runPull(dockerCli *command.DockerCli, opts pullOptions) error {
if command.IsTrusted() && !isCanonical { if command.IsTrusted() && !isCanonical {
err = trustedPull(ctx, dockerCli, repoInfo, distributionRef, authConfig, requestPrivilege) err = trustedPull(ctx, dockerCli, repoInfo, distributionRef, authConfig, requestPrivilege)
} else { } else {
err = imagePullPrivileged(ctx, dockerCli, authConfig, distributionRef.String(), requestPrivilege, opts.all) err = imagePullPrivileged(ctx, dockerCli, authConfig, reference.FamiliarString(distributionRef), requestPrivilege, opts.all)
} }
if err != nil { if err != nil {
if strings.Contains(err.Error(), "target is plugin") { if strings.Contains(err.Error(), "target is plugin") {

View File

@ -3,10 +3,10 @@ package image
import ( import (
"golang.org/x/net/context" "golang.org/x/net/context"
"github.com/docker/distribution/reference"
"github.com/docker/docker/cli" "github.com/docker/docker/cli"
"github.com/docker/docker/cli/command" "github.com/docker/docker/cli/command"
"github.com/docker/docker/pkg/jsonmessage" "github.com/docker/docker/pkg/jsonmessage"
"github.com/docker/docker/reference"
"github.com/docker/docker/registry" "github.com/docker/docker/registry"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -30,7 +30,7 @@ func NewPushCommand(dockerCli *command.DockerCli) *cobra.Command {
} }
func runPush(dockerCli *command.DockerCli, remote string) error { func runPush(dockerCli *command.DockerCli, remote string) error {
ref, err := reference.ParseNamed(remote) ref, err := reference.ParseNormalizedNamed(remote)
if err != nil { if err != nil {
return err return err
} }
@ -51,7 +51,7 @@ func runPush(dockerCli *command.DockerCli, remote string) error {
return trustedPush(ctx, dockerCli, repoInfo, ref, authConfig, requestPrivilege) return trustedPush(ctx, dockerCli, repoInfo, ref, authConfig, requestPrivilege)
} }
responseBody, err := imagePushPrivileged(ctx, dockerCli, authConfig, ref.String(), requestPrivilege) responseBody, err := imagePushPrivileged(ctx, dockerCli, authConfig, ref, requestPrivilege)
if err != nil { if err != nil {
return err return err
} }

View File

@ -10,11 +10,11 @@ import (
"sort" "sort"
"github.com/Sirupsen/logrus" "github.com/Sirupsen/logrus"
"github.com/docker/distribution/reference"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"github.com/docker/docker/cli/command" "github.com/docker/docker/cli/command"
"github.com/docker/docker/cli/trust" "github.com/docker/docker/cli/trust"
"github.com/docker/docker/pkg/jsonmessage" "github.com/docker/docker/pkg/jsonmessage"
"github.com/docker/docker/reference"
"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"
@ -30,7 +30,7 @@ type target struct {
// trustedPush handles content trust pushing of an image // trustedPush handles content trust pushing of an image
func trustedPush(ctx context.Context, cli *command.DockerCli, repoInfo *registry.RepositoryInfo, ref reference.Named, authConfig types.AuthConfig, requestPrivilege types.RequestPrivilegeFunc) error { func trustedPush(ctx context.Context, cli *command.DockerCli, repoInfo *registry.RepositoryInfo, ref reference.Named, authConfig types.AuthConfig, requestPrivilege types.RequestPrivilegeFunc) error {
responseBody, err := imagePushPrivileged(ctx, cli, authConfig, ref.String(), requestPrivilege) responseBody, err := imagePushPrivileged(ctx, cli, authConfig, ref, requestPrivilege)
if err != nil { if err != nil {
return err return err
} }
@ -202,7 +202,7 @@ func addTargetToAllSignableRoles(repo *client.NotaryRepository, target *client.T
} }
// imagePushPrivileged push the image // imagePushPrivileged push the image
func imagePushPrivileged(ctx context.Context, cli *command.DockerCli, authConfig types.AuthConfig, ref string, requestPrivilege types.RequestPrivilegeFunc) (io.ReadCloser, error) { func imagePushPrivileged(ctx context.Context, cli *command.DockerCli, authConfig types.AuthConfig, ref reference.Named, requestPrivilege types.RequestPrivilegeFunc) (io.ReadCloser, error) {
encodedAuth, err := command.EncodeAuthToBase64(authConfig) encodedAuth, err := command.EncodeAuthToBase64(authConfig)
if err != nil { if err != nil {
return nil, err return nil, err
@ -212,7 +212,7 @@ func imagePushPrivileged(ctx context.Context, cli *command.DockerCli, authConfig
PrivilegeFunc: requestPrivilege, PrivilegeFunc: requestPrivilege,
} }
return cli.Client().ImagePush(ctx, ref, options) return cli.Client().ImagePush(ctx, reference.FamiliarString(ref), options)
} }
// trustedPull handles content trust pulling of an image // trustedPull handles content trust pulling of an image
@ -229,12 +229,12 @@ func trustedPull(ctx context.Context, cli *command.DockerCli, repoInfo *registry
// List all targets // List all targets
targets, err := notaryRepo.ListTargets(trust.ReleasesRole, data.CanonicalTargetsRole) targets, err := notaryRepo.ListTargets(trust.ReleasesRole, data.CanonicalTargetsRole)
if err != nil { if err != nil {
return trust.NotaryError(repoInfo.FullName(), err) return trust.NotaryError(ref.Name(), err)
} }
for _, tgt := range targets { for _, tgt := range targets {
t, err := convertTarget(tgt.Target) t, err := convertTarget(tgt.Target)
if err != nil { if err != nil {
fmt.Fprintf(cli.Out(), "Skipping target for %q\n", repoInfo.Name()) fmt.Fprintf(cli.Out(), "Skipping target for %q\n", reference.FamiliarName(ref))
continue continue
} }
// Only list tags in the top level targets role or the releases delegation role - ignore // Only list tags in the top level targets role or the releases delegation role - ignore
@ -245,17 +245,17 @@ func trustedPull(ctx context.Context, cli *command.DockerCli, repoInfo *registry
refs = append(refs, t) refs = append(refs, t)
} }
if len(refs) == 0 { if len(refs) == 0 {
return trust.NotaryError(repoInfo.FullName(), fmt.Errorf("No trusted tags for %s", repoInfo.FullName())) return trust.NotaryError(ref.Name(), fmt.Errorf("No trusted tags for %s", ref.Name()))
} }
} else { } else {
t, err := notaryRepo.GetTargetByName(tagged.Tag(), trust.ReleasesRole, data.CanonicalTargetsRole) t, err := notaryRepo.GetTargetByName(tagged.Tag(), trust.ReleasesRole, data.CanonicalTargetsRole)
if err != nil { if err != nil {
return trust.NotaryError(repoInfo.FullName(), err) return trust.NotaryError(ref.Name(), err)
} }
// Only get the tag if it's in the top level targets role or the releases delegation role // 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 // ignore it if it's in any other delegation roles
if t.Role != trust.ReleasesRole && t.Role != data.CanonicalTargetsRole { if t.Role != trust.ReleasesRole && t.Role != data.CanonicalTargetsRole {
return trust.NotaryError(repoInfo.FullName(), fmt.Errorf("No trust data for %s", tagged.Tag())) return trust.NotaryError(ref.Name(), fmt.Errorf("No trust data for %s", tagged.Tag()))
} }
logrus.Debugf("retrieving target for %s role\n", t.Role) logrus.Debugf("retrieving target for %s role\n", t.Role)
@ -272,24 +272,21 @@ func trustedPull(ctx context.Context, cli *command.DockerCli, repoInfo *registry
if displayTag != "" { if displayTag != "" {
displayTag = ":" + displayTag displayTag = ":" + displayTag
} }
fmt.Fprintf(cli.Out(), "Pull (%d of %d): %s%s@%s\n", i+1, len(refs), repoInfo.Name(), displayTag, r.digest) fmt.Fprintf(cli.Out(), "Pull (%d of %d): %s%s@%s\n", i+1, len(refs), reference.FamiliarName(ref), displayTag, r.digest)
ref, err := reference.WithDigest(reference.TrimNamed(repoInfo), r.digest) trustedRef, err := reference.WithDigest(reference.TrimNamed(ref), r.digest)
if err != nil { if err != nil {
return err return err
} }
if err := imagePullPrivileged(ctx, cli, authConfig, ref.String(), requestPrivilege, false); err != nil { if err := imagePullPrivileged(ctx, cli, authConfig, reference.FamiliarString(trustedRef), requestPrivilege, false); err != nil {
return err return err
} }
tagged, err := reference.WithTag(repoInfo, r.name) tagged, err := reference.WithTag(reference.TrimNamed(ref), r.name)
if err != nil {
return err
}
trustedRef, err := reference.WithDigest(reference.TrimNamed(repoInfo), r.digest)
if err != nil { if err != nil {
return err return err
} }
if err := TagTrusted(ctx, cli, trustedRef, tagged); err != nil { if err := TagTrusted(ctx, cli, trustedRef, tagged); err != nil {
return err return err
} }
@ -375,7 +372,11 @@ func convertTarget(t client.Target) (target, error) {
// TagTrusted tags a trusted ref // TagTrusted tags a trusted ref
func TagTrusted(ctx context.Context, cli *command.DockerCli, trustedRef reference.Canonical, ref reference.NamedTagged) error { func TagTrusted(ctx context.Context, cli *command.DockerCli, trustedRef reference.Canonical, ref reference.NamedTagged) error {
fmt.Fprintf(cli.Out(), "Tagging %s as %s\n", trustedRef.String(), ref.String()) // Use familiar references when interacting with client and output
familiarRef := reference.FamiliarString(ref)
trustedFamiliarRef := reference.FamiliarString(trustedRef)
return cli.Client().ImageTag(ctx, trustedRef.String(), ref.String()) fmt.Fprintf(cli.Out(), "Tagging %s as %s\n", trustedFamiliarRef, familiarRef)
return cli.Client().ImageTag(ctx, trustedFamiliarRef, familiarRef)
} }

View File

@ -8,18 +8,18 @@ import (
"path/filepath" "path/filepath"
"github.com/Sirupsen/logrus" "github.com/Sirupsen/logrus"
"github.com/docker/distribution/reference"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"github.com/docker/docker/cli" "github.com/docker/docker/cli"
"github.com/docker/docker/cli/command" "github.com/docker/docker/cli/command"
"github.com/docker/docker/pkg/archive" "github.com/docker/docker/pkg/archive"
"github.com/docker/docker/reference"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"golang.org/x/net/context" "golang.org/x/net/context"
) )
// validateTag checks if the given repoName can be resolved. // validateTag checks if the given repoName can be resolved.
func validateTag(rawRepo string) error { func validateTag(rawRepo string) error {
_, err := reference.ParseNamed(rawRepo) _, err := reference.ParseNormalizedNamed(rawRepo)
return err return err
} }

View File

@ -6,14 +6,13 @@ import (
"fmt" "fmt"
"strings" "strings"
distreference "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" registrytypes "github.com/docker/docker/api/types/registry"
"github.com/docker/docker/cli" "github.com/docker/docker/cli"
"github.com/docker/docker/cli/command" "github.com/docker/docker/cli/command"
"github.com/docker/docker/cli/command/image" "github.com/docker/docker/cli/command/image"
"github.com/docker/docker/pkg/jsonmessage" "github.com/docker/docker/pkg/jsonmessage"
"github.com/docker/docker/reference"
"github.com/docker/docker/registry" "github.com/docker/docker/registry"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"golang.org/x/net/context" "golang.org/x/net/context"
@ -52,8 +51,8 @@ func newInstallCommand(dockerCli *command.DockerCli) *cobra.Command {
return cmd return cmd
} }
func getRepoIndexFromUnnormalizedRef(ref distreference.Named) (*registrytypes.IndexInfo, error) { func getRepoIndexFromUnnormalizedRef(ref reference.Named) (*registrytypes.IndexInfo, error) {
named, err := reference.ParseNamed(ref.Name()) named, err := reference.ParseNormalizedNamed(ref.Name())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -85,71 +84,60 @@ func newRegistryService() registry.Service {
} }
func runInstall(dockerCli *command.DockerCli, opts pluginOptions) error { func runInstall(dockerCli *command.DockerCli, opts pluginOptions) error {
// Parse name using distribution reference package to support name // Names with both tag and digest will be treated by the daemon
// containing both tag and digest. Names with both tag and digest // as a pull by digest with an alias for the tag
// will be treated by the daemon as a pull by digest with // (if no alias is provided).
// an alias for the tag (if no alias is provided). ref, err := reference.ParseNormalizedNamed(opts.name)
ref, err := distreference.ParseNamed(opts.name)
if err != nil { if err != nil {
return err return err
} }
alias := "" alias := ""
if opts.alias != "" { if opts.alias != "" {
aref, err := reference.ParseNamed(opts.alias) aref, err := reference.ParseNormalizedNamed(opts.alias)
if err != nil { if err != nil {
return err return err
} }
aref = reference.WithDefaultTag(aref) if _, ok := aref.(reference.Canonical); ok {
if _, ok := aref.(reference.NamedTagged); !ok {
return fmt.Errorf("invalid name: %s", opts.alias) return fmt.Errorf("invalid name: %s", opts.alias)
} }
alias = aref.String() alias = reference.FamiliarString(reference.EnsureTagged(aref))
} }
ctx := context.Background() ctx := context.Background()
index, err := getRepoIndexFromUnnormalizedRef(ref) repoInfo, err := registry.ParseRepositoryInfo(ref)
if err != nil { if err != nil {
return err return err
} }
remote := ref.String() remote := ref.String()
_, isCanonical := ref.(distreference.Canonical) _, isCanonical := ref.(reference.Canonical)
if command.IsTrusted() && !isCanonical { if command.IsTrusted() && !isCanonical {
if alias == "" { if alias == "" {
alias = ref.String() alias = reference.FamiliarString(ref)
} }
var nt reference.NamedTagged
named, err := reference.ParseNamed(ref.Name()) nt, ok := ref.(reference.NamedTagged)
if err != nil { if !ok {
return err nt = reference.EnsureTagged(ref)
}
if tagged, ok := ref.(distreference.Tagged); ok {
nt, err = reference.WithTag(named, tagged.Tag())
if err != nil {
return err
}
} else {
named = reference.WithDefaultTag(named)
nt = named.(reference.NamedTagged)
} }
trusted, err := image.TrustedReference(ctx, dockerCli, nt, newRegistryService()) trusted, err := image.TrustedReference(ctx, dockerCli, nt, newRegistryService())
if err != nil { if err != nil {
return err return err
} }
remote = trusted.String() remote = reference.FamiliarString(trusted)
} }
authConfig := command.ResolveAuthConfig(ctx, dockerCli, index) authConfig := command.ResolveAuthConfig(ctx, dockerCli, repoInfo.Index)
encodedAuth, err := command.EncodeAuthToBase64(authConfig) encodedAuth, err := command.EncodeAuthToBase64(authConfig)
if err != nil { if err != nil {
return err return err
} }
registryAuthFunc := command.RegistryAuthenticationPrivilegedFunc(dockerCli, index, "plugin install") registryAuthFunc := command.RegistryAuthenticationPrivilegedFunc(dockerCli, repoInfo.Index, "plugin install")
options := types.PluginInstallOptions{ options := types.PluginInstallOptions{
RegistryAuth: encodedAuth, RegistryAuth: encodedAuth,

View File

@ -5,11 +5,11 @@ import (
"golang.org/x/net/context" "golang.org/x/net/context"
"github.com/docker/distribution/reference"
"github.com/docker/docker/cli" "github.com/docker/docker/cli"
"github.com/docker/docker/cli/command" "github.com/docker/docker/cli/command"
"github.com/docker/docker/cli/command/image" "github.com/docker/docker/cli/command/image"
"github.com/docker/docker/pkg/jsonmessage" "github.com/docker/docker/pkg/jsonmessage"
"github.com/docker/docker/reference"
"github.com/docker/docker/registry" "github.com/docker/docker/registry"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -32,16 +32,17 @@ func newPushCommand(dockerCli *command.DockerCli) *cobra.Command {
} }
func runPush(dockerCli *command.DockerCli, name string) error { func runPush(dockerCli *command.DockerCli, name string) error {
named, err := reference.ParseNamed(name) // FIXME: validate named, err := reference.ParseNormalizedNamed(name)
if err != nil { if err != nil {
return err return err
} }
if reference.IsNameOnly(named) { if _, ok := named.(reference.Canonical); ok {
named = reference.WithDefaultTag(named) return fmt.Errorf("invalid name: %s", name)
} }
ref, ok := named.(reference.NamedTagged)
taggedRef, ok := named.(reference.NamedTagged)
if !ok { if !ok {
return fmt.Errorf("invalid name: %s", named.String()) taggedRef = reference.EnsureTagged(named)
} }
ctx := context.Background() ctx := context.Background()
@ -56,7 +57,8 @@ func runPush(dockerCli *command.DockerCli, name string) error {
if err != nil { if err != nil {
return err return err
} }
responseBody, err := dockerCli.Client().PluginPush(ctx, ref.String(), encodedAuth)
responseBody, err := dockerCli.Client().PluginPush(ctx, reference.FamiliarString(taggedRef), encodedAuth)
if err != nil { if err != nil {
return err return err
} }

View File

@ -12,10 +12,10 @@ import (
"golang.org/x/net/context" "golang.org/x/net/context"
"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" registrytypes "github.com/docker/docker/api/types/registry"
"github.com/docker/docker/pkg/term" "github.com/docker/docker/pkg/term"
"github.com/docker/docker/reference"
"github.com/docker/docker/registry" "github.com/docker/docker/registry"
) )
@ -174,7 +174,7 @@ func RetrieveAuthTokenFromImage(ctx context.Context, cli *DockerCli, image strin
// resolveAuthConfigFromImage retrieves that AuthConfig using the image string // resolveAuthConfigFromImage retrieves that AuthConfig using the image string
func resolveAuthConfigFromImage(ctx context.Context, cli *DockerCli, image string) (types.AuthConfig, error) { func resolveAuthConfigFromImage(ctx context.Context, cli *DockerCli, image string) (types.AuthConfig, error) {
registryRef, err := reference.ParseNamed(image) registryRef, err := reference.ParseNormalizedNamed(image)
if err != nil { if err != nil {
return types.AuthConfig{}, err return types.AuthConfig{}, err
} }

View File

@ -5,11 +5,10 @@ import (
"fmt" "fmt"
"github.com/Sirupsen/logrus" "github.com/Sirupsen/logrus"
distreference "github.com/docker/distribution/reference" "github.com/docker/distribution/reference"
"github.com/docker/docker/api/types/swarm" "github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/cli/command" "github.com/docker/docker/cli/command"
"github.com/docker/docker/cli/trust" "github.com/docker/docker/cli/trust"
"github.com/docker/docker/reference"
"github.com/docker/docker/registry" "github.com/docker/docker/registry"
"github.com/docker/notary/tuf/data" "github.com/docker/notary/tuf/data"
"github.com/opencontainers/go-digest" "github.com/opencontainers/go-digest"
@ -24,41 +23,34 @@ func resolveServiceImageDigest(dockerCli *command.DockerCli, service *swarm.Serv
return nil return nil
} }
image := service.TaskTemplate.ContainerSpec.Image ref, err := reference.ParseAnyReference(service.TaskTemplate.ContainerSpec.Image)
// We only attempt to resolve the digest if the reference
// could be parsed as a digest reference. Specifying an image ID
// is valid but not resolvable. There is no warning message for
// an image ID because it's valid to use one.
if _, err := digest.Parse(image); err == nil {
return nil
}
ref, err := reference.ParseNamed(image)
if err != nil { if err != nil {
return fmt.Errorf("Could not parse image reference %s", service.TaskTemplate.ContainerSpec.Image) return errors.Wrapf(err, "invalid reference %s", service.TaskTemplate.ContainerSpec.Image)
} }
if _, ok := ref.(reference.Canonical); !ok {
ref = reference.WithDefaultTag(ref)
taggedRef, ok := ref.(reference.NamedTagged) // If reference does not have digest (is not canonical nor image id)
if _, ok := ref.(reference.Digested); !ok {
namedRef, ok := ref.(reference.Named)
if !ok { if !ok {
// This should never happen because a reference either return errors.New("failed to resolve image digest using content trust: reference is not named")
// has a digest, or WithDefaultTag would give it a tag.
return errors.New("Failed to resolve image digest using content trust: reference is missing a tag")
} }
taggedRef := reference.EnsureTagged(namedRef)
resolvedImage, err := trustedResolveDigest(context.Background(), dockerCli, taggedRef) resolvedImage, err := trustedResolveDigest(context.Background(), dockerCli, taggedRef)
if err != nil { if err != nil {
return fmt.Errorf("Failed to resolve image digest using content trust: %v", err) return errors.Wrap(err, "failed to resolve image digest using content trust")
} }
logrus.Debugf("resolved image tag to %s using content trust", resolvedImage.String()) resolvedFamiliar := reference.FamiliarString(resolvedImage)
service.TaskTemplate.ContainerSpec.Image = resolvedImage.String() logrus.Debugf("resolved image tag to %s using content trust", resolvedFamiliar)
service.TaskTemplate.ContainerSpec.Image = resolvedFamiliar
} }
return nil return nil
} }
func trustedResolveDigest(ctx context.Context, cli *command.DockerCli, ref reference.NamedTagged) (distreference.Canonical, error) { func trustedResolveDigest(ctx context.Context, cli *command.DockerCli, ref reference.NamedTagged) (reference.Canonical, error) {
repoInfo, err := registry.ParseRepositoryInfo(ref) repoInfo, err := registry.ParseRepositoryInfo(ref)
if err != nil { if err != nil {
return nil, err return nil, err
@ -78,7 +70,7 @@ func trustedResolveDigest(ctx context.Context, cli *command.DockerCli, ref refer
// Only get the tag if it's in the top level targets role or the releases delegation role // 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 // ignore it if it's in any other delegation roles
if t.Role != trust.ReleasesRole && t.Role != data.CanonicalTargetsRole { if t.Role != trust.ReleasesRole && t.Role != data.CanonicalTargetsRole {
return nil, trust.NotaryError(repoInfo.FullName(), fmt.Errorf("No trust data for %s", ref.String())) return nil, trust.NotaryError(repoInfo.FullName(), fmt.Errorf("No trust data for %s", reference.FamiliarString(ref)))
} }
logrus.Debugf("retrieving target for %s role\n", t.Role) logrus.Debugf("retrieving target for %s role\n", t.Role)
@ -89,8 +81,6 @@ func trustedResolveDigest(ctx context.Context, cli *command.DockerCli, ref refer
dgst := digest.NewDigestFromHex("sha256", hex.EncodeToString(h)) dgst := digest.NewDigestFromHex("sha256", hex.EncodeToString(h))
// Using distribution reference package to make sure that adding a // Allow returning canonical reference with tag
// digest does not erase the tag. When the two reference packages return reference.WithDigest(ref, dgst)
// are unified, this will no longer be an issue.
return distreference.WithDigest(ref, dgst)
} }