From 78cba3d0adbc5c8ce3a1d891474648fb80a6ffb0 Mon Sep 17 00:00:00 2001 From: Derek McGowan Date: Wed, 25 Jan 2017 16:54:18 -0800 Subject: [PATCH] Use distribution reference Remove forked reference package. Use normalized named values everywhere and familiar functions to convert back to familiar strings for UX and storage compatibility. Enforce that the source repository in the distribution metadata is always a normalized string, ignore invalid values which are not. Update distribution tests to use normalized values. Signed-off-by: Derek McGowan (github: dmcgowan) Upstream-commit: 635d686a88e7ff6c5a3f9e36ec333779926b3151 Component: cli --- components/cli/command/container/create.go | 6 +----- .../cli/command/formatter/disk_usage.go | 4 ++-- components/cli/command/formatter/image.go | 4 ++-- components/cli/command/formatter/service.go | 13 ++++++------ components/cli/command/image/build.go | 4 +--- components/cli/command/image/pull.go | 8 ++++---- components/cli/command/image/trust.go | 16 +++++++-------- components/cli/command/plugin/install.go | 20 +++---------------- components/cli/command/plugin/push.go | 7 ++----- components/cli/command/plugin/upgrade.go | 12 +++++------ components/cli/command/service/trust.go | 12 ++++++----- components/cli/command/task/print.go | 14 +++++++------ components/cli/trust/trust.go | 4 ++-- 13 files changed, 53 insertions(+), 71 deletions(-) diff --git a/components/cli/command/container/create.go b/components/cli/command/container/create.go index cfd672e77a..9559ba0c05 100644 --- a/components/cli/command/container/create.go +++ b/components/cli/command/container/create.go @@ -168,11 +168,7 @@ func createContainer(ctx context.Context, dockerCli *command.DockerCli, config * return nil, err } if named, ok := ref.(reference.Named); ok { - if reference.IsNameOnly(named) { - namedRef = reference.EnsureTagged(named) - } else { - namedRef = named - } + namedRef = reference.TagNameOnly(named) if taggedRef, ok := namedRef.(reference.NamedTagged); ok && command.IsTrusted() { var err error diff --git a/components/cli/command/formatter/disk_usage.go b/components/cli/command/formatter/disk_usage.go index dc5eec41d7..fd7aabc7c2 100644 --- a/components/cli/command/formatter/disk_usage.go +++ b/components/cli/command/formatter/disk_usage.go @@ -94,12 +94,12 @@ func (ctx *DiskUsageContext) Write() { tag := "" if len(i.RepoTags) > 0 && !isDangling(*i) { // Only show the first tag - ref, err := reference.ParseNamed(i.RepoTags[0]) + ref, err := reference.ParseNormalizedNamed(i.RepoTags[0]) if err != nil { continue } if nt, ok := ref.(reference.NamedTagged); ok { - repo = ref.Name() + repo = reference.FamiliarName(ref) tag = nt.Tag() } } diff --git a/components/cli/command/formatter/image.go b/components/cli/command/formatter/image.go index 06319b9355..b6508224a3 100644 --- a/components/cli/command/formatter/image.go +++ b/components/cli/command/formatter/image.go @@ -94,7 +94,7 @@ func imageFormat(ctx ImageContext, images []types.ImageSummary, format func(subC repoTags := map[string][]string{} repoDigests := map[string][]string{} - for _, refString := range append(image.RepoTags) { + for _, refString := range image.RepoTags { ref, err := reference.ParseNormalizedNamed(refString) if err != nil { continue @@ -104,7 +104,7 @@ func imageFormat(ctx ImageContext, images []types.ImageSummary, format func(subC repoTags[familiarRef] = append(repoTags[familiarRef], nt.Tag()) } } - for _, refString := range append(image.RepoDigests) { + for _, refString := range image.RepoDigests { ref, err := reference.ParseNormalizedNamed(refString) if err != nil { continue diff --git a/components/cli/command/formatter/service.go b/components/cli/command/formatter/service.go index 9d9241b224..8e38cb3a11 100644 --- a/components/cli/command/formatter/service.go +++ b/components/cli/command/formatter/service.go @@ -5,7 +5,7 @@ import ( "strings" "time" - distreference "github.com/docker/distribution/reference" + "github.com/docker/distribution/reference" mounttypes "github.com/docker/docker/api/types/mount" "github.com/docker/docker/api/types/swarm" "github.com/docker/docker/cli/command/inspect" @@ -409,11 +409,12 @@ func (c *serviceContext) Replicas() string { func (c *serviceContext) Image() string { c.AddHeader(imageHeader) image := c.service.Spec.TaskTemplate.ContainerSpec.Image - if ref, err := distreference.ParseNamed(image); err == nil { - // update image string for display - namedTagged, ok := ref.(distreference.NamedTagged) - if ok { - image = namedTagged.Name() + ":" + namedTagged.Tag() + if ref, err := reference.ParseNormalizedNamed(image); err == nil { + // update image string for display, (strips any digest) + if nt, ok := ref.(reference.NamedTagged); ok { + if namedTagged, err := reference.WithTag(reference.TrimNamed(nt), nt.Tag()); err == nil { + image = reference.FamiliarString(namedTagged) + } } } diff --git a/components/cli/command/image/build.go b/components/cli/command/image/build.go index 34e0a39500..96d90cf585 100644 --- a/components/cli/command/image/build.go +++ b/components/cli/command/image/build.go @@ -397,9 +397,7 @@ func rewriteDockerfileFrom(ctx context.Context, dockerfile io.Reader, translator if err != nil { return nil, nil, err } - if reference.IsNameOnly(ref) { - ref = reference.EnsureTagged(ref) - } + ref = reference.TagNameOnly(ref) if ref, ok := ref.(reference.NamedTagged); ok && command.IsTrusted() { trustedRef, err := translator(ctx, ref) if err != nil { diff --git a/components/cli/command/image/pull.go b/components/cli/command/image/pull.go index 967beca86f..515273d43c 100644 --- a/components/cli/command/image/pull.go +++ b/components/cli/command/image/pull.go @@ -42,7 +42,6 @@ func NewPullCommand(dockerCli *command.DockerCli) *cobra.Command { } func runPull(dockerCli *command.DockerCli, opts pullOptions) error { - var distributionRef reference.Named distributionRef, err := reference.ParseNormalizedNamed(opts.remote) if err != nil { return err @@ -52,9 +51,10 @@ func runPull(dockerCli *command.DockerCli, opts pullOptions) error { } if !opts.all && reference.IsNameOnly(distributionRef) { - taggedRef := reference.EnsureTagged(distributionRef) - fmt.Fprintf(dockerCli.Out(), "Using default tag: %s\n", taggedRef.Tag()) - distributionRef = taggedRef + distributionRef = reference.TagNameOnly(distributionRef) + if tagged, ok := distributionRef.(reference.Tagged); ok { + fmt.Fprintf(dockerCli.Out(), "Using default tag: %s\n", tagged.Tag()) + } } // Resolve the Repository name from fqn to RepositoryInfo diff --git a/components/cli/command/image/trust.go b/components/cli/command/image/trust.go index 2ff9b463d5..8332dd7deb 100644 --- a/components/cli/command/image/trust.go +++ b/components/cli/command/image/trust.go @@ -129,15 +129,15 @@ func PushTrustedReference(cli *command.DockerCli, repoInfo *registry.RepositoryI // Initialize the notary repository with a remotely managed snapshot key if err := repo.Initialize([]string{rootKeyID}, data.CanonicalSnapshotRole); err != nil { - return trust.NotaryError(repoInfo.FullName(), err) + return trust.NotaryError(repoInfo.Name.Name(), err) } - fmt.Fprintf(cli.Out(), "Finished initializing %q\n", repoInfo.FullName()) + fmt.Fprintf(cli.Out(), "Finished initializing %q\n", repoInfo.Name.Name()) err = repo.AddTarget(target, data.CanonicalTargetsRole) case nil: // already initialized and we have successfully downloaded the latest metadata err = addTargetToAllSignableRoles(repo, target) default: - return trust.NotaryError(repoInfo.FullName(), err) + return trust.NotaryError(repoInfo.Name.Name(), err) } if err == nil { @@ -145,11 +145,11 @@ func PushTrustedReference(cli *command.DockerCli, repoInfo *registry.RepositoryI } if err != nil { - fmt.Fprintf(cli.Out(), "Failed to sign %q:%s - %s\n", repoInfo.FullName(), tag, err.Error()) - return trust.NotaryError(repoInfo.FullName(), err) + fmt.Fprintf(cli.Out(), "Failed to sign %q:%s - %s\n", repoInfo.Name.Name(), tag, err.Error()) + return trust.NotaryError(repoInfo.Name.Name(), err) } - fmt.Fprintf(cli.Out(), "Successfully signed %q:%s\n", repoInfo.FullName(), tag) + fmt.Fprintf(cli.Out(), "Successfully signed %q:%s\n", repoInfo.Name.Name(), tag) return nil } @@ -342,12 +342,12 @@ func TrustedReference(ctx context.Context, cli *command.DockerCli, ref reference t, err := notaryRepo.GetTargetByName(ref.Tag(), trust.ReleasesRole, data.CanonicalTargetsRole) if err != nil { - return nil, trust.NotaryError(repoInfo.FullName(), err) + return nil, trust.NotaryError(repoInfo.Name.Name(), err) } // Only list tags in the top level targets role or the releases delegation role - ignore // all other delegation roles if t.Role != trust.ReleasesRole && t.Role != data.CanonicalTargetsRole { - return nil, trust.NotaryError(repoInfo.FullName(), fmt.Errorf("No trust data for %s", ref.Tag())) + return nil, trust.NotaryError(repoInfo.Name.Name(), fmt.Errorf("No trust data for %s", ref.Tag())) } r, err := convertTarget(t.Target) if err != nil { diff --git a/components/cli/command/plugin/install.go b/components/cli/command/plugin/install.go index 15877761af..9e9ea40e2a 100644 --- a/components/cli/command/plugin/install.go +++ b/components/cli/command/plugin/install.go @@ -7,7 +7,6 @@ import ( "github.com/docker/distribution/reference" "github.com/docker/docker/api/types" - registrytypes "github.com/docker/docker/api/types/registry" "github.com/docker/docker/cli" "github.com/docker/docker/cli/command" "github.com/docker/docker/cli/command/image" @@ -54,20 +53,6 @@ func newInstallCommand(dockerCli *command.DockerCli) *cobra.Command { return cmd } -func getRepoIndexFromUnnormalizedRef(ref reference.Named) (*registrytypes.IndexInfo, error) { - named, err := reference.ParseNormalizedNamed(ref.Name()) - if err != nil { - return nil, err - } - - repoInfo, err := registry.ParseRepositoryInfo(named) - if err != nil { - return nil, err - } - - return repoInfo.Index, nil -} - type pluginRegistryService struct { registry.Service } @@ -104,9 +89,10 @@ func buildPullConfig(ctx context.Context, dockerCli *command.DockerCli, opts plu _, isCanonical := ref.(reference.Canonical) if command.IsTrusted() && !isCanonical { + ref = reference.TagNameOnly(ref) nt, ok := ref.(reference.NamedTagged) if !ok { - nt = reference.EnsureTagged(ref) + return types.PluginInstallOptions{}, fmt.Errorf("invalid name: %s", ref.String()) } ctx := context.Background() @@ -148,7 +134,7 @@ func runInstall(dockerCli *command.DockerCli, opts pluginOptions) error { if _, ok := aref.(reference.Canonical); ok { return fmt.Errorf("invalid name: %s", opts.localName) } - localName = reference.FamiliarString(reference.EnsureTagged(aref)) + localName = reference.FamiliarString(reference.TagNameOnly(aref)) } ctx := context.Background() diff --git a/components/cli/command/plugin/push.go b/components/cli/command/plugin/push.go index 6b826dce68..f3643b7f1b 100644 --- a/components/cli/command/plugin/push.go +++ b/components/cli/command/plugin/push.go @@ -40,10 +40,7 @@ func runPush(dockerCli *command.DockerCli, name string) error { return fmt.Errorf("invalid name: %s", name) } - taggedRef, ok := named.(reference.NamedTagged) - if !ok { - taggedRef = reference.EnsureTagged(named) - } + named = reference.TagNameOnly(named) ctx := context.Background() @@ -58,7 +55,7 @@ func runPush(dockerCli *command.DockerCli, name string) error { return err } - responseBody, err := dockerCli.Client().PluginPush(ctx, reference.FamiliarString(taggedRef), encodedAuth) + responseBody, err := dockerCli.Client().PluginPush(ctx, reference.FamiliarString(named), encodedAuth) if err != nil { return err } diff --git a/components/cli/command/plugin/upgrade.go b/components/cli/command/plugin/upgrade.go index 6861aa1b32..07f0c7bb91 100644 --- a/components/cli/command/plugin/upgrade.go +++ b/components/cli/command/plugin/upgrade.go @@ -5,10 +5,10 @@ import ( "fmt" "strings" + "github.com/docker/distribution/reference" "github.com/docker/docker/cli" "github.com/docker/docker/cli/command" "github.com/docker/docker/pkg/jsonmessage" - "github.com/docker/docker/reference" "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -49,19 +49,19 @@ func runUpgrade(dockerCli *command.DockerCli, opts pluginOptions) error { if opts.remote == "" { opts.remote = p.PluginReference } - remote, err := reference.ParseNamed(opts.remote) + remote, err := reference.ParseNormalizedNamed(opts.remote) if err != nil { return errors.Wrap(err, "error parsing remote upgrade image reference") } - remote = reference.WithDefaultTag(remote) + remote = reference.TagNameOnly(remote) - old, err := reference.ParseNamed(p.PluginReference) + old, err := reference.ParseNormalizedNamed(p.PluginReference) if err != nil { return errors.Wrap(err, "error parsing current image reference") } - old = reference.WithDefaultTag(old) + old = reference.TagNameOnly(old) - fmt.Fprintf(dockerCli.Out(), "Upgrading plugin %s from %s to %s\n", p.Name, old, remote) + fmt.Fprintf(dockerCli.Out(), "Upgrading plugin %s from %s to %s\n", p.Name, reference.FamiliarString(old), reference.FamiliarString(remote)) if !opts.skipRemoteCheck && remote.String() != old.String() { if !command.PromptForConfirmation(dockerCli.In(), dockerCli.Out(), "Plugin images do not match, are you sure?") { return errors.New("canceling upgrade request") diff --git a/components/cli/command/service/trust.go b/components/cli/command/service/trust.go index d466f3b648..3fd80ae879 100644 --- a/components/cli/command/service/trust.go +++ b/components/cli/command/service/trust.go @@ -33,10 +33,12 @@ func resolveServiceImageDigest(dockerCli *command.DockerCli, service *swarm.Serv namedRef, ok := ref.(reference.Named) if !ok { return errors.New("failed to resolve image digest using content trust: reference is not named") - } - - taggedRef := reference.EnsureTagged(namedRef) + namedRef = reference.TagNameOnly(namedRef) + taggedRef, ok := namedRef.(reference.NamedTagged) + if !ok { + return errors.New("failed to resolve image digest using content trust: reference is not tagged") + } resolvedImage, err := trustedResolveDigest(context.Background(), dockerCli, taggedRef) if err != nil { @@ -65,12 +67,12 @@ func trustedResolveDigest(ctx context.Context, cli *command.DockerCli, ref refer t, err := notaryRepo.GetTargetByName(ref.Tag(), trust.ReleasesRole, data.CanonicalTargetsRole) if err != nil { - return nil, trust.NotaryError(repoInfo.FullName(), err) + return nil, trust.NotaryError(repoInfo.Name.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(repoInfo.FullName(), fmt.Errorf("No trust data for %s", reference.FamiliarString(ref))) + return nil, trust.NotaryError(repoInfo.Name.Name(), fmt.Errorf("No trust data for %s", reference.FamiliarString(ref))) } logrus.Debugf("retrieving target for %s role\n", t.Role) diff --git a/components/cli/command/task/print.go b/components/cli/command/task/print.go index 60a2bca85b..d7e20bb59a 100644 --- a/components/cli/command/task/print.go +++ b/components/cli/command/task/print.go @@ -10,7 +10,7 @@ import ( "golang.org/x/net/context" - distreference "github.com/docker/distribution/reference" + "github.com/docker/distribution/reference" "github.com/docker/docker/api/types/swarm" "github.com/docker/docker/cli/command" "github.com/docker/docker/cli/command/idresolver" @@ -129,13 +129,15 @@ func print(out io.Writer, ctx context.Context, tasks []swarm.Task, resolver *idr image := task.Spec.ContainerSpec.Image if !noTrunc { - ref, err := distreference.ParseNamed(image) + ref, err := reference.ParseNormalizedNamed(image) if err == nil { - // update image string for display - namedTagged, ok := ref.(distreference.NamedTagged) - if ok { - image = namedTagged.Name() + ":" + namedTagged.Tag() + // update image string for display, (strips any digest) + if nt, ok := ref.(reference.NamedTagged); ok { + if namedTagged, err := reference.WithTag(reference.TrimNamed(nt), nt.Tag()); err == nil { + image = reference.FamiliarString(namedTagged) + } } + } } diff --git a/components/cli/trust/trust.go b/components/cli/trust/trust.go index 44f8197ba2..777a611181 100644 --- a/components/cli/trust/trust.go +++ b/components/cli/trust/trust.go @@ -148,7 +148,7 @@ func GetNotaryRepository(streams command.Streams, repoInfo *registry.RepositoryI } scope := auth.RepositoryScope{ - Repository: repoInfo.FullName(), + Repository: repoInfo.Name.Name(), Actions: actions, Class: repoInfo.Class, } @@ -166,7 +166,7 @@ func GetNotaryRepository(streams command.Streams, repoInfo *registry.RepositoryI return client.NewNotaryRepository( trustDirectory(), - repoInfo.FullName(), + repoInfo.Name.Name(), server, tr, getPassphraseRetriever(streams),