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 <derek@mcgstyle.net> (github: dmcgowan)
This commit is contained in:
parent
2bea87393b
commit
3a1279393f
78 changed files with 538 additions and 1117 deletions
|
@ -4,9 +4,9 @@ import (
|
|||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
enginetypes "github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/reference"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
|
|
|
@ -7,13 +7,12 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
distreference "github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/pkg/streamformatter"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
@ -47,39 +46,27 @@ func parseHeaders(headers http.Header) (map[string][]string, *types.AuthConfig)
|
|||
// be returned.
|
||||
func parseRemoteRef(remote string) (reference.Named, string, error) {
|
||||
// Parse remote reference, supporting remotes with name and tag
|
||||
// NOTE: Using distribution reference to handle references
|
||||
// containing both a name and digest
|
||||
remoteRef, err := distreference.ParseNamed(remote)
|
||||
remoteRef, err := reference.ParseNormalizedNamed(remote)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
var tag string
|
||||
if t, ok := remoteRef.(distreference.Tagged); ok {
|
||||
tag = t.Tag()
|
||||
type canonicalWithTag interface {
|
||||
reference.Canonical
|
||||
Tag() string
|
||||
}
|
||||
|
||||
// Convert distribution reference to docker reference
|
||||
// TODO: remove when docker reference changes reconciled upstream
|
||||
ref, err := reference.WithName(remoteRef.Name())
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
if d, ok := remoteRef.(distreference.Digested); ok {
|
||||
ref, err = reference.WithDigest(ref, d.Digest())
|
||||
if canonical, ok := remoteRef.(canonicalWithTag); ok {
|
||||
remoteRef, err = reference.WithDigest(reference.TrimNamed(remoteRef), canonical.Digest())
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
} else if tag != "" {
|
||||
ref, err = reference.WithTag(ref, tag)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
} else {
|
||||
ref = reference.WithDefaultTag(ref)
|
||||
return remoteRef, canonical.Tag(), nil
|
||||
}
|
||||
|
||||
return ref, tag, nil
|
||||
remoteRef = reference.TagNameOnly(remoteRef)
|
||||
|
||||
return remoteRef, "", nil
|
||||
}
|
||||
|
||||
func (pr *pluginRouter) getPrivileges(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
|
@ -188,24 +175,24 @@ func getName(ref reference.Named, tag, name string) (string, error) {
|
|||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
name = nt.String()
|
||||
name = reference.FamiliarString(nt)
|
||||
} else {
|
||||
name = reference.WithDefaultTag(trimmed).String()
|
||||
name = reference.FamiliarString(reference.TagNameOnly(trimmed))
|
||||
}
|
||||
} else {
|
||||
name = ref.String()
|
||||
name = reference.FamiliarString(ref)
|
||||
}
|
||||
} else {
|
||||
localRef, err := reference.ParseNamed(name)
|
||||
localRef, err := reference.ParseNormalizedNamed(name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if _, ok := localRef.(reference.Canonical); ok {
|
||||
return "", errors.New("cannot use digest in plugin tag")
|
||||
}
|
||||
if distreference.IsNameOnly(localRef) {
|
||||
if reference.IsNameOnly(localRef) {
|
||||
// TODO: log change in name to out stream
|
||||
name = reference.WithDefaultTag(localRef).String()
|
||||
name = reference.FamiliarString(reference.TagNameOnly(localRef))
|
||||
}
|
||||
}
|
||||
return name, nil
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
package reference
|
||||
|
||||
import (
|
||||
distreference "github.com/docker/distribution/reference"
|
||||
)
|
||||
|
||||
// Parse parses the given references and returns the repository and
|
||||
// tag (if present) from it. If there is an error during parsing, it will
|
||||
// return an error.
|
||||
func Parse(ref string) (string, string, error) {
|
||||
distributionRef, err := distreference.ParseNamed(ref)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
tag := GetTagFromNamedRef(distributionRef)
|
||||
return distributionRef.Name(), tag, nil
|
||||
}
|
||||
|
||||
// GetTagFromNamedRef returns a tag from the specified reference.
|
||||
// This function is necessary as long as the docker "server" api makes the distinction between repository
|
||||
// and tags.
|
||||
func GetTagFromNamedRef(ref distreference.Named) string {
|
||||
var tag string
|
||||
switch x := ref.(type) {
|
||||
case distreference.Digested:
|
||||
tag = x.Digest().String()
|
||||
case distreference.NamedTagged:
|
||||
tag = x.Tag()
|
||||
default:
|
||||
tag = "latest"
|
||||
}
|
||||
return tag
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
package reference
|
||||
|
||||
import (
|
||||
_ "crypto/sha256"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParse(t *testing.T) {
|
||||
testCases := []struct {
|
||||
ref string
|
||||
expectedName string
|
||||
expectedTag string
|
||||
expectedError bool
|
||||
}{
|
||||
{
|
||||
ref: "",
|
||||
expectedName: "",
|
||||
expectedTag: "",
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
ref: "repository",
|
||||
expectedName: "repository",
|
||||
expectedTag: "latest",
|
||||
expectedError: false,
|
||||
},
|
||||
{
|
||||
ref: "repository:tag",
|
||||
expectedName: "repository",
|
||||
expectedTag: "tag",
|
||||
expectedError: false,
|
||||
},
|
||||
{
|
||||
ref: "test.com/repository",
|
||||
expectedName: "test.com/repository",
|
||||
expectedTag: "latest",
|
||||
expectedError: false,
|
||||
},
|
||||
{
|
||||
ref: "test.com:5000/test/repository",
|
||||
expectedName: "test.com:5000/test/repository",
|
||||
expectedTag: "latest",
|
||||
expectedError: false,
|
||||
},
|
||||
{
|
||||
ref: "test.com:5000/repo@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
expectedName: "test.com:5000/repo",
|
||||
expectedTag: "sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
expectedError: false,
|
||||
},
|
||||
{
|
||||
ref: "test.com:5000/repo:tag@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
expectedName: "test.com:5000/repo",
|
||||
expectedTag: "sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
expectedError: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range testCases {
|
||||
name, tag, err := Parse(c.ref)
|
||||
if err != nil && c.expectedError {
|
||||
continue
|
||||
} else if err != nil {
|
||||
t.Fatalf("error with %s: %s", c.ref, err.Error())
|
||||
}
|
||||
if name != c.expectedName {
|
||||
t.Fatalf("expected name %s, got %s", c.expectedName, name)
|
||||
}
|
||||
if tag != c.expectedTag {
|
||||
t.Fatalf("expected tag %s, got %s", c.expectedTag, tag)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,11 +9,11 @@ import (
|
|||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/reference"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution/reference"
|
||||
apierrors "github.com/docker/docker/api/errors"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
|
@ -19,7 +20,6 @@ import (
|
|||
"github.com/docker/docker/builder/dockerfile/parser"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/docker/reference"
|
||||
perrors "github.com/pkg/errors"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
@ -176,23 +176,16 @@ func sanitizeRepoAndTags(names []string) ([]reference.Named, error) {
|
|||
continue
|
||||
}
|
||||
|
||||
ref, err := reference.ParseNamed(repo)
|
||||
ref, err := reference.ParseNormalizedNamed(repo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ref = reference.WithDefaultTag(ref)
|
||||
|
||||
if _, isCanonical := ref.(reference.Canonical); isCanonical {
|
||||
return nil, errors.New("build tag cannot contain a digest")
|
||||
}
|
||||
|
||||
if _, isTagged := ref.(reference.NamedTagged); !isTagged {
|
||||
ref, err = reference.WithTag(ref, reference.DefaultTag)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
ref = reference.TagNameOnly(ref)
|
||||
|
||||
nameWithTag := ref.String()
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -94,12 +94,12 @@ func (ctx *DiskUsageContext) Write() {
|
|||
tag := "<none>"
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -5,9 +5,8 @@ import (
|
|||
"errors"
|
||||
"net/url"
|
||||
|
||||
distreference "github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/reference"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
|
@ -15,17 +14,20 @@ import (
|
|||
func (cli *Client) ContainerCommit(ctx context.Context, container string, options types.ContainerCommitOptions) (types.IDResponse, error) {
|
||||
var repository, tag string
|
||||
if options.Reference != "" {
|
||||
distributionRef, err := distreference.ParseNamed(options.Reference)
|
||||
ref, err := reference.ParseNormalizedNamed(options.Reference)
|
||||
if err != nil {
|
||||
return types.IDResponse{}, err
|
||||
}
|
||||
|
||||
if _, isCanonical := distributionRef.(distreference.Canonical); isCanonical {
|
||||
if _, isCanonical := ref.(reference.Canonical); isCanonical {
|
||||
return types.IDResponse{}, errors.New("refusing to create a tag with a digest reference")
|
||||
}
|
||||
ref = reference.TagNameOnly(ref)
|
||||
|
||||
tag = reference.GetTagFromNamedRef(distributionRef)
|
||||
repository = distributionRef.Name()
|
||||
if tagged, ok := ref.(reference.Tagged); ok {
|
||||
tag = tagged.Tag()
|
||||
}
|
||||
repository = reference.FamiliarName(ref)
|
||||
}
|
||||
|
||||
query := url.Values{}
|
||||
|
|
|
@ -6,21 +6,21 @@ import (
|
|||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/reference"
|
||||
)
|
||||
|
||||
// ImageCreate creates a new image based in the parent options.
|
||||
// It returns the JSON content in the response body.
|
||||
func (cli *Client) ImageCreate(ctx context.Context, parentReference string, options types.ImageCreateOptions) (io.ReadCloser, error) {
|
||||
repository, tag, err := reference.Parse(parentReference)
|
||||
ref, err := reference.ParseNormalizedNamed(parentReference)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
query := url.Values{}
|
||||
query.Set("fromImage", repository)
|
||||
query.Set("tag", tag)
|
||||
query.Set("fromImage", reference.FamiliarName(ref))
|
||||
query.Set("tag", getAPITagFromNamedRef(ref))
|
||||
resp, err := cli.tryImageCreate(ctx, query, options.RegistryAuth)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -15,7 +15,7 @@ import (
|
|||
func (cli *Client) ImageImport(ctx context.Context, source types.ImageImportSource, ref string, options types.ImageImportOptions) (io.ReadCloser, error) {
|
||||
if ref != "" {
|
||||
//Check if the given image name can be resolved
|
||||
if _, err := reference.ParseNamed(ref); err != nil {
|
||||
if _, err := reference.ParseNormalizedNamed(ref); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,8 +7,8 @@ import (
|
|||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/reference"
|
||||
)
|
||||
|
||||
// ImagePull requests the docker host to pull an image from a remote registry.
|
||||
|
@ -19,16 +19,16 @@ import (
|
|||
// FIXME(vdemeester): there is currently used in a few way in docker/docker
|
||||
// - if not in trusted content, ref is used to pass the whole reference, and tag is empty
|
||||
// - if in trusted content, ref is used to pass the reference name, and tag for the digest
|
||||
func (cli *Client) ImagePull(ctx context.Context, ref string, options types.ImagePullOptions) (io.ReadCloser, error) {
|
||||
repository, tag, err := reference.Parse(ref)
|
||||
func (cli *Client) ImagePull(ctx context.Context, refStr string, options types.ImagePullOptions) (io.ReadCloser, error) {
|
||||
ref, err := reference.ParseNormalizedNamed(refStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
query := url.Values{}
|
||||
query.Set("fromImage", repository)
|
||||
if tag != "" && !options.All {
|
||||
query.Set("tag", tag)
|
||||
query.Set("fromImage", reference.FamiliarName(ref))
|
||||
if !options.All {
|
||||
query.Set("tag", getAPITagFromNamedRef(ref))
|
||||
}
|
||||
|
||||
resp, err := cli.tryImageCreate(ctx, query, options.RegistryAuth)
|
||||
|
@ -44,3 +44,18 @@ func (cli *Client) ImagePull(ctx context.Context, ref string, options types.Imag
|
|||
}
|
||||
return resp.body, nil
|
||||
}
|
||||
|
||||
// getAPITagFromNamedRef returns a tag from the specified reference.
|
||||
// This function is necessary as long as the docker "server" api expects
|
||||
// digests to be sent as tags and makes a distinction between the name
|
||||
// and tag/digest part of a reference.
|
||||
func getAPITagFromNamedRef(ref reference.Named) string {
|
||||
if digested, ok := ref.(reference.Digested); ok {
|
||||
return digested.Digest().String()
|
||||
}
|
||||
ref = reference.TagNameOnly(ref)
|
||||
if tagged, ok := ref.(reference.Tagged); ok {
|
||||
return tagged.Tag()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ func TestImagePullReferenceParseError(t *testing.T) {
|
|||
}
|
||||
// An empty reference is an invalid reference
|
||||
_, err := client.ImagePull(context.Background(), "", types.ImagePullOptions{})
|
||||
if err == nil || err.Error() != "repository name must have at least one component" {
|
||||
if err == nil || !strings.Contains(err.Error(), "invalid reference format") {
|
||||
t.Fatalf("expected an error, got %v", err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
distreference "github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
)
|
||||
|
||||
|
@ -16,31 +16,33 @@ import (
|
|||
// It executes the privileged function if the operation is unauthorized
|
||||
// and it tries one more time.
|
||||
// It's up to the caller to handle the io.ReadCloser and close it properly.
|
||||
func (cli *Client) ImagePush(ctx context.Context, ref string, options types.ImagePushOptions) (io.ReadCloser, error) {
|
||||
distributionRef, err := distreference.ParseNamed(ref)
|
||||
func (cli *Client) ImagePush(ctx context.Context, image string, options types.ImagePushOptions) (io.ReadCloser, error) {
|
||||
ref, err := reference.ParseNormalizedNamed(image)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, isCanonical := distributionRef.(distreference.Canonical); isCanonical {
|
||||
if _, isCanonical := ref.(reference.Canonical); isCanonical {
|
||||
return nil, errors.New("cannot push a digest reference")
|
||||
}
|
||||
|
||||
var tag = ""
|
||||
if nameTaggedRef, isNamedTagged := distributionRef.(distreference.NamedTagged); isNamedTagged {
|
||||
tag := ""
|
||||
name := reference.FamiliarName(ref)
|
||||
|
||||
if nameTaggedRef, isNamedTagged := ref.(reference.NamedTagged); isNamedTagged {
|
||||
tag = nameTaggedRef.Tag()
|
||||
}
|
||||
|
||||
query := url.Values{}
|
||||
query.Set("tag", tag)
|
||||
|
||||
resp, err := cli.tryImagePush(ctx, distributionRef.Name(), query, options.RegistryAuth)
|
||||
resp, err := cli.tryImagePush(ctx, name, query, options.RegistryAuth)
|
||||
if resp.statusCode == http.StatusUnauthorized && options.PrivilegeFunc != nil {
|
||||
newAuthHeader, privilegeErr := options.PrivilegeFunc()
|
||||
if privilegeErr != nil {
|
||||
return nil, privilegeErr
|
||||
}
|
||||
resp, err = cli.tryImagePush(ctx, distributionRef.Name(), query, newAuthHeader)
|
||||
resp, err = cli.tryImagePush(ctx, name, query, newAuthHeader)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -21,7 +21,7 @@ func TestImagePushReferenceError(t *testing.T) {
|
|||
}
|
||||
// An empty reference is an invalid reference
|
||||
_, err := client.ImagePush(context.Background(), "", types.ImagePushOptions{})
|
||||
if err == nil || err.Error() != "repository name must have at least one component" {
|
||||
if err == nil || !strings.Contains(err.Error(), "invalid reference format") {
|
||||
t.Fatalf("expected an error, got %v", err)
|
||||
}
|
||||
// An canonical reference cannot be pushed
|
||||
|
|
|
@ -3,32 +3,33 @@ package client
|
|||
import (
|
||||
"net/url"
|
||||
|
||||
distreference "github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types/reference"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// ImageTag tags an image in the docker host
|
||||
func (cli *Client) ImageTag(ctx context.Context, source, target string) error {
|
||||
if _, err := distreference.ParseNamed(source); err != nil {
|
||||
if _, err := reference.ParseNormalizedNamed(source); err != nil {
|
||||
return errors.Wrapf(err, "Error parsing reference: %q is not a valid repository/tag", source)
|
||||
}
|
||||
|
||||
distributionRef, err := distreference.ParseNamed(target)
|
||||
ref, err := reference.ParseNormalizedNamed(target)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Error parsing reference: %q is not a valid repository/tag", target)
|
||||
}
|
||||
|
||||
if _, isCanonical := distributionRef.(distreference.Canonical); isCanonical {
|
||||
if _, isCanonical := ref.(reference.Canonical); isCanonical {
|
||||
return errors.New("refusing to create a tag with a digest reference")
|
||||
}
|
||||
|
||||
tag := reference.GetTagFromNamedRef(distributionRef)
|
||||
ref = reference.TagNameOnly(ref)
|
||||
|
||||
query := url.Values{}
|
||||
query.Set("repo", distributionRef.Name())
|
||||
query.Set("tag", tag)
|
||||
query.Set("repo", reference.FamiliarName(ref))
|
||||
if tagged, ok := ref.(reference.Tagged); ok {
|
||||
query.Set("tag", tagged.Tag())
|
||||
}
|
||||
|
||||
resp, err := cli.post(ctx, "/images/"+source+"/tag", query, nil, nil)
|
||||
ensureReaderClosed(resp)
|
||||
|
|
|
@ -15,7 +15,7 @@ import (
|
|||
// PluginInstall installs a plugin
|
||||
func (cli *Client) PluginInstall(ctx context.Context, name string, options types.PluginInstallOptions) (rc io.ReadCloser, err error) {
|
||||
query := url.Values{}
|
||||
if _, err := reference.ParseNamed(options.RemoteRef); err != nil {
|
||||
if _, err := reference.ParseNormalizedNamed(options.RemoteRef); err != nil {
|
||||
return nil, errors.Wrap(err, "invalid remote reference")
|
||||
}
|
||||
query.Set("remote", options.RemoteRef)
|
||||
|
|
|
@ -14,7 +14,7 @@ import (
|
|||
// PluginUpgrade upgrades a plugin
|
||||
func (cli *Client) PluginUpgrade(ctx context.Context, name string, options types.PluginInstallOptions) (rc io.ReadCloser, err error) {
|
||||
query := url.Values{}
|
||||
if _, err := reference.ParseNamed(options.RemoteRef); err != nil {
|
||||
if _, err := reference.ParseNormalizedNamed(options.RemoteRef); err != nil {
|
||||
return nil, errors.Wrap(err, "invalid remote reference")
|
||||
}
|
||||
query.Set("remote", options.RemoteRef)
|
||||
|
|
|
@ -52,7 +52,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
distreference "github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/reference"
|
||||
apierrors "github.com/docker/docker/api/errors"
|
||||
apitypes "github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
|
@ -66,13 +66,11 @@ import (
|
|||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/pkg/signal"
|
||||
"github.com/docker/docker/pkg/stdcopy"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/docker/docker/runconfig"
|
||||
swarmapi "github.com/docker/swarmkit/api"
|
||||
"github.com/docker/swarmkit/manager/encryption"
|
||||
swarmnode "github.com/docker/swarmkit/node"
|
||||
gogotypes "github.com/gogo/protobuf/types"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
@ -829,50 +827,46 @@ func (c *Cluster) GetServices(options apitypes.ServiceListOptions) ([]types.Serv
|
|||
}
|
||||
|
||||
// imageWithDigestString takes an image such as name or name:tag
|
||||
// and returns the image pinned to a digest, such as name@sha256:34234...
|
||||
// Due to the difference between the docker/docker/reference, and the
|
||||
// docker/distribution/reference packages, we're parsing the image twice.
|
||||
// As the two packages converge, this function should be simplified.
|
||||
// TODO(nishanttotla): After the packages converge, the function must
|
||||
// convert distreference.Named -> distreference.Canonical, and the logic simplified.
|
||||
// and returns the image pinned to a digest, such as name@sha256:34234
|
||||
func (c *Cluster) imageWithDigestString(ctx context.Context, image string, authConfig *apitypes.AuthConfig) (string, error) {
|
||||
if _, err := digest.Parse(image); err == nil {
|
||||
return "", errors.New("image reference is an image ID")
|
||||
}
|
||||
ref, err := distreference.ParseNamed(image)
|
||||
ref, err := reference.ParseAnyReference(image)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
namedRef, ok := ref.(reference.Named)
|
||||
if !ok {
|
||||
if _, ok := ref.(reference.Digested); ok {
|
||||
return "", errors.New("image reference is an image ID")
|
||||
}
|
||||
return "", errors.Errorf("unknown image reference format: %s", image)
|
||||
}
|
||||
// only query registry if not a canonical reference (i.e. with digest)
|
||||
if _, ok := ref.(distreference.Canonical); !ok {
|
||||
// create a docker/docker/reference Named object because GetRepository needs it
|
||||
dockerRef, err := reference.ParseNamed(image)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
dockerRef = reference.WithDefaultTag(dockerRef)
|
||||
namedTaggedRef, ok := dockerRef.(reference.NamedTagged)
|
||||
if _, ok := namedRef.(reference.Canonical); !ok {
|
||||
namedRef = reference.TagNameOnly(namedRef)
|
||||
|
||||
taggedRef, ok := namedRef.(reference.NamedTagged)
|
||||
if !ok {
|
||||
return "", errors.New("unable to cast image to NamedTagged reference object")
|
||||
return "", errors.Errorf("image reference not tagged: %s", image)
|
||||
}
|
||||
|
||||
repo, _, err := c.config.Backend.GetRepository(ctx, namedTaggedRef, authConfig)
|
||||
repo, _, err := c.config.Backend.GetRepository(ctx, taggedRef, authConfig)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
dscrptr, err := repo.Tags(ctx).Get(ctx, namedTaggedRef.Tag())
|
||||
dscrptr, err := repo.Tags(ctx).Get(ctx, taggedRef.Tag())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
namedDigestedRef, err := distreference.WithDigest(distreference.EnsureTagged(ref), dscrptr.Digest)
|
||||
namedDigestedRef, err := reference.WithDigest(taggedRef, dscrptr.Digest)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return namedDigestedRef.String(), nil
|
||||
// return familiar form until interface updated to return type
|
||||
return reference.FamiliarString(namedDigestedRef), nil
|
||||
}
|
||||
// reference already contains a digest, so just return it
|
||||
return ref.String(), nil
|
||||
return reference.FamiliarString(ref), nil
|
||||
}
|
||||
|
||||
// CreateService creates a new service in a managed swarm cluster.
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/docker/distribution"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
|
@ -14,7 +15,6 @@ import (
|
|||
swarmtypes "github.com/docker/docker/api/types/swarm"
|
||||
clustertypes "github.com/docker/docker/daemon/cluster/provider"
|
||||
"github.com/docker/docker/plugin"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/docker/libnetwork"
|
||||
"github.com/docker/libnetwork/cluster"
|
||||
networktypes "github.com/docker/libnetwork/types"
|
||||
|
|
|
@ -11,13 +11,13 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
containertypes "github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/events"
|
||||
"github.com/docker/docker/daemon/cluster/convert"
|
||||
executorpkg "github.com/docker/docker/daemon/cluster/executor"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/docker/libnetwork"
|
||||
"github.com/docker/swarmkit/agent/exec"
|
||||
"github.com/docker/swarmkit/api"
|
||||
|
@ -60,7 +60,7 @@ func (c *containerAdapter) pullImage(ctx context.Context) error {
|
|||
|
||||
// Skip pulling if the image is referenced by digest and already
|
||||
// exists locally.
|
||||
named, err := reference.ParseNamed(spec.Image)
|
||||
named, err := reference.ParseNormalizedNamed(spec.Image)
|
||||
if err == nil {
|
||||
if _, ok := named.(reference.Canonical); ok {
|
||||
_, err := c.backend.LookupImage(spec.Image)
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
|
||||
"github.com/Sirupsen/logrus"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
enginecontainer "github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/events"
|
||||
|
@ -18,7 +19,6 @@ import (
|
|||
"github.com/docker/docker/api/types/network"
|
||||
volumetypes "github.com/docker/docker/api/types/volume"
|
||||
clustertypes "github.com/docker/docker/daemon/cluster/provider"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/docker/go-connections/nat"
|
||||
"github.com/docker/swarmkit/agent/exec"
|
||||
"github.com/docker/swarmkit/api"
|
||||
|
@ -132,11 +132,11 @@ func (c *containerConfig) name() string {
|
|||
|
||||
func (c *containerConfig) image() string {
|
||||
raw := c.spec().Image
|
||||
ref, err := reference.ParseNamed(raw)
|
||||
ref, err := reference.ParseNormalizedNamed(raw)
|
||||
if err != nil {
|
||||
return raw
|
||||
}
|
||||
return reference.WithDefaultTag(ref).String()
|
||||
return reference.FamiliarString(reference.TagNameOnly(ref))
|
||||
}
|
||||
|
||||
func (c *containerConfig) portBindings() nat.PortMap {
|
||||
|
|
|
@ -2,12 +2,12 @@ package daemon
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
containertypes "github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/builder/dockerfile"
|
||||
|
@ -16,7 +16,7 @@ import (
|
|||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// merge merges two Config, the image container configuration (defaults values),
|
||||
|
@ -128,7 +128,7 @@ func (daemon *Daemon) Commit(name string, c *backend.ContainerCommitConfig) (str
|
|||
|
||||
// It is not possible to commit a running container on Windows and on Solaris.
|
||||
if (runtime.GOOS == "windows" || runtime.GOOS == "solaris") && container.IsRunning() {
|
||||
return "", fmt.Errorf("%+v does not support commit of a running container", runtime.GOOS)
|
||||
return "", errors.Errorf("%+v does not support commit of a running container", runtime.GOOS)
|
||||
}
|
||||
|
||||
if c.Pause && !container.IsPaused() {
|
||||
|
@ -228,10 +228,13 @@ func (daemon *Daemon) Commit(name string, c *backend.ContainerCommitConfig) (str
|
|||
|
||||
imageRef := ""
|
||||
if c.Repo != "" {
|
||||
newTag, err := reference.WithName(c.Repo) // todo: should move this to API layer
|
||||
newTag, err := reference.ParseNormalizedNamed(c.Repo) // todo: should move this to API layer
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if !reference.IsNameOnly(newTag) {
|
||||
return "", errors.Errorf("unexpected repository name: %s", c.Repo)
|
||||
}
|
||||
if c.Tag != "" {
|
||||
if newTag, err = reference.WithTag(newTag, c.Tag); err != nil {
|
||||
return "", err
|
||||
|
@ -240,7 +243,7 @@ func (daemon *Daemon) Commit(name string, c *backend.ContainerCommitConfig) (str
|
|||
if err := daemon.TagImageWithReference(id, newTag); err != nil {
|
||||
return "", err
|
||||
}
|
||||
imageRef = newTag.String()
|
||||
imageRef = reference.FamiliarString(newTag)
|
||||
}
|
||||
|
||||
attributes := map[string]string{
|
||||
|
|
|
@ -46,7 +46,7 @@ import (
|
|||
"github.com/docker/docker/pkg/system"
|
||||
"github.com/docker/docker/pkg/truncindex"
|
||||
"github.com/docker/docker/plugin"
|
||||
"github.com/docker/docker/reference"
|
||||
refstore "github.com/docker/docker/reference"
|
||||
"github.com/docker/docker/registry"
|
||||
"github.com/docker/docker/runconfig"
|
||||
volumedrivers "github.com/docker/docker/volume/drivers"
|
||||
|
@ -76,7 +76,7 @@ type Daemon struct {
|
|||
repository string
|
||||
containers container.Store
|
||||
execCommands *exec.Store
|
||||
referenceStore reference.Store
|
||||
referenceStore refstore.Store
|
||||
downloadManager *xfer.LayerDownloadManager
|
||||
uploadManager *xfer.LayerUploadManager
|
||||
distributionMetadataStore dmetadata.Store
|
||||
|
@ -637,7 +637,7 @@ func NewDaemon(config *Config, registryService registry.Service, containerdRemot
|
|||
|
||||
eventsService := events.New()
|
||||
|
||||
referenceStore, err := reference.NewReferenceStore(filepath.Join(imageRoot, "repositories.json"))
|
||||
referenceStore, err := refstore.NewReferenceStore(filepath.Join(imageRoot, "repositories.json"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Couldn't create Tag store repositories: %s", err)
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ import (
|
|||
"github.com/docker/docker/pkg/idtools"
|
||||
"github.com/docker/docker/pkg/parsers/kernel"
|
||||
"github.com/docker/docker/pkg/sysinfo"
|
||||
"github.com/docker/docker/reference"
|
||||
refstore "github.com/docker/docker/reference"
|
||||
"github.com/docker/libnetwork"
|
||||
nwconfig "github.com/docker/libnetwork/config"
|
||||
"github.com/docker/libnetwork/drivers/solaris/bridge"
|
||||
|
@ -491,7 +491,7 @@ func (daemon *Daemon) conditionalUnmountOnCleanup(container *container.Container
|
|||
return daemon.Unmount(container)
|
||||
}
|
||||
|
||||
func restoreCustomImage(is image.Store, ls layer.Store, rs reference.Store) error {
|
||||
func restoreCustomImage(is image.Store, ls layer.Store, rs refstore.Store) error {
|
||||
// Solaris has no custom images to register
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -2,29 +2,13 @@ package daemon
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/api/errors"
|
||||
"github.com/docker/docker/reference"
|
||||
)
|
||||
|
||||
func (d *Daemon) imageNotExistToErrcode(err error) error {
|
||||
if dne, isDNE := err.(ErrImageDoesNotExist); isDNE {
|
||||
if strings.Contains(dne.RefOrID, "@") {
|
||||
e := fmt.Errorf("No such image: %s", dne.RefOrID)
|
||||
return errors.NewRequestNotFoundError(e)
|
||||
}
|
||||
tag := reference.DefaultTag
|
||||
ref, err := reference.ParseNamed(dne.RefOrID)
|
||||
if err != nil {
|
||||
e := fmt.Errorf("No such image: %s:%s", dne.RefOrID, tag)
|
||||
return errors.NewRequestNotFoundError(e)
|
||||
}
|
||||
if tagged, isTagged := ref.(reference.NamedTagged); isTagged {
|
||||
tag = tagged.Tag()
|
||||
}
|
||||
e := fmt.Errorf("No such image: %s:%s", ref.Name(), tag)
|
||||
return errors.NewRequestNotFoundError(e)
|
||||
return errors.NewRequestNotFoundError(dne)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package events
|
||||
|
||||
import (
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types/events"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/reference"
|
||||
)
|
||||
|
||||
// Filter can filter out docker events from a stream
|
||||
|
@ -102,9 +102,9 @@ func (ef *Filter) matchImage(ev events.Message) bool {
|
|||
}
|
||||
|
||||
func stripTag(image string) string {
|
||||
ref, err := reference.ParseNamed(image)
|
||||
ref, err := reference.ParseNormalizedNamed(image)
|
||||
if err != nil {
|
||||
return image
|
||||
}
|
||||
return ref.Name()
|
||||
return reference.FamiliarName(ref)
|
||||
}
|
||||
|
|
|
@ -3,45 +3,55 @@ package daemon
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/builder"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/docker/reference"
|
||||
)
|
||||
|
||||
// ErrImageDoesNotExist is error returned when no image can be found for a reference.
|
||||
type ErrImageDoesNotExist struct {
|
||||
RefOrID string
|
||||
ref reference.Reference
|
||||
}
|
||||
|
||||
func (e ErrImageDoesNotExist) Error() string {
|
||||
return fmt.Sprintf("no such id: %s", e.RefOrID)
|
||||
ref := e.ref
|
||||
if named, ok := ref.(reference.Named); ok {
|
||||
ref = reference.TagNameOnly(named)
|
||||
}
|
||||
return fmt.Sprintf("No such image: %s", reference.FamiliarString(ref))
|
||||
}
|
||||
|
||||
// GetImageID returns an image ID corresponding to the image referred to by
|
||||
// refOrID.
|
||||
func (daemon *Daemon) GetImageID(refOrID string) (image.ID, error) {
|
||||
id, ref, err := reference.ParseIDOrReference(refOrID)
|
||||
ref, err := reference.ParseAnyReference(refOrID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if id != "" {
|
||||
if _, err := daemon.imageStore.Get(image.IDFromDigest(id)); err != nil {
|
||||
return "", ErrImageDoesNotExist{refOrID}
|
||||
namedRef, ok := ref.(reference.Named)
|
||||
if !ok {
|
||||
digested, ok := ref.(reference.Digested)
|
||||
if !ok {
|
||||
return "", ErrImageDoesNotExist{ref}
|
||||
}
|
||||
return image.IDFromDigest(id), nil
|
||||
id := image.IDFromDigest(digested.Digest())
|
||||
if _, err := daemon.imageStore.Get(id); err != nil {
|
||||
return "", ErrImageDoesNotExist{ref}
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
|
||||
if id, err := daemon.referenceStore.Get(ref); err == nil {
|
||||
if id, err := daemon.referenceStore.Get(namedRef); err == nil {
|
||||
return image.IDFromDigest(id), nil
|
||||
}
|
||||
|
||||
// deprecated: repo:shortid https://github.com/docker/docker/pull/799
|
||||
if tagged, ok := ref.(reference.NamedTagged); ok {
|
||||
if tagged, ok := namedRef.(reference.Tagged); ok {
|
||||
if tag := tagged.Tag(); stringid.IsShortID(stringid.TruncateID(tag)) {
|
||||
if id, err := daemon.imageStore.Search(tag); err == nil {
|
||||
for _, namedRef := range daemon.referenceStore.References(id.Digest()) {
|
||||
if namedRef.Name() == ref.Name() {
|
||||
for _, storeRef := range daemon.referenceStore.References(id.Digest()) {
|
||||
if storeRef.Name() == namedRef.Name() {
|
||||
return id, nil
|
||||
}
|
||||
}
|
||||
|
@ -54,7 +64,7 @@ func (daemon *Daemon) GetImageID(refOrID string) (image.ID, error) {
|
|||
return id, nil
|
||||
}
|
||||
|
||||
return "", ErrImageDoesNotExist{refOrID}
|
||||
return "", ErrImageDoesNotExist{ref}
|
||||
}
|
||||
|
||||
// GetImage returns an image corresponding to the image referred to by refOrID.
|
||||
|
|
|
@ -5,12 +5,12 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/errors"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/container"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/docker/reference"
|
||||
)
|
||||
|
||||
type conflictType int
|
||||
|
@ -89,7 +89,7 @@ func (daemon *Daemon) ImageDelete(imageRef string, force, prune bool) ([]types.I
|
|||
}
|
||||
}
|
||||
|
||||
parsedRef, err := reference.ParseNamed(imageRef)
|
||||
parsedRef, err := reference.ParseNormalizedNamed(imageRef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -99,7 +99,7 @@ func (daemon *Daemon) ImageDelete(imageRef string, force, prune bool) ([]types.I
|
|||
return nil, err
|
||||
}
|
||||
|
||||
untaggedRecord := types.ImageDeleteResponseItem{Untagged: parsedRef.String()}
|
||||
untaggedRecord := types.ImageDeleteResponseItem{Untagged: reference.FamiliarString(parsedRef)}
|
||||
|
||||
daemon.LogImageEvent(imgID.String(), imgID.String(), "untag")
|
||||
records = append(records, untaggedRecord)
|
||||
|
@ -126,7 +126,7 @@ func (daemon *Daemon) ImageDelete(imageRef string, force, prune bool) ([]types.I
|
|||
return records, err
|
||||
}
|
||||
|
||||
untaggedRecord := types.ImageDeleteResponseItem{Untagged: repoRef.String()}
|
||||
untaggedRecord := types.ImageDeleteResponseItem{Untagged: reference.FamiliarString(repoRef)}
|
||||
records = append(records, untaggedRecord)
|
||||
} else {
|
||||
remainingRefs = append(remainingRefs, repoRef)
|
||||
|
@ -162,7 +162,7 @@ func (daemon *Daemon) ImageDelete(imageRef string, force, prune bool) ([]types.I
|
|||
return nil, err
|
||||
}
|
||||
|
||||
untaggedRecord := types.ImageDeleteResponseItem{Untagged: parsedRef.String()}
|
||||
untaggedRecord := types.ImageDeleteResponseItem{Untagged: reference.FamiliarString(parsedRef)}
|
||||
|
||||
daemon.LogImageEvent(imgID.String(), imgID.String(), "untag")
|
||||
records = append(records, untaggedRecord)
|
||||
|
@ -232,7 +232,8 @@ func (daemon *Daemon) getContainerUsingImage(imageID image.ID) *container.Contai
|
|||
// optional tag or digest reference. If tag or digest is omitted, the default
|
||||
// tag is used. Returns the resolved image reference and an error.
|
||||
func (daemon *Daemon) removeImageRef(ref reference.Named) (reference.Named, error) {
|
||||
ref = reference.WithDefaultTag(ref)
|
||||
ref = reference.TagNameOnly(ref)
|
||||
|
||||
// Ignore the boolean value returned, as far as we're concerned, this
|
||||
// is an idempotent operation and it's okay if the reference didn't
|
||||
// exist in the first place.
|
||||
|
@ -255,7 +256,7 @@ func (daemon *Daemon) removeAllReferencesToImageID(imgID image.ID, records *[]ty
|
|||
return err
|
||||
}
|
||||
|
||||
untaggedRecord := types.ImageDeleteResponseItem{Untagged: parsedRef.String()}
|
||||
untaggedRecord := types.ImageDeleteResponseItem{Untagged: reference.FamiliarString(parsedRef)}
|
||||
|
||||
daemon.LogImageEvent(imgID.String(), imgID.String(), "untag")
|
||||
*records = append(*records, untaggedRecord)
|
||||
|
|
|
@ -4,9 +4,9 @@ import (
|
|||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types/image"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/docker/docker/reference"
|
||||
)
|
||||
|
||||
// ImageHistory returns a slice of ImageHistory structures for the specified image
|
||||
|
@ -64,7 +64,7 @@ func (daemon *Daemon) ImageHistory(name string) ([]*image.HistoryResponseItem, e
|
|||
var tags []string
|
||||
for _, r := range daemon.referenceStore.References(id.Digest()) {
|
||||
if _, ok := r.(reference.NamedTagged); ok {
|
||||
tags = append(tags, r.String())
|
||||
tags = append(tags, reference.FamiliarString(r))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,9 +3,9 @@ package daemon
|
|||
import (
|
||||
"time"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
|
@ -23,9 +23,9 @@ func (daemon *Daemon) LookupImage(name string) (*types.ImageInspect, error) {
|
|||
for _, ref := range refs {
|
||||
switch ref.(type) {
|
||||
case reference.NamedTagged:
|
||||
repoTags = append(repoTags, ref.String())
|
||||
repoTags = append(repoTags, reference.FamiliarString(ref))
|
||||
case reference.Canonical:
|
||||
repoDigests = append(repoDigests, ref.String())
|
||||
repoDigests = append(repoDigests, reference.FamiliarString(ref))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,12 +5,12 @@ import (
|
|||
"strings"
|
||||
|
||||
dist "github.com/docker/distribution"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/builder"
|
||||
"github.com/docker/docker/distribution"
|
||||
progressutils "github.com/docker/docker/distribution/utils"
|
||||
"github.com/docker/docker/pkg/progress"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/docker/docker/registry"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"golang.org/x/net/context"
|
||||
|
@ -24,7 +24,7 @@ func (daemon *Daemon) PullImage(ctx context.Context, image, tag string, metaHead
|
|||
// compatibility.
|
||||
image = strings.TrimSuffix(image, ":")
|
||||
|
||||
ref, err := reference.ParseNamed(image)
|
||||
ref, err := reference.ParseNormalizedNamed(image)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -48,11 +48,11 @@ func (daemon *Daemon) PullImage(ctx context.Context, image, tag string, metaHead
|
|||
|
||||
// PullOnBuild tells Docker to pull image referenced by `name`.
|
||||
func (daemon *Daemon) PullOnBuild(ctx context.Context, name string, authConfigs map[string]types.AuthConfig, output io.Writer) (builder.Image, error) {
|
||||
ref, err := reference.ParseNamed(name)
|
||||
ref, err := reference.ParseNormalizedNamed(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ref = reference.WithDefaultTag(ref)
|
||||
ref = reference.TagNameOnly(ref)
|
||||
|
||||
pullRegistryAuth := &types.AuthConfig{}
|
||||
if len(authConfigs) > 0 {
|
||||
|
@ -118,12 +118,12 @@ func (daemon *Daemon) GetRepository(ctx context.Context, ref reference.NamedTagg
|
|||
return nil, false, err
|
||||
}
|
||||
// makes sure name is not empty or `scratch`
|
||||
if err := distribution.ValidateRepoName(repoInfo.Name()); err != nil {
|
||||
if err := distribution.ValidateRepoName(repoInfo.Name); err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
// get endpoints
|
||||
endpoints, err := daemon.RegistryService.LookupPullEndpoints(repoInfo.Hostname())
|
||||
endpoints, err := daemon.RegistryService.LookupPullEndpoints(reference.Domain(repoInfo.Name))
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
|
|
|
@ -4,17 +4,17 @@ import (
|
|||
"io"
|
||||
|
||||
"github.com/docker/distribution/manifest/schema2"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/distribution"
|
||||
progressutils "github.com/docker/docker/distribution/utils"
|
||||
"github.com/docker/docker/pkg/progress"
|
||||
"github.com/docker/docker/reference"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// PushImage initiates a push operation on the repository named localName.
|
||||
func (daemon *Daemon) PushImage(ctx context.Context, image, tag string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
|
||||
ref, err := reference.ParseNamed(image)
|
||||
ref, err := reference.ParseNormalizedNamed(image)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package daemon
|
||||
|
||||
import (
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/reference"
|
||||
)
|
||||
|
||||
// TagImage creates the tag specified by newTag, pointing to the image named
|
||||
|
@ -13,12 +13,12 @@ func (daemon *Daemon) TagImage(imageName, repository, tag string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
newTag, err := reference.WithName(repository)
|
||||
newTag, err := reference.ParseNormalizedNamed(repository)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if tag != "" {
|
||||
if newTag, err = reference.WithTag(newTag, tag); err != nil {
|
||||
if newTag, err = reference.WithTag(reference.TrimNamed(newTag), tag); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,6 @@ func (daemon *Daemon) TagImageWithReference(imageID image.ID, newTag reference.N
|
|||
return err
|
||||
}
|
||||
|
||||
daemon.LogImageEvent(imageID.String(), newTag.String(), "tag")
|
||||
daemon.LogImageEvent(imageID.String(), reference.FamiliarString(newTag), "tag")
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -135,7 +135,7 @@ func (daemon *Daemon) Images(imageFilters filters.Args, all bool, withExtraAttrs
|
|||
var found bool
|
||||
var matchErr error
|
||||
for _, pattern := range imageFilters.Get("reference") {
|
||||
found, matchErr = reference.Match(pattern, ref)
|
||||
found, matchErr = reference.FamiliarMatch(pattern, ref)
|
||||
if matchErr != nil {
|
||||
return nil, matchErr
|
||||
}
|
||||
|
@ -145,10 +145,10 @@ func (daemon *Daemon) Images(imageFilters filters.Args, all bool, withExtraAttrs
|
|||
}
|
||||
}
|
||||
if _, ok := ref.(reference.Canonical); ok {
|
||||
newImage.RepoDigests = append(newImage.RepoDigests, ref.String())
|
||||
newImage.RepoDigests = append(newImage.RepoDigests, reference.FamiliarString(ref))
|
||||
}
|
||||
if _, ok := ref.(reference.NamedTagged); ok {
|
||||
newImage.RepoTags = append(newImage.RepoTags, ref.String())
|
||||
newImage.RepoTags = append(newImage.RepoTags, reference.FamiliarString(ref))
|
||||
}
|
||||
}
|
||||
if newImage.RepoDigests == nil && newImage.RepoTags == nil {
|
||||
|
|
|
@ -2,13 +2,13 @@ package daemon
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/builder/dockerfile"
|
||||
"github.com/docker/docker/dockerversion"
|
||||
|
@ -18,7 +18,7 @@ import (
|
|||
"github.com/docker/docker/pkg/httputils"
|
||||
"github.com/docker/docker/pkg/progress"
|
||||
"github.com/docker/docker/pkg/streamformatter"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// ImportImage imports an image, getting the archived layer data either from
|
||||
|
@ -35,11 +35,10 @@ func (daemon *Daemon) ImportImage(src string, repository, tag string, msg string
|
|||
|
||||
if repository != "" {
|
||||
var err error
|
||||
newRef, err = reference.ParseNamed(repository)
|
||||
newRef, err = reference.ParseNormalizedNamed(repository)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, isCanonical := newRef.(reference.Canonical); isCanonical {
|
||||
return errors.New("cannot import digest reference")
|
||||
}
|
||||
|
|
|
@ -6,13 +6,13 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
timetypes "github.com/docker/docker/api/types/time"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/docker/docker/pkg/directory"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/docker/docker/runconfig"
|
||||
"github.com/docker/docker/volume"
|
||||
"github.com/docker/libnetwork"
|
||||
|
|
|
@ -14,7 +14,7 @@ import (
|
|||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/docker/docker/pkg/progress"
|
||||
"github.com/docker/docker/reference"
|
||||
refstore "github.com/docker/docker/reference"
|
||||
"github.com/docker/docker/registry"
|
||||
"github.com/docker/libtrust"
|
||||
"github.com/opencontainers/go-digest"
|
||||
|
@ -44,7 +44,7 @@ type Config struct {
|
|||
ImageStore ImageConfigStore
|
||||
// ReferenceStore manages tags. This value is optional, when excluded
|
||||
// content will not be tagged.
|
||||
ReferenceStore reference.Store
|
||||
ReferenceStore refstore.Store
|
||||
// RequireSchema2 ensures that only schema2 manifests are used.
|
||||
RequireSchema2 bool
|
||||
}
|
||||
|
|
|
@ -7,12 +7,12 @@ import (
|
|||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/registry/api/errcode"
|
||||
"github.com/docker/distribution/registry/api/v2"
|
||||
"github.com/docker/distribution/registry/client"
|
||||
"github.com/docker/distribution/registry/client/auth"
|
||||
"github.com/docker/docker/distribution/xfer"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
|
@ -78,11 +78,11 @@ func TranslatePullError(err error, ref reference.Named) error {
|
|||
switch v.Code {
|
||||
case errcode.ErrorCodeDenied:
|
||||
// ErrorCodeDenied is used when access to the repository was denied
|
||||
newErr = errors.Errorf("repository %s not found: does not exist or no pull access", ref.Name())
|
||||
newErr = errors.Errorf("repository %s not found: does not exist or no pull access", reference.FamiliarName(ref))
|
||||
case v2.ErrorCodeManifestUnknown:
|
||||
newErr = errors.Errorf("manifest for %s not found", ref.String())
|
||||
newErr = errors.Errorf("manifest for %s not found", reference.FamiliarString(ref))
|
||||
case v2.ErrorCodeNameUnknown:
|
||||
newErr = errors.Errorf("repository %s not found", ref.Name())
|
||||
newErr = errors.Errorf("repository %s not found", reference.FamiliarName(ref))
|
||||
}
|
||||
if newErr != nil {
|
||||
logrus.Infof("Translating %q to %q", err, newErr)
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
package distribution
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api"
|
||||
"github.com/docker/docker/distribution/metadata"
|
||||
"github.com/docker/docker/pkg/progress"
|
||||
"github.com/docker/docker/reference"
|
||||
refstore "github.com/docker/docker/reference"
|
||||
"github.com/docker/docker/registry"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"golang.org/x/net/context"
|
||||
|
@ -56,12 +56,12 @@ func Pull(ctx context.Context, ref reference.Named, imagePullConfig *ImagePullCo
|
|||
return err
|
||||
}
|
||||
|
||||
// makes sure name is not empty or `scratch`
|
||||
if err := ValidateRepoName(repoInfo.Name()); err != nil {
|
||||
// makes sure name is not `scratch`
|
||||
if err := ValidateRepoName(repoInfo.Name); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
endpoints, err := imagePullConfig.RegistryService.LookupPullEndpoints(repoInfo.Hostname())
|
||||
endpoints, err := imagePullConfig.RegistryService.LookupPullEndpoints(reference.Domain(repoInfo.Name))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -105,7 +105,7 @@ func Pull(ctx context.Context, ref reference.Named, imagePullConfig *ImagePullCo
|
|||
}
|
||||
}
|
||||
|
||||
logrus.Debugf("Trying to pull %s from %s %s", repoInfo.Name(), endpoint.URL, endpoint.Version)
|
||||
logrus.Debugf("Trying to pull %s from %s %s", reference.FamiliarName(repoInfo.Name), endpoint.URL, endpoint.Version)
|
||||
|
||||
puller, err := newPuller(endpoint, repoInfo, imagePullConfig)
|
||||
if err != nil {
|
||||
|
@ -147,12 +147,12 @@ func Pull(ctx context.Context, ref reference.Named, imagePullConfig *ImagePullCo
|
|||
return TranslatePullError(err, ref)
|
||||
}
|
||||
|
||||
imagePullConfig.ImageEventLogger(ref.String(), repoInfo.Name(), "pull")
|
||||
imagePullConfig.ImageEventLogger(reference.FamiliarString(ref), reference.FamiliarName(repoInfo.Name), "pull")
|
||||
return nil
|
||||
}
|
||||
|
||||
if lastErr == nil {
|
||||
lastErr = fmt.Errorf("no endpoints found for %s", ref.String())
|
||||
lastErr = fmt.Errorf("no endpoints found for %s", reference.FamiliarString(ref))
|
||||
}
|
||||
|
||||
return TranslatePullError(lastErr, ref)
|
||||
|
@ -171,17 +171,14 @@ func writeStatus(requestedTag string, out progress.Output, layersDownloaded bool
|
|||
}
|
||||
|
||||
// ValidateRepoName validates the name of a repository.
|
||||
func ValidateRepoName(name string) error {
|
||||
if name == "" {
|
||||
return errors.New("Repository name can't be empty")
|
||||
}
|
||||
if name == api.NoBaseImageSpecifier {
|
||||
func ValidateRepoName(name reference.Named) error {
|
||||
if reference.FamiliarName(name) == api.NoBaseImageSpecifier {
|
||||
return fmt.Errorf("'%s' is a reserved name", api.NoBaseImageSpecifier)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func addDigestReference(store reference.Store, ref reference.Named, dgst digest.Digest, id digest.Digest) error {
|
||||
func addDigestReference(store refstore.Store, ref reference.Named, dgst digest.Digest, id digest.Digest) error {
|
||||
dgstRef, err := reference.WithDigest(reference.TrimNamed(ref), dgst)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -193,7 +190,7 @@ func addDigestReference(store reference.Store, ref reference.Named, dgst digest.
|
|||
logrus.Errorf("Image ID for digest %s changed from %s to %s, cannot update", dgst.String(), oldTagID, id)
|
||||
}
|
||||
return nil
|
||||
} else if err != reference.ErrDoesNotExist {
|
||||
} else if err != refstore.ErrDoesNotExist {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/registry/client/transport"
|
||||
"github.com/docker/docker/distribution/metadata"
|
||||
"github.com/docker/docker/distribution/xfer"
|
||||
|
@ -22,7 +23,6 @@ import (
|
|||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/pkg/progress"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/docker/docker/registry"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
@ -67,23 +67,23 @@ func (p *v1Puller) Pull(ctx context.Context, ref reference.Named) error {
|
|||
// TODO(dmcgowan): Check if should fallback
|
||||
return err
|
||||
}
|
||||
progress.Message(p.config.ProgressOutput, "", p.repoInfo.FullName()+": this image was pulled from a legacy registry. Important: This registry version will not be supported in future versions of docker.")
|
||||
progress.Message(p.config.ProgressOutput, "", p.repoInfo.Name.Name()+": this image was pulled from a legacy registry. Important: This registry version will not be supported in future versions of docker.")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *v1Puller) pullRepository(ctx context.Context, ref reference.Named) error {
|
||||
progress.Message(p.config.ProgressOutput, "", "Pulling repository "+p.repoInfo.FullName())
|
||||
progress.Message(p.config.ProgressOutput, "", "Pulling repository "+p.repoInfo.Name.Name())
|
||||
|
||||
tagged, isTagged := ref.(reference.NamedTagged)
|
||||
|
||||
repoData, err := p.session.GetRepositoryData(p.repoInfo)
|
||||
repoData, err := p.session.GetRepositoryData(p.repoInfo.Name)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "HTTP code: 404") {
|
||||
if isTagged {
|
||||
return fmt.Errorf("Error: image %s:%s not found", p.repoInfo.RemoteName(), tagged.Tag())
|
||||
return fmt.Errorf("Error: image %s:%s not found", reference.Path(p.repoInfo.Name), tagged.Tag())
|
||||
}
|
||||
return fmt.Errorf("Error: image %s not found", p.repoInfo.RemoteName())
|
||||
return fmt.Errorf("Error: image %s not found", reference.Path(p.repoInfo.Name))
|
||||
}
|
||||
// Unexpected HTTP error
|
||||
return err
|
||||
|
@ -92,13 +92,13 @@ func (p *v1Puller) pullRepository(ctx context.Context, ref reference.Named) erro
|
|||
logrus.Debug("Retrieving the tag list")
|
||||
var tagsList map[string]string
|
||||
if !isTagged {
|
||||
tagsList, err = p.session.GetRemoteTags(repoData.Endpoints, p.repoInfo)
|
||||
tagsList, err = p.session.GetRemoteTags(repoData.Endpoints, p.repoInfo.Name)
|
||||
} else {
|
||||
var tagID string
|
||||
tagsList = make(map[string]string)
|
||||
tagID, err = p.session.GetRemoteTag(repoData.Endpoints, p.repoInfo, tagged.Tag())
|
||||
tagID, err = p.session.GetRemoteTag(repoData.Endpoints, p.repoInfo.Name, tagged.Tag())
|
||||
if err == registry.ErrRepoNotFound {
|
||||
return fmt.Errorf("Tag %s not found in repository %s", tagged.Tag(), p.repoInfo.FullName())
|
||||
return fmt.Errorf("Tag %s not found in repository %s", tagged.Tag(), p.repoInfo.Name.Name())
|
||||
}
|
||||
tagsList[tagged.Tag()] = tagID
|
||||
}
|
||||
|
@ -127,7 +127,7 @@ func (p *v1Puller) pullRepository(ctx context.Context, ref reference.Named) erro
|
|||
}
|
||||
}
|
||||
|
||||
writeStatus(ref.String(), p.config.ProgressOutput, layersDownloaded)
|
||||
writeStatus(reference.FamiliarString(ref), p.config.ProgressOutput, layersDownloaded)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -137,7 +137,7 @@ func (p *v1Puller) downloadImage(ctx context.Context, repoData *registry.Reposit
|
|||
return nil
|
||||
}
|
||||
|
||||
localNameRef, err := reference.WithTag(p.repoInfo, img.Tag)
|
||||
localNameRef, err := reference.WithTag(p.repoInfo.Name, img.Tag)
|
||||
if err != nil {
|
||||
retErr := fmt.Errorf("Image (id: %s) has invalid tag: %s", img.ID, img.Tag)
|
||||
logrus.Debug(retErr.Error())
|
||||
|
@ -148,15 +148,15 @@ func (p *v1Puller) downloadImage(ctx context.Context, repoData *registry.Reposit
|
|||
return err
|
||||
}
|
||||
|
||||
progress.Updatef(p.config.ProgressOutput, stringid.TruncateID(img.ID), "Pulling image (%s) from %s", img.Tag, p.repoInfo.FullName())
|
||||
progress.Updatef(p.config.ProgressOutput, stringid.TruncateID(img.ID), "Pulling image (%s) from %s", img.Tag, p.repoInfo.Name.Name())
|
||||
success := false
|
||||
var lastErr error
|
||||
for _, ep := range p.repoInfo.Index.Mirrors {
|
||||
ep += "v1/"
|
||||
progress.Updatef(p.config.ProgressOutput, stringid.TruncateID(img.ID), fmt.Sprintf("Pulling image (%s) from %s, mirror: %s", img.Tag, p.repoInfo.FullName(), ep))
|
||||
progress.Updatef(p.config.ProgressOutput, stringid.TruncateID(img.ID), fmt.Sprintf("Pulling image (%s) from %s, mirror: %s", img.Tag, p.repoInfo.Name.Name(), ep))
|
||||
if err = p.pullImage(ctx, img.ID, ep, localNameRef, layersDownloaded); err != nil {
|
||||
// Don't report errors when pulling from mirrors.
|
||||
logrus.Debugf("Error pulling image (%s) from %s, mirror: %s, %s", img.Tag, p.repoInfo.FullName(), ep, err)
|
||||
logrus.Debugf("Error pulling image (%s) from %s, mirror: %s, %s", img.Tag, p.repoInfo.Name.Name(), ep, err)
|
||||
continue
|
||||
}
|
||||
success = true
|
||||
|
@ -164,12 +164,12 @@ func (p *v1Puller) downloadImage(ctx context.Context, repoData *registry.Reposit
|
|||
}
|
||||
if !success {
|
||||
for _, ep := range repoData.Endpoints {
|
||||
progress.Updatef(p.config.ProgressOutput, stringid.TruncateID(img.ID), "Pulling image (%s) from %s, endpoint: %s", img.Tag, p.repoInfo.FullName(), ep)
|
||||
progress.Updatef(p.config.ProgressOutput, stringid.TruncateID(img.ID), "Pulling image (%s) from %s, endpoint: %s", img.Tag, p.repoInfo.Name.Name(), ep)
|
||||
if err = p.pullImage(ctx, img.ID, ep, localNameRef, layersDownloaded); err != nil {
|
||||
// It's not ideal that only the last error is returned, it would be better to concatenate the errors.
|
||||
// As the error is also given to the output stream the user will see the error.
|
||||
lastErr = err
|
||||
progress.Updatef(p.config.ProgressOutput, stringid.TruncateID(img.ID), "Error pulling image (%s) from %s, endpoint: %s, %s", img.Tag, p.repoInfo.FullName(), ep, err)
|
||||
progress.Updatef(p.config.ProgressOutput, stringid.TruncateID(img.ID), "Error pulling image (%s) from %s, endpoint: %s, %s", img.Tag, p.repoInfo.Name.Name(), ep, err)
|
||||
continue
|
||||
}
|
||||
success = true
|
||||
|
@ -177,7 +177,7 @@ func (p *v1Puller) downloadImage(ctx context.Context, repoData *registry.Reposit
|
|||
}
|
||||
}
|
||||
if !success {
|
||||
err := fmt.Errorf("Error pulling image (%s) from %s, %v", img.Tag, p.repoInfo.FullName(), lastErr)
|
||||
err := fmt.Errorf("Error pulling image (%s) from %s, %v", img.Tag, p.repoInfo.Name.Name(), lastErr)
|
||||
progress.Update(p.config.ProgressOutput, stringid.TruncateID(img.ID), err.Error())
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ import (
|
|||
"github.com/docker/distribution/manifest/manifestlist"
|
||||
"github.com/docker/distribution/manifest/schema1"
|
||||
"github.com/docker/distribution/manifest/schema2"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/registry/api/errcode"
|
||||
"github.com/docker/distribution/registry/client/auth"
|
||||
"github.com/docker/distribution/registry/client/transport"
|
||||
|
@ -26,7 +27,7 @@ import (
|
|||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/pkg/progress"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/docker/reference"
|
||||
refstore "github.com/docker/docker/reference"
|
||||
"github.com/docker/docker/registry"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"golang.org/x/net/context"
|
||||
|
@ -124,7 +125,7 @@ func (p *v2Puller) pullV2Repository(ctx context.Context, ref reference.Named) (e
|
|||
}
|
||||
}
|
||||
|
||||
writeStatus(ref.String(), p.config.ProgressOutput, layersDownloaded)
|
||||
writeStatus(reference.FamiliarString(ref), p.config.ProgressOutput, layersDownloaded)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -317,7 +318,7 @@ func (ld *v2LayerDescriptor) truncateDownloadFile() error {
|
|||
|
||||
func (ld *v2LayerDescriptor) Registered(diffID layer.DiffID) {
|
||||
// Cache mapping from this layer's DiffID to the blobsum
|
||||
ld.V2MetadataService.Add(diffID, metadata.V2Metadata{Digest: ld.digest, SourceRepository: ld.repoInfo.FullName()})
|
||||
ld.V2MetadataService.Add(diffID, metadata.V2Metadata{Digest: ld.digest, SourceRepository: ld.repoInfo.Name.Name()})
|
||||
}
|
||||
|
||||
func (p *v2Puller) pullV2Tag(ctx context.Context, ref reference.Named) (tagUpdated bool, err error) {
|
||||
|
@ -343,7 +344,7 @@ func (p *v2Puller) pullV2Tag(ctx context.Context, ref reference.Named) (tagUpdat
|
|||
}
|
||||
tagOrDigest = digested.Digest().String()
|
||||
} else {
|
||||
return false, fmt.Errorf("internal error: reference has neither a tag nor a digest: %s", ref.String())
|
||||
return false, fmt.Errorf("internal error: reference has neither a tag nor a digest: %s", reference.FamiliarString(ref))
|
||||
}
|
||||
|
||||
if manifest == nil {
|
||||
|
@ -371,8 +372,8 @@ func (p *v2Puller) pullV2Tag(ctx context.Context, ref reference.Named) (tagUpdat
|
|||
// the other side speaks the v2 protocol.
|
||||
p.confirmedV2 = true
|
||||
|
||||
logrus.Debugf("Pulling ref from V2 registry: %s", ref.String())
|
||||
progress.Message(p.config.ProgressOutput, tagOrDigest, "Pulling from "+p.repo.Named().Name())
|
||||
logrus.Debugf("Pulling ref from V2 registry: %s", reference.FamiliarString(ref))
|
||||
progress.Message(p.config.ProgressOutput, tagOrDigest, "Pulling from "+reference.FamiliarName(p.repo.Named()))
|
||||
|
||||
var (
|
||||
id digest.Digest
|
||||
|
@ -410,7 +411,7 @@ func (p *v2Puller) pullV2Tag(ctx context.Context, ref reference.Named) (tagUpdat
|
|||
if oldTagID == id {
|
||||
return false, addDigestReference(p.config.ReferenceStore, ref, manifestDigest, id)
|
||||
}
|
||||
} else if err != reference.ErrDoesNotExist {
|
||||
} else if err != refstore.ErrDoesNotExist {
|
||||
return false, err
|
||||
}
|
||||
|
||||
|
@ -802,13 +803,13 @@ func verifySchema1Manifest(signedManifest *schema1.SignedManifest, ref reference
|
|||
m = &signedManifest.Manifest
|
||||
|
||||
if m.SchemaVersion != 1 {
|
||||
return nil, fmt.Errorf("unsupported schema version %d for %q", m.SchemaVersion, ref.String())
|
||||
return nil, fmt.Errorf("unsupported schema version %d for %q", m.SchemaVersion, reference.FamiliarString(ref))
|
||||
}
|
||||
if len(m.FSLayers) != len(m.History) {
|
||||
return nil, fmt.Errorf("length of history not equal to number of layers for %q", ref.String())
|
||||
return nil, fmt.Errorf("length of history not equal to number of layers for %q", reference.FamiliarString(ref))
|
||||
}
|
||||
if len(m.FSLayers) == 0 {
|
||||
return nil, fmt.Errorf("no FSLayers in manifest for %q", ref.String())
|
||||
return nil, fmt.Errorf("no FSLayers in manifest for %q", reference.FamiliarString(ref))
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/docker/distribution/manifest/schema1"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/opencontainers/go-digest"
|
||||
)
|
||||
|
||||
|
@ -113,7 +113,7 @@ func TestValidateManifest(t *testing.T) {
|
|||
if runtime.GOOS == "windows" {
|
||||
t.Skip("Needs fixing on Windows")
|
||||
}
|
||||
expectedDigest, err := reference.ParseNamed("repo@sha256:02fee8c3220ba806531f606525eceb83f4feb654f62b207191b1c9209188dedd")
|
||||
expectedDigest, err := reference.ParseNormalizedNamed("repo@sha256:02fee8c3220ba806531f606525eceb83f4feb654f62b207191b1c9209188dedd")
|
||||
if err != nil {
|
||||
t.Fatal("could not parse reference")
|
||||
}
|
||||
|
|
|
@ -7,9 +7,9 @@ import (
|
|||
"io"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/distribution/metadata"
|
||||
"github.com/docker/docker/pkg/progress"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/docker/docker/registry"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
@ -64,16 +64,16 @@ func Push(ctx context.Context, ref reference.Named, imagePushConfig *ImagePushCo
|
|||
return err
|
||||
}
|
||||
|
||||
endpoints, err := imagePushConfig.RegistryService.LookupPushEndpoints(repoInfo.Hostname())
|
||||
endpoints, err := imagePushConfig.RegistryService.LookupPushEndpoints(reference.Domain(repoInfo.Name))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
progress.Messagef(imagePushConfig.ProgressOutput, "", "The push refers to a repository [%s]", repoInfo.FullName())
|
||||
progress.Messagef(imagePushConfig.ProgressOutput, "", "The push refers to a repository [%s]", repoInfo.Name.Name())
|
||||
|
||||
associations := imagePushConfig.ReferenceStore.ReferencesByName(repoInfo)
|
||||
associations := imagePushConfig.ReferenceStore.ReferencesByName(repoInfo.Name)
|
||||
if len(associations) == 0 {
|
||||
return fmt.Errorf("An image does not exist locally with the tag: %s", repoInfo.Name())
|
||||
return fmt.Errorf("An image does not exist locally with the tag: %s", reference.FamiliarName(repoInfo.Name))
|
||||
}
|
||||
|
||||
var (
|
||||
|
@ -106,7 +106,7 @@ func Push(ctx context.Context, ref reference.Named, imagePushConfig *ImagePushCo
|
|||
}
|
||||
}
|
||||
|
||||
logrus.Debugf("Trying to push %s to %s %s", repoInfo.FullName(), endpoint.URL, endpoint.Version)
|
||||
logrus.Debugf("Trying to push %s to %s %s", repoInfo.Name.Name(), endpoint.URL, endpoint.Version)
|
||||
|
||||
pusher, err := NewPusher(ref, endpoint, repoInfo, imagePushConfig)
|
||||
if err != nil {
|
||||
|
@ -135,12 +135,12 @@ func Push(ctx context.Context, ref reference.Named, imagePushConfig *ImagePushCo
|
|||
return err
|
||||
}
|
||||
|
||||
imagePushConfig.ImageEventLogger(ref.String(), repoInfo.Name(), "push")
|
||||
imagePushConfig.ImageEventLogger(reference.FamiliarString(ref), reference.FamiliarName(repoInfo.Name), "push")
|
||||
return nil
|
||||
}
|
||||
|
||||
if lastErr == nil {
|
||||
lastErr = fmt.Errorf("no endpoints found for %s", repoInfo.FullName())
|
||||
lastErr = fmt.Errorf("no endpoints found for %s", repoInfo.Name.Name())
|
||||
}
|
||||
return lastErr
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"sync"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/registry/client/transport"
|
||||
"github.com/docker/docker/distribution/metadata"
|
||||
"github.com/docker/docker/dockerversion"
|
||||
|
@ -14,7 +15,6 @@ import (
|
|||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/pkg/progress"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/docker/docker/registry"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"golang.org/x/net/context"
|
||||
|
@ -356,8 +356,8 @@ func (p *v1Pusher) pushImageToEndpoint(ctx context.Context, endpoint string, ima
|
|||
}
|
||||
if topImage, isTopImage := img.(*v1TopImage); isTopImage {
|
||||
for _, tag := range tags[topImage.imageID] {
|
||||
progress.Messagef(p.config.ProgressOutput, "", "Pushing tag for rev [%s] on {%s}", stringid.TruncateID(v1ID), endpoint+"repositories/"+p.repoInfo.RemoteName()+"/tags/"+tag)
|
||||
if err := p.session.PushRegistryTag(p.repoInfo, v1ID, tag, endpoint); err != nil {
|
||||
progress.Messagef(p.config.ProgressOutput, "", "Pushing tag for rev [%s] on {%s}", stringid.TruncateID(v1ID), endpoint+"repositories/"+reference.Path(p.repoInfo.Name)+"/tags/"+tag)
|
||||
if err := p.session.PushRegistryTag(p.repoInfo.Name, v1ID, tag, endpoint); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -385,7 +385,7 @@ func (p *v1Pusher) pushRepository(ctx context.Context) error {
|
|||
|
||||
// Register all the images in a repository with the registry
|
||||
// If an image is not in this list it will not be associated with the repository
|
||||
repoData, err := p.session.PushImageJSONIndex(p.repoInfo, imageIndex, false, nil)
|
||||
repoData, err := p.session.PushImageJSONIndex(p.repoInfo.Name, imageIndex, false, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -395,7 +395,7 @@ func (p *v1Pusher) pushRepository(ctx context.Context) error {
|
|||
return err
|
||||
}
|
||||
}
|
||||
_, err = p.session.PushImageJSONIndex(p.repoInfo, imageIndex, true, repoData.Endpoints)
|
||||
_, err = p.session.PushImageJSONIndex(p.repoInfo.Name, imageIndex, true, repoData.Endpoints)
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ import (
|
|||
"github.com/docker/distribution"
|
||||
"github.com/docker/distribution/manifest/schema1"
|
||||
"github.com/docker/distribution/manifest/schema2"
|
||||
distreference "github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/registry/client"
|
||||
apitypes "github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/distribution/metadata"
|
||||
|
@ -24,7 +24,6 @@ import (
|
|||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/pkg/progress"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/docker/docker/registry"
|
||||
"github.com/opencontainers/go-digest"
|
||||
)
|
||||
|
@ -83,7 +82,7 @@ func (p *v2Pusher) pushV2Repository(ctx context.Context) (err error) {
|
|||
if namedTagged, isNamedTagged := p.ref.(reference.NamedTagged); isNamedTagged {
|
||||
imageID, err := p.config.ReferenceStore.Get(p.ref)
|
||||
if err != nil {
|
||||
return fmt.Errorf("tag does not exist: %s", p.ref.String())
|
||||
return fmt.Errorf("tag does not exist: %s", reference.FamiliarString(p.ref))
|
||||
}
|
||||
|
||||
return p.pushV2Tag(ctx, namedTagged, imageID)
|
||||
|
@ -105,23 +104,23 @@ func (p *v2Pusher) pushV2Repository(ctx context.Context) (err error) {
|
|||
}
|
||||
|
||||
if pushed == 0 {
|
||||
return fmt.Errorf("no tags to push for %s", p.repoInfo.Name())
|
||||
return fmt.Errorf("no tags to push for %s", reference.FamiliarName(p.repoInfo.Name))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *v2Pusher) pushV2Tag(ctx context.Context, ref reference.NamedTagged, id digest.Digest) error {
|
||||
logrus.Debugf("Pushing repository: %s", ref.String())
|
||||
logrus.Debugf("Pushing repository: %s", reference.FamiliarString(ref))
|
||||
|
||||
imgConfig, err := p.config.ImageStore.Get(id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not find image from tag %s: %v", ref.String(), err)
|
||||
return fmt.Errorf("could not find image from tag %s: %v", reference.FamiliarString(ref), err)
|
||||
}
|
||||
|
||||
rootfs, err := p.config.ImageStore.RootFSFromConfig(imgConfig)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to get rootfs for image %s: %s", ref.String(), err)
|
||||
return fmt.Errorf("unable to get rootfs for image %s: %s", reference.FamiliarString(ref), err)
|
||||
}
|
||||
|
||||
l, err := p.config.LayerStore.Get(rootfs.ChainID())
|
||||
|
@ -140,7 +139,7 @@ func (p *v2Pusher) pushV2Tag(ctx context.Context, ref reference.NamedTagged, id
|
|||
descriptorTemplate := v2PushDescriptor{
|
||||
v2MetadataService: p.v2MetadataService,
|
||||
hmacKey: hmacKey,
|
||||
repoInfo: p.repoInfo,
|
||||
repoInfo: p.repoInfo.Name,
|
||||
ref: p.ref,
|
||||
repo: p.repo,
|
||||
pushState: &p.pushState,
|
||||
|
@ -181,7 +180,7 @@ func (p *v2Pusher) pushV2Tag(ctx context.Context, ref reference.NamedTagged, id
|
|||
|
||||
logrus.Warnf("failed to upload schema2 manifest: %v - falling back to schema1", err)
|
||||
|
||||
manifestRef, err := distreference.WithTag(p.repo.Named(), ref.Tag())
|
||||
manifestRef, err := reference.WithTag(p.repo.Named(), ref.Tag())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -248,7 +247,7 @@ type v2PushDescriptor struct {
|
|||
}
|
||||
|
||||
func (pd *v2PushDescriptor) Key() string {
|
||||
return "v2push:" + pd.ref.FullName() + " " + pd.layer.DiffID().String()
|
||||
return "v2push:" + pd.ref.Name() + " " + pd.layer.DiffID().String()
|
||||
}
|
||||
|
||||
func (pd *v2PushDescriptor) ID() string {
|
||||
|
@ -304,23 +303,22 @@ func (pd *v2PushDescriptor) Upload(ctx context.Context, progressOutput progress.
|
|||
createOpts := []distribution.BlobCreateOption{}
|
||||
|
||||
if len(mountCandidate.SourceRepository) > 0 {
|
||||
namedRef, err := reference.WithName(mountCandidate.SourceRepository)
|
||||
namedRef, err := reference.ParseNormalizedNamed(mountCandidate.SourceRepository)
|
||||
if err != nil {
|
||||
logrus.Errorf("failed to parse source repository reference %v: %v", namedRef.String(), err)
|
||||
logrus.Errorf("failed to parse source repository reference %v: %v", reference.FamiliarString(namedRef), err)
|
||||
pd.v2MetadataService.Remove(mountCandidate)
|
||||
continue
|
||||
}
|
||||
|
||||
// TODO (brianbland): We need to construct a reference where the Name is
|
||||
// only the full remote name, so clean this up when distribution has a
|
||||
// richer reference package
|
||||
remoteRef, err := distreference.WithName(namedRef.RemoteName())
|
||||
// Candidates are always under same domain, create remote reference
|
||||
// with only path to set mount from with
|
||||
remoteRef, err := reference.WithName(reference.Path(namedRef))
|
||||
if err != nil {
|
||||
logrus.Errorf("failed to make remote reference out of %q: %v", namedRef.RemoteName(), namedRef.RemoteName())
|
||||
logrus.Errorf("failed to make remote reference out of %q: %v", reference.Path(namedRef), err)
|
||||
continue
|
||||
}
|
||||
|
||||
canonicalRef, err := distreference.WithDigest(distreference.TrimNamed(remoteRef), mountCandidate.Digest)
|
||||
canonicalRef, err := reference.WithDigest(reference.TrimNamed(remoteRef), mountCandidate.Digest)
|
||||
if err != nil {
|
||||
logrus.Errorf("failed to make canonical reference: %v", err)
|
||||
continue
|
||||
|
@ -347,7 +345,7 @@ func (pd *v2PushDescriptor) Upload(ctx context.Context, progressOutput progress.
|
|||
// Cache mapping from this layer's DiffID to the blobsum
|
||||
if err := pd.v2MetadataService.TagAndAdd(diffID, pd.hmacKey, metadata.V2Metadata{
|
||||
Digest: err.Descriptor.Digest,
|
||||
SourceRepository: pd.repoInfo.FullName(),
|
||||
SourceRepository: pd.repoInfo.Name(),
|
||||
}); err != nil {
|
||||
return distribution.Descriptor{}, xfer.DoNotRetry{Err: err}
|
||||
}
|
||||
|
@ -455,7 +453,7 @@ func (pd *v2PushDescriptor) uploadUsingSession(
|
|||
// Cache mapping from this layer's DiffID to the blobsum
|
||||
if err := pd.v2MetadataService.TagAndAdd(diffID, pd.hmacKey, metadata.V2Metadata{
|
||||
Digest: pushDigest,
|
||||
SourceRepository: pd.repoInfo.FullName(),
|
||||
SourceRepository: pd.repoInfo.Name(),
|
||||
}); err != nil {
|
||||
return distribution.Descriptor{}, xfer.DoNotRetry{Err: err}
|
||||
}
|
||||
|
@ -490,7 +488,7 @@ func (pd *v2PushDescriptor) layerAlreadyExists(
|
|||
// filter the metadata
|
||||
candidates := []metadata.V2Metadata{}
|
||||
for _, meta := range v2Metadata {
|
||||
if len(meta.SourceRepository) > 0 && !checkOtherRepositories && meta.SourceRepository != pd.repoInfo.FullName() {
|
||||
if len(meta.SourceRepository) > 0 && !checkOtherRepositories && meta.SourceRepository != pd.repoInfo.Name() {
|
||||
continue
|
||||
}
|
||||
candidates = append(candidates, meta)
|
||||
|
@ -521,16 +519,16 @@ func (pd *v2PushDescriptor) layerAlreadyExists(
|
|||
attempts:
|
||||
for _, dgst := range layerDigests {
|
||||
meta := digestToMetadata[dgst]
|
||||
logrus.Debugf("Checking for presence of layer %s (%s) in %s", diffID, dgst, pd.repoInfo.FullName())
|
||||
logrus.Debugf("Checking for presence of layer %s (%s) in %s", diffID, dgst, pd.repoInfo.Name())
|
||||
desc, err = pd.repo.Blobs(ctx).Stat(ctx, dgst)
|
||||
pd.checkedDigests[meta.Digest] = struct{}{}
|
||||
switch err {
|
||||
case nil:
|
||||
if m, ok := digestToMetadata[desc.Digest]; !ok || m.SourceRepository != pd.repoInfo.FullName() || !metadata.CheckV2MetadataHMAC(m, pd.hmacKey) {
|
||||
if m, ok := digestToMetadata[desc.Digest]; !ok || m.SourceRepository != pd.repoInfo.Name() || !metadata.CheckV2MetadataHMAC(m, pd.hmacKey) {
|
||||
// cache mapping from this layer's DiffID to the blobsum
|
||||
if err := pd.v2MetadataService.TagAndAdd(diffID, pd.hmacKey, metadata.V2Metadata{
|
||||
Digest: desc.Digest,
|
||||
SourceRepository: pd.repoInfo.FullName(),
|
||||
SourceRepository: pd.repoInfo.Name(),
|
||||
}); err != nil {
|
||||
return distribution.Descriptor{}, false, xfer.DoNotRetry{Err: err}
|
||||
}
|
||||
|
@ -539,12 +537,12 @@ attempts:
|
|||
exists = true
|
||||
break attempts
|
||||
case distribution.ErrBlobUnknown:
|
||||
if meta.SourceRepository == pd.repoInfo.FullName() {
|
||||
if meta.SourceRepository == pd.repoInfo.Name() {
|
||||
// remove the mapping to the target repository
|
||||
pd.v2MetadataService.Remove(*meta)
|
||||
}
|
||||
default:
|
||||
logrus.WithError(err).Debugf("Failed to check for presence of layer %s (%s) in %s", diffID, dgst, pd.repoInfo.FullName())
|
||||
logrus.WithError(err).Debugf("Failed to check for presence of layer %s (%s) in %s", diffID, dgst, pd.repoInfo.Name())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -598,11 +596,11 @@ func getRepositoryMountCandidates(
|
|||
candidates := []metadata.V2Metadata{}
|
||||
for _, meta := range v2Metadata {
|
||||
sourceRepo, err := reference.ParseNamed(meta.SourceRepository)
|
||||
if err != nil || repoInfo.Hostname() != sourceRepo.Hostname() {
|
||||
if err != nil || reference.Domain(repoInfo) != reference.Domain(sourceRepo) {
|
||||
continue
|
||||
}
|
||||
// target repository is not a viable candidate
|
||||
if meta.SourceRepository == repoInfo.FullName() {
|
||||
if meta.SourceRepository == repoInfo.Name() {
|
||||
continue
|
||||
}
|
||||
candidates = append(candidates, meta)
|
||||
|
@ -653,7 +651,7 @@ func sortV2MetadataByLikenessAndAge(repoInfo reference.Named, hmacKey []byte, ma
|
|||
sort.Stable(byLikeness{
|
||||
arr: marr,
|
||||
hmacKey: hmacKey,
|
||||
pathComponents: getPathComponents(repoInfo.FullName()),
|
||||
pathComponents: getPathComponents(repoInfo.Name()),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -670,11 +668,6 @@ func numOfMatchingPathComponents(pth string, matchComponents []string) int {
|
|||
}
|
||||
|
||||
func getPathComponents(path string) []string {
|
||||
// make sure to add docker.io/ prefix to the path
|
||||
named, err := reference.ParseNamed(path)
|
||||
if err == nil {
|
||||
path = named.FullName()
|
||||
}
|
||||
return strings.Split(path, "/")
|
||||
}
|
||||
|
||||
|
|
|
@ -8,11 +8,10 @@ import (
|
|||
"github.com/docker/distribution"
|
||||
"github.com/docker/distribution/context"
|
||||
"github.com/docker/distribution/manifest/schema2"
|
||||
distreference "github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/distribution/metadata"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/docker/docker/pkg/progress"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/opencontainers/go-digest"
|
||||
)
|
||||
|
||||
|
@ -43,8 +42,8 @@ func TestGetRepositoryMountCandidates(t *testing.T) {
|
|||
name: "one item matching",
|
||||
targetRepo: "busybox",
|
||||
maxCandidates: -1,
|
||||
metadata: []metadata.V2Metadata{taggedMetadata("hash", "1", "hello-world")},
|
||||
candidates: []metadata.V2Metadata{taggedMetadata("hash", "1", "hello-world")},
|
||||
metadata: []metadata.V2Metadata{taggedMetadata("hash", "1", "docker.io/library/hello-world")},
|
||||
candidates: []metadata.V2Metadata{taggedMetadata("hash", "1", "docker.io/library/hello-world")},
|
||||
},
|
||||
{
|
||||
name: "allow missing SourceRepository",
|
||||
|
@ -63,13 +62,13 @@ func TestGetRepositoryMountCandidates(t *testing.T) {
|
|||
maxCandidates: -1,
|
||||
metadata: []metadata.V2Metadata{
|
||||
{Digest: digest.Digest("1"), SourceRepository: "docker.io/user/foo"},
|
||||
{Digest: digest.Digest("3"), SourceRepository: "user/bar"},
|
||||
{Digest: digest.Digest("2"), SourceRepository: "app"},
|
||||
{Digest: digest.Digest("3"), SourceRepository: "docker.io/user/bar"},
|
||||
{Digest: digest.Digest("2"), SourceRepository: "docker.io/library/app"},
|
||||
},
|
||||
candidates: []metadata.V2Metadata{
|
||||
{Digest: digest.Digest("3"), SourceRepository: "user/bar"},
|
||||
{Digest: digest.Digest("3"), SourceRepository: "docker.io/user/bar"},
|
||||
{Digest: digest.Digest("1"), SourceRepository: "docker.io/user/foo"},
|
||||
{Digest: digest.Digest("2"), SourceRepository: "app"},
|
||||
{Digest: digest.Digest("2"), SourceRepository: "docker.io/library/app"},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -78,10 +77,10 @@ func TestGetRepositoryMountCandidates(t *testing.T) {
|
|||
targetRepo: "127.0.0.1/foo/bar",
|
||||
maxCandidates: -1,
|
||||
metadata: []metadata.V2Metadata{
|
||||
taggedMetadata("hash", "1", "hello-world"),
|
||||
taggedMetadata("hash", "1", "docker.io/library/hello-world"),
|
||||
taggedMetadata("efgh", "2", "127.0.0.1/hello-world"),
|
||||
taggedMetadata("abcd", "3", "busybox"),
|
||||
taggedMetadata("hash", "4", "busybox"),
|
||||
taggedMetadata("abcd", "3", "docker.io/library/busybox"),
|
||||
taggedMetadata("hash", "4", "docker.io/library/busybox"),
|
||||
taggedMetadata("hash", "5", "127.0.0.1/foo"),
|
||||
taggedMetadata("hash", "6", "127.0.0.1/bar"),
|
||||
taggedMetadata("efgh", "7", "127.0.0.1/foo/bar"),
|
||||
|
@ -105,23 +104,25 @@ func TestGetRepositoryMountCandidates(t *testing.T) {
|
|||
targetRepo: "user/app",
|
||||
maxCandidates: 3,
|
||||
metadata: []metadata.V2Metadata{
|
||||
taggedMetadata("abcd", "1", "user/app1"),
|
||||
taggedMetadata("abcd", "2", "user/app/base"),
|
||||
taggedMetadata("hash", "3", "user/app"),
|
||||
taggedMetadata("abcd", "1", "docker.io/user/app1"),
|
||||
taggedMetadata("abcd", "2", "docker.io/user/app/base"),
|
||||
taggedMetadata("hash", "3", "docker.io/user/app"),
|
||||
taggedMetadata("abcd", "4", "127.0.0.1/user/app"),
|
||||
taggedMetadata("hash", "5", "user/foo"),
|
||||
taggedMetadata("hash", "6", "app/bar"),
|
||||
taggedMetadata("hash", "5", "docker.io/user/foo"),
|
||||
taggedMetadata("hash", "6", "docker.io/app/bar"),
|
||||
},
|
||||
candidates: []metadata.V2Metadata{
|
||||
// first by matching hash
|
||||
taggedMetadata("abcd", "2", "user/app/base"),
|
||||
taggedMetadata("abcd", "1", "user/app1"),
|
||||
taggedMetadata("abcd", "2", "docker.io/user/app/base"),
|
||||
taggedMetadata("abcd", "1", "docker.io/user/app1"),
|
||||
// then by longest matching prefix
|
||||
taggedMetadata("hash", "3", "user/app"),
|
||||
// "docker.io/usr/app" is excluded since candidates must
|
||||
// be from a different repository
|
||||
taggedMetadata("hash", "5", "docker.io/user/foo"),
|
||||
},
|
||||
},
|
||||
} {
|
||||
repoInfo, err := reference.ParseNamed(tc.targetRepo)
|
||||
repoInfo, err := reference.ParseNormalizedNamed(tc.targetRepo)
|
||||
if err != nil {
|
||||
t.Fatalf("[%s] failed to parse reference name: %v", tc.name, err)
|
||||
}
|
||||
|
@ -204,10 +205,13 @@ func TestLayerAlreadyExists(t *testing.T) {
|
|||
{Digest: digest.Digest("apple"), SourceRepository: "docker.io/library/hello-world"},
|
||||
{Digest: digest.Digest("orange"), SourceRepository: "docker.io/busybox/subapp"},
|
||||
{Digest: digest.Digest("pear"), SourceRepository: "docker.io/busybox"},
|
||||
{Digest: digest.Digest("plum"), SourceRepository: "busybox"},
|
||||
{Digest: digest.Digest("plum"), SourceRepository: "docker.io/library/busybox"},
|
||||
{Digest: digest.Digest("banana"), SourceRepository: "127.0.0.1/busybox"},
|
||||
},
|
||||
expectedRequests: []string{"plum", "pear", "apple", "orange", "banana"},
|
||||
expectedRequests: []string{"plum", "apple", "pear", "orange", "banana"},
|
||||
expectedRemovals: []metadata.V2Metadata{
|
||||
{Digest: digest.Digest("plum"), SourceRepository: "docker.io/library/busybox"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "find existing blob",
|
||||
|
@ -374,7 +378,7 @@ func TestLayerAlreadyExists(t *testing.T) {
|
|||
},
|
||||
},
|
||||
} {
|
||||
repoInfo, err := reference.ParseNamed(tc.targetRepo)
|
||||
repoInfo, err := reference.ParseNormalizedNamed(tc.targetRepo)
|
||||
if err != nil {
|
||||
t.Fatalf("[%s] failed to parse reference name: %v", tc.name, err)
|
||||
}
|
||||
|
@ -476,7 +480,7 @@ type mockRepo struct {
|
|||
|
||||
var _ distribution.Repository = &mockRepo{}
|
||||
|
||||
func (m *mockRepo) Named() distreference.Named {
|
||||
func (m *mockRepo) Named() reference.Named {
|
||||
m.t.Fatalf("Named() not implemented")
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
|
||||
"github.com/docker/distribution"
|
||||
"github.com/docker/distribution/manifest/schema2"
|
||||
distreference "github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/registry/client"
|
||||
"github.com/docker/distribution/registry/client/auth"
|
||||
"github.com/docker/distribution/registry/client/transport"
|
||||
|
@ -55,10 +55,10 @@ func init() {
|
|||
// providing timeout settings and authentication support, and also verifies the
|
||||
// remote API version.
|
||||
func NewV2Repository(ctx context.Context, repoInfo *registry.RepositoryInfo, endpoint registry.APIEndpoint, metaHeaders http.Header, authConfig *types.AuthConfig, actions ...string) (repo distribution.Repository, foundVersion bool, err error) {
|
||||
repoName := repoInfo.FullName()
|
||||
repoName := repoInfo.Name.Name()
|
||||
// If endpoint does not support CanonicalName, use the RemoteName instead
|
||||
if endpoint.TrimHostname {
|
||||
repoName = repoInfo.RemoteName()
|
||||
repoName = reference.Path(repoInfo.Name)
|
||||
}
|
||||
|
||||
direct := &net.Dialer{
|
||||
|
@ -122,7 +122,7 @@ func NewV2Repository(ctx context.Context, repoInfo *registry.RepositoryInfo, end
|
|||
}
|
||||
tr := transport.NewTransport(base, modifiers...)
|
||||
|
||||
repoNameRef, err := distreference.ParseNamed(repoName)
|
||||
repoNameRef, err := reference.WithName(repoName)
|
||||
if err != nil {
|
||||
return nil, foundVersion, fallbackError{
|
||||
err: err,
|
||||
|
|
|
@ -12,11 +12,11 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
registrytypes "github.com/docker/docker/api/types/registry"
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/docker/docker/registry"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
@ -61,9 +61,9 @@ func testTokenPassThru(t *testing.T, ts *httptest.Server) {
|
|||
TrimHostname: false,
|
||||
TLSConfig: nil,
|
||||
}
|
||||
n, _ := reference.ParseNamed("testremotename")
|
||||
n, _ := reference.ParseNormalizedNamed("testremotename")
|
||||
repoInfo := ®istry.RepositoryInfo{
|
||||
Named: n,
|
||||
Name: n,
|
||||
Index: ®istrytypes.IndexInfo{
|
||||
Name: "testrepo",
|
||||
Mirrors: nil,
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/image/v1"
|
||||
"github.com/docker/docker/layer"
|
||||
|
@ -21,7 +22,6 @@ import (
|
|||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/docker/pkg/symlink"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/opencontainers/go-digest"
|
||||
)
|
||||
|
||||
|
@ -117,7 +117,7 @@ func (l *tarexporter) Load(inTar io.ReadCloser, outStream io.Writer, quiet bool)
|
|||
|
||||
imageRefCount = 0
|
||||
for _, repoTag := range m.RepoTags {
|
||||
named, err := reference.ParseNamed(repoTag)
|
||||
named, err := reference.ParseNormalizedNamed(repoTag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -126,7 +126,7 @@ func (l *tarexporter) Load(inTar io.ReadCloser, outStream io.Writer, quiet bool)
|
|||
return fmt.Errorf("invalid tag %q", repoTag)
|
||||
}
|
||||
l.setLoadedTag(ref, imgID.Digest(), outStream)
|
||||
outStream.Write([]byte(fmt.Sprintf("Loaded image: %s\n", ref)))
|
||||
outStream.Write([]byte(fmt.Sprintf("Loaded image: %s\n", reference.FamiliarString(ref))))
|
||||
imageRefCount++
|
||||
}
|
||||
|
||||
|
@ -201,7 +201,7 @@ func (l *tarexporter) loadLayer(filename string, rootFS image.RootFS, id string,
|
|||
|
||||
func (l *tarexporter) setLoadedTag(ref reference.NamedTagged, imgID digest.Digest, outStream io.Writer) error {
|
||||
if prevID, err := l.rs.Get(ref); err == nil && prevID != imgID {
|
||||
fmt.Fprintf(outStream, "The image %s already exists, renaming the old one with ID %s to empty string\n", ref.String(), string(prevID)) // todo: this message is wrong in case of multiple tags
|
||||
fmt.Fprintf(outStream, "The image %s already exists, renaming the old one with ID %s to empty string\n", reference.FamiliarString(ref), string(prevID)) // todo: this message is wrong in case of multiple tags
|
||||
}
|
||||
|
||||
if err := l.rs.AddTag(ref, imgID, true); err != nil {
|
||||
|
@ -249,7 +249,7 @@ func (l *tarexporter) legacyLoad(tmpDir string, outStream io.Writer, progressOut
|
|||
if !ok {
|
||||
return fmt.Errorf("invalid target ID: %v", oldID)
|
||||
}
|
||||
named, err := reference.WithName(name)
|
||||
named, err := reference.ParseNormalizedNamed(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -10,12 +10,12 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/docker/distribution"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/image/v1"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
@ -51,16 +51,12 @@ func (l *tarexporter) parseNames(names []string) (map[image.ID]*imageDescriptor,
|
|||
}
|
||||
|
||||
if ref != nil {
|
||||
var tagged reference.NamedTagged
|
||||
if _, ok := ref.(reference.Canonical); ok {
|
||||
return
|
||||
}
|
||||
var ok bool
|
||||
if tagged, ok = ref.(reference.NamedTagged); !ok {
|
||||
var err error
|
||||
if tagged, err = reference.WithTag(ref, reference.DefaultTag); err != nil {
|
||||
return
|
||||
}
|
||||
tagged, ok := reference.TagNameOnly(ref).(reference.NamedTagged)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
for _, t := range imgDescr[id].refs {
|
||||
|
@ -73,19 +69,26 @@ func (l *tarexporter) parseNames(names []string) (map[image.ID]*imageDescriptor,
|
|||
}
|
||||
|
||||
for _, name := range names {
|
||||
id, ref, err := reference.ParseIDOrReference(name)
|
||||
ref, err := reference.ParseAnyReference(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if id != "" {
|
||||
_, err := l.is.Get(image.IDFromDigest(id))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
namedRef, ok := ref.(reference.Named)
|
||||
if !ok {
|
||||
// Check if digest ID reference
|
||||
if digested, ok := ref.(reference.Digested); ok {
|
||||
id := image.IDFromDigest(digested.Digest())
|
||||
_, err := l.is.Get(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
addAssoc(id, nil)
|
||||
continue
|
||||
}
|
||||
addAssoc(image.IDFromDigest(id), nil)
|
||||
continue
|
||||
return nil, errors.Errorf("invalid reference: %v", name)
|
||||
}
|
||||
if ref.Name() == string(digest.Canonical) {
|
||||
|
||||
if reference.FamiliarName(namedRef) == string(digest.Canonical) {
|
||||
imgID, err := l.is.Search(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -93,8 +96,8 @@ func (l *tarexporter) parseNames(names []string) (map[image.ID]*imageDescriptor,
|
|||
addAssoc(imgID, nil)
|
||||
continue
|
||||
}
|
||||
if reference.IsNameOnly(ref) {
|
||||
assocs := l.rs.ReferencesByName(ref)
|
||||
if reference.IsNameOnly(namedRef) {
|
||||
assocs := l.rs.ReferencesByName(namedRef)
|
||||
for _, assoc := range assocs {
|
||||
addAssoc(image.IDFromDigest(assoc.ID), assoc.Ref)
|
||||
}
|
||||
|
@ -107,11 +110,11 @@ func (l *tarexporter) parseNames(names []string) (map[image.ID]*imageDescriptor,
|
|||
}
|
||||
continue
|
||||
}
|
||||
id, err = l.rs.Get(ref)
|
||||
id, err := l.rs.Get(namedRef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
addAssoc(image.IDFromDigest(id), ref)
|
||||
addAssoc(image.IDFromDigest(id), namedRef)
|
||||
|
||||
}
|
||||
return imgDescr, nil
|
||||
|
@ -144,11 +147,12 @@ func (s *saveSession) save(outStream io.Writer) error {
|
|||
var layers []string
|
||||
|
||||
for _, ref := range imageDescr.refs {
|
||||
if _, ok := reposLegacy[ref.Name()]; !ok {
|
||||
reposLegacy[ref.Name()] = make(map[string]string)
|
||||
familiarName := reference.FamiliarName(ref)
|
||||
if _, ok := reposLegacy[familiarName]; !ok {
|
||||
reposLegacy[familiarName] = make(map[string]string)
|
||||
}
|
||||
reposLegacy[ref.Name()][ref.Tag()] = imageDescr.layers[len(imageDescr.layers)-1]
|
||||
repoTags = append(repoTags, ref.String())
|
||||
reposLegacy[familiarName][ref.Tag()] = imageDescr.layers[len(imageDescr.layers)-1]
|
||||
repoTags = append(repoTags, reference.FamiliarString(ref))
|
||||
}
|
||||
|
||||
for _, l := range imageDescr.layers {
|
||||
|
|
|
@ -4,7 +4,7 @@ import (
|
|||
"github.com/docker/distribution"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/docker/docker/reference"
|
||||
refstore "github.com/docker/docker/reference"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -26,7 +26,7 @@ type manifestItem struct {
|
|||
type tarexporter struct {
|
||||
is image.Store
|
||||
ls layer.Store
|
||||
rs reference.Store
|
||||
rs refstore.Store
|
||||
loggerImgEvent LogImageEvent
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,7 @@ type LogImageEvent interface {
|
|||
}
|
||||
|
||||
// NewTarExporter returns new Exporter for tar packages
|
||||
func NewTarExporter(is image.Store, ls layer.Store, rs reference.Store, loggerImgEvent LogImageEvent) image.Exporter {
|
||||
func NewTarExporter(is image.Store, ls layer.Store, rs refstore.Store, loggerImgEvent LogImageEvent) image.Exporter {
|
||||
return &tarexporter{
|
||||
is: is,
|
||||
ls: ls,
|
||||
|
|
|
@ -335,7 +335,7 @@ func (s *DockerSuite) TestImagesFormat(c *check.C) {
|
|||
expected := []string{"myimage", "myimage"}
|
||||
var names []string
|
||||
names = append(names, lines...)
|
||||
c.Assert(expected, checker.DeepEquals, names, check.Commentf("Expected array with truncated names: %v, got: %v", expected, names))
|
||||
c.Assert(names, checker.DeepEquals, expected, check.Commentf("Expected array with truncated names: %v, got: %v", expected, names))
|
||||
}
|
||||
|
||||
// ImagesDefaultFormatAndQuiet
|
||||
|
|
|
@ -14,12 +14,13 @@ import (
|
|||
"encoding/json"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/distribution/metadata"
|
||||
"github.com/docker/docker/image"
|
||||
imagev1 "github.com/docker/docker/image/v1"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/reference"
|
||||
refstore "github.com/docker/docker/reference"
|
||||
"github.com/opencontainers/go-digest"
|
||||
)
|
||||
|
||||
|
@ -56,7 +57,7 @@ var (
|
|||
|
||||
// Migrate takes an old graph directory and transforms the metadata into the
|
||||
// new format.
|
||||
func Migrate(root, driverName string, ls layer.Store, is image.Store, rs reference.Store, ms metadata.Store) error {
|
||||
func Migrate(root, driverName string, ls layer.Store, is image.Store, rs refstore.Store, ms metadata.Store) error {
|
||||
graphDir := filepath.Join(root, graphDirName)
|
||||
if _, err := os.Lstat(graphDir); os.IsNotExist(err) {
|
||||
return nil
|
||||
|
@ -322,11 +323,15 @@ func migrateRefs(root, driverName string, rs refAdder, mappings map[string]image
|
|||
for name, repo := range repos.Repositories {
|
||||
for tag, id := range repo {
|
||||
if strongID, exists := mappings[id]; exists {
|
||||
ref, err := reference.WithName(name)
|
||||
ref, err := reference.ParseNormalizedNamed(name)
|
||||
if err != nil {
|
||||
logrus.Errorf("migrate tags: invalid name %q, %q", name, err)
|
||||
continue
|
||||
}
|
||||
if !reference.IsNameOnly(ref) {
|
||||
logrus.Errorf("migrate tags: invalid name %q, unexpected tag or digest", name)
|
||||
continue
|
||||
}
|
||||
if dgst, err := digest.Parse(tag); err == nil {
|
||||
canonical, err := reference.WithDigest(reference.TrimNamed(ref), dgst)
|
||||
if err != nil {
|
||||
|
@ -334,7 +339,7 @@ func migrateRefs(root, driverName string, rs refAdder, mappings map[string]image
|
|||
continue
|
||||
}
|
||||
if err := rs.AddDigest(canonical, strongID.Digest(), false); err != nil {
|
||||
logrus.Errorf("can't migrate digest %q for %q, err: %q", ref.String(), strongID, err)
|
||||
logrus.Errorf("can't migrate digest %q for %q, err: %q", reference.FamiliarString(ref), strongID, err)
|
||||
}
|
||||
} else {
|
||||
tagRef, err := reference.WithTag(ref, tag)
|
||||
|
@ -343,7 +348,7 @@ func migrateRefs(root, driverName string, rs refAdder, mappings map[string]image
|
|||
continue
|
||||
}
|
||||
if err := rs.AddTag(tagRef, strongID.Digest(), false); err != nil {
|
||||
logrus.Errorf("can't migrate tag %q for %q, err: %q", ref.String(), strongID, err)
|
||||
logrus.Errorf("can't migrate tag %q for %q, err: %q", reference.FamiliarString(ref), strongID, err)
|
||||
}
|
||||
}
|
||||
logrus.Infof("migrated tag %s:%s to point to %s", name, tag, strongID)
|
||||
|
|
|
@ -13,10 +13,10 @@ import (
|
|||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/distribution/metadata"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/opencontainers/go-digest"
|
||||
)
|
||||
|
||||
|
@ -40,9 +40,9 @@ func TestMigrateRefs(t *testing.T) {
|
|||
}
|
||||
|
||||
expected := map[string]string{
|
||||
"busybox:latest": "sha256:fcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9",
|
||||
"busybox@sha256:16a2a52884c2a9481ed267c2d46483eac7693b813a63132368ab098a71303f8a": "sha256:fcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9",
|
||||
"registry:2": "sha256:2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae",
|
||||
"docker.io/library/busybox:latest": "sha256:fcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9",
|
||||
"docker.io/library/busybox@sha256:16a2a52884c2a9481ed267c2d46483eac7693b813a63132368ab098a71303f8a": "sha256:fcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9",
|
||||
"docker.io/library/registry:2": "sha256:2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae",
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(expected, ta.refs) {
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution/manifest/schema2"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/distribution"
|
||||
|
@ -30,7 +31,7 @@ import (
|
|||
"github.com/docker/docker/pkg/pools"
|
||||
"github.com/docker/docker/pkg/progress"
|
||||
"github.com/docker/docker/plugin/v2"
|
||||
"github.com/docker/docker/reference"
|
||||
refstore "github.com/docker/docker/reference"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/net/context"
|
||||
|
@ -232,11 +233,11 @@ func (pm *Manager) Upgrade(ctx context.Context, ref reference.Named, name string
|
|||
defer pm.muGC.RUnlock()
|
||||
|
||||
// revalidate because Pull is public
|
||||
nameref, err := reference.ParseNamed(name)
|
||||
nameref, err := reference.ParseNormalizedNamed(name)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to parse %q", name)
|
||||
}
|
||||
name = reference.WithDefaultTag(nameref).String()
|
||||
name = reference.FamiliarString(reference.TagNameOnly(nameref))
|
||||
|
||||
tmpRootFSDir, err := ioutil.TempDir(pm.tmpDir(), ".rootfs")
|
||||
defer os.RemoveAll(tmpRootFSDir)
|
||||
|
@ -277,11 +278,11 @@ func (pm *Manager) Pull(ctx context.Context, ref reference.Named, name string, m
|
|||
defer pm.muGC.RUnlock()
|
||||
|
||||
// revalidate because Pull is public
|
||||
nameref, err := reference.ParseNamed(name)
|
||||
nameref, err := reference.ParseNormalizedNamed(name)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to parse %q", name)
|
||||
}
|
||||
name = reference.WithDefaultTag(nameref).String()
|
||||
name = reference.FamiliarString(reference.TagNameOnly(nameref))
|
||||
|
||||
if err := pm.config.Store.validateName(name); err != nil {
|
||||
return err
|
||||
|
@ -370,7 +371,7 @@ func (pm *Manager) Push(ctx context.Context, name string, metaHeader http.Header
|
|||
return err
|
||||
}
|
||||
|
||||
ref, err := reference.ParseNamed(p.Name())
|
||||
ref, err := reference.ParseNormalizedNamed(p.Name())
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "plugin has invalid name %v for push", p.Name())
|
||||
}
|
||||
|
@ -448,8 +449,8 @@ func (r *pluginReference) References(id digest.Digest) []reference.Named {
|
|||
return []reference.Named{r.name}
|
||||
}
|
||||
|
||||
func (r *pluginReference) ReferencesByName(ref reference.Named) []reference.Association {
|
||||
return []reference.Association{
|
||||
func (r *pluginReference) ReferencesByName(ref reference.Named) []refstore.Association {
|
||||
return []refstore.Association{
|
||||
{
|
||||
Ref: r.name,
|
||||
ID: r.pluginID,
|
||||
|
@ -459,7 +460,7 @@ func (r *pluginReference) ReferencesByName(ref reference.Named) []reference.Asso
|
|||
|
||||
func (r *pluginReference) Get(ref reference.Named) (digest.Digest, error) {
|
||||
if r.name.String() != ref.String() {
|
||||
return digest.Digest(""), reference.ErrDoesNotExist
|
||||
return digest.Digest(""), refstore.ErrDoesNotExist
|
||||
}
|
||||
return r.pluginID, nil
|
||||
}
|
||||
|
@ -664,15 +665,14 @@ func (pm *Manager) CreateFromContext(ctx context.Context, tarCtx io.ReadCloser,
|
|||
pm.muGC.RLock()
|
||||
defer pm.muGC.RUnlock()
|
||||
|
||||
ref, err := reference.ParseNamed(options.RepoName)
|
||||
ref, err := reference.ParseNormalizedNamed(options.RepoName)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to parse reference %v", options.RepoName)
|
||||
}
|
||||
if _, ok := ref.(reference.Canonical); ok {
|
||||
return errors.Errorf("canonical references are not permitted")
|
||||
}
|
||||
taggedRef := reference.WithDefaultTag(ref)
|
||||
name := taggedRef.String()
|
||||
name := reference.FamiliarString(reference.TagNameOnly(ref))
|
||||
|
||||
if err := pm.config.Store.validateName(name); err != nil { // fast check, real check is in createPlugin()
|
||||
return err
|
||||
|
@ -754,7 +754,7 @@ func (pm *Manager) CreateFromContext(ctx context.Context, tarCtx io.ReadCloser,
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.PluginObj.PluginReference = taggedRef.String()
|
||||
p.PluginObj.PluginReference = name
|
||||
|
||||
pm.config.LogPluginEvent(p.PluginObj.ID, name, "create")
|
||||
|
||||
|
|
|
@ -7,9 +7,9 @@ import (
|
|||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/reference"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
|
|
|
@ -5,10 +5,10 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/pkg/plugingetter"
|
||||
"github.com/docker/docker/pkg/plugins"
|
||||
"github.com/docker/docker/plugin/v2"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
|
@ -230,19 +230,19 @@ func (ps *Store) resolvePluginID(idOrName string) (string, error) {
|
|||
return idOrName, nil
|
||||
}
|
||||
|
||||
ref, err := reference.ParseNamed(idOrName)
|
||||
ref, err := reference.ParseNormalizedNamed(idOrName)
|
||||
if err != nil {
|
||||
return "", errors.WithStack(ErrNotFound(idOrName))
|
||||
}
|
||||
if _, ok := ref.(reference.Canonical); ok {
|
||||
logrus.Warnf("canonical references cannot be resolved: %v", ref.String())
|
||||
logrus.Warnf("canonical references cannot be resolved: %v", reference.FamiliarString(ref))
|
||||
return "", errors.WithStack(ErrNotFound(idOrName))
|
||||
}
|
||||
|
||||
fullRef := reference.WithDefaultTag(ref)
|
||||
ref = reference.TagNameOnly(ref)
|
||||
|
||||
for _, p := range ps.plugins {
|
||||
if p.PluginObj.Name == fullRef.String() {
|
||||
if p.PluginObj.Name == reference.FamiliarString(ref) {
|
||||
return p.PluginObj.ID, nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,194 +0,0 @@
|
|||
package reference
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
distreference "github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultTag defines the default tag used when performing images related actions and no tag or digest is specified
|
||||
DefaultTag = "latest"
|
||||
// DefaultHostname is the default built-in hostname
|
||||
DefaultHostname = "docker.io"
|
||||
// LegacyDefaultHostname is automatically converted to DefaultHostname
|
||||
LegacyDefaultHostname = "index.docker.io"
|
||||
// DefaultRepoPrefix is the prefix used for default repositories in default host
|
||||
DefaultRepoPrefix = "library/"
|
||||
)
|
||||
|
||||
// Named is an object with a full name
|
||||
type Named interface {
|
||||
// Name returns normalized repository name, like "ubuntu".
|
||||
Name() string
|
||||
// String returns full reference, like "ubuntu@sha256:abcdef..."
|
||||
String() string
|
||||
// FullName returns full repository name with hostname, like "docker.io/library/ubuntu"
|
||||
FullName() string
|
||||
// Hostname returns hostname for the reference, like "docker.io"
|
||||
Hostname() string
|
||||
// RemoteName returns the repository component of the full name, like "library/ubuntu"
|
||||
RemoteName() string
|
||||
}
|
||||
|
||||
// NamedTagged is an object including a name and tag.
|
||||
type NamedTagged interface {
|
||||
Named
|
||||
Tag() string
|
||||
}
|
||||
|
||||
// Canonical reference is an object with a fully unique
|
||||
// name including a name with hostname and digest
|
||||
type Canonical interface {
|
||||
Named
|
||||
Digest() digest.Digest
|
||||
}
|
||||
|
||||
// ParseNamed parses s and returns a syntactically valid reference implementing
|
||||
// the Named interface. The reference must have a name, otherwise an error is
|
||||
// returned.
|
||||
// If an error was encountered it is returned, along with a nil Reference.
|
||||
func ParseNamed(s string) (Named, error) {
|
||||
named, err := distreference.ParseNormalizedNamed(s)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to parse reference %q", s)
|
||||
}
|
||||
if err := validateName(distreference.FamiliarName(named)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Ensure returned reference cannot have tag and digest
|
||||
if canonical, isCanonical := named.(distreference.Canonical); isCanonical {
|
||||
r, err := distreference.WithDigest(distreference.TrimNamed(named), canonical.Digest())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &canonicalRef{namedRef{r}}, nil
|
||||
}
|
||||
if tagged, isTagged := named.(distreference.NamedTagged); isTagged {
|
||||
r, err := distreference.WithTag(distreference.TrimNamed(named), tagged.Tag())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &taggedRef{namedRef{r}}, nil
|
||||
}
|
||||
|
||||
return &namedRef{named}, nil
|
||||
}
|
||||
|
||||
// TrimNamed removes any tag or digest from the named reference
|
||||
func TrimNamed(ref Named) Named {
|
||||
return &namedRef{distreference.TrimNamed(ref)}
|
||||
}
|
||||
|
||||
// WithName returns a named object representing the given string. If the input
|
||||
// is invalid ErrReferenceInvalidFormat will be returned.
|
||||
func WithName(name string) (Named, error) {
|
||||
r, err := distreference.ParseNormalizedNamed(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := validateName(distreference.FamiliarName(r)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !distreference.IsNameOnly(r) {
|
||||
return nil, distreference.ErrReferenceInvalidFormat
|
||||
}
|
||||
return &namedRef{r}, nil
|
||||
}
|
||||
|
||||
// WithTag combines the name from "name" and the tag from "tag" to form a
|
||||
// reference incorporating both the name and the tag.
|
||||
func WithTag(name Named, tag string) (NamedTagged, error) {
|
||||
r, err := distreference.WithTag(name, tag)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &taggedRef{namedRef{r}}, nil
|
||||
}
|
||||
|
||||
// WithDigest combines the name from "name" and the digest from "digest" to form
|
||||
// a reference incorporating both the name and the digest.
|
||||
func WithDigest(name Named, digest digest.Digest) (Canonical, error) {
|
||||
r, err := distreference.WithDigest(name, digest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &canonicalRef{namedRef{r}}, nil
|
||||
}
|
||||
|
||||
type namedRef struct {
|
||||
distreference.Named
|
||||
}
|
||||
type taggedRef struct {
|
||||
namedRef
|
||||
}
|
||||
type canonicalRef struct {
|
||||
namedRef
|
||||
}
|
||||
|
||||
func (r *namedRef) Name() string {
|
||||
return distreference.FamiliarName(r.Named)
|
||||
}
|
||||
|
||||
func (r *namedRef) String() string {
|
||||
return distreference.FamiliarString(r.Named)
|
||||
}
|
||||
|
||||
func (r *namedRef) FullName() string {
|
||||
return r.Named.Name()
|
||||
}
|
||||
func (r *namedRef) Hostname() string {
|
||||
return distreference.Domain(r.Named)
|
||||
}
|
||||
func (r *namedRef) RemoteName() string {
|
||||
return distreference.Path(r.Named)
|
||||
}
|
||||
func (r *taggedRef) Tag() string {
|
||||
return r.namedRef.Named.(distreference.NamedTagged).Tag()
|
||||
}
|
||||
func (r *canonicalRef) Digest() digest.Digest {
|
||||
return r.namedRef.Named.(distreference.Canonical).Digest()
|
||||
}
|
||||
|
||||
// WithDefaultTag adds a default tag to a reference if it only has a repo name.
|
||||
func WithDefaultTag(ref Named) Named {
|
||||
if IsNameOnly(ref) {
|
||||
ref, _ = WithTag(ref, DefaultTag)
|
||||
}
|
||||
return ref
|
||||
}
|
||||
|
||||
// IsNameOnly returns true if reference only contains a repo name.
|
||||
func IsNameOnly(ref Named) bool {
|
||||
if _, ok := ref.(NamedTagged); ok {
|
||||
return false
|
||||
}
|
||||
if _, ok := ref.(Canonical); ok {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// ParseIDOrReference parses string for an image ID or a reference. ID can be
|
||||
// without a default prefix.
|
||||
func ParseIDOrReference(idOrRef string) (digest.Digest, Named, error) {
|
||||
if err := stringid.ValidateID(idOrRef); err == nil {
|
||||
idOrRef = "sha256:" + idOrRef
|
||||
}
|
||||
if dgst, err := digest.Parse(idOrRef); err == nil {
|
||||
return dgst, nil, nil
|
||||
}
|
||||
ref, err := ParseNamed(idOrRef)
|
||||
return "", ref, err
|
||||
}
|
||||
|
||||
func validateName(name string) error {
|
||||
if err := stringid.ValidateID(name); err == nil {
|
||||
return fmt.Errorf("Invalid repository name (%s), cannot specify 64-byte hexadecimal strings", name)
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -1,275 +0,0 @@
|
|||
package reference
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/opencontainers/go-digest"
|
||||
)
|
||||
|
||||
func TestValidateReferenceName(t *testing.T) {
|
||||
validRepoNames := []string{
|
||||
"docker/docker",
|
||||
"library/debian",
|
||||
"debian",
|
||||
"docker.io/docker/docker",
|
||||
"docker.io/library/debian",
|
||||
"docker.io/debian",
|
||||
"index.docker.io/docker/docker",
|
||||
"index.docker.io/library/debian",
|
||||
"index.docker.io/debian",
|
||||
"127.0.0.1:5000/docker/docker",
|
||||
"127.0.0.1:5000/library/debian",
|
||||
"127.0.0.1:5000/debian",
|
||||
"thisisthesongthatneverendsitgoesonandonandonthisisthesongthatnev",
|
||||
}
|
||||
invalidRepoNames := []string{
|
||||
"https://github.com/docker/docker",
|
||||
"docker/Docker",
|
||||
"-docker",
|
||||
"-docker/docker",
|
||||
"-docker.io/docker/docker",
|
||||
"docker///docker",
|
||||
"docker.io/docker/Docker",
|
||||
"docker.io/docker///docker",
|
||||
"1a3f5e7d9c1b3a5f7e9d1c3b5a7f9e1d3c5b7a9f1e3d5d7c9b1a3f5e7d9c1b3a",
|
||||
"docker.io/1a3f5e7d9c1b3a5f7e9d1c3b5a7f9e1d3c5b7a9f1e3d5d7c9b1a3f5e7d9c1b3a",
|
||||
}
|
||||
|
||||
for _, name := range invalidRepoNames {
|
||||
_, err := ParseNamed(name)
|
||||
if err == nil {
|
||||
t.Fatalf("Expected invalid repo name for %q", name)
|
||||
}
|
||||
}
|
||||
|
||||
for _, name := range validRepoNames {
|
||||
_, err := ParseNamed(name)
|
||||
if err != nil {
|
||||
t.Fatalf("Error parsing repo name %s, got: %q", name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateRemoteName(t *testing.T) {
|
||||
validRepositoryNames := []string{
|
||||
// Sanity check.
|
||||
"docker/docker",
|
||||
|
||||
// Allow 64-character non-hexadecimal names (hexadecimal names are forbidden).
|
||||
"thisisthesongthatneverendsitgoesonandonandonthisisthesongthatnev",
|
||||
|
||||
// Allow embedded hyphens.
|
||||
"docker-rules/docker",
|
||||
|
||||
// Allow multiple hyphens as well.
|
||||
"docker---rules/docker",
|
||||
|
||||
//Username doc and image name docker being tested.
|
||||
"doc/docker",
|
||||
|
||||
// single character names are now allowed.
|
||||
"d/docker",
|
||||
"jess/t",
|
||||
|
||||
// Consecutive underscores.
|
||||
"dock__er/docker",
|
||||
}
|
||||
for _, repositoryName := range validRepositoryNames {
|
||||
_, err := ParseNamed(repositoryName)
|
||||
if err != nil {
|
||||
t.Errorf("Repository name should be valid: %v. Error: %v", repositoryName, err)
|
||||
}
|
||||
}
|
||||
|
||||
invalidRepositoryNames := []string{
|
||||
// Disallow capital letters.
|
||||
"docker/Docker",
|
||||
|
||||
// Only allow one slash.
|
||||
"docker///docker",
|
||||
|
||||
// Disallow 64-character hexadecimal.
|
||||
"1a3f5e7d9c1b3a5f7e9d1c3b5a7f9e1d3c5b7a9f1e3d5d7c9b1a3f5e7d9c1b3a",
|
||||
|
||||
// Disallow leading and trailing hyphens in namespace.
|
||||
"-docker/docker",
|
||||
"docker-/docker",
|
||||
"-docker-/docker",
|
||||
|
||||
// Don't allow underscores everywhere (as opposed to hyphens).
|
||||
"____/____",
|
||||
|
||||
"_docker/_docker",
|
||||
|
||||
// Disallow consecutive periods.
|
||||
"dock..er/docker",
|
||||
"dock_.er/docker",
|
||||
"dock-.er/docker",
|
||||
|
||||
// No repository.
|
||||
"docker/",
|
||||
|
||||
//namespace too long
|
||||
"this_is_not_a_valid_namespace_because_its_lenth_is_greater_than_255_this_is_not_a_valid_namespace_because_its_lenth_is_greater_than_255_this_is_not_a_valid_namespace_because_its_lenth_is_greater_than_255_this_is_not_a_valid_namespace_because_its_lenth_is_greater_than_255/docker",
|
||||
}
|
||||
for _, repositoryName := range invalidRepositoryNames {
|
||||
if _, err := ParseNamed(repositoryName); err == nil {
|
||||
t.Errorf("Repository name should be invalid: %v", repositoryName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseRepositoryInfo(t *testing.T) {
|
||||
type tcase struct {
|
||||
RemoteName, NormalizedName, FullName, AmbiguousName, Hostname string
|
||||
}
|
||||
|
||||
tcases := []tcase{
|
||||
{
|
||||
RemoteName: "fooo/bar",
|
||||
NormalizedName: "fooo/bar",
|
||||
FullName: "docker.io/fooo/bar",
|
||||
AmbiguousName: "index.docker.io/fooo/bar",
|
||||
Hostname: "docker.io",
|
||||
},
|
||||
{
|
||||
RemoteName: "library/ubuntu",
|
||||
NormalizedName: "ubuntu",
|
||||
FullName: "docker.io/library/ubuntu",
|
||||
AmbiguousName: "library/ubuntu",
|
||||
Hostname: "docker.io",
|
||||
},
|
||||
{
|
||||
RemoteName: "nonlibrary/ubuntu",
|
||||
NormalizedName: "nonlibrary/ubuntu",
|
||||
FullName: "docker.io/nonlibrary/ubuntu",
|
||||
AmbiguousName: "",
|
||||
Hostname: "docker.io",
|
||||
},
|
||||
{
|
||||
RemoteName: "other/library",
|
||||
NormalizedName: "other/library",
|
||||
FullName: "docker.io/other/library",
|
||||
AmbiguousName: "",
|
||||
Hostname: "docker.io",
|
||||
},
|
||||
{
|
||||
RemoteName: "private/moonbase",
|
||||
NormalizedName: "127.0.0.1:8000/private/moonbase",
|
||||
FullName: "127.0.0.1:8000/private/moonbase",
|
||||
AmbiguousName: "",
|
||||
Hostname: "127.0.0.1:8000",
|
||||
},
|
||||
{
|
||||
RemoteName: "privatebase",
|
||||
NormalizedName: "127.0.0.1:8000/privatebase",
|
||||
FullName: "127.0.0.1:8000/privatebase",
|
||||
AmbiguousName: "",
|
||||
Hostname: "127.0.0.1:8000",
|
||||
},
|
||||
{
|
||||
RemoteName: "private/moonbase",
|
||||
NormalizedName: "example.com/private/moonbase",
|
||||
FullName: "example.com/private/moonbase",
|
||||
AmbiguousName: "",
|
||||
Hostname: "example.com",
|
||||
},
|
||||
{
|
||||
RemoteName: "privatebase",
|
||||
NormalizedName: "example.com/privatebase",
|
||||
FullName: "example.com/privatebase",
|
||||
AmbiguousName: "",
|
||||
Hostname: "example.com",
|
||||
},
|
||||
{
|
||||
RemoteName: "private/moonbase",
|
||||
NormalizedName: "example.com:8000/private/moonbase",
|
||||
FullName: "example.com:8000/private/moonbase",
|
||||
AmbiguousName: "",
|
||||
Hostname: "example.com:8000",
|
||||
},
|
||||
{
|
||||
RemoteName: "privatebasee",
|
||||
NormalizedName: "example.com:8000/privatebasee",
|
||||
FullName: "example.com:8000/privatebasee",
|
||||
AmbiguousName: "",
|
||||
Hostname: "example.com:8000",
|
||||
},
|
||||
{
|
||||
RemoteName: "library/ubuntu-12.04-base",
|
||||
NormalizedName: "ubuntu-12.04-base",
|
||||
FullName: "docker.io/library/ubuntu-12.04-base",
|
||||
AmbiguousName: "index.docker.io/library/ubuntu-12.04-base",
|
||||
Hostname: "docker.io",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tcase := range tcases {
|
||||
refStrings := []string{tcase.NormalizedName, tcase.FullName}
|
||||
if tcase.AmbiguousName != "" {
|
||||
refStrings = append(refStrings, tcase.AmbiguousName)
|
||||
}
|
||||
|
||||
var refs []Named
|
||||
for _, r := range refStrings {
|
||||
named, err := ParseNamed(r)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
refs = append(refs, named)
|
||||
named, err = WithName(r)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
refs = append(refs, named)
|
||||
}
|
||||
|
||||
for _, r := range refs {
|
||||
if expected, actual := tcase.NormalizedName, r.Name(); expected != actual {
|
||||
t.Fatalf("Invalid normalized reference for %q. Expected %q, got %q", r, expected, actual)
|
||||
}
|
||||
if expected, actual := tcase.FullName, r.FullName(); expected != actual {
|
||||
t.Fatalf("Invalid fullName for %q. Expected %q, got %q", r, expected, actual)
|
||||
}
|
||||
if expected, actual := tcase.Hostname, r.Hostname(); expected != actual {
|
||||
t.Fatalf("Invalid hostname for %q. Expected %q, got %q", r, expected, actual)
|
||||
}
|
||||
if expected, actual := tcase.RemoteName, r.RemoteName(); expected != actual {
|
||||
t.Fatalf("Invalid remoteName for %q. Expected %q, got %q", r, expected, actual)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseReferenceWithTagAndDigest(t *testing.T) {
|
||||
ref, err := ParseNamed("busybox:latest@sha256:86e0e091d0da6bde2456dbb48306f3956bbeb2eae1b5b9a43045843f69fe4aaa")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, isTagged := ref.(NamedTagged); isTagged {
|
||||
t.Fatalf("Reference from %q should not support tag", ref)
|
||||
}
|
||||
if _, isCanonical := ref.(Canonical); !isCanonical {
|
||||
t.Fatalf("Reference from %q should not support digest", ref)
|
||||
}
|
||||
if expected, actual := "busybox@sha256:86e0e091d0da6bde2456dbb48306f3956bbeb2eae1b5b9a43045843f69fe4aaa", ref.String(); actual != expected {
|
||||
t.Fatalf("Invalid parsed reference for %q: expected %q, got %q", ref, expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvalidReferenceComponents(t *testing.T) {
|
||||
if _, err := WithName("-foo"); err == nil {
|
||||
t.Fatal("Expected WithName to detect invalid name")
|
||||
}
|
||||
ref, err := WithName("busybox")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := WithTag(ref, "-foo"); err == nil {
|
||||
t.Fatal("Expected WithName to detect invalid tag")
|
||||
}
|
||||
if _, err := WithDigest(ref, digest.Digest("foo")); err == nil {
|
||||
t.Fatal("Expected WithName to detect invalid digest")
|
||||
}
|
||||
}
|
|
@ -9,6 +9,7 @@ import (
|
|||
"sort"
|
||||
"sync"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/opencontainers/go-digest"
|
||||
)
|
||||
|
@ -21,18 +22,18 @@ var (
|
|||
|
||||
// An Association is a tuple associating a reference with an image ID.
|
||||
type Association struct {
|
||||
Ref Named
|
||||
Ref reference.Named
|
||||
ID digest.Digest
|
||||
}
|
||||
|
||||
// Store provides the set of methods which can operate on a tag store.
|
||||
type Store interface {
|
||||
References(id digest.Digest) []Named
|
||||
ReferencesByName(ref Named) []Association
|
||||
AddTag(ref Named, id digest.Digest, force bool) error
|
||||
AddDigest(ref Canonical, id digest.Digest, force bool) error
|
||||
Delete(ref Named) (bool, error)
|
||||
Get(ref Named) (digest.Digest, error)
|
||||
References(id digest.Digest) []reference.Named
|
||||
ReferencesByName(ref reference.Named) []Association
|
||||
AddTag(ref reference.Named, id digest.Digest, force bool) error
|
||||
AddDigest(ref reference.Canonical, id digest.Digest, force bool) error
|
||||
Delete(ref reference.Named) (bool, error)
|
||||
Get(ref reference.Named) (digest.Digest, error)
|
||||
}
|
||||
|
||||
type store struct {
|
||||
|
@ -44,24 +45,28 @@ type store struct {
|
|||
Repositories map[string]repository
|
||||
// referencesByIDCache is a cache of references indexed by ID, to speed
|
||||
// up References.
|
||||
referencesByIDCache map[digest.Digest]map[string]Named
|
||||
referencesByIDCache map[digest.Digest]map[string]reference.Named
|
||||
}
|
||||
|
||||
// Repository maps tags to digests. The key is a stringified Reference,
|
||||
// including the repository name.
|
||||
type repository map[string]digest.Digest
|
||||
|
||||
type lexicalRefs []Named
|
||||
type lexicalRefs []reference.Named
|
||||
|
||||
func (a lexicalRefs) Len() int { return len(a) }
|
||||
func (a lexicalRefs) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
func (a lexicalRefs) Less(i, j int) bool { return a[i].String() < a[j].String() }
|
||||
func (a lexicalRefs) Len() int { return len(a) }
|
||||
func (a lexicalRefs) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
func (a lexicalRefs) Less(i, j int) bool {
|
||||
return a[i].String() < a[j].String()
|
||||
}
|
||||
|
||||
type lexicalAssociations []Association
|
||||
|
||||
func (a lexicalAssociations) Len() int { return len(a) }
|
||||
func (a lexicalAssociations) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
func (a lexicalAssociations) Less(i, j int) bool { return a[i].Ref.String() < a[j].Ref.String() }
|
||||
func (a lexicalAssociations) Len() int { return len(a) }
|
||||
func (a lexicalAssociations) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
func (a lexicalAssociations) Less(i, j int) bool {
|
||||
return a[i].Ref.String() < a[j].Ref.String()
|
||||
}
|
||||
|
||||
// NewReferenceStore creates a new reference store, tied to a file path where
|
||||
// the set of references are serialized in JSON format.
|
||||
|
@ -74,7 +79,7 @@ func NewReferenceStore(jsonPath string) (Store, error) {
|
|||
store := &store{
|
||||
jsonPath: abspath,
|
||||
Repositories: make(map[string]repository),
|
||||
referencesByIDCache: make(map[digest.Digest]map[string]Named),
|
||||
referencesByIDCache: make(map[digest.Digest]map[string]reference.Named),
|
||||
}
|
||||
// Load the json file if it exists, otherwise create it.
|
||||
if err := store.reload(); os.IsNotExist(err) {
|
||||
|
@ -89,43 +94,45 @@ func NewReferenceStore(jsonPath string) (Store, error) {
|
|||
|
||||
// AddTag adds a tag reference to the store. If force is set to true, existing
|
||||
// references can be overwritten. This only works for tags, not digests.
|
||||
func (store *store) AddTag(ref Named, id digest.Digest, force bool) error {
|
||||
if _, isCanonical := ref.(Canonical); isCanonical {
|
||||
func (store *store) AddTag(ref reference.Named, id digest.Digest, force bool) error {
|
||||
if _, isCanonical := ref.(reference.Canonical); isCanonical {
|
||||
return errors.New("refusing to create a tag with a digest reference")
|
||||
}
|
||||
return store.addReference(WithDefaultTag(ref), id, force)
|
||||
return store.addReference(reference.TagNameOnly(ref), id, force)
|
||||
}
|
||||
|
||||
// AddDigest adds a digest reference to the store.
|
||||
func (store *store) AddDigest(ref Canonical, id digest.Digest, force bool) error {
|
||||
func (store *store) AddDigest(ref reference.Canonical, id digest.Digest, force bool) error {
|
||||
return store.addReference(ref, id, force)
|
||||
}
|
||||
|
||||
func (store *store) addReference(ref Named, id digest.Digest, force bool) error {
|
||||
if ref.Name() == string(digest.Canonical) {
|
||||
func (store *store) addReference(ref reference.Named, id digest.Digest, force bool) error {
|
||||
refName := reference.FamiliarName(ref)
|
||||
refStr := reference.FamiliarString(ref)
|
||||
|
||||
if refName == string(digest.Canonical) {
|
||||
return errors.New("refusing to create an ambiguous tag using digest algorithm as name")
|
||||
}
|
||||
|
||||
store.mu.Lock()
|
||||
defer store.mu.Unlock()
|
||||
|
||||
repository, exists := store.Repositories[ref.Name()]
|
||||
repository, exists := store.Repositories[refName]
|
||||
if !exists || repository == nil {
|
||||
repository = make(map[string]digest.Digest)
|
||||
store.Repositories[ref.Name()] = repository
|
||||
store.Repositories[refName] = repository
|
||||
}
|
||||
|
||||
refStr := ref.String()
|
||||
oldID, exists := repository[refStr]
|
||||
|
||||
if exists {
|
||||
// force only works for tags
|
||||
if digested, isDigest := ref.(Canonical); isDigest {
|
||||
if digested, isDigest := ref.(reference.Canonical); isDigest {
|
||||
return fmt.Errorf("Cannot overwrite digest %s", digested.Digest().String())
|
||||
}
|
||||
|
||||
if !force {
|
||||
return fmt.Errorf("Conflict: Tag %s is already set to image %s, if you want to replace it, please use -f option", ref.String(), oldID.String())
|
||||
return fmt.Errorf("Conflict: Tag %s is already set to image %s, if you want to replace it, please use -f option", refStr, oldID.String())
|
||||
}
|
||||
|
||||
if store.referencesByIDCache[oldID] != nil {
|
||||
|
@ -138,7 +145,7 @@ func (store *store) addReference(ref Named, id digest.Digest, force bool) error
|
|||
|
||||
repository[refStr] = id
|
||||
if store.referencesByIDCache[id] == nil {
|
||||
store.referencesByIDCache[id] = make(map[string]Named)
|
||||
store.referencesByIDCache[id] = make(map[string]reference.Named)
|
||||
}
|
||||
store.referencesByIDCache[id][refStr] = ref
|
||||
|
||||
|
@ -147,24 +154,24 @@ func (store *store) addReference(ref Named, id digest.Digest, force bool) error
|
|||
|
||||
// Delete deletes a reference from the store. It returns true if a deletion
|
||||
// happened, or false otherwise.
|
||||
func (store *store) Delete(ref Named) (bool, error) {
|
||||
ref = WithDefaultTag(ref)
|
||||
func (store *store) Delete(ref reference.Named) (bool, error) {
|
||||
ref = reference.TagNameOnly(ref)
|
||||
|
||||
refName := reference.FamiliarName(ref)
|
||||
refStr := reference.FamiliarString(ref)
|
||||
|
||||
store.mu.Lock()
|
||||
defer store.mu.Unlock()
|
||||
|
||||
repoName := ref.Name()
|
||||
|
||||
repository, exists := store.Repositories[repoName]
|
||||
repository, exists := store.Repositories[refName]
|
||||
if !exists {
|
||||
return false, ErrDoesNotExist
|
||||
}
|
||||
|
||||
refStr := ref.String()
|
||||
if id, exists := repository[refStr]; exists {
|
||||
delete(repository, refStr)
|
||||
if len(repository) == 0 {
|
||||
delete(store.Repositories, repoName)
|
||||
delete(store.Repositories, refName)
|
||||
}
|
||||
if store.referencesByIDCache[id] != nil {
|
||||
delete(store.referencesByIDCache[id], refStr)
|
||||
|
@ -179,18 +186,34 @@ func (store *store) Delete(ref Named) (bool, error) {
|
|||
}
|
||||
|
||||
// Get retrieves an item from the store by reference
|
||||
func (store *store) Get(ref Named) (digest.Digest, error) {
|
||||
ref = WithDefaultTag(ref)
|
||||
func (store *store) Get(ref reference.Named) (digest.Digest, error) {
|
||||
if canonical, ok := ref.(reference.Canonical); ok {
|
||||
// If reference contains both tag and digest, only
|
||||
// lookup by digest as it takes precendent over
|
||||
// tag, until tag/digest combos are stored.
|
||||
if _, ok := ref.(reference.Tagged); ok {
|
||||
var err error
|
||||
ref, err = reference.WithDigest(reference.TrimNamed(canonical), canonical.Digest())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ref = reference.TagNameOnly(ref)
|
||||
}
|
||||
|
||||
refName := reference.FamiliarName(ref)
|
||||
refStr := reference.FamiliarString(ref)
|
||||
|
||||
store.mu.RLock()
|
||||
defer store.mu.RUnlock()
|
||||
|
||||
repository, exists := store.Repositories[ref.Name()]
|
||||
repository, exists := store.Repositories[refName]
|
||||
if !exists || repository == nil {
|
||||
return "", ErrDoesNotExist
|
||||
}
|
||||
|
||||
id, exists := repository[ref.String()]
|
||||
id, exists := repository[refStr]
|
||||
if !exists {
|
||||
return "", ErrDoesNotExist
|
||||
}
|
||||
|
@ -200,7 +223,7 @@ func (store *store) Get(ref Named) (digest.Digest, error) {
|
|||
|
||||
// References returns a slice of references to the given ID. The slice
|
||||
// will be nil if there are no references to this ID.
|
||||
func (store *store) References(id digest.Digest) []Named {
|
||||
func (store *store) References(id digest.Digest) []reference.Named {
|
||||
store.mu.RLock()
|
||||
defer store.mu.RUnlock()
|
||||
|
||||
|
@ -208,7 +231,7 @@ func (store *store) References(id digest.Digest) []Named {
|
|||
// 1) We must not return a mutable
|
||||
// 2) It would be ugly to expose the extraneous map keys to callers.
|
||||
|
||||
var references []Named
|
||||
var references []reference.Named
|
||||
for _, ref := range store.referencesByIDCache[id] {
|
||||
references = append(references, ref)
|
||||
}
|
||||
|
@ -221,18 +244,20 @@ func (store *store) References(id digest.Digest) []Named {
|
|||
// ReferencesByName returns the references for a given repository name.
|
||||
// If there are no references known for this repository name,
|
||||
// ReferencesByName returns nil.
|
||||
func (store *store) ReferencesByName(ref Named) []Association {
|
||||
func (store *store) ReferencesByName(ref reference.Named) []Association {
|
||||
refName := reference.FamiliarName(ref)
|
||||
|
||||
store.mu.RLock()
|
||||
defer store.mu.RUnlock()
|
||||
|
||||
repository, exists := store.Repositories[ref.Name()]
|
||||
repository, exists := store.Repositories[refName]
|
||||
if !exists {
|
||||
return nil
|
||||
}
|
||||
|
||||
var associations []Association
|
||||
for refStr, refID := range repository {
|
||||
ref, err := ParseNamed(refStr)
|
||||
ref, err := reference.ParseNormalizedNamed(refStr)
|
||||
if err != nil {
|
||||
// Should never happen
|
||||
return nil
|
||||
|
@ -270,13 +295,13 @@ func (store *store) reload() error {
|
|||
|
||||
for _, repository := range store.Repositories {
|
||||
for refStr, refID := range repository {
|
||||
ref, err := ParseNamed(refStr)
|
||||
ref, err := reference.ParseNormalizedNamed(refStr)
|
||||
if err != nil {
|
||||
// Should never happen
|
||||
continue
|
||||
}
|
||||
if store.referencesByIDCache[refID] == nil {
|
||||
store.referencesByIDCache[refID] = make(map[string]Named)
|
||||
store.referencesByIDCache[refID] = make(map[string]reference.Named)
|
||||
}
|
||||
store.referencesByIDCache[refID][refStr] = ref
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/opencontainers/go-digest"
|
||||
)
|
||||
|
||||
|
@ -45,7 +46,7 @@ func TestLoad(t *testing.T) {
|
|||
}
|
||||
|
||||
for refStr, expectedID := range saveLoadTestCases {
|
||||
ref, err := ParseNamed(refStr)
|
||||
ref, err := reference.ParseNormalizedNamed(refStr)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to parse reference: %v", err)
|
||||
}
|
||||
|
@ -74,11 +75,11 @@ func TestSave(t *testing.T) {
|
|||
}
|
||||
|
||||
for refStr, id := range saveLoadTestCases {
|
||||
ref, err := ParseNamed(refStr)
|
||||
ref, err := reference.ParseNormalizedNamed(refStr)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to parse reference: %v", err)
|
||||
}
|
||||
if canonical, ok := ref.(Canonical); ok {
|
||||
if canonical, ok := ref.(reference.Canonical); ok {
|
||||
err = store.AddDigest(canonical, id, false)
|
||||
if err != nil {
|
||||
t.Fatalf("could not add digest reference %s: %v", refStr, err)
|
||||
|
@ -120,7 +121,7 @@ func TestAddDeleteGet(t *testing.T) {
|
|||
testImageID3 := digest.Digest("sha256:9655aef5fd742a1b4e1b7b163aa9f1c76c186304bf39102283d80927c916ca9e")
|
||||
|
||||
// Try adding a reference with no tag or digest
|
||||
nameOnly, err := WithName("username/repo")
|
||||
nameOnly, err := reference.ParseNormalizedNamed("username/repo")
|
||||
if err != nil {
|
||||
t.Fatalf("could not parse reference: %v", err)
|
||||
}
|
||||
|
@ -129,7 +130,7 @@ func TestAddDeleteGet(t *testing.T) {
|
|||
}
|
||||
|
||||
// Add a few references
|
||||
ref1, err := ParseNamed("username/repo1:latest")
|
||||
ref1, err := reference.ParseNormalizedNamed("username/repo1:latest")
|
||||
if err != nil {
|
||||
t.Fatalf("could not parse reference: %v", err)
|
||||
}
|
||||
|
@ -137,7 +138,7 @@ func TestAddDeleteGet(t *testing.T) {
|
|||
t.Fatalf("error adding to store: %v", err)
|
||||
}
|
||||
|
||||
ref2, err := ParseNamed("username/repo1:old")
|
||||
ref2, err := reference.ParseNormalizedNamed("username/repo1:old")
|
||||
if err != nil {
|
||||
t.Fatalf("could not parse reference: %v", err)
|
||||
}
|
||||
|
@ -145,7 +146,7 @@ func TestAddDeleteGet(t *testing.T) {
|
|||
t.Fatalf("error adding to store: %v", err)
|
||||
}
|
||||
|
||||
ref3, err := ParseNamed("username/repo1:alias")
|
||||
ref3, err := reference.ParseNormalizedNamed("username/repo1:alias")
|
||||
if err != nil {
|
||||
t.Fatalf("could not parse reference: %v", err)
|
||||
}
|
||||
|
@ -153,7 +154,7 @@ func TestAddDeleteGet(t *testing.T) {
|
|||
t.Fatalf("error adding to store: %v", err)
|
||||
}
|
||||
|
||||
ref4, err := ParseNamed("username/repo2:latest")
|
||||
ref4, err := reference.ParseNormalizedNamed("username/repo2:latest")
|
||||
if err != nil {
|
||||
t.Fatalf("could not parse reference: %v", err)
|
||||
}
|
||||
|
@ -161,11 +162,11 @@ func TestAddDeleteGet(t *testing.T) {
|
|||
t.Fatalf("error adding to store: %v", err)
|
||||
}
|
||||
|
||||
ref5, err := ParseNamed("username/repo3@sha256:58153dfb11794fad694460162bf0cb0a4fa710cfa3f60979c177d920813e267c")
|
||||
ref5, err := reference.ParseNormalizedNamed("username/repo3@sha256:58153dfb11794fad694460162bf0cb0a4fa710cfa3f60979c177d920813e267c")
|
||||
if err != nil {
|
||||
t.Fatalf("could not parse reference: %v", err)
|
||||
}
|
||||
if err = store.AddDigest(ref5.(Canonical), testImageID2, false); err != nil {
|
||||
if err = store.AddDigest(ref5.(reference.Canonical), testImageID2, false); err != nil {
|
||||
t.Fatalf("error adding to store: %v", err)
|
||||
}
|
||||
|
||||
|
@ -228,7 +229,7 @@ func TestAddDeleteGet(t *testing.T) {
|
|||
}
|
||||
|
||||
// Get should return ErrDoesNotExist for a nonexistent repo
|
||||
nonExistRepo, err := ParseNamed("username/nonexistrepo:latest")
|
||||
nonExistRepo, err := reference.ParseNormalizedNamed("username/nonexistrepo:latest")
|
||||
if err != nil {
|
||||
t.Fatalf("could not parse reference: %v", err)
|
||||
}
|
||||
|
@ -237,7 +238,7 @@ func TestAddDeleteGet(t *testing.T) {
|
|||
}
|
||||
|
||||
// Get should return ErrDoesNotExist for a nonexistent tag
|
||||
nonExistTag, err := ParseNamed("username/repo1:nonexist")
|
||||
nonExistTag, err := reference.ParseNormalizedNamed("username/repo1:nonexist")
|
||||
if err != nil {
|
||||
t.Fatalf("could not parse reference: %v", err)
|
||||
}
|
||||
|
@ -263,7 +264,7 @@ func TestAddDeleteGet(t *testing.T) {
|
|||
}
|
||||
|
||||
// Check ReferencesByName
|
||||
repoName, err := WithName("username/repo1")
|
||||
repoName, err := reference.ParseNormalizedNamed("username/repo1")
|
||||
if err != nil {
|
||||
t.Fatalf("could not parse reference: %v", err)
|
||||
}
|
||||
|
@ -334,7 +335,7 @@ func TestInvalidTags(t *testing.T) {
|
|||
id := digest.Digest("sha256:470022b8af682154f57a2163d030eb369549549cba00edc69e1b99b46bb924d6")
|
||||
|
||||
// sha256 as repo name
|
||||
ref, err := ParseNamed("sha256:abc")
|
||||
ref, err := reference.ParseNormalizedNamed("sha256:abc")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -344,7 +345,7 @@ func TestInvalidTags(t *testing.T) {
|
|||
}
|
||||
|
||||
// setting digest as a tag
|
||||
ref, err = ParseNamed("registry@sha256:367eb40fd0330a7e464777121e39d2f5b3e8e23a1e159342e53ab05c9e4d94e6")
|
||||
ref, err = reference.ParseNormalizedNamed("registry@sha256:367eb40fd0330a7e464777121e39d2f5b3e8e23a1e159342e53ab05c9e4d94e6")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ import (
|
|||
"github.com/docker/distribution/reference"
|
||||
registrytypes "github.com/docker/docker/api/types/registry"
|
||||
"github.com/docker/docker/opts"
|
||||
forkedref "github.com/docker/docker/reference"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
@ -271,8 +270,9 @@ func ValidateMirror(val string) (string, error) {
|
|||
|
||||
// ValidateIndexName validates an index name.
|
||||
func ValidateIndexName(val string) (string, error) {
|
||||
if val == forkedref.LegacyDefaultHostname {
|
||||
val = forkedref.DefaultHostname
|
||||
// TODO: upstream this to check to reference package
|
||||
if val == "index.docker.io" {
|
||||
val = "docker.io"
|
||||
}
|
||||
if strings.HasPrefix(val, "-") || strings.HasSuffix(val, "-") {
|
||||
return "", fmt.Errorf("Invalid index name (%s). Cannot begin or end with a hyphen.", val)
|
||||
|
@ -328,13 +328,8 @@ func newRepositoryInfo(config *serviceConfig, name reference.Named) (*Repository
|
|||
}
|
||||
official := !strings.ContainsRune(reference.FamiliarName(name), '/')
|
||||
|
||||
// TODO: remove used of forked reference package
|
||||
nameref, err := forkedref.ParseNamed(name.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &RepositoryInfo{
|
||||
Named: nameref,
|
||||
Name: reference.TrimNamed(name),
|
||||
Index: index,
|
||||
Official: official,
|
||||
}, nil
|
||||
|
|
|
@ -17,8 +17,8 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
registrytypes "github.com/docker/docker/api/types/registry"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/gorilla/mux"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
|
|
|
@ -14,7 +14,6 @@ import (
|
|||
"github.com/docker/distribution/registry/client/transport"
|
||||
"github.com/docker/docker/api/types"
|
||||
registrytypes "github.com/docker/docker/api/types/registry"
|
||||
forkedref "github.com/docker/docker/reference"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -202,7 +201,7 @@ func TestGetRemoteImageLayer(t *testing.T) {
|
|||
|
||||
func TestGetRemoteTag(t *testing.T) {
|
||||
r := spawnTestRegistrySession(t)
|
||||
repoRef, err := forkedref.ParseNamed(REPO)
|
||||
repoRef, err := reference.ParseNormalizedNamed(REPO)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -212,7 +211,7 @@ func TestGetRemoteTag(t *testing.T) {
|
|||
}
|
||||
assertEqual(t, tag, imageID, "Expected tag test to map to "+imageID)
|
||||
|
||||
bazRef, err := forkedref.ParseNamed("foo42/baz")
|
||||
bazRef, err := reference.ParseNormalizedNamed("foo42/baz")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -224,7 +223,7 @@ func TestGetRemoteTag(t *testing.T) {
|
|||
|
||||
func TestGetRemoteTags(t *testing.T) {
|
||||
r := spawnTestRegistrySession(t)
|
||||
repoRef, err := forkedref.ParseNamed(REPO)
|
||||
repoRef, err := reference.ParseNormalizedNamed(REPO)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -236,7 +235,7 @@ func TestGetRemoteTags(t *testing.T) {
|
|||
assertEqual(t, tags["latest"], imageID, "Expected tag latest to map to "+imageID)
|
||||
assertEqual(t, tags["test"], imageID, "Expected tag test to map to "+imageID)
|
||||
|
||||
bazRef, err := forkedref.ParseNamed("foo42/baz")
|
||||
bazRef, err := reference.ParseNormalizedNamed("foo42/baz")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -253,7 +252,7 @@ func TestGetRepositoryData(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
host := "http://" + parsedURL.Host + "/v1/"
|
||||
repoRef, err := forkedref.ParseNamed(REPO)
|
||||
repoRef, err := reference.ParseNormalizedNamed(REPO)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -516,9 +515,9 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||
t.Error(err)
|
||||
} else {
|
||||
checkEqual(t, repoInfo.Index.Name, expectedRepoInfo.Index.Name, reposName)
|
||||
checkEqual(t, repoInfo.RemoteName(), expectedRepoInfo.RemoteName, reposName)
|
||||
checkEqual(t, repoInfo.Name(), expectedRepoInfo.LocalName, reposName)
|
||||
checkEqual(t, repoInfo.FullName(), expectedRepoInfo.CanonicalName, reposName)
|
||||
checkEqual(t, reference.Path(repoInfo.Name), expectedRepoInfo.RemoteName, reposName)
|
||||
checkEqual(t, reference.FamiliarName(repoInfo.Name), expectedRepoInfo.LocalName, reposName)
|
||||
checkEqual(t, repoInfo.Name.Name(), expectedRepoInfo.CanonicalName, reposName)
|
||||
checkEqual(t, repoInfo.Index.Official, expectedRepoInfo.Index.Official, reposName)
|
||||
checkEqual(t, repoInfo.Official, expectedRepoInfo.Official, reposName)
|
||||
}
|
||||
|
@ -689,7 +688,7 @@ func TestMirrorEndpointLookup(t *testing.T) {
|
|||
|
||||
func TestPushRegistryTag(t *testing.T) {
|
||||
r := spawnTestRegistrySession(t)
|
||||
repoRef, err := forkedref.ParseNamed(REPO)
|
||||
repoRef, err := reference.ParseNormalizedNamed(REPO)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -711,7 +710,7 @@ func TestPushImageJSONIndex(t *testing.T) {
|
|||
Checksum: "sha256:bea7bf2e4bacd479344b737328db47b18880d09096e6674165533aa994f5e9f2",
|
||||
},
|
||||
}
|
||||
repoRef, err := forkedref.ParseNamed(REPO)
|
||||
repoRef, err := reference.ParseNormalizedNamed(REPO)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/registry/api/errcode"
|
||||
"github.com/docker/docker/api/types"
|
||||
registrytypes "github.com/docker/docker/api/types/registry"
|
||||
|
@ -26,7 +27,6 @@ import (
|
|||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/docker/pkg/tarsum"
|
||||
"github.com/docker/docker/reference"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -324,7 +324,7 @@ func (r *Session) GetRemoteImageLayer(imgID, registry string, imgSize int64) (io
|
|||
// argument, and returns data from the first one that answers the query
|
||||
// successfully.
|
||||
func (r *Session) GetRemoteTag(registries []string, repositoryRef reference.Named, askedTag string) (string, error) {
|
||||
repository := repositoryRef.RemoteName()
|
||||
repository := reference.Path(repositoryRef)
|
||||
|
||||
if strings.Count(repository, "/") == 0 {
|
||||
// This will be removed once the registry supports auto-resolution on
|
||||
|
@ -362,7 +362,7 @@ func (r *Session) GetRemoteTag(registries []string, repositoryRef reference.Name
|
|||
// the first one that answers the query successfully. It returns a map with
|
||||
// tag names as the keys and image IDs as the values.
|
||||
func (r *Session) GetRemoteTags(registries []string, repositoryRef reference.Named) (map[string]string, error) {
|
||||
repository := repositoryRef.RemoteName()
|
||||
repository := reference.Path(repositoryRef)
|
||||
|
||||
if strings.Count(repository, "/") == 0 {
|
||||
// This will be removed once the registry supports auto-resolution on
|
||||
|
@ -416,7 +416,7 @@ func buildEndpointsList(headers []string, indexEp string) ([]string, error) {
|
|||
|
||||
// GetRepositoryData returns lists of images and endpoints for the repository
|
||||
func (r *Session) GetRepositoryData(name reference.Named) (*RepositoryData, error) {
|
||||
repositoryTarget := fmt.Sprintf("%srepositories/%s/images", r.indexEndpoint.String(), name.RemoteName())
|
||||
repositoryTarget := fmt.Sprintf("%srepositories/%s/images", r.indexEndpoint.String(), reference.Path(name))
|
||||
|
||||
logrus.Debugf("[registry] Calling GET %s", repositoryTarget)
|
||||
|
||||
|
@ -450,7 +450,7 @@ func (r *Session) GetRepositoryData(name reference.Named) (*RepositoryData, erro
|
|||
if err != nil {
|
||||
logrus.Debugf("Error reading response body: %s", err)
|
||||
}
|
||||
return nil, httputils.NewHTTPRequestError(fmt.Sprintf("Error: Status %d trying to pull repository %s: %q", res.StatusCode, name.RemoteName(), errBody), res)
|
||||
return nil, httputils.NewHTTPRequestError(fmt.Sprintf("Error: Status %d trying to pull repository %s: %q", res.StatusCode, reference.Path(name), errBody), res)
|
||||
}
|
||||
|
||||
var endpoints []string
|
||||
|
@ -605,7 +605,7 @@ func (r *Session) PushImageLayerRegistry(imgID string, layer io.Reader, registry
|
|||
func (r *Session) PushRegistryTag(remote reference.Named, revision, tag, registry string) error {
|
||||
// "jsonify" the string
|
||||
revision = "\"" + revision + "\""
|
||||
path := fmt.Sprintf("repositories/%s/tags/%s", remote.RemoteName(), tag)
|
||||
path := fmt.Sprintf("repositories/%s/tags/%s", reference.Path(remote), tag)
|
||||
|
||||
req, err := http.NewRequest("PUT", registry+path, strings.NewReader(revision))
|
||||
if err != nil {
|
||||
|
@ -619,7 +619,7 @@ func (r *Session) PushRegistryTag(remote reference.Named, revision, tag, registr
|
|||
}
|
||||
res.Body.Close()
|
||||
if res.StatusCode != 200 && res.StatusCode != 201 {
|
||||
return httputils.NewHTTPRequestError(fmt.Sprintf("Internal server error: %d trying to push tag %s on %s", res.StatusCode, tag, remote.RemoteName()), res)
|
||||
return httputils.NewHTTPRequestError(fmt.Sprintf("Internal server error: %d trying to push tag %s on %s", res.StatusCode, tag, reference.Path(remote)), res)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -645,7 +645,7 @@ func (r *Session) PushImageJSONIndex(remote reference.Named, imgList []*ImgData,
|
|||
if validate {
|
||||
suffix = "images"
|
||||
}
|
||||
u := fmt.Sprintf("%srepositories/%s/%s", r.indexEndpoint.String(), remote.RemoteName(), suffix)
|
||||
u := fmt.Sprintf("%srepositories/%s/%s", r.indexEndpoint.String(), reference.Path(remote), suffix)
|
||||
logrus.Debugf("[registry] PUT %s", u)
|
||||
logrus.Debugf("Image list pushed to index:\n%s", imgListJSON)
|
||||
headers := map[string][]string{
|
||||
|
@ -683,7 +683,7 @@ func (r *Session) PushImageJSONIndex(remote reference.Named, imgList []*ImgData,
|
|||
if err != nil {
|
||||
logrus.Debugf("Error reading response body: %s", err)
|
||||
}
|
||||
return nil, httputils.NewHTTPRequestError(fmt.Sprintf("Error: Status %d trying to push repository %s: %q", res.StatusCode, remote.RemoteName(), errBody), res)
|
||||
return nil, httputils.NewHTTPRequestError(fmt.Sprintf("Error: Status %d trying to push repository %s: %q", res.StatusCode, reference.Path(remote), errBody), res)
|
||||
}
|
||||
tokens = res.Header["X-Docker-Token"]
|
||||
logrus.Debugf("Auth token: %v", tokens)
|
||||
|
@ -701,7 +701,7 @@ func (r *Session) PushImageJSONIndex(remote reference.Named, imgList []*ImgData,
|
|||
if err != nil {
|
||||
logrus.Debugf("Error reading response body: %s", err)
|
||||
}
|
||||
return nil, httputils.NewHTTPRequestError(fmt.Sprintf("Error: Status %d trying to push checksums %s: %q", res.StatusCode, remote.RemoteName(), errBody), res)
|
||||
return nil, httputils.NewHTTPRequestError(fmt.Sprintf("Error: Status %d trying to push checksums %s: %q", res.StatusCode, reference.Path(remote), errBody), res)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package registry
|
||||
|
||||
import (
|
||||
"github.com/docker/distribution/reference"
|
||||
registrytypes "github.com/docker/docker/api/types/registry"
|
||||
"github.com/docker/docker/reference"
|
||||
)
|
||||
|
||||
// RepositoryData tracks the image list, list of endpoints for a repository
|
||||
|
@ -57,7 +57,7 @@ var apiVersions = map[APIVersion]string{
|
|||
|
||||
// RepositoryInfo describes a repository
|
||||
type RepositoryInfo struct {
|
||||
reference.Named
|
||||
Name reference.Named
|
||||
// Index points to registry information
|
||||
Index *registrytypes.IndexInfo
|
||||
// Official indicates whether the repository is considered official.
|
||||
|
|
Loading…
Reference in a new issue