mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Merge pull request #18586 from tonistiigi/tag-reference-squashed
Improve reference validation
This commit is contained in:
commit
dc81c25031
50 changed files with 847 additions and 826 deletions
|
@ -13,7 +13,6 @@ import (
|
|||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/builder/dockerignore"
|
||||
|
@ -29,8 +28,7 @@ import (
|
|||
"github.com/docker/docker/pkg/streamformatter"
|
||||
"github.com/docker/docker/pkg/ulimit"
|
||||
"github.com/docker/docker/pkg/urlutil"
|
||||
"github.com/docker/docker/registry"
|
||||
tagpkg "github.com/docker/docker/tag"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/docker/docker/utils"
|
||||
"github.com/docker/go-units"
|
||||
)
|
||||
|
@ -261,15 +259,11 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
|
|||
|
||||
// validateTag checks if the given image name can be resolved.
|
||||
func validateTag(rawRepo string) (string, error) {
|
||||
ref, err := reference.ParseNamed(rawRepo)
|
||||
_, err := reference.ParseNamed(rawRepo)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if err := registry.ValidateRepositoryName(ref); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return rawRepo, nil
|
||||
}
|
||||
|
||||
|
@ -482,7 +476,6 @@ func (td *trustedDockerfile) Close() error {
|
|||
// resolvedTag records the repository, tag, and resolved digest reference
|
||||
// from a Dockerfile rewrite.
|
||||
type resolvedTag struct {
|
||||
repoInfo *registry.RepositoryInfo
|
||||
digestRef reference.Canonical
|
||||
tagRef reference.NamedTagged
|
||||
}
|
||||
|
@ -529,35 +522,17 @@ func rewriteDockerfileFrom(dockerfileName string, translator func(reference.Name
|
|||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
digested := false
|
||||
switch ref.(type) {
|
||||
case reference.Tagged:
|
||||
case reference.Digested:
|
||||
digested = true
|
||||
default:
|
||||
ref, err = reference.WithTag(ref, tagpkg.DefaultTag)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
repoInfo, err := registry.ParseRepositoryInfo(ref)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("unable to parse repository info %q: %v", ref.String(), err)
|
||||
}
|
||||
|
||||
if !digested && isTrusted() {
|
||||
trustedRef, err := translator(ref.(reference.NamedTagged))
|
||||
ref = reference.WithDefaultTag(ref)
|
||||
if ref, ok := ref.(reference.NamedTagged); ok && isTrusted() {
|
||||
trustedRef, err := translator(ref)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
line = dockerfileFromLinePattern.ReplaceAllLiteralString(line, fmt.Sprintf("FROM %s", trustedRef.String()))
|
||||
resolvedTags = append(resolvedTags, &resolvedTag{
|
||||
repoInfo: repoInfo,
|
||||
digestRef: trustedRef,
|
||||
tagRef: ref.(reference.NamedTagged),
|
||||
tagRef: ref,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,12 +5,11 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
Cli "github.com/docker/docker/cli"
|
||||
"github.com/docker/docker/opts"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
"github.com/docker/docker/registry"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/docker/docker/runconfig"
|
||||
)
|
||||
|
||||
|
@ -44,16 +43,13 @@ func (cli *DockerCli) CmdCommit(args ...string) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := registry.ValidateRepositoryName(ref); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
repositoryName = ref.Name()
|
||||
|
||||
switch x := ref.(type) {
|
||||
case reference.Digested:
|
||||
case reference.Canonical:
|
||||
return errors.New("cannot commit to digest reference")
|
||||
case reference.Tagged:
|
||||
case reference.NamedTagged:
|
||||
tag = x.Tag()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,14 +5,13 @@ import (
|
|||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/client/lib"
|
||||
"github.com/docker/docker/api/types"
|
||||
Cli "github.com/docker/docker/cli"
|
||||
"github.com/docker/docker/pkg/jsonmessage"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/docker/docker/registry"
|
||||
"github.com/docker/docker/runconfig"
|
||||
tagpkg "github.com/docker/docker/tag"
|
||||
)
|
||||
|
||||
func (cli *DockerCli) pullImage(image string) error {
|
||||
|
@ -26,14 +25,11 @@ func (cli *DockerCli) pullImageCustomOut(image string, out io.Writer) error {
|
|||
}
|
||||
|
||||
var tag string
|
||||
switch x := ref.(type) {
|
||||
case reference.Digested:
|
||||
switch x := reference.WithDefaultTag(ref).(type) {
|
||||
case reference.Canonical:
|
||||
tag = x.Digest().String()
|
||||
case reference.Tagged:
|
||||
case reference.NamedTagged:
|
||||
tag = x.Tag()
|
||||
default:
|
||||
// pull only the image tagged 'latest' if no tag was specified
|
||||
tag = tagpkg.DefaultTag
|
||||
}
|
||||
|
||||
// Resolve the Repository name from fqn to RepositoryInfo
|
||||
|
@ -98,24 +94,13 @@ func (cli *DockerCli) createContainer(config *runconfig.Config, hostConfig *runc
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
isDigested := false
|
||||
switch ref.(type) {
|
||||
case reference.Tagged:
|
||||
case reference.Digested:
|
||||
isDigested = true
|
||||
default:
|
||||
ref, err = reference.WithTag(ref, tagpkg.DefaultTag)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
ref = reference.WithDefaultTag(ref)
|
||||
|
||||
var trustedRef reference.Canonical
|
||||
|
||||
if isTrusted() && !isDigested {
|
||||
if ref, ok := ref.(reference.NamedTagged); ok && isTrusted() {
|
||||
var err error
|
||||
trustedRef, err = cli.trustedReference(ref.(reference.NamedTagged))
|
||||
trustedRef, err = cli.trustedReference(ref)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -133,8 +118,8 @@ func (cli *DockerCli) createContainer(config *runconfig.Config, hostConfig *runc
|
|||
if err = cli.pullImageCustomOut(config.Image, cli.err); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if trustedRef != nil && !isDigested {
|
||||
if err := cli.tagTrusted(trustedRef, ref.(reference.NamedTagged)); err != nil {
|
||||
if ref, ok := ref.(reference.NamedTagged); ok && trustedRef != nil {
|
||||
if err := cli.tagTrusted(trustedRef, ref); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,13 +6,13 @@ import (
|
|||
"text/tabwriter"
|
||||
"time"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
Cli "github.com/docker/docker/cli"
|
||||
"github.com/docker/docker/opts"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/docker/go-units"
|
||||
)
|
||||
|
||||
|
@ -98,9 +98,9 @@ func (cli *DockerCli) CmdImages(args ...string) error {
|
|||
repo = ref.Name()
|
||||
|
||||
switch x := ref.(type) {
|
||||
case reference.Digested:
|
||||
case reference.Canonical:
|
||||
digest = x.Digest().String()
|
||||
case reference.Tagged:
|
||||
case reference.NamedTagged:
|
||||
tag = x.Tag()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,14 +5,13 @@ import (
|
|||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
Cli "github.com/docker/docker/cli"
|
||||
"github.com/docker/docker/opts"
|
||||
"github.com/docker/docker/pkg/jsonmessage"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
"github.com/docker/docker/pkg/urlutil"
|
||||
"github.com/docker/docker/registry"
|
||||
"github.com/docker/docker/reference"
|
||||
)
|
||||
|
||||
// CmdImport creates an empty filesystem image, imports the contents of the tarball into the image, and optionally tags the image.
|
||||
|
@ -45,11 +44,7 @@ func (cli *DockerCli) CmdImport(args ...string) error {
|
|||
|
||||
if repository != "" {
|
||||
//Check if the given image name can be resolved
|
||||
ref, err := reference.ParseNamed(repository)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := registry.ValidateRepositoryName(ref); err != nil {
|
||||
if _, err := reference.ParseNamed(repository); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -64,7 +59,6 @@ func (cli *DockerCli) CmdImport(args ...string) error {
|
|||
}
|
||||
defer file.Close()
|
||||
in = file
|
||||
|
||||
}
|
||||
|
||||
options := types.ImageImportOptions{
|
||||
|
|
|
@ -4,18 +4,15 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/client/lib"
|
||||
"github.com/docker/docker/api/types"
|
||||
Cli "github.com/docker/docker/cli"
|
||||
"github.com/docker/docker/pkg/jsonmessage"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/docker/docker/registry"
|
||||
tagpkg "github.com/docker/docker/tag"
|
||||
)
|
||||
|
||||
var errTagCantBeUsed = errors.New("tag can't be used with --all-tags/-a")
|
||||
|
||||
// CmdPull pulls an image or a repository from the registry.
|
||||
//
|
||||
// Usage: docker pull [OPTIONS] IMAGENAME[:TAG|@DIGEST]
|
||||
|
@ -32,28 +29,21 @@ func (cli *DockerCli) CmdPull(args ...string) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if *allTags && !reference.IsNameOnly(distributionRef) {
|
||||
return errors.New("tag can't be used with --all-tags/-a")
|
||||
}
|
||||
|
||||
if !*allTags && reference.IsNameOnly(distributionRef) {
|
||||
distributionRef = reference.WithDefaultTag(distributionRef)
|
||||
fmt.Fprintf(cli.out, "Using default tag: %s\n", reference.DefaultTag)
|
||||
}
|
||||
|
||||
var tag string
|
||||
switch x := distributionRef.(type) {
|
||||
case reference.Digested:
|
||||
if *allTags {
|
||||
return errTagCantBeUsed
|
||||
}
|
||||
case reference.Canonical:
|
||||
tag = x.Digest().String()
|
||||
case reference.Tagged:
|
||||
if *allTags {
|
||||
return errTagCantBeUsed
|
||||
}
|
||||
case reference.NamedTagged:
|
||||
tag = x.Tag()
|
||||
default:
|
||||
if !*allTags {
|
||||
tag = tagpkg.DefaultTag
|
||||
distributionRef, err = reference.WithTag(distributionRef, tag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(cli.out, "Using default tag: %s\n", tag)
|
||||
}
|
||||
}
|
||||
|
||||
ref := registry.ParseReference(tag)
|
||||
|
|
|
@ -4,12 +4,12 @@ import (
|
|||
"errors"
|
||||
"io"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/client/lib"
|
||||
"github.com/docker/docker/api/types"
|
||||
Cli "github.com/docker/docker/cli"
|
||||
"github.com/docker/docker/pkg/jsonmessage"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/docker/docker/registry"
|
||||
)
|
||||
|
||||
|
@ -30,9 +30,9 @@ func (cli *DockerCli) CmdPush(args ...string) error {
|
|||
|
||||
var tag string
|
||||
switch x := ref.(type) {
|
||||
case reference.Digested:
|
||||
case reference.Canonical:
|
||||
return errors.New("cannot push a digest reference")
|
||||
case reference.Tagged:
|
||||
case reference.NamedTagged:
|
||||
tag = x.Tag()
|
||||
}
|
||||
|
||||
|
|
|
@ -3,11 +3,10 @@ package client
|
|||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
Cli "github.com/docker/docker/cli"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
"github.com/docker/docker/registry"
|
||||
"github.com/docker/docker/reference"
|
||||
)
|
||||
|
||||
// CmdTag tags an image into a repository.
|
||||
|
@ -25,22 +24,15 @@ func (cli *DockerCli) CmdTag(args ...string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
_, isDigested := ref.(reference.Digested)
|
||||
if isDigested {
|
||||
if _, isCanonical := ref.(reference.Canonical); isCanonical {
|
||||
return errors.New("refusing to create a tag with a digest reference")
|
||||
}
|
||||
|
||||
tag := ""
|
||||
tagged, isTagged := ref.(reference.Tagged)
|
||||
if isTagged {
|
||||
var tag string
|
||||
if tagged, isTagged := ref.(reference.NamedTagged); isTagged {
|
||||
tag = tagged.Tag()
|
||||
}
|
||||
|
||||
//Check if the given image name can be resolved
|
||||
if err := registry.ValidateRepositoryName(ref); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
options := types.ImageTagOptions{
|
||||
ImageID: cmd.Arg(0),
|
||||
RepositoryName: ref.Name(),
|
||||
|
|
|
@ -19,7 +19,6 @@ import (
|
|||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution/digest"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/registry/client/auth"
|
||||
"github.com/docker/distribution/registry/client/transport"
|
||||
"github.com/docker/docker/api/client/lib"
|
||||
|
@ -30,6 +29,7 @@ import (
|
|||
"github.com/docker/docker/pkg/ioutils"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
"github.com/docker/docker/pkg/tlsconfig"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/docker/docker/registry"
|
||||
"github.com/docker/notary/client"
|
||||
"github.com/docker/notary/passphrase"
|
||||
|
@ -167,12 +167,12 @@ func (cli *DockerCli) getNotaryRepository(repoInfo *registry.RepositoryInfo, aut
|
|||
}
|
||||
|
||||
creds := simpleCredentialStore{auth: authConfig}
|
||||
tokenHandler := auth.NewTokenHandler(authTransport, creds, repoInfo.CanonicalName.Name(), "push", "pull")
|
||||
tokenHandler := auth.NewTokenHandler(authTransport, creds, repoInfo.FullName(), "push", "pull")
|
||||
basicHandler := auth.NewBasicHandler(creds)
|
||||
modifiers = append(modifiers, transport.RequestModifier(auth.NewAuthorizer(challengeManager, tokenHandler, basicHandler)))
|
||||
tr := transport.NewTransport(base, modifiers...)
|
||||
|
||||
return client.NewNotaryRepository(cli.trustDirectory(), repoInfo.CanonicalName.Name(), server, tr, cli.getPassphraseRetriever())
|
||||
return client.NewNotaryRepository(cli.trustDirectory(), repoInfo.FullName(), server, tr, cli.getPassphraseRetriever())
|
||||
}
|
||||
|
||||
func convertTarget(t client.Target) (target, error) {
|
||||
|
@ -298,7 +298,7 @@ func (cli *DockerCli) trustedPull(repoInfo *registry.RepositoryInfo, ref registr
|
|||
for _, tgt := range targets {
|
||||
t, err := convertTarget(*tgt)
|
||||
if err != nil {
|
||||
fmt.Fprintf(cli.out, "Skipping target for %q\n", repoInfo.LocalName)
|
||||
fmt.Fprintf(cli.out, "Skipping target for %q\n", repoInfo.Name())
|
||||
continue
|
||||
}
|
||||
refs = append(refs, t)
|
||||
|
@ -321,22 +321,24 @@ func (cli *DockerCli) trustedPull(repoInfo *registry.RepositoryInfo, ref registr
|
|||
if displayTag != "" {
|
||||
displayTag = ":" + displayTag
|
||||
}
|
||||
fmt.Fprintf(cli.out, "Pull (%d of %d): %s%s@%s\n", i+1, len(refs), repoInfo.LocalName, displayTag, r.digest)
|
||||
fmt.Fprintf(cli.out, "Pull (%d of %d): %s%s@%s\n", i+1, len(refs), repoInfo.Name(), displayTag, r.digest)
|
||||
|
||||
if err := cli.imagePullPrivileged(authConfig, repoInfo.LocalName.Name(), r.digest.String(), requestPrivilege); err != nil {
|
||||
if err := cli.imagePullPrivileged(authConfig, repoInfo.Name(), r.digest.String(), requestPrivilege); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If reference is not trusted, tag by trusted reference
|
||||
if !r.reference.HasDigest() {
|
||||
tagged, err := reference.WithTag(repoInfo.LocalName, r.reference.String())
|
||||
tagged, err := reference.WithTag(repoInfo, r.reference.String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
trustedRef, err := reference.WithDigest(repoInfo, r.digest)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
trustedRef, err := reference.WithDigest(repoInfo.LocalName, r.digest)
|
||||
if err := cli.tagTrusted(trustedRef, tagged); err != nil {
|
||||
return err
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -384,7 +386,7 @@ func targetStream(in io.Writer) (io.WriteCloser, <-chan []target) {
|
|||
func (cli *DockerCli) trustedPush(repoInfo *registry.RepositoryInfo, tag string, authConfig types.AuthConfig, requestPrivilege lib.RequestPrivilegeFunc) error {
|
||||
streamOut, targetChan := targetStream(cli.out)
|
||||
|
||||
reqError := cli.imagePushPrivileged(authConfig, repoInfo.LocalName.Name(), tag, streamOut, requestPrivilege)
|
||||
reqError := cli.imagePushPrivileged(authConfig, repoInfo.Name(), tag, streamOut, requestPrivilege)
|
||||
|
||||
// Close stream channel to finish target parsing
|
||||
if err := streamOut.Close(); err != nil {
|
||||
|
@ -455,7 +457,7 @@ func (cli *DockerCli) trustedPush(repoInfo *registry.RepositoryInfo, tag string,
|
|||
if err := repo.Initialize(rootKeyID); err != nil {
|
||||
return notaryError(err)
|
||||
}
|
||||
fmt.Fprintf(cli.out, "Finished initializing %q\n", repoInfo.CanonicalName)
|
||||
fmt.Fprintf(cli.out, "Finished initializing %q\n", repoInfo.FullName())
|
||||
|
||||
return notaryError(repo.Publish())
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ import (
|
|||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution/digest"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/builder"
|
||||
|
@ -25,8 +24,8 @@ import (
|
|||
"github.com/docker/docker/pkg/progress"
|
||||
"github.com/docker/docker/pkg/streamformatter"
|
||||
"github.com/docker/docker/pkg/ulimit"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/docker/docker/runconfig"
|
||||
tagpkg "github.com/docker/docker/tag"
|
||||
"github.com/docker/docker/utils"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
@ -155,8 +154,7 @@ func (s *router) postImagesCreate(ctx context.Context, w http.ResponseWriter, r
|
|||
return err
|
||||
}
|
||||
|
||||
switch newRef.(type) {
|
||||
case reference.Digested:
|
||||
if _, isCanonical := newRef.(reference.Canonical); isCanonical {
|
||||
return errors.New("cannot import digest reference")
|
||||
}
|
||||
|
||||
|
@ -497,13 +495,10 @@ func sanitizeRepoAndTags(names []string) ([]reference.Named, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ref = reference.WithDefaultTag(ref)
|
||||
|
||||
if _, isDigested := ref.(reference.Digested); isDigested {
|
||||
return nil, errors.New("build tag cannot be a digest")
|
||||
}
|
||||
|
||||
if _, isTagged := ref.(reference.Tagged); !isTagged {
|
||||
ref, err = reference.WithTag(ref, tagpkg.DefaultTag)
|
||||
if _, isCanonical := ref.(reference.Canonical); isCanonical {
|
||||
return nil, errors.New("build tag cannot contain a digest")
|
||||
}
|
||||
|
||||
nameWithTag := ref.String()
|
||||
|
|
|
@ -7,7 +7,6 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/container"
|
||||
"github.com/docker/docker/dockerversion"
|
||||
|
@ -15,6 +14,7 @@ import (
|
|||
"github.com/docker/docker/layer"
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/docker/docker/runconfig"
|
||||
)
|
||||
|
||||
|
|
|
@ -19,7 +19,6 @@ import (
|
|||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution/digest"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
|
@ -58,9 +57,9 @@ import (
|
|||
"github.com/docker/docker/pkg/sysinfo"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
"github.com/docker/docker/pkg/truncindex"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/docker/docker/registry"
|
||||
"github.com/docker/docker/runconfig"
|
||||
"github.com/docker/docker/tag"
|
||||
"github.com/docker/docker/utils"
|
||||
volumedrivers "github.com/docker/docker/volume/drivers"
|
||||
"github.com/docker/docker/volume/local"
|
||||
|
@ -138,7 +137,7 @@ type Daemon struct {
|
|||
repository string
|
||||
containers *contStore
|
||||
execCommands *exec.Store
|
||||
tagStore tag.Store
|
||||
referenceStore reference.Store
|
||||
downloadManager *xfer.LayerDownloadManager
|
||||
uploadManager *xfer.LayerUploadManager
|
||||
distributionMetadataStore dmetadata.Store
|
||||
|
@ -789,16 +788,16 @@ func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemo
|
|||
|
||||
eventsService := events.New()
|
||||
|
||||
tagStore, err := tag.NewTagStore(filepath.Join(imageRoot, "repositories.json"))
|
||||
referenceStore, err := reference.NewReferenceStore(filepath.Join(imageRoot, "repositories.json"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Couldn't create Tag store repositories: %s", err)
|
||||
}
|
||||
|
||||
if err := restoreCustomImage(d.driver, d.imageStore, d.layerStore, tagStore); err != nil {
|
||||
if err := restoreCustomImage(d.driver, d.imageStore, d.layerStore, referenceStore); err != nil {
|
||||
return nil, fmt.Errorf("Couldn't restore custom images: %s", err)
|
||||
}
|
||||
|
||||
if err := v1.Migrate(config.Root, d.driver.String(), d.layerStore, d.imageStore, tagStore, distributionMetadataStore); err != nil {
|
||||
if err := v1.Migrate(config.Root, d.driver.String(), d.layerStore, d.imageStore, referenceStore, distributionMetadataStore); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -848,7 +847,7 @@ func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemo
|
|||
d.repository = daemonRepo
|
||||
d.containers = &contStore{s: make(map[string]*container.Container)}
|
||||
d.execCommands = exec.NewStore()
|
||||
d.tagStore = tagStore
|
||||
d.referenceStore = referenceStore
|
||||
d.distributionMetadataStore = distributionMetadataStore
|
||||
d.trustKey = trustKey
|
||||
d.idIndex = truncindex.NewTruncIndex([]string{})
|
||||
|
@ -1044,8 +1043,7 @@ func (daemon *Daemon) TagImage(newTag reference.Named, imageName string) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newTag = registry.NormalizeLocalReference(newTag)
|
||||
if err := daemon.tagStore.AddTag(newTag, imageID, true); err != nil {
|
||||
if err := daemon.referenceStore.AddTag(newTag, imageID, true); err != nil {
|
||||
return err
|
||||
}
|
||||
daemon.EventsService.Log("tag", newTag.String(), "")
|
||||
|
@ -1091,7 +1089,7 @@ func (daemon *Daemon) PullImage(ref reference.Named, metaHeaders map[string][]st
|
|||
EventsService: daemon.EventsService,
|
||||
MetadataStore: daemon.distributionMetadataStore,
|
||||
ImageStore: daemon.imageStore,
|
||||
TagStore: daemon.tagStore,
|
||||
ReferenceStore: daemon.referenceStore,
|
||||
DownloadManager: daemon.downloadManager,
|
||||
}
|
||||
|
||||
|
@ -1107,7 +1105,7 @@ func (daemon *Daemon) PullImage(ref reference.Named, metaHeaders map[string][]st
|
|||
// the same tag are exported. names is the set of tags to export, and
|
||||
// outStream is the writer which the images are written to.
|
||||
func (daemon *Daemon) ExportImage(names []string, outStream io.Writer) error {
|
||||
imageExporter := tarexport.NewTarExporter(daemon.imageStore, daemon.layerStore, daemon.tagStore)
|
||||
imageExporter := tarexport.NewTarExporter(daemon.imageStore, daemon.layerStore, daemon.referenceStore)
|
||||
return imageExporter.Save(names, outStream)
|
||||
}
|
||||
|
||||
|
@ -1135,7 +1133,7 @@ func (daemon *Daemon) PushImage(ref reference.Named, metaHeaders map[string][]st
|
|||
MetadataStore: daemon.distributionMetadataStore,
|
||||
LayerStore: daemon.layerStore,
|
||||
ImageStore: daemon.imageStore,
|
||||
TagStore: daemon.tagStore,
|
||||
ReferenceStore: daemon.referenceStore,
|
||||
TrustKey: daemon.trustKey,
|
||||
UploadManager: daemon.uploadManager,
|
||||
}
|
||||
|
@ -1154,14 +1152,14 @@ func (daemon *Daemon) LookupImage(name string) (*types.ImageInspect, error) {
|
|||
return nil, fmt.Errorf("No such image: %s", name)
|
||||
}
|
||||
|
||||
refs := daemon.tagStore.References(img.ID())
|
||||
refs := daemon.referenceStore.References(img.ID())
|
||||
repoTags := []string{}
|
||||
repoDigests := []string{}
|
||||
for _, ref := range refs {
|
||||
switch ref.(type) {
|
||||
case reference.Tagged:
|
||||
case reference.NamedTagged:
|
||||
repoTags = append(repoTags, ref.String())
|
||||
case reference.Digested:
|
||||
case reference.Canonical:
|
||||
repoDigests = append(repoDigests, ref.String())
|
||||
}
|
||||
}
|
||||
|
@ -1215,7 +1213,7 @@ func (daemon *Daemon) LookupImage(name string) (*types.ImageInspect, error) {
|
|||
// complement of ImageExport. The input stream is an uncompressed tar
|
||||
// ball containing images and metadata.
|
||||
func (daemon *Daemon) LoadImage(inTar io.ReadCloser, outStream io.Writer) error {
|
||||
imageExporter := tarexport.NewTarExporter(daemon.imageStore, daemon.layerStore, daemon.tagStore)
|
||||
imageExporter := tarexport.NewTarExporter(daemon.imageStore, daemon.layerStore, daemon.referenceStore)
|
||||
return imageExporter.Load(inTar, outStream)
|
||||
}
|
||||
|
||||
|
@ -1271,7 +1269,7 @@ func (daemon *Daemon) ImageHistory(name string) ([]*types.ImageHistory, error) {
|
|||
h.ID = id.String()
|
||||
|
||||
var tags []string
|
||||
for _, r := range daemon.tagStore.References(id) {
|
||||
for _, r := range daemon.referenceStore.References(id) {
|
||||
if _, ok := r.(reference.NamedTagged); ok {
|
||||
tags = append(tags, r.String())
|
||||
}
|
||||
|
@ -1302,13 +1300,12 @@ func (daemon *Daemon) GetImageID(refOrID string) (image.ID, error) {
|
|||
|
||||
// Treat it as a possible tag or digest reference
|
||||
if ref, err := reference.ParseNamed(refOrID); err == nil {
|
||||
ref = registry.NormalizeLocalReference(ref)
|
||||
if id, err := daemon.tagStore.Get(ref); err == nil {
|
||||
if id, err := daemon.referenceStore.Get(ref); err == nil {
|
||||
return id, nil
|
||||
}
|
||||
if tagged, ok := ref.(reference.Tagged); ok {
|
||||
if tagged, ok := ref.(reference.NamedTagged); ok {
|
||||
if id, err := daemon.imageStore.Search(tagged.Tag()); err == nil {
|
||||
for _, namedRef := range daemon.tagStore.References(id) {
|
||||
for _, namedRef := range daemon.referenceStore.References(id) {
|
||||
if namedRef.Name() == ref.Name() {
|
||||
return id, nil
|
||||
}
|
||||
|
|
|
@ -21,8 +21,8 @@ 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"
|
||||
"github.com/docker/docker/runconfig"
|
||||
"github.com/docker/docker/tag"
|
||||
"github.com/docker/libnetwork"
|
||||
nwconfig "github.com/docker/libnetwork/config"
|
||||
"github.com/docker/libnetwork/drivers/bridge"
|
||||
|
@ -693,7 +693,7 @@ func (daemon *Daemon) conditionalUnmountOnCleanup(container *container.Container
|
|||
daemon.Unmount(container)
|
||||
}
|
||||
|
||||
func restoreCustomImage(driver graphdriver.Driver, is image.Store, ls layer.Store, ts tag.Store) error {
|
||||
func restoreCustomImage(driver graphdriver.Driver, is image.Store, ls layer.Store, rs reference.Store) error {
|
||||
// Unix has no custom images to register
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -9,13 +9,12 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/container"
|
||||
"github.com/docker/docker/daemon/graphdriver"
|
||||
"github.com/docker/docker/dockerversion"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/docker/docker/tag"
|
||||
"github.com/docker/docker/reference"
|
||||
// register the windows graph driver
|
||||
"github.com/docker/docker/daemon/graphdriver/windows"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
|
@ -153,7 +152,7 @@ func (daemon *Daemon) conditionalUnmountOnCleanup(container *container.Container
|
|||
}
|
||||
}
|
||||
|
||||
func restoreCustomImage(driver graphdriver.Driver, is image.Store, ls layer.Store, ts tag.Store) error {
|
||||
func restoreCustomImage(driver graphdriver.Driver, is image.Store, ls layer.Store, rs reference.Store) error {
|
||||
if wd, ok := driver.(*windows.Driver); ok {
|
||||
imageInfos, err := wd.GetCustomImageInfos()
|
||||
if err != nil {
|
||||
|
@ -206,7 +205,7 @@ func restoreCustomImage(driver graphdriver.Driver, is image.Store, ls layer.Stor
|
|||
return err
|
||||
}
|
||||
|
||||
if err := ts.AddTag(ref, id, true); err != nil {
|
||||
if err := rs.AddTag(ref, id, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/builder"
|
||||
|
@ -20,6 +19,7 @@ import (
|
|||
"github.com/docker/docker/pkg/idtools"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/pkg/urlutil"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/docker/docker/registry"
|
||||
"github.com/docker/docker/runconfig"
|
||||
)
|
||||
|
@ -41,15 +41,7 @@ func (d Docker) Pull(name string) (*image.Image, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch ref.(type) {
|
||||
case reference.Tagged:
|
||||
case reference.Digested:
|
||||
default:
|
||||
ref, err = reference.WithTag(ref, "latest")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
ref = reference.WithDefaultTag(ref)
|
||||
|
||||
pullRegistryAuth := &types.AuthConfig{}
|
||||
if len(d.AuthConfigs) > 0 {
|
||||
|
|
|
@ -3,9 +3,8 @@ package daemon
|
|||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
derr "github.com/docker/docker/errors"
|
||||
tagpkg "github.com/docker/docker/tag"
|
||||
"github.com/docker/docker/reference"
|
||||
)
|
||||
|
||||
func (d *Daemon) imageNotExistToErrcode(err error) error {
|
||||
|
@ -13,12 +12,12 @@ func (d *Daemon) imageNotExistToErrcode(err error) error {
|
|||
if strings.Contains(dne.RefOrID, "@") {
|
||||
return derr.ErrorCodeNoSuchImageHash.WithArgs(dne.RefOrID)
|
||||
}
|
||||
tag := tagpkg.DefaultTag
|
||||
tag := reference.DefaultTag
|
||||
ref, err := reference.ParseNamed(dne.RefOrID)
|
||||
if err != nil {
|
||||
return derr.ErrorCodeNoSuchImageTag.WithArgs(dne.RefOrID, tag)
|
||||
}
|
||||
if tagged, isTagged := ref.(reference.Tagged); isTagged {
|
||||
if tagged, isTagged := ref.(reference.NamedTagged); isTagged {
|
||||
tag = tagged.Tag()
|
||||
}
|
||||
return derr.ErrorCodeNoSuchImageTag.WithArgs(ref.Name(), tag)
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package events
|
||||
|
||||
import (
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/pkg/jsonmessage"
|
||||
"github.com/docker/docker/reference"
|
||||
)
|
||||
|
||||
// Filter can filter out docker events from a stream
|
||||
|
|
|
@ -4,13 +4,12 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/container"
|
||||
derr "github.com/docker/docker/errors"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
tagpkg "github.com/docker/docker/tag"
|
||||
"github.com/docker/docker/reference"
|
||||
)
|
||||
|
||||
// ImageDelete deletes the image referenced by the given imageRef from this
|
||||
|
@ -58,7 +57,7 @@ func (daemon *Daemon) ImageDelete(imageRef string, force, prune bool) ([]types.I
|
|||
return nil, daemon.imageNotExistToErrcode(err)
|
||||
}
|
||||
|
||||
repoRefs := daemon.tagStore.References(imgID)
|
||||
repoRefs := daemon.referenceStore.References(imgID)
|
||||
|
||||
var removedRepositoryRef bool
|
||||
if !isImageIDPrefix(imgID.String(), imageRef) {
|
||||
|
@ -150,21 +149,11 @@ 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) {
|
||||
switch ref.(type) {
|
||||
case reference.Tagged:
|
||||
case reference.Digested:
|
||||
default:
|
||||
var err error
|
||||
ref, err = reference.WithTag(ref, tagpkg.DefaultTag)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
ref = reference.WithDefaultTag(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.
|
||||
_, err := daemon.tagStore.Delete(ref)
|
||||
_, err := daemon.referenceStore.Delete(ref)
|
||||
|
||||
return ref, err
|
||||
}
|
||||
|
@ -175,7 +164,7 @@ func (daemon *Daemon) removeImageRef(ref reference.Named) (reference.Named, erro
|
|||
// daemon's event service. An "Untagged" types.ImageDelete is added to the
|
||||
// given list of records.
|
||||
func (daemon *Daemon) removeAllReferencesToImageID(imgID image.ID, records *[]types.ImageDelete) error {
|
||||
imageRefs := daemon.tagStore.References(imgID)
|
||||
imageRefs := daemon.referenceStore.References(imgID)
|
||||
|
||||
for _, imageRef := range imageRefs {
|
||||
parsedRef, err := daemon.removeImageRef(imageRef)
|
||||
|
@ -325,7 +314,7 @@ func (daemon *Daemon) checkImageDeleteHardConflict(imgID image.ID) *imageDeleteC
|
|||
|
||||
func (daemon *Daemon) checkImageDeleteSoftConflict(imgID image.ID) *imageDeleteConflict {
|
||||
// Check if any repository tags/digest reference this image.
|
||||
if len(daemon.tagStore.References(imgID)) > 0 {
|
||||
if len(daemon.referenceStore.References(imgID)) > 0 {
|
||||
return &imageDeleteConflict{
|
||||
imgID: imgID,
|
||||
message: "image is referenced in one or more repositories",
|
||||
|
@ -355,5 +344,5 @@ func (daemon *Daemon) checkImageDeleteSoftConflict(imgID image.ID) *imageDeleteC
|
|||
// that there are no repository references to the given image and it has no
|
||||
// child images.
|
||||
func (daemon *Daemon) imageIsDangling(imgID image.ID) bool {
|
||||
return !(len(daemon.tagStore.References(imgID)) > 0 || len(daemon.imageStore.Children(imgID)) > 0)
|
||||
return !(len(daemon.referenceStore.References(imgID)) > 0 || len(daemon.imageStore.Children(imgID)) > 0)
|
||||
}
|
||||
|
|
|
@ -5,11 +5,11 @@ import (
|
|||
"path"
|
||||
"sort"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/docker/docker/reference"
|
||||
)
|
||||
|
||||
var acceptedImageFilterTags = map[string]bool{
|
||||
|
@ -68,9 +68,9 @@ func (daemon *Daemon) Images(filterArgs, filter string, all bool) ([]*types.Imag
|
|||
|
||||
var filterTagged bool
|
||||
if filter != "" {
|
||||
filterRef, err := reference.Parse(filter)
|
||||
filterRef, err := reference.ParseNamed(filter)
|
||||
if err == nil { // parse error means wildcard repo
|
||||
if _, ok := filterRef.(reference.Tagged); ok {
|
||||
if _, ok := filterRef.(reference.NamedTagged); ok {
|
||||
filterTagged = true
|
||||
}
|
||||
}
|
||||
|
@ -105,7 +105,7 @@ func (daemon *Daemon) Images(filterArgs, filter string, all bool) ([]*types.Imag
|
|||
|
||||
newImage := newImage(img, size)
|
||||
|
||||
for _, ref := range daemon.tagStore.References(id) {
|
||||
for _, ref := range daemon.referenceStore.References(id) {
|
||||
if filter != "" { // filter by tag/repo name
|
||||
if filterTagged { // filter by tag, require full ref match
|
||||
if ref.String() != filter {
|
||||
|
@ -115,10 +115,10 @@ func (daemon *Daemon) Images(filterArgs, filter string, all bool) ([]*types.Imag
|
|||
continue
|
||||
}
|
||||
}
|
||||
if _, ok := ref.(reference.Digested); ok {
|
||||
if _, ok := ref.(reference.Canonical); ok {
|
||||
newImage.RepoDigests = append(newImage.RepoDigests, ref.String())
|
||||
}
|
||||
if _, ok := ref.(reference.Tagged); ok {
|
||||
if _, ok := ref.(reference.NamedTagged); ok {
|
||||
newImage.RepoTags = append(newImage.RepoTags, ref.String())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,13 +8,13 @@ import (
|
|||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/dockerversion"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/layer"
|
||||
"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/docker/docker/runconfig"
|
||||
)
|
||||
|
||||
|
@ -90,7 +90,7 @@ func (daemon *Daemon) ImportImage(src string, newRef reference.Named, msg string
|
|||
return err
|
||||
}
|
||||
|
||||
// FIXME: connect with commit code and call tagstore directly
|
||||
// FIXME: connect with commit code and call refstore directly
|
||||
if newRef != nil {
|
||||
if err := daemon.TagImage(newRef, id.String()); err != nil {
|
||||
return err
|
||||
|
|
|
@ -6,15 +6,14 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/daemon/events"
|
||||
"github.com/docker/docker/distribution/metadata"
|
||||
"github.com/docker/docker/distribution/xfer"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/pkg/progress"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/docker/docker/registry"
|
||||
"github.com/docker/docker/tag"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
|
@ -39,8 +38,8 @@ type ImagePullConfig struct {
|
|||
MetadataStore metadata.Store
|
||||
// ImageStore manages images.
|
||||
ImageStore image.Store
|
||||
// TagStore manages tags.
|
||||
TagStore tag.Store
|
||||
// ReferenceStore manages tags.
|
||||
ReferenceStore reference.Store
|
||||
// DownloadManager manages concurrent pulls.
|
||||
DownloadManager *xfer.LayerDownloadManager
|
||||
}
|
||||
|
@ -88,17 +87,15 @@ func Pull(ctx context.Context, ref reference.Named, imagePullConfig *ImagePullCo
|
|||
}
|
||||
|
||||
// makes sure name is not empty or `scratch`
|
||||
if err := validateRepoName(repoInfo.LocalName.Name()); err != nil {
|
||||
if err := validateRepoName(repoInfo.Name()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
endpoints, err := imagePullConfig.RegistryService.LookupPullEndpoints(repoInfo.CanonicalName)
|
||||
endpoints, err := imagePullConfig.RegistryService.LookupPullEndpoints(repoInfo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
localName := registry.NormalizeLocalReference(ref)
|
||||
|
||||
var (
|
||||
// use a slice to append the error strings and return a joined string to caller
|
||||
errors []string
|
||||
|
@ -113,7 +110,7 @@ func Pull(ctx context.Context, ref reference.Named, imagePullConfig *ImagePullCo
|
|||
discardNoSupportErrors bool
|
||||
)
|
||||
for _, endpoint := range endpoints {
|
||||
logrus.Debugf("Trying to pull %s from %s %s", repoInfo.LocalName, endpoint.URL, endpoint.Version)
|
||||
logrus.Debugf("Trying to pull %s from %s %s", repoInfo.Name(), endpoint.URL, endpoint.Version)
|
||||
|
||||
puller, err := newPuller(endpoint, repoInfo, imagePullConfig)
|
||||
if err != nil {
|
||||
|
@ -149,7 +146,7 @@ func Pull(ctx context.Context, ref reference.Named, imagePullConfig *ImagePullCo
|
|||
}
|
||||
}
|
||||
|
||||
imagePullConfig.EventsService.Log("pull", localName.String(), "")
|
||||
imagePullConfig.EventsService.Log("pull", ref.String(), "")
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@ 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"
|
||||
|
@ -21,6 +20,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"
|
||||
"github.com/docker/docker/registry"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
@ -34,7 +34,7 @@ type v1Puller struct {
|
|||
}
|
||||
|
||||
func (p *v1Puller) Pull(ctx context.Context, ref reference.Named) (fallback bool, err error) {
|
||||
if _, isDigested := ref.(reference.Digested); isDigested {
|
||||
if _, isCanonical := ref.(reference.Canonical); isCanonical {
|
||||
// Allowing fallback, because HTTPS v1 is before HTTP v2
|
||||
return true, registry.ErrNoSupport{Err: errors.New("Cannot pull by digest with v1 registry")}
|
||||
}
|
||||
|
@ -65,18 +65,18 @@ func (p *v1Puller) Pull(ctx context.Context, ref reference.Named) (fallback bool
|
|||
// TODO(dmcgowan): Check if should fallback
|
||||
return false, err
|
||||
}
|
||||
progress.Message(p.config.ProgressOutput, "", p.repoInfo.CanonicalName.Name()+": 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.FullName()+": this image was pulled from a legacy registry. Important: This registry version will not be supported in future versions of docker.")
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (p *v1Puller) pullRepository(ctx context.Context, ref reference.Named) error {
|
||||
progress.Message(p.config.ProgressOutput, "", "Pulling repository "+p.repoInfo.CanonicalName.Name())
|
||||
progress.Message(p.config.ProgressOutput, "", "Pulling repository "+p.repoInfo.FullName())
|
||||
|
||||
repoData, err := p.session.GetRepositoryData(p.repoInfo.RemoteName)
|
||||
repoData, err := p.session.GetRepositoryData(p.repoInfo)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "HTTP code: 404") {
|
||||
return fmt.Errorf("Error: image %s not found", p.repoInfo.RemoteName.Name())
|
||||
return fmt.Errorf("Error: image %s not found", p.repoInfo.RemoteName())
|
||||
}
|
||||
// Unexpected HTTP error
|
||||
return err
|
||||
|
@ -84,15 +84,15 @@ func (p *v1Puller) pullRepository(ctx context.Context, ref reference.Named) erro
|
|||
|
||||
logrus.Debugf("Retrieving the tag list")
|
||||
var tagsList map[string]string
|
||||
tagged, isTagged := ref.(reference.Tagged)
|
||||
tagged, isTagged := ref.(reference.NamedTagged)
|
||||
if !isTagged {
|
||||
tagsList, err = p.session.GetRemoteTags(repoData.Endpoints, p.repoInfo.RemoteName)
|
||||
tagsList, err = p.session.GetRemoteTags(repoData.Endpoints, p.repoInfo)
|
||||
} else {
|
||||
var tagID string
|
||||
tagsList = make(map[string]string)
|
||||
tagID, err = p.session.GetRemoteTag(repoData.Endpoints, p.repoInfo.RemoteName, tagged.Tag())
|
||||
tagID, err = p.session.GetRemoteTag(repoData.Endpoints, p.repoInfo, tagged.Tag())
|
||||
if err == registry.ErrRepoNotFound {
|
||||
return fmt.Errorf("Tag %s not found in repository %s", tagged.Tag(), p.repoInfo.CanonicalName.Name())
|
||||
return fmt.Errorf("Tag %s not found in repository %s", tagged.Tag(), p.repoInfo.FullName())
|
||||
}
|
||||
tagsList[tagged.Tag()] = tagID
|
||||
}
|
||||
|
@ -121,14 +121,7 @@ func (p *v1Puller) pullRepository(ctx context.Context, ref reference.Named) erro
|
|||
}
|
||||
}
|
||||
|
||||
localNameRef := p.repoInfo.LocalName
|
||||
if isTagged {
|
||||
localNameRef, err = reference.WithTag(localNameRef, tagged.Tag())
|
||||
if err != nil {
|
||||
localNameRef = p.repoInfo.LocalName
|
||||
}
|
||||
}
|
||||
writeStatus(localNameRef.String(), p.config.ProgressOutput, layersDownloaded)
|
||||
writeStatus(ref.String(), p.config.ProgressOutput, layersDownloaded)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -138,7 +131,7 @@ func (p *v1Puller) downloadImage(ctx context.Context, repoData *registry.Reposit
|
|||
return nil
|
||||
}
|
||||
|
||||
localNameRef, err := reference.WithTag(p.repoInfo.LocalName, img.Tag)
|
||||
localNameRef, err := reference.WithTag(p.repoInfo, img.Tag)
|
||||
if err != nil {
|
||||
retErr := fmt.Errorf("Image (id: %s) has invalid tag: %s", img.ID, img.Tag)
|
||||
logrus.Debug(retErr.Error())
|
||||
|
@ -149,15 +142,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.CanonicalName.Name())
|
||||
progress.Updatef(p.config.ProgressOutput, stringid.TruncateID(img.ID), "Pulling image (%s) from %s", img.Tag, p.repoInfo.FullName())
|
||||
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.CanonicalName.Name(), ep))
|
||||
progress.Updatef(p.config.ProgressOutput, stringid.TruncateID(img.ID), fmt.Sprintf("Pulling image (%s) from %s, mirror: %s", img.Tag, p.repoInfo.FullName(), 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.CanonicalName.Name(), ep, err)
|
||||
logrus.Debugf("Error pulling image (%s) from %s, mirror: %s, %s", img.Tag, p.repoInfo.FullName(), ep, err)
|
||||
continue
|
||||
}
|
||||
success = true
|
||||
|
@ -165,12 +158,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.CanonicalName.Name(), ep)
|
||||
progress.Updatef(p.config.ProgressOutput, stringid.TruncateID(img.ID), "Pulling image (%s) from %s, endpoint: %s", img.Tag, p.repoInfo.FullName(), 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.CanonicalName.Name(), ep, 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)
|
||||
continue
|
||||
}
|
||||
success = true
|
||||
|
@ -178,7 +171,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.CanonicalName.Name(), lastErr)
|
||||
err := fmt.Errorf("Error pulling image (%s) from %s, %v", img.Tag, p.repoInfo.FullName(), lastErr)
|
||||
progress.Update(p.config.ProgressOutput, stringid.TruncateID(img.ID), err.Error())
|
||||
return err
|
||||
}
|
||||
|
@ -250,7 +243,7 @@ func (p *v1Puller) pullImage(ctx context.Context, v1ID, endpoint string, localNa
|
|||
return err
|
||||
}
|
||||
|
||||
if err := p.config.TagStore.AddTag(localNameRef, imageID, true); err != nil {
|
||||
if err := p.config.ReferenceStore.AddTag(localNameRef, imageID, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@ import (
|
|||
"github.com/docker/distribution"
|
||||
"github.com/docker/distribution/digest"
|
||||
"github.com/docker/distribution/manifest/schema1"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/distribution/metadata"
|
||||
"github.com/docker/docker/distribution/xfer"
|
||||
"github.com/docker/docker/image"
|
||||
|
@ -22,6 +21,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"
|
||||
"github.com/docker/docker/registry"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
@ -54,19 +54,8 @@ func (p *v2Puller) Pull(ctx context.Context, ref reference.Named) (fallback bool
|
|||
|
||||
func (p *v2Puller) pullV2Repository(ctx context.Context, ref reference.Named) (err error) {
|
||||
var refs []reference.Named
|
||||
taggedName := p.repoInfo.LocalName
|
||||
if tagged, isTagged := ref.(reference.Tagged); isTagged {
|
||||
taggedName, err = reference.WithTag(p.repoInfo.LocalName, tagged.Tag())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
refs = []reference.Named{taggedName}
|
||||
} else if digested, isDigested := ref.(reference.Digested); isDigested {
|
||||
taggedName, err = reference.WithDigest(p.repoInfo.LocalName, digested.Digest())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
refs = []reference.Named{taggedName}
|
||||
if !reference.IsNameOnly(ref) {
|
||||
refs = []reference.Named{ref}
|
||||
} else {
|
||||
manSvc, err := p.repo.Manifests(ctx)
|
||||
if err != nil {
|
||||
|
@ -81,7 +70,7 @@ func (p *v2Puller) pullV2Repository(ctx context.Context, ref reference.Named) (e
|
|||
// This probably becomes a lot nicer after the manifest
|
||||
// refactor...
|
||||
for _, tag := range tags {
|
||||
tagRef, err := reference.WithTag(p.repoInfo.LocalName, tag)
|
||||
tagRef, err := reference.WithTag(ref, tag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -100,7 +89,7 @@ func (p *v2Puller) pullV2Repository(ctx context.Context, ref reference.Named) (e
|
|||
layersDownloaded = layersDownloaded || pulledNew
|
||||
}
|
||||
|
||||
writeStatus(taggedName.String(), p.config.ProgressOutput, layersDownloaded)
|
||||
writeStatus(ref.String(), p.config.ProgressOutput, layersDownloaded)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -197,9 +186,9 @@ func (ld *v2LayerDescriptor) Registered(diffID layer.DiffID) {
|
|||
|
||||
func (p *v2Puller) pullV2Tag(ctx context.Context, ref reference.Named) (tagUpdated bool, err error) {
|
||||
tagOrDigest := ""
|
||||
if tagged, isTagged := ref.(reference.Tagged); isTagged {
|
||||
if tagged, isTagged := ref.(reference.NamedTagged); isTagged {
|
||||
tagOrDigest = tagged.Tag()
|
||||
} else if digested, isDigested := ref.(reference.Digested); isDigested {
|
||||
} else if digested, isCanonical := ref.(reference.Canonical); isCanonical {
|
||||
tagOrDigest = digested.Digest().String()
|
||||
} else {
|
||||
return false, fmt.Errorf("internal error: reference has neither a tag nor a digest: %s", ref.String())
|
||||
|
@ -291,7 +280,7 @@ func (p *v2Puller) pullV2Tag(ctx context.Context, ref reference.Named) (tagUpdat
|
|||
return false, err
|
||||
}
|
||||
|
||||
manifestDigest, _, err := digestFromManifest(unverifiedManifest, p.repoInfo.LocalName.Name())
|
||||
manifestDigest, _, err := digestFromManifest(unverifiedManifest, p.repoInfo)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
@ -300,27 +289,27 @@ func (p *v2Puller) pullV2Tag(ctx context.Context, ref reference.Named) (tagUpdat
|
|||
progress.Message(p.config.ProgressOutput, "", "Digest: "+manifestDigest.String())
|
||||
}
|
||||
|
||||
oldTagImageID, err := p.config.TagStore.Get(ref)
|
||||
oldTagImageID, err := p.config.ReferenceStore.Get(ref)
|
||||
if err == nil && oldTagImageID == imageID {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if canonical, ok := ref.(reference.Canonical); ok {
|
||||
if err = p.config.TagStore.AddDigest(canonical, imageID, true); err != nil {
|
||||
if err = p.config.ReferenceStore.AddDigest(canonical, imageID, true); err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else if err = p.config.TagStore.AddTag(ref, imageID, true); err != nil {
|
||||
} else if err = p.config.ReferenceStore.AddTag(ref, imageID, true); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func verifyManifest(signedManifest *schema1.SignedManifest, ref reference.Reference) (m *schema1.Manifest, err error) {
|
||||
func verifyManifest(signedManifest *schema1.SignedManifest, ref reference.Named) (m *schema1.Manifest, err error) {
|
||||
// If pull by digest, then verify the manifest digest. NOTE: It is
|
||||
// important to do this first, before any other content validation. If the
|
||||
// digest cannot be verified, don't even bother with those other things.
|
||||
if digested, isDigested := ref.(reference.Digested); isDigested {
|
||||
if digested, isCanonical := ref.(reference.Canonical); isCanonical {
|
||||
verifier, err := digest.NewDigestVerifier(digested.Digest())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
|
||||
"github.com/docker/distribution/digest"
|
||||
"github.com/docker/distribution/manifest/schema1"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/reference"
|
||||
)
|
||||
|
||||
// TestFixManifestLayers checks that fixManifestLayers removes a duplicate
|
||||
|
@ -104,7 +104,7 @@ func TestFixManifestLayersBadParent(t *testing.T) {
|
|||
|
||||
// TestValidateManifest verifies the validateManifest function
|
||||
func TestValidateManifest(t *testing.T) {
|
||||
expectedDigest, err := reference.Parse("repo@sha256:02fee8c3220ba806531f606525eceb83f4feb654f62b207191b1c9209188dedd")
|
||||
expectedDigest, err := reference.ParseNamed("repo@sha256:02fee8c3220ba806531f606525eceb83f4feb654f62b207191b1c9209188dedd")
|
||||
if err != nil {
|
||||
t.Fatal("could not parse reference")
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ import (
|
|||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution/digest"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/daemon/events"
|
||||
"github.com/docker/docker/distribution/metadata"
|
||||
|
@ -16,8 +15,8 @@ import (
|
|||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/docker/docker/pkg/progress"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/docker/docker/registry"
|
||||
"github.com/docker/docker/tag"
|
||||
"github.com/docker/libtrust"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
@ -45,8 +44,8 @@ type ImagePushConfig struct {
|
|||
LayerStore layer.Store
|
||||
// ImageStore manages images.
|
||||
ImageStore image.Store
|
||||
// TagStore manages tags.
|
||||
TagStore tag.Store
|
||||
// ReferenceStore manages tags.
|
||||
ReferenceStore reference.Store
|
||||
// TrustKey is the private key for legacy signatures. This is typically
|
||||
// an ephemeral key, since these signatures are no longer verified.
|
||||
TrustKey libtrust.PrivateKey
|
||||
|
@ -105,21 +104,21 @@ func Push(ctx context.Context, ref reference.Named, imagePushConfig *ImagePushCo
|
|||
return err
|
||||
}
|
||||
|
||||
endpoints, err := imagePushConfig.RegistryService.LookupPushEndpoints(repoInfo.CanonicalName)
|
||||
endpoints, err := imagePushConfig.RegistryService.LookupPushEndpoints(repoInfo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
progress.Messagef(imagePushConfig.ProgressOutput, "", "The push refers to a repository [%s]", repoInfo.CanonicalName.String())
|
||||
progress.Messagef(imagePushConfig.ProgressOutput, "", "The push refers to a repository [%s]", repoInfo.FullName())
|
||||
|
||||
associations := imagePushConfig.TagStore.ReferencesByName(repoInfo.LocalName)
|
||||
associations := imagePushConfig.ReferenceStore.ReferencesByName(repoInfo)
|
||||
if len(associations) == 0 {
|
||||
return fmt.Errorf("Repository does not exist: %s", repoInfo.LocalName)
|
||||
return fmt.Errorf("Repository does not exist: %s", repoInfo.Name())
|
||||
}
|
||||
|
||||
var lastErr error
|
||||
for _, endpoint := range endpoints {
|
||||
logrus.Debugf("Trying to push %s to %s %s", repoInfo.CanonicalName, endpoint.URL, endpoint.Version)
|
||||
logrus.Debugf("Trying to push %s to %s %s", repoInfo.FullName(), endpoint.URL, endpoint.Version)
|
||||
|
||||
pusher, err := NewPusher(ref, endpoint, repoInfo, imagePushConfig)
|
||||
if err != nil {
|
||||
|
@ -144,12 +143,12 @@ func Push(ctx context.Context, ref reference.Named, imagePushConfig *ImagePushCo
|
|||
|
||||
}
|
||||
|
||||
imagePushConfig.EventsService.Log("push", repoInfo.LocalName.Name(), "")
|
||||
imagePushConfig.EventsService.Log("push", repoInfo.Name(), "")
|
||||
return nil
|
||||
}
|
||||
|
||||
if lastErr == nil {
|
||||
lastErr = fmt.Errorf("no endpoints found for %s", repoInfo.CanonicalName)
|
||||
lastErr = fmt.Errorf("no endpoints found for %s", repoInfo.FullName())
|
||||
}
|
||||
return lastErr
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ import (
|
|||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution/digest"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/registry/client/transport"
|
||||
"github.com/docker/docker/distribution/metadata"
|
||||
"github.com/docker/docker/image"
|
||||
|
@ -15,6 +14,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"
|
||||
"github.com/docker/docker/registry"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
@ -141,16 +141,15 @@ func (p *v1Pusher) getImageList() (imageList []v1Image, tagsByImage map[image.ID
|
|||
tagsByImage = make(map[image.ID][]string)
|
||||
|
||||
// Ignore digest references
|
||||
_, isDigested := p.ref.(reference.Digested)
|
||||
if isDigested {
|
||||
if _, isCanonical := p.ref.(reference.Canonical); isCanonical {
|
||||
return
|
||||
}
|
||||
|
||||
tagged, isTagged := p.ref.(reference.Tagged)
|
||||
tagged, isTagged := p.ref.(reference.NamedTagged)
|
||||
if isTagged {
|
||||
// Push a specific tag
|
||||
var imgID image.ID
|
||||
imgID, err = p.config.TagStore.Get(p.ref)
|
||||
imgID, err = p.config.ReferenceStore.Get(p.ref)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -168,9 +167,9 @@ func (p *v1Pusher) getImageList() (imageList []v1Image, tagsByImage map[image.ID
|
|||
imagesSeen := make(map[image.ID]struct{})
|
||||
dependenciesSeen := make(map[layer.ChainID]*v1DependencyImage)
|
||||
|
||||
associations := p.config.TagStore.ReferencesByName(p.ref)
|
||||
associations := p.config.ReferenceStore.ReferencesByName(p.ref)
|
||||
for _, association := range associations {
|
||||
if tagged, isTagged = association.Ref.(reference.Tagged); !isTagged {
|
||||
if tagged, isTagged = association.Ref.(reference.NamedTagged); !isTagged {
|
||||
// Ignore digest references.
|
||||
continue
|
||||
}
|
||||
|
@ -352,8 +351,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.Name()+"/tags/"+tag)
|
||||
if err := p.session.PushRegistryTag(p.repoInfo.RemoteName, v1ID, tag, endpoint); err != nil {
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -382,18 +381,18 @@ 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.RemoteName, imageIndex, false, nil)
|
||||
repoData, err := p.session.PushImageJSONIndex(p.repoInfo, imageIndex, false, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
progress.Message(p.config.ProgressOutput, "", "Pushing repository "+p.repoInfo.CanonicalName.String())
|
||||
progress.Message(p.config.ProgressOutput, "", "Pushing repository "+p.repoInfo.FullName())
|
||||
// push the repository to each of the endpoints only if it does not exist.
|
||||
for _, endpoint := range repoData.Endpoints {
|
||||
if err := p.pushImageToEndpoint(ctx, endpoint, imgList, tags, repoData); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
_, err = p.session.PushImageJSONIndex(p.repoInfo.RemoteName, imageIndex, true, repoData.Endpoints)
|
||||
_, err = p.session.PushImageJSONIndex(p.repoInfo, imageIndex, true, repoData.Endpoints)
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@ import (
|
|||
"github.com/docker/distribution/digest"
|
||||
"github.com/docker/distribution/manifest"
|
||||
"github.com/docker/distribution/manifest/schema1"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/distribution/metadata"
|
||||
"github.com/docker/docker/distribution/xfer"
|
||||
"github.com/docker/docker/image"
|
||||
|
@ -22,8 +21,8 @@ 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/docker/docker/tag"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
|
@ -53,16 +52,14 @@ func (p *v2Pusher) Push(ctx context.Context) (fallback bool, err error) {
|
|||
return true, err
|
||||
}
|
||||
|
||||
localName := p.repoInfo.LocalName.Name()
|
||||
|
||||
var associations []tag.Association
|
||||
if _, isTagged := p.ref.(reference.Tagged); isTagged {
|
||||
imageID, err := p.config.TagStore.Get(p.ref)
|
||||
var associations []reference.Association
|
||||
if _, isTagged := p.ref.(reference.NamedTagged); isTagged {
|
||||
imageID, err := p.config.ReferenceStore.Get(p.ref)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("tag does not exist: %s", p.ref.String())
|
||||
}
|
||||
|
||||
associations = []tag.Association{
|
||||
associations = []reference.Association{
|
||||
{
|
||||
Ref: p.ref,
|
||||
ImageID: imageID,
|
||||
|
@ -70,13 +67,13 @@ func (p *v2Pusher) Push(ctx context.Context) (fallback bool, err error) {
|
|||
}
|
||||
} else {
|
||||
// Pull all tags
|
||||
associations = p.config.TagStore.ReferencesByName(p.ref)
|
||||
associations = p.config.ReferenceStore.ReferencesByName(p.ref)
|
||||
}
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("error getting tags for %s: %s", localName, err)
|
||||
return false, fmt.Errorf("error getting tags for %s: %s", p.repoInfo.Name(), err)
|
||||
}
|
||||
if len(associations) == 0 {
|
||||
return false, fmt.Errorf("no tags to push for %s", localName)
|
||||
return false, fmt.Errorf("no tags to push for %s", p.repoInfo.Name())
|
||||
}
|
||||
|
||||
for _, association := range associations {
|
||||
|
@ -88,7 +85,7 @@ func (p *v2Pusher) Push(ctx context.Context) (fallback bool, err error) {
|
|||
return false, nil
|
||||
}
|
||||
|
||||
func (p *v2Pusher) pushV2Tag(ctx context.Context, association tag.Association) error {
|
||||
func (p *v2Pusher) pushV2Tag(ctx context.Context, association reference.Association) error {
|
||||
ref := association.Ref
|
||||
logrus.Debugf("Pushing repository: %s", ref.String())
|
||||
|
||||
|
@ -146,7 +143,7 @@ func (p *v2Pusher) pushV2Tag(ctx context.Context, association tag.Association) e
|
|||
}
|
||||
|
||||
var tag string
|
||||
if tagged, isTagged := ref.(reference.Tagged); isTagged {
|
||||
if tagged, isTagged := ref.(reference.NamedTagged); isTagged {
|
||||
tag = tagged.Tag()
|
||||
}
|
||||
m, err := CreateV2Manifest(p.repo.Name(), tag, img, fsLayers)
|
||||
|
@ -160,12 +157,12 @@ func (p *v2Pusher) pushV2Tag(ctx context.Context, association tag.Association) e
|
|||
return err
|
||||
}
|
||||
|
||||
manifestDigest, manifestSize, err := digestFromManifest(signed, p.repo.Name())
|
||||
manifestDigest, manifestSize, err := digestFromManifest(signed, ref)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if manifestDigest != "" {
|
||||
if tagged, isTagged := ref.(reference.Tagged); isTagged {
|
||||
if tagged, isTagged := ref.(reference.NamedTagged); isTagged {
|
||||
// NOTE: do not change this format without first changing the trust client
|
||||
// code. This information is used to determine what was pushed and should be signed.
|
||||
progress.Messagef(p.config.ProgressOutput, "", "%s: digest: %s size: %d", tagged.Tag(), manifestDigest, manifestSize)
|
||||
|
|
|
@ -19,6 +19,7 @@ import (
|
|||
"github.com/docker/distribution/registry/client/transport"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/distribution/xfer"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/docker/docker/registry"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
@ -37,10 +38,10 @@ func (dcs dumbCredentialStore) Basic(*url.URL) (string, string) {
|
|||
func NewV2Repository(repoInfo *registry.RepositoryInfo, endpoint registry.APIEndpoint, metaHeaders http.Header, authConfig *types.AuthConfig, actions ...string) (distribution.Repository, error) {
|
||||
ctx := context.Background()
|
||||
|
||||
repoName := repoInfo.CanonicalName
|
||||
repoName := repoInfo.FullName()
|
||||
// If endpoint does not support CanonicalName, use the RemoteName instead
|
||||
if endpoint.TrimHostname {
|
||||
repoName = repoInfo.RemoteName
|
||||
repoName = repoInfo.RemoteName()
|
||||
}
|
||||
|
||||
// TODO(dmcgowan): Call close idle connections when complete, use keep alive
|
||||
|
@ -99,16 +100,16 @@ func NewV2Repository(repoInfo *registry.RepositoryInfo, endpoint registry.APIEnd
|
|||
modifiers = append(modifiers, auth.NewAuthorizer(challengeManager, passThruTokenHandler))
|
||||
} else {
|
||||
creds := dumbCredentialStore{auth: authConfig}
|
||||
tokenHandler := auth.NewTokenHandler(authTransport, creds, repoName.Name(), actions...)
|
||||
tokenHandler := auth.NewTokenHandler(authTransport, creds, repoName, actions...)
|
||||
basicHandler := auth.NewBasicHandler(creds)
|
||||
modifiers = append(modifiers, auth.NewAuthorizer(challengeManager, tokenHandler, basicHandler))
|
||||
}
|
||||
tr := transport.NewTransport(base, modifiers...)
|
||||
|
||||
return client.NewRepository(ctx, repoName.Name(), endpoint.URL, tr)
|
||||
return client.NewRepository(ctx, repoName, endpoint.URL, tr)
|
||||
}
|
||||
|
||||
func digestFromManifest(m *schema1.SignedManifest, localName string) (digest.Digest, int, error) {
|
||||
func digestFromManifest(m *schema1.SignedManifest, name reference.Named) (digest.Digest, int, error) {
|
||||
payload, err := m.Payload()
|
||||
if err != nil {
|
||||
// If this failed, the signatures section was corrupted
|
||||
|
@ -117,7 +118,7 @@ func digestFromManifest(m *schema1.SignedManifest, localName string) (digest.Dig
|
|||
}
|
||||
manifestDigest, err := digest.FromBytes(payload)
|
||||
if err != nil {
|
||||
logrus.Infof("Could not compute manifest digest for %s:%s : %v", localName, m.Tag, err)
|
||||
logrus.Infof("Could not compute manifest digest for %s:%s : %v", name.Name(), m.Tag, err)
|
||||
}
|
||||
return manifestDigest, len(payload), nil
|
||||
}
|
||||
|
|
|
@ -8,10 +8,10 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/registry/client/auth"
|
||||
"github.com/docker/docker/api/types"
|
||||
registrytypes "github.com/docker/docker/api/types/registry"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/docker/docker/registry"
|
||||
"github.com/docker/docker/utils"
|
||||
"golang.org/x/net/context"
|
||||
|
@ -58,16 +58,14 @@ func TestTokenPassThru(t *testing.T) {
|
|||
}
|
||||
n, _ := reference.ParseNamed("testremotename")
|
||||
repoInfo := ®istry.RepositoryInfo{
|
||||
Named: n,
|
||||
Index: ®istrytypes.IndexInfo{
|
||||
Name: "testrepo",
|
||||
Mirrors: nil,
|
||||
Secure: false,
|
||||
Official: false,
|
||||
},
|
||||
RemoteName: n,
|
||||
LocalName: n,
|
||||
CanonicalName: n,
|
||||
Official: false,
|
||||
Official: false,
|
||||
}
|
||||
imagePullConfig := &ImagePullConfig{
|
||||
MetaHeaders: http.Header{},
|
||||
|
|
|
@ -9,13 +9,13 @@ import (
|
|||
"path/filepath"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"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/chrootarchive"
|
||||
"github.com/docker/docker/pkg/symlink"
|
||||
"github.com/docker/docker/reference"
|
||||
)
|
||||
|
||||
func (l *tarexporter) Load(inTar io.ReadCloser, outStream io.Writer) error {
|
||||
|
@ -124,11 +124,11 @@ func (l *tarexporter) loadLayer(filename string, rootFS image.RootFS) (layer.Lay
|
|||
}
|
||||
|
||||
func (l *tarexporter) setLoadedTag(ref reference.NamedTagged, imgID image.ID, outStream io.Writer) error {
|
||||
if prevID, err := l.ts.Get(ref); err == nil && prevID != imgID {
|
||||
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
|
||||
}
|
||||
|
||||
if err := l.ts.AddTag(ref, imgID, true); err != nil {
|
||||
if err := l.rs.AddTag(ref, imgID, true); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -10,13 +10,11 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/docker/distribution/digest"
|
||||
"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/registry"
|
||||
"github.com/docker/docker/tag"
|
||||
"github.com/docker/docker/reference"
|
||||
)
|
||||
|
||||
type imageDescriptor struct {
|
||||
|
@ -50,13 +48,13 @@ func (l *tarexporter) parseNames(names []string) (map[image.ID]*imageDescriptor,
|
|||
|
||||
if ref != nil {
|
||||
var tagged reference.NamedTagged
|
||||
if _, ok := ref.(reference.Digested); ok {
|
||||
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, tag.DefaultTag); err != nil {
|
||||
if tagged, err = reference.WithTag(ref, reference.DefaultTag); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -75,7 +73,6 @@ func (l *tarexporter) parseNames(names []string) (map[image.ID]*imageDescriptor,
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ref = registry.NormalizeLocalReference(ref)
|
||||
if ref.Name() == string(digest.Canonical) {
|
||||
imgID, err := l.is.Search(name)
|
||||
if err != nil {
|
||||
|
@ -84,24 +81,22 @@ func (l *tarexporter) parseNames(names []string) (map[image.ID]*imageDescriptor,
|
|||
addAssoc(imgID, nil)
|
||||
continue
|
||||
}
|
||||
if _, ok := ref.(reference.Digested); !ok {
|
||||
if _, ok := ref.(reference.NamedTagged); !ok {
|
||||
assocs := l.ts.ReferencesByName(ref)
|
||||
for _, assoc := range assocs {
|
||||
addAssoc(assoc.ImageID, assoc.Ref)
|
||||
}
|
||||
if len(assocs) == 0 {
|
||||
imgID, err := l.is.Search(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
addAssoc(imgID, nil)
|
||||
}
|
||||
continue
|
||||
if reference.IsNameOnly(ref) {
|
||||
assocs := l.rs.ReferencesByName(ref)
|
||||
for _, assoc := range assocs {
|
||||
addAssoc(assoc.ImageID, assoc.Ref)
|
||||
}
|
||||
if len(assocs) == 0 {
|
||||
imgID, err := l.is.Search(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
addAssoc(imgID, nil)
|
||||
}
|
||||
continue
|
||||
}
|
||||
var imgID image.ID
|
||||
if imgID, err = l.ts.Get(ref); err != nil {
|
||||
if imgID, err = l.rs.Get(ref); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
addAssoc(imgID, ref)
|
||||
|
|
|
@ -3,7 +3,7 @@ package tarexport
|
|||
import (
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/docker/docker/tag"
|
||||
"github.com/docker/docker/reference"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -23,14 +23,14 @@ type manifestItem struct {
|
|||
type tarexporter struct {
|
||||
is image.Store
|
||||
ls layer.Store
|
||||
ts tag.Store
|
||||
rs reference.Store
|
||||
}
|
||||
|
||||
// NewTarExporter returns new ImageExporter for tar packages
|
||||
func NewTarExporter(is image.Store, ls layer.Store, ts tag.Store) image.Exporter {
|
||||
func NewTarExporter(is image.Store, ls layer.Store, rs reference.Store) image.Exporter {
|
||||
return &tarexporter{
|
||||
is: is,
|
||||
ls: ls,
|
||||
ts: ts,
|
||||
rs: rs,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4614,7 +4614,7 @@ func (s *DockerSuite) TestBuildInvalidTag(c *check.C) {
|
|||
_, out, err := buildImageWithOut(name, "FROM scratch\nMAINTAINER quux\n", true)
|
||||
// if the error doesn't check for illegal tag name, or the image is built
|
||||
// then this should fail
|
||||
if !strings.Contains(out, "invalid reference format") || strings.Contains(out, "Sending build context to Docker daemon") {
|
||||
if !strings.Contains(out, "Error parsing reference") || strings.Contains(out, "Sending build context to Docker daemon") {
|
||||
c.Fatalf("failed to stop before building. Error: %s, Output: %s", err, out)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -265,7 +265,7 @@ func (s *DockerSuite) TestCreateByImageID(c *check.C) {
|
|||
c.Fatalf("expected non-zero exit code; received %d", exit)
|
||||
}
|
||||
|
||||
if expected := "invalid reference format"; !strings.Contains(out, expected) {
|
||||
if expected := "Error parsing reference"; !strings.Contains(out, expected) {
|
||||
c.Fatalf(`Expected %q in output; got: %s`, expected, out)
|
||||
}
|
||||
|
||||
|
|
|
@ -3758,8 +3758,8 @@ func (s *DockerSuite) TestRunInvalidReference(c *check.C) {
|
|||
c.Fatalf("expected non-zero exist code; received %d", exit)
|
||||
}
|
||||
|
||||
if !strings.Contains(out, "invalid reference format") {
|
||||
c.Fatalf(`Expected "invalid reference format" in output; got: %s`, out)
|
||||
if !strings.Contains(out, "Error parsing reference") {
|
||||
c.Fatalf(`Expected "Error parsing reference" in output; got: %s`, out)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -99,17 +99,17 @@ func (s *DockerSuite) TestTagWithPrefixHyphen(c *check.C) {
|
|||
// test repository name begin with '-'
|
||||
out, _, err := dockerCmdWithError("tag", "busybox:latest", "-busybox:test")
|
||||
c.Assert(err, checker.NotNil, check.Commentf(out))
|
||||
c.Assert(out, checker.Contains, "invalid reference format", check.Commentf("tag a name begin with '-' should failed"))
|
||||
c.Assert(out, checker.Contains, "Error parsing reference", check.Commentf("tag a name begin with '-' should failed"))
|
||||
|
||||
// test namespace name begin with '-'
|
||||
out, _, err = dockerCmdWithError("tag", "busybox:latest", "-test/busybox:test")
|
||||
c.Assert(err, checker.NotNil, check.Commentf(out))
|
||||
c.Assert(out, checker.Contains, "invalid reference format", check.Commentf("tag a name begin with '-' should failed"))
|
||||
c.Assert(out, checker.Contains, "Error parsing reference", check.Commentf("tag a name begin with '-' should failed"))
|
||||
|
||||
// test index name begin with '-'
|
||||
out, _, err = dockerCmdWithError("tag", "busybox:latest", "-index:5000/busybox:test")
|
||||
c.Assert(err, checker.NotNil, check.Commentf(out))
|
||||
c.Assert(out, checker.Contains, "invalid reference format", check.Commentf("tag a name begin with '-' should failed"))
|
||||
c.Assert(out, checker.Contains, "Error parsing reference", check.Commentf("tag a name begin with '-' should failed"))
|
||||
}
|
||||
|
||||
// ensure tagging using official names works
|
||||
|
|
|
@ -11,12 +11,11 @@ import (
|
|||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution/digest"
|
||||
"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/tag"
|
||||
"github.com/docker/docker/reference"
|
||||
)
|
||||
|
||||
type graphIDRegistrar interface {
|
||||
|
@ -46,7 +45,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, ts tag.Store, ms metadata.Store) error {
|
||||
func Migrate(root, driverName string, ls layer.Store, is image.Store, rs reference.Store, ms metadata.Store) error {
|
||||
mappings := make(map[string]image.ID)
|
||||
|
||||
if registrar, ok := ls.(graphIDRegistrar); !ok {
|
||||
|
@ -61,7 +60,7 @@ func Migrate(root, driverName string, ls layer.Store, is image.Store, ts tag.Sto
|
|||
return err
|
||||
}
|
||||
|
||||
if err := migrateTags(root, driverName, ts, mappings); err != nil {
|
||||
if err := migrateRefs(root, driverName, rs, mappings); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -189,12 +188,12 @@ func migrateContainers(root string, ls graphIDMounter, is image.Store, imageMapp
|
|||
return nil
|
||||
}
|
||||
|
||||
type tagAdder interface {
|
||||
type refAdder interface {
|
||||
AddTag(ref reference.Named, id image.ID, force bool) error
|
||||
AddDigest(ref reference.Canonical, id image.ID, force bool) error
|
||||
}
|
||||
|
||||
func migrateTags(root, driverName string, ts tagAdder, mappings map[string]image.ID) error {
|
||||
func migrateRefs(root, driverName string, rs refAdder, mappings map[string]image.ID) error {
|
||||
migrationFile := filepath.Join(root, migrationTagsFileName)
|
||||
if _, err := os.Lstat(migrationFile); !os.IsNotExist(err) {
|
||||
return err
|
||||
|
@ -232,7 +231,7 @@ func migrateTags(root, driverName string, ts tagAdder, mappings map[string]image
|
|||
logrus.Errorf("migrate tags: invalid digest %q, %q", dgst, err)
|
||||
continue
|
||||
}
|
||||
if err := ts.AddDigest(canonical, strongID, false); err != nil {
|
||||
if err := rs.AddDigest(canonical, strongID, false); err != nil {
|
||||
logrus.Errorf("can't migrate digest %q for %q, err: %q", ref.String(), strongID, err)
|
||||
}
|
||||
} else {
|
||||
|
@ -241,7 +240,7 @@ func migrateTags(root, driverName string, ts tagAdder, mappings map[string]image
|
|||
logrus.Errorf("migrate tags: invalid tag %q, %q", tag, err)
|
||||
continue
|
||||
}
|
||||
if err := ts.AddTag(tagRef, strongID, false); err != nil {
|
||||
if err := rs.AddTag(tagRef, strongID, false); err != nil {
|
||||
logrus.Errorf("can't migrate tag %q for %q, err: %q", ref.String(), strongID, err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,13 +13,13 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/docker/distribution/digest"
|
||||
"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"
|
||||
)
|
||||
|
||||
func TestMigrateTags(t *testing.T) {
|
||||
func TestMigrateRefs(t *testing.T) {
|
||||
tmpdir, err := ioutil.TempDir("", "migrate-tags")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -29,7 +29,7 @@ func TestMigrateTags(t *testing.T) {
|
|||
ioutil.WriteFile(filepath.Join(tmpdir, "repositories-generic"), []byte(`{"Repositories":{"busybox":{"latest":"b3ca410aa2c115c05969a7b2c8cf8a9fcf62c1340ed6a601c9ee50df337ec108","sha256:16a2a52884c2a9481ed267c2d46483eac7693b813a63132368ab098a71303f8a":"b3ca410aa2c115c05969a7b2c8cf8a9fcf62c1340ed6a601c9ee50df337ec108"},"registry":{"2":"5d165b8e4b203685301c815e95663231691d383fd5e3d3185d1ce3f8dddead3d","latest":"8d5547a9f329b1d3f93198cd661fb5117e5a96b721c5cf9a2c389e7dd4877128"}}}`), 0600)
|
||||
|
||||
ta := &mockTagAdder{}
|
||||
err = migrateTags(tmpdir, "generic", ta, map[string]image.ID{
|
||||
err = migrateRefs(tmpdir, "generic", ta, map[string]image.ID{
|
||||
"5d165b8e4b203685301c815e95663231691d383fd5e3d3185d1ce3f8dddead3d": image.ID("sha256:2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae"),
|
||||
"b3ca410aa2c115c05969a7b2c8cf8a9fcf62c1340ed6a601c9ee50df337ec108": image.ID("sha256:fcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9"),
|
||||
"abcdef3434c115c05969a7b2c8cf8a9fcf62c1340ed6a601c9ee50df337ec108": image.ID("sha256:56434342345ae68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae"),
|
||||
|
@ -50,7 +50,7 @@ func TestMigrateTags(t *testing.T) {
|
|||
|
||||
// second migration is no-op
|
||||
ioutil.WriteFile(filepath.Join(tmpdir, "repositories-generic"), []byte(`{"Repositories":{"busybox":{"latest":"b3ca410aa2c115c05969a7b2c8cf8a9fcf62c1340ed6a601c9ee50df337ec108"`), 0600)
|
||||
err = migrateTags(tmpdir, "generic", ta, map[string]image.ID{
|
||||
err = migrateRefs(tmpdir, "generic", ta, map[string]image.ID{
|
||||
"b3ca410aa2c115c05969a7b2c8cf8a9fcf62c1340ed6a601c9ee50df337ec108": image.ID("sha256:fcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9"),
|
||||
})
|
||||
if err != nil {
|
||||
|
|
191
reference/reference.go
Normal file
191
reference/reference.go
Normal file
|
@ -0,0 +1,191 @@
|
|||
package reference
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/distribution/digest"
|
||||
distreference "github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/image/v1"
|
||||
)
|
||||
|
||||
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.ParseNamed(s)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error parsing reference: %q is not a valid repository/tag", s)
|
||||
}
|
||||
r, err := WithName(named.Name())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if canonical, isCanonical := named.(distreference.Canonical); isCanonical {
|
||||
return WithDigest(r, canonical.Digest())
|
||||
}
|
||||
if tagged, isTagged := named.(distreference.NamedTagged); isTagged {
|
||||
return WithTag(r, tagged.Tag())
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// WithName returns a named object representing the given string. If the input
|
||||
// is invalid ErrReferenceInvalidFormat will be returned.
|
||||
func WithName(name string) (Named, error) {
|
||||
name = normalize(name)
|
||||
if err := validateName(name); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r, err := distreference.WithName(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
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) FullName() string {
|
||||
hostname, remoteName := splitHostname(r.Name())
|
||||
return hostname + "/" + remoteName
|
||||
}
|
||||
func (r *namedRef) Hostname() string {
|
||||
hostname, _ := splitHostname(r.Name())
|
||||
return hostname
|
||||
}
|
||||
func (r *namedRef) RemoteName() string {
|
||||
_, remoteName := splitHostname(r.Name())
|
||||
return remoteName
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
// splitHostname splits a repository name to hostname and remotename string.
|
||||
// If no valid hostname is found, the default hostname is used. Repository name
|
||||
// needs to be already validated before.
|
||||
func splitHostname(name string) (hostname, remoteName string) {
|
||||
i := strings.IndexRune(name, '/')
|
||||
if i == -1 || (!strings.ContainsAny(name[:i], ".:") && name[:i] != "localhost") {
|
||||
hostname, remoteName = DefaultHostname, name
|
||||
} else {
|
||||
hostname, remoteName = name[:i], name[i+1:]
|
||||
}
|
||||
if hostname == LegacyDefaultHostname {
|
||||
hostname = DefaultHostname
|
||||
}
|
||||
if hostname == DefaultHostname && !strings.ContainsRune(remoteName, '/') {
|
||||
remoteName = DefaultRepoPrefix + remoteName
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// normalize returns a repository name in its normalized form, meaning it
|
||||
// will not contain default hostname nor library/ prefix for official images.
|
||||
func normalize(name string) string {
|
||||
host, remoteName := splitHostname(name)
|
||||
if host == DefaultHostname {
|
||||
if strings.HasPrefix(remoteName, DefaultRepoPrefix) {
|
||||
return strings.TrimPrefix(remoteName, DefaultRepoPrefix)
|
||||
}
|
||||
return remoteName
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
func validateName(name string) error {
|
||||
if err := v1.ValidateID(name); err == nil {
|
||||
return fmt.Errorf("Invalid repository name (%s), cannot specify 64-byte hexadecimal strings", name)
|
||||
}
|
||||
return nil
|
||||
}
|
275
reference/reference_test.go
Normal file
275
reference/reference_test.go
Normal file
|
@ -0,0 +1,275 @@
|
|||
package reference
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/docker/distribution/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 normalized reference 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")
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package tag
|
||||
package reference
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
@ -11,13 +11,9 @@ import (
|
|||
"sync"
|
||||
|
||||
"github.com/docker/distribution/digest"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/image"
|
||||
)
|
||||
|
||||
// DefaultTag defines the default tag used when performing images related actions and no tag string is specified
|
||||
const DefaultTag = "latest"
|
||||
|
||||
var (
|
||||
// ErrDoesNotExist is returned if a reference is not found in the
|
||||
// store.
|
||||
|
@ -26,18 +22,18 @@ var (
|
|||
|
||||
// An Association is a tuple associating a reference with an image ID.
|
||||
type Association struct {
|
||||
Ref reference.Named
|
||||
Ref Named
|
||||
ImageID image.ID
|
||||
}
|
||||
|
||||
// Store provides the set of methods which can operate on a tag store.
|
||||
type Store interface {
|
||||
References(id image.ID) []reference.Named
|
||||
ReferencesByName(ref reference.Named) []Association
|
||||
AddTag(ref reference.Named, id image.ID, force bool) error
|
||||
AddDigest(ref reference.Canonical, id image.ID, force bool) error
|
||||
Delete(ref reference.Named) (bool, error)
|
||||
Get(ref reference.Named) (image.ID, error)
|
||||
References(id image.ID) []Named
|
||||
ReferencesByName(ref Named) []Association
|
||||
AddTag(ref Named, id image.ID, force bool) error
|
||||
AddDigest(ref Canonical, id image.ID, force bool) error
|
||||
Delete(ref Named) (bool, error)
|
||||
Get(ref Named) (image.ID, error)
|
||||
}
|
||||
|
||||
type store struct {
|
||||
|
@ -49,14 +45,14 @@ type store struct {
|
|||
Repositories map[string]repository
|
||||
// referencesByIDCache is a cache of references indexed by ID, to speed
|
||||
// up References.
|
||||
referencesByIDCache map[image.ID]map[string]reference.Named
|
||||
referencesByIDCache map[image.ID]map[string]Named
|
||||
}
|
||||
|
||||
// Repository maps tags to image IDs. The key is a a stringified Reference,
|
||||
// including the repository name.
|
||||
type repository map[string]image.ID
|
||||
|
||||
type lexicalRefs []reference.Named
|
||||
type lexicalRefs []Named
|
||||
|
||||
func (a lexicalRefs) Len() int { return len(a) }
|
||||
func (a lexicalRefs) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
|
@ -68,22 +64,9 @@ 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 defaultTagIfNameOnly(ref reference.Named) reference.Named {
|
||||
switch ref.(type) {
|
||||
case reference.Tagged:
|
||||
return ref
|
||||
case reference.Digested:
|
||||
return ref
|
||||
default:
|
||||
// Should never fail
|
||||
ref, _ = reference.WithTag(ref, DefaultTag)
|
||||
return ref
|
||||
}
|
||||
}
|
||||
|
||||
// NewTagStore creates a new tag store, tied to a file path where the set of
|
||||
// tags is serialized in JSON format.
|
||||
func NewTagStore(jsonPath string) (Store, error) {
|
||||
// NewReferenceStore creates a new reference store, tied to a file path where
|
||||
// the set of references are serialized in JSON format.
|
||||
func NewReferenceStore(jsonPath string) (Store, error) {
|
||||
abspath, err := filepath.Abs(jsonPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -92,7 +75,7 @@ func NewTagStore(jsonPath string) (Store, error) {
|
|||
store := &store{
|
||||
jsonPath: abspath,
|
||||
Repositories: make(map[string]repository),
|
||||
referencesByIDCache: make(map[image.ID]map[string]reference.Named),
|
||||
referencesByIDCache: make(map[image.ID]map[string]Named),
|
||||
}
|
||||
// Load the json file if it exists, otherwise create it.
|
||||
if err := store.reload(); os.IsNotExist(err) {
|
||||
|
@ -105,21 +88,21 @@ func NewTagStore(jsonPath string) (Store, error) {
|
|||
return store, nil
|
||||
}
|
||||
|
||||
// Add adds a tag to the store. If force is set to true, existing
|
||||
// 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 reference.Named, id image.ID, force bool) error {
|
||||
if _, isDigested := ref.(reference.Digested); isDigested {
|
||||
func (store *store) AddTag(ref Named, id image.ID, force bool) error {
|
||||
if _, isCanonical := ref.(Canonical); isCanonical {
|
||||
return errors.New("refusing to create a tag with a digest reference")
|
||||
}
|
||||
return store.addReference(defaultTagIfNameOnly(ref), id, force)
|
||||
return store.addReference(WithDefaultTag(ref), id, force)
|
||||
}
|
||||
|
||||
// Add adds a digest reference to the store.
|
||||
func (store *store) AddDigest(ref reference.Canonical, id image.ID, force bool) error {
|
||||
// AddDigest adds a digest reference to the store.
|
||||
func (store *store) AddDigest(ref Canonical, id image.ID, force bool) error {
|
||||
return store.addReference(ref, id, force)
|
||||
}
|
||||
|
||||
func (store *store) addReference(ref reference.Named, id image.ID, force bool) error {
|
||||
func (store *store) addReference(ref Named, id image.ID, force bool) error {
|
||||
if ref.Name() == string(digest.Canonical) {
|
||||
return errors.New("refusing to create an ambiguous tag using digest algorithm as name")
|
||||
}
|
||||
|
@ -138,7 +121,7 @@ func (store *store) addReference(ref reference.Named, id image.ID, force bool) e
|
|||
|
||||
if exists {
|
||||
// force only works for tags
|
||||
if digested, isDigest := ref.(reference.Digested); isDigest {
|
||||
if digested, isDigest := ref.(Canonical); isDigest {
|
||||
return fmt.Errorf("Cannot overwrite digest %s", digested.Digest().String())
|
||||
}
|
||||
|
||||
|
@ -156,7 +139,7 @@ func (store *store) addReference(ref reference.Named, id image.ID, force bool) e
|
|||
|
||||
repository[refStr] = id
|
||||
if store.referencesByIDCache[id] == nil {
|
||||
store.referencesByIDCache[id] = make(map[string]reference.Named)
|
||||
store.referencesByIDCache[id] = make(map[string]Named)
|
||||
}
|
||||
store.referencesByIDCache[id][refStr] = ref
|
||||
|
||||
|
@ -165,8 +148,8 @@ func (store *store) addReference(ref reference.Named, id image.ID, force bool) e
|
|||
|
||||
// Delete deletes a reference from the store. It returns true if a deletion
|
||||
// happened, or false otherwise.
|
||||
func (store *store) Delete(ref reference.Named) (bool, error) {
|
||||
ref = defaultTagIfNameOnly(ref)
|
||||
func (store *store) Delete(ref Named) (bool, error) {
|
||||
ref = WithDefaultTag(ref)
|
||||
|
||||
store.mu.Lock()
|
||||
defer store.mu.Unlock()
|
||||
|
@ -196,9 +179,9 @@ func (store *store) Delete(ref reference.Named) (bool, error) {
|
|||
return false, ErrDoesNotExist
|
||||
}
|
||||
|
||||
// Get retrieves an item from the store by reference.
|
||||
func (store *store) Get(ref reference.Named) (image.ID, error) {
|
||||
ref = defaultTagIfNameOnly(ref)
|
||||
// Get retrieves an item from the store by
|
||||
func (store *store) Get(ref Named) (image.ID, error) {
|
||||
ref = WithDefaultTag(ref)
|
||||
|
||||
store.mu.RLock()
|
||||
defer store.mu.RUnlock()
|
||||
|
@ -218,15 +201,15 @@ func (store *store) Get(ref reference.Named) (image.ID, error) {
|
|||
|
||||
// References returns a slice of references to the given image ID. The slice
|
||||
// will be nil if there are no references to this image ID.
|
||||
func (store *store) References(id image.ID) []reference.Named {
|
||||
func (store *store) References(id image.ID) []Named {
|
||||
store.mu.RLock()
|
||||
defer store.mu.RUnlock()
|
||||
|
||||
// Convert the internal map to an array for two reasons:
|
||||
// 1) We must not return a mutable reference.
|
||||
// 1) We must not return a mutable
|
||||
// 2) It would be ugly to expose the extraneous map keys to callers.
|
||||
|
||||
var references []reference.Named
|
||||
var references []Named
|
||||
for _, ref := range store.referencesByIDCache[id] {
|
||||
references = append(references, ref)
|
||||
}
|
||||
|
@ -239,7 +222,7 @@ func (store *store) References(id image.ID) []reference.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 reference.Named) []Association {
|
||||
func (store *store) ReferencesByName(ref Named) []Association {
|
||||
store.mu.RLock()
|
||||
defer store.mu.RUnlock()
|
||||
|
||||
|
@ -250,7 +233,7 @@ func (store *store) ReferencesByName(ref reference.Named) []Association {
|
|||
|
||||
var associations []Association
|
||||
for refStr, refID := range repository {
|
||||
ref, err := reference.ParseNamed(refStr)
|
||||
ref, err := ParseNamed(refStr)
|
||||
if err != nil {
|
||||
// Should never happen
|
||||
return nil
|
||||
|
@ -299,13 +282,13 @@ func (store *store) reload() error {
|
|||
|
||||
for _, repository := range store.Repositories {
|
||||
for refStr, refID := range repository {
|
||||
ref, err := reference.ParseNamed(refStr)
|
||||
ref, err := ParseNamed(refStr)
|
||||
if err != nil {
|
||||
// Should never happen
|
||||
continue
|
||||
}
|
||||
if store.referencesByIDCache[refID] == nil {
|
||||
store.referencesByIDCache[refID] = make(map[string]reference.Named)
|
||||
store.referencesByIDCache[refID] = make(map[string]Named)
|
||||
}
|
||||
store.referencesByIDCache[refID][refStr] = ref
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package tag
|
||||
package reference
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
@ -8,7 +8,6 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/image"
|
||||
)
|
||||
|
||||
|
@ -40,13 +39,13 @@ func TestLoad(t *testing.T) {
|
|||
}
|
||||
jsonFile.Close()
|
||||
|
||||
store, err := NewTagStore(jsonFile.Name())
|
||||
store, err := NewReferenceStore(jsonFile.Name())
|
||||
if err != nil {
|
||||
t.Fatalf("error creating tag store: %v", err)
|
||||
}
|
||||
|
||||
for refStr, expectedID := range saveLoadTestCases {
|
||||
ref, err := reference.ParseNamed(refStr)
|
||||
ref, err := ParseNamed(refStr)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to parse reference: %v", err)
|
||||
}
|
||||
|
@ -69,17 +68,17 @@ func TestSave(t *testing.T) {
|
|||
jsonFile.Close()
|
||||
defer os.RemoveAll(jsonFile.Name())
|
||||
|
||||
store, err := NewTagStore(jsonFile.Name())
|
||||
store, err := NewReferenceStore(jsonFile.Name())
|
||||
if err != nil {
|
||||
t.Fatalf("error creating tag store: %v", err)
|
||||
}
|
||||
|
||||
for refStr, id := range saveLoadTestCases {
|
||||
ref, err := reference.ParseNamed(refStr)
|
||||
ref, err := ParseNamed(refStr)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to parse reference: %v", err)
|
||||
}
|
||||
if canonical, ok := ref.(reference.Canonical); ok {
|
||||
if canonical, ok := ref.(Canonical); ok {
|
||||
err = store.AddDigest(canonical, id, false)
|
||||
if err != nil {
|
||||
t.Fatalf("could not add digest reference %s: %v", refStr, err)
|
||||
|
@ -111,7 +110,7 @@ func TestAddDeleteGet(t *testing.T) {
|
|||
jsonFile.Close()
|
||||
defer os.RemoveAll(jsonFile.Name())
|
||||
|
||||
store, err := NewTagStore(jsonFile.Name())
|
||||
store, err := NewReferenceStore(jsonFile.Name())
|
||||
if err != nil {
|
||||
t.Fatalf("error creating tag store: %v", err)
|
||||
}
|
||||
|
@ -121,7 +120,7 @@ func TestAddDeleteGet(t *testing.T) {
|
|||
testImageID3 := image.ID("sha256:9655aef5fd742a1b4e1b7b163aa9f1c76c186304bf39102283d80927c916ca9e")
|
||||
|
||||
// Try adding a reference with no tag or digest
|
||||
nameOnly, err := reference.WithName("username/repo")
|
||||
nameOnly, err := WithName("username/repo")
|
||||
if err != nil {
|
||||
t.Fatalf("could not parse reference: %v", err)
|
||||
}
|
||||
|
@ -130,7 +129,7 @@ func TestAddDeleteGet(t *testing.T) {
|
|||
}
|
||||
|
||||
// Add a few references
|
||||
ref1, err := reference.ParseNamed("username/repo1:latest")
|
||||
ref1, err := ParseNamed("username/repo1:latest")
|
||||
if err != nil {
|
||||
t.Fatalf("could not parse reference: %v", err)
|
||||
}
|
||||
|
@ -138,7 +137,7 @@ func TestAddDeleteGet(t *testing.T) {
|
|||
t.Fatalf("error adding to store: %v", err)
|
||||
}
|
||||
|
||||
ref2, err := reference.ParseNamed("username/repo1:old")
|
||||
ref2, err := ParseNamed("username/repo1:old")
|
||||
if err != nil {
|
||||
t.Fatalf("could not parse reference: %v", err)
|
||||
}
|
||||
|
@ -146,7 +145,7 @@ func TestAddDeleteGet(t *testing.T) {
|
|||
t.Fatalf("error adding to store: %v", err)
|
||||
}
|
||||
|
||||
ref3, err := reference.ParseNamed("username/repo1:alias")
|
||||
ref3, err := ParseNamed("username/repo1:alias")
|
||||
if err != nil {
|
||||
t.Fatalf("could not parse reference: %v", err)
|
||||
}
|
||||
|
@ -154,7 +153,7 @@ func TestAddDeleteGet(t *testing.T) {
|
|||
t.Fatalf("error adding to store: %v", err)
|
||||
}
|
||||
|
||||
ref4, err := reference.ParseNamed("username/repo2:latest")
|
||||
ref4, err := ParseNamed("username/repo2:latest")
|
||||
if err != nil {
|
||||
t.Fatalf("could not parse reference: %v", err)
|
||||
}
|
||||
|
@ -162,11 +161,11 @@ func TestAddDeleteGet(t *testing.T) {
|
|||
t.Fatalf("error adding to store: %v", err)
|
||||
}
|
||||
|
||||
ref5, err := reference.ParseNamed("username/repo3@sha256:58153dfb11794fad694460162bf0cb0a4fa710cfa3f60979c177d920813e267c")
|
||||
ref5, err := ParseNamed("username/repo3@sha256:58153dfb11794fad694460162bf0cb0a4fa710cfa3f60979c177d920813e267c")
|
||||
if err != nil {
|
||||
t.Fatalf("could not parse reference: %v", err)
|
||||
}
|
||||
if err = store.AddDigest(ref5.(reference.Canonical), testImageID2, false); err != nil {
|
||||
if err = store.AddDigest(ref5.(Canonical), testImageID2, false); err != nil {
|
||||
t.Fatalf("error adding to store: %v", err)
|
||||
}
|
||||
|
||||
|
@ -229,7 +228,7 @@ func TestAddDeleteGet(t *testing.T) {
|
|||
}
|
||||
|
||||
// Get should return ErrDoesNotExist for a nonexistent repo
|
||||
nonExistRepo, err := reference.ParseNamed("username/nonexistrepo:latest")
|
||||
nonExistRepo, err := ParseNamed("username/nonexistrepo:latest")
|
||||
if err != nil {
|
||||
t.Fatalf("could not parse reference: %v", err)
|
||||
}
|
||||
|
@ -238,7 +237,7 @@ func TestAddDeleteGet(t *testing.T) {
|
|||
}
|
||||
|
||||
// Get should return ErrDoesNotExist for a nonexistent tag
|
||||
nonExistTag, err := reference.ParseNamed("username/repo1:nonexist")
|
||||
nonExistTag, err := ParseNamed("username/repo1:nonexist")
|
||||
if err != nil {
|
||||
t.Fatalf("could not parse reference: %v", err)
|
||||
}
|
||||
|
@ -264,7 +263,7 @@ func TestAddDeleteGet(t *testing.T) {
|
|||
}
|
||||
|
||||
// Check ReferencesByName
|
||||
repoName, err := reference.WithName("username/repo1")
|
||||
repoName, err := WithName("username/repo1")
|
||||
if err != nil {
|
||||
t.Fatalf("could not parse reference: %v", err)
|
||||
}
|
||||
|
@ -328,14 +327,14 @@ func TestInvalidTags(t *testing.T) {
|
|||
tmpDir, err := ioutil.TempDir("", "tag-store-test")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
store, err := NewTagStore(filepath.Join(tmpDir, "repositories.json"))
|
||||
store, err := NewReferenceStore(filepath.Join(tmpDir, "repositories.json"))
|
||||
if err != nil {
|
||||
t.Fatalf("error creating tag store: %v", err)
|
||||
}
|
||||
id := image.ID("sha256:470022b8af682154f57a2163d030eb369549549cba00edc69e1b99b46bb924d6")
|
||||
|
||||
// sha256 as repo name
|
||||
ref, err := reference.ParseNamed("sha256:abc")
|
||||
ref, err := ParseNamed("sha256:abc")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -345,7 +344,7 @@ func TestInvalidTags(t *testing.T) {
|
|||
}
|
||||
|
||||
// setting digest as a tag
|
||||
ref, err = reference.ParseNamed("registry@sha256:367eb40fd0330a7e464777121e39d2f5b3e8e23a1e159342e53ab05c9e4d94e6")
|
||||
ref, err = ParseNamed("registry@sha256:367eb40fd0330a7e464777121e39d2f5b3e8e23a1e159342e53ab05c9e4d94e6")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
|
@ -7,11 +7,10 @@ import (
|
|||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
registrytypes "github.com/docker/docker/api/types/registry"
|
||||
"github.com/docker/docker/image/v1"
|
||||
"github.com/docker/docker/opts"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
"github.com/docker/docker/reference"
|
||||
)
|
||||
|
||||
// Options holds command line options.
|
||||
|
@ -181,28 +180,15 @@ func ValidateMirror(val string) (string, error) {
|
|||
|
||||
// ValidateIndexName validates an index name.
|
||||
func ValidateIndexName(val string) (string, error) {
|
||||
// 'index.docker.io' => 'docker.io'
|
||||
if val == "index."+IndexName {
|
||||
val = IndexName
|
||||
if val == reference.LegacyDefaultHostname {
|
||||
val = reference.DefaultHostname
|
||||
}
|
||||
if strings.HasPrefix(val, "-") || strings.HasSuffix(val, "-") {
|
||||
return "", fmt.Errorf("Invalid index name (%s). Cannot begin or end with a hyphen.", val)
|
||||
}
|
||||
// *TODO: Check if valid hostname[:port]/ip[:port]?
|
||||
return val, nil
|
||||
}
|
||||
|
||||
func validateRemoteName(remoteName reference.Named) error {
|
||||
remoteNameStr := remoteName.Name()
|
||||
if !strings.Contains(remoteNameStr, "/") {
|
||||
// the repository name must not be a valid image ID
|
||||
if err := v1.ValidateID(remoteNameStr); err == nil {
|
||||
return fmt.Errorf("Invalid repository name (%s), cannot specify 64-byte hexadecimal strings", remoteName)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateNoSchema(reposName string) error {
|
||||
if strings.Contains(reposName, "://") {
|
||||
// It cannot contain a scheme!
|
||||
|
@ -211,29 +197,6 @@ func validateNoSchema(reposName string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ValidateRepositoryName validates a repository name
|
||||
func ValidateRepositoryName(reposName reference.Named) error {
|
||||
_, _, err := loadRepositoryName(reposName)
|
||||
return err
|
||||
}
|
||||
|
||||
// loadRepositoryName returns the repo name splitted into index name
|
||||
// and remote repo name. It returns an error if the name is not valid.
|
||||
func loadRepositoryName(reposName reference.Named) (string, reference.Named, error) {
|
||||
if err := validateNoSchema(reposName.Name()); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
indexName, remoteName, err := splitReposName(reposName)
|
||||
|
||||
if indexName, err = ValidateIndexName(indexName); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
if err = validateRemoteName(remoteName); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
return indexName, remoteName, nil
|
||||
}
|
||||
|
||||
// newIndexInfo returns IndexInfo configuration from indexName
|
||||
func newIndexInfo(config *registrytypes.ServiceConfig, indexName string) (*registrytypes.IndexInfo, error) {
|
||||
var err error
|
||||
|
@ -266,75 +229,14 @@ func GetAuthConfigKey(index *registrytypes.IndexInfo) string {
|
|||
return index.Name
|
||||
}
|
||||
|
||||
// splitReposName breaks a reposName into an index name and remote name
|
||||
func splitReposName(reposName reference.Named) (indexName string, remoteName reference.Named, err error) {
|
||||
var remoteNameStr string
|
||||
indexName, remoteNameStr = reference.SplitHostname(reposName)
|
||||
if indexName == "" || (!strings.Contains(indexName, ".") &&
|
||||
!strings.Contains(indexName, ":") && indexName != "localhost") {
|
||||
// This is a Docker Index repos (ex: samalba/hipache or ubuntu)
|
||||
// 'docker.io'
|
||||
indexName = IndexName
|
||||
remoteName = reposName
|
||||
} else {
|
||||
remoteName, err = reference.WithName(remoteNameStr)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// newRepositoryInfo validates and breaks down a repository name into a RepositoryInfo
|
||||
func newRepositoryInfo(config *registrytypes.ServiceConfig, reposName reference.Named) (*RepositoryInfo, error) {
|
||||
if err := validateNoSchema(reposName.Name()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
repoInfo := &RepositoryInfo{}
|
||||
var (
|
||||
indexName string
|
||||
err error
|
||||
)
|
||||
|
||||
indexName, repoInfo.RemoteName, err = loadRepositoryName(reposName)
|
||||
func newRepositoryInfo(config *registrytypes.ServiceConfig, name reference.Named) (*RepositoryInfo, error) {
|
||||
index, err := newIndexInfo(config, name.Hostname())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
repoInfo.Index, err = newIndexInfo(config, indexName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if repoInfo.Index.Official {
|
||||
repoInfo.LocalName, err = normalizeLibraryRepoName(repoInfo.RemoteName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
repoInfo.RemoteName = repoInfo.LocalName
|
||||
|
||||
// If the normalized name does not contain a '/' (e.g. "foo")
|
||||
// then it is an official repo.
|
||||
if strings.IndexRune(repoInfo.RemoteName.Name(), '/') == -1 {
|
||||
repoInfo.Official = true
|
||||
// Fix up remote name for official repos.
|
||||
repoInfo.RemoteName, err = reference.WithName("library/" + repoInfo.RemoteName.Name())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
repoInfo.CanonicalName, err = reference.WithName("docker.io/" + repoInfo.RemoteName.Name())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
repoInfo.LocalName, err = localNameFromRemote(repoInfo.Index.Name, repoInfo.RemoteName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
repoInfo.CanonicalName = repoInfo.LocalName
|
||||
}
|
||||
|
||||
return repoInfo, nil
|
||||
official := !strings.ContainsRune(name.Name(), '/')
|
||||
return &RepositoryInfo{name, index, official}, nil
|
||||
}
|
||||
|
||||
// ParseRepositoryInfo performs the breakdown of a repository name into a RepositoryInfo, but
|
||||
|
@ -353,70 +255,3 @@ func ParseSearchIndexInfo(reposName string) (*registrytypes.IndexInfo, error) {
|
|||
}
|
||||
return indexInfo, nil
|
||||
}
|
||||
|
||||
// NormalizeLocalName transforms a repository name into a normalized LocalName
|
||||
// Passes through the name without transformation on error (image id, etc)
|
||||
// It does not use the repository info because we don't want to load
|
||||
// the repository index and do request over the network.
|
||||
func NormalizeLocalName(name reference.Named) reference.Named {
|
||||
indexName, remoteName, err := loadRepositoryName(name)
|
||||
if err != nil {
|
||||
return name
|
||||
}
|
||||
|
||||
var officialIndex bool
|
||||
// Return any configured index info, first.
|
||||
if index, ok := emptyServiceConfig.IndexConfigs[indexName]; ok {
|
||||
officialIndex = index.Official
|
||||
}
|
||||
|
||||
if officialIndex {
|
||||
localName, err := normalizeLibraryRepoName(remoteName)
|
||||
if err != nil {
|
||||
return name
|
||||
}
|
||||
return localName
|
||||
}
|
||||
localName, err := localNameFromRemote(indexName, remoteName)
|
||||
if err != nil {
|
||||
return name
|
||||
}
|
||||
return localName
|
||||
}
|
||||
|
||||
// normalizeLibraryRepoName removes the library prefix from
|
||||
// the repository name for official repos.
|
||||
func normalizeLibraryRepoName(name reference.Named) (reference.Named, error) {
|
||||
if strings.HasPrefix(name.Name(), "library/") {
|
||||
// If pull "library/foo", it's stored locally under "foo"
|
||||
return reference.WithName(strings.SplitN(name.Name(), "/", 2)[1])
|
||||
}
|
||||
return name, nil
|
||||
}
|
||||
|
||||
// localNameFromRemote combines the index name and the repo remote name
|
||||
// to generate a repo local name.
|
||||
func localNameFromRemote(indexName string, remoteName reference.Named) (reference.Named, error) {
|
||||
return reference.WithName(indexName + "/" + remoteName.Name())
|
||||
}
|
||||
|
||||
// NormalizeLocalReference transforms a reference to use a normalized LocalName
|
||||
// for the name poriton. Passes through the reference without transformation on
|
||||
// error.
|
||||
func NormalizeLocalReference(ref reference.Named) reference.Named {
|
||||
localName := NormalizeLocalName(ref)
|
||||
if tagged, isTagged := ref.(reference.Tagged); isTagged {
|
||||
newRef, err := reference.WithTag(localName, tagged.Tag())
|
||||
if err != nil {
|
||||
return ref
|
||||
}
|
||||
return newRef
|
||||
} else if digested, isDigested := ref.(reference.Digested); isDigested {
|
||||
newRef, err := reference.WithDigest(localName, digested.Digest())
|
||||
if err != nil {
|
||||
return ref
|
||||
}
|
||||
return newRef
|
||||
}
|
||||
return localName
|
||||
}
|
||||
|
|
|
@ -15,9 +15,9 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
registrytypes "github.com/docker/docker/api/types/registry"
|
||||
"github.com/docker/docker/opts"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/gorilla/mux"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
|
@ -356,7 +356,6 @@ func handlerGetDeleteTags(w http.ResponseWriter, r *http.Request) {
|
|||
apiError(w, "Could not parse repository", 400)
|
||||
return
|
||||
}
|
||||
repositoryName = NormalizeLocalName(repositoryName)
|
||||
tags, exists := testRepositories[repositoryName.String()]
|
||||
if !exists {
|
||||
apiError(w, "Repository not found", 404)
|
||||
|
@ -380,7 +379,6 @@ func handlerGetTag(w http.ResponseWriter, r *http.Request) {
|
|||
apiError(w, "Could not parse repository", 400)
|
||||
return
|
||||
}
|
||||
repositoryName = NormalizeLocalName(repositoryName)
|
||||
tagName := vars["tag"]
|
||||
tags, exists := testRepositories[repositoryName.String()]
|
||||
if !exists {
|
||||
|
@ -405,7 +403,6 @@ func handlerPutTag(w http.ResponseWriter, r *http.Request) {
|
|||
apiError(w, "Could not parse repository", 400)
|
||||
return
|
||||
}
|
||||
repositoryName = NormalizeLocalName(repositoryName)
|
||||
tagName := vars["tag"]
|
||||
tags, exists := testRepositories[repositoryName.String()]
|
||||
if !exists {
|
||||
|
|
|
@ -8,10 +8,10 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/registry/client/transport"
|
||||
"github.com/docker/docker/api/types"
|
||||
registrytypes "github.com/docker/docker/api/types/registry"
|
||||
"github.com/docker/docker/reference"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -307,71 +307,24 @@ func TestPushImageLayerRegistry(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestValidateRepositoryName(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 {
|
||||
named, err := reference.WithName(name)
|
||||
if err == nil {
|
||||
err := ValidateRepositoryName(named)
|
||||
assertNotEqual(t, err, nil, "Expected invalid repo name: "+name)
|
||||
}
|
||||
}
|
||||
|
||||
for _, name := range validRepoNames {
|
||||
named, err := reference.WithName(name)
|
||||
if err != nil {
|
||||
t.Fatalf("could not parse valid name: %s", name)
|
||||
}
|
||||
err = ValidateRepositoryName(named)
|
||||
assertEqual(t, err, nil, "Expected valid repo name: "+name)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseRepositoryInfo(t *testing.T) {
|
||||
withName := func(name string) reference.Named {
|
||||
named, err := reference.WithName(name)
|
||||
if err != nil {
|
||||
t.Fatalf("could not parse reference %s", name)
|
||||
}
|
||||
return named
|
||||
type staticRepositoryInfo struct {
|
||||
Index *registrytypes.IndexInfo
|
||||
RemoteName string
|
||||
CanonicalName string
|
||||
LocalName string
|
||||
Official bool
|
||||
}
|
||||
|
||||
expectedRepoInfos := map[string]RepositoryInfo{
|
||||
expectedRepoInfos := map[string]staticRepositoryInfo{
|
||||
"fooo/bar": {
|
||||
Index: ®istrytypes.IndexInfo{
|
||||
Name: IndexName,
|
||||
Official: true,
|
||||
},
|
||||
RemoteName: withName("fooo/bar"),
|
||||
LocalName: withName("fooo/bar"),
|
||||
CanonicalName: withName("docker.io/fooo/bar"),
|
||||
RemoteName: "fooo/bar",
|
||||
LocalName: "fooo/bar",
|
||||
CanonicalName: "docker.io/fooo/bar",
|
||||
Official: false,
|
||||
},
|
||||
"library/ubuntu": {
|
||||
|
@ -379,9 +332,9 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||
Name: IndexName,
|
||||
Official: true,
|
||||
},
|
||||
RemoteName: withName("library/ubuntu"),
|
||||
LocalName: withName("ubuntu"),
|
||||
CanonicalName: withName("docker.io/library/ubuntu"),
|
||||
RemoteName: "library/ubuntu",
|
||||
LocalName: "ubuntu",
|
||||
CanonicalName: "docker.io/library/ubuntu",
|
||||
Official: true,
|
||||
},
|
||||
"nonlibrary/ubuntu": {
|
||||
|
@ -389,9 +342,9 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||
Name: IndexName,
|
||||
Official: true,
|
||||
},
|
||||
RemoteName: withName("nonlibrary/ubuntu"),
|
||||
LocalName: withName("nonlibrary/ubuntu"),
|
||||
CanonicalName: withName("docker.io/nonlibrary/ubuntu"),
|
||||
RemoteName: "nonlibrary/ubuntu",
|
||||
LocalName: "nonlibrary/ubuntu",
|
||||
CanonicalName: "docker.io/nonlibrary/ubuntu",
|
||||
Official: false,
|
||||
},
|
||||
"ubuntu": {
|
||||
|
@ -399,9 +352,9 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||
Name: IndexName,
|
||||
Official: true,
|
||||
},
|
||||
RemoteName: withName("library/ubuntu"),
|
||||
LocalName: withName("ubuntu"),
|
||||
CanonicalName: withName("docker.io/library/ubuntu"),
|
||||
RemoteName: "library/ubuntu",
|
||||
LocalName: "ubuntu",
|
||||
CanonicalName: "docker.io/library/ubuntu",
|
||||
Official: true,
|
||||
},
|
||||
"other/library": {
|
||||
|
@ -409,9 +362,9 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||
Name: IndexName,
|
||||
Official: true,
|
||||
},
|
||||
RemoteName: withName("other/library"),
|
||||
LocalName: withName("other/library"),
|
||||
CanonicalName: withName("docker.io/other/library"),
|
||||
RemoteName: "other/library",
|
||||
LocalName: "other/library",
|
||||
CanonicalName: "docker.io/other/library",
|
||||
Official: false,
|
||||
},
|
||||
"127.0.0.1:8000/private/moonbase": {
|
||||
|
@ -419,9 +372,9 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||
Name: "127.0.0.1:8000",
|
||||
Official: false,
|
||||
},
|
||||
RemoteName: withName("private/moonbase"),
|
||||
LocalName: withName("127.0.0.1:8000/private/moonbase"),
|
||||
CanonicalName: withName("127.0.0.1:8000/private/moonbase"),
|
||||
RemoteName: "private/moonbase",
|
||||
LocalName: "127.0.0.1:8000/private/moonbase",
|
||||
CanonicalName: "127.0.0.1:8000/private/moonbase",
|
||||
Official: false,
|
||||
},
|
||||
"127.0.0.1:8000/privatebase": {
|
||||
|
@ -429,9 +382,9 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||
Name: "127.0.0.1:8000",
|
||||
Official: false,
|
||||
},
|
||||
RemoteName: withName("privatebase"),
|
||||
LocalName: withName("127.0.0.1:8000/privatebase"),
|
||||
CanonicalName: withName("127.0.0.1:8000/privatebase"),
|
||||
RemoteName: "privatebase",
|
||||
LocalName: "127.0.0.1:8000/privatebase",
|
||||
CanonicalName: "127.0.0.1:8000/privatebase",
|
||||
Official: false,
|
||||
},
|
||||
"localhost:8000/private/moonbase": {
|
||||
|
@ -439,9 +392,9 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||
Name: "localhost:8000",
|
||||
Official: false,
|
||||
},
|
||||
RemoteName: withName("private/moonbase"),
|
||||
LocalName: withName("localhost:8000/private/moonbase"),
|
||||
CanonicalName: withName("localhost:8000/private/moonbase"),
|
||||
RemoteName: "private/moonbase",
|
||||
LocalName: "localhost:8000/private/moonbase",
|
||||
CanonicalName: "localhost:8000/private/moonbase",
|
||||
Official: false,
|
||||
},
|
||||
"localhost:8000/privatebase": {
|
||||
|
@ -449,9 +402,9 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||
Name: "localhost:8000",
|
||||
Official: false,
|
||||
},
|
||||
RemoteName: withName("privatebase"),
|
||||
LocalName: withName("localhost:8000/privatebase"),
|
||||
CanonicalName: withName("localhost:8000/privatebase"),
|
||||
RemoteName: "privatebase",
|
||||
LocalName: "localhost:8000/privatebase",
|
||||
CanonicalName: "localhost:8000/privatebase",
|
||||
Official: false,
|
||||
},
|
||||
"example.com/private/moonbase": {
|
||||
|
@ -459,9 +412,9 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||
Name: "example.com",
|
||||
Official: false,
|
||||
},
|
||||
RemoteName: withName("private/moonbase"),
|
||||
LocalName: withName("example.com/private/moonbase"),
|
||||
CanonicalName: withName("example.com/private/moonbase"),
|
||||
RemoteName: "private/moonbase",
|
||||
LocalName: "example.com/private/moonbase",
|
||||
CanonicalName: "example.com/private/moonbase",
|
||||
Official: false,
|
||||
},
|
||||
"example.com/privatebase": {
|
||||
|
@ -469,9 +422,9 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||
Name: "example.com",
|
||||
Official: false,
|
||||
},
|
||||
RemoteName: withName("privatebase"),
|
||||
LocalName: withName("example.com/privatebase"),
|
||||
CanonicalName: withName("example.com/privatebase"),
|
||||
RemoteName: "privatebase",
|
||||
LocalName: "example.com/privatebase",
|
||||
CanonicalName: "example.com/privatebase",
|
||||
Official: false,
|
||||
},
|
||||
"example.com:8000/private/moonbase": {
|
||||
|
@ -479,9 +432,9 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||
Name: "example.com:8000",
|
||||
Official: false,
|
||||
},
|
||||
RemoteName: withName("private/moonbase"),
|
||||
LocalName: withName("example.com:8000/private/moonbase"),
|
||||
CanonicalName: withName("example.com:8000/private/moonbase"),
|
||||
RemoteName: "private/moonbase",
|
||||
LocalName: "example.com:8000/private/moonbase",
|
||||
CanonicalName: "example.com:8000/private/moonbase",
|
||||
Official: false,
|
||||
},
|
||||
"example.com:8000/privatebase": {
|
||||
|
@ -489,9 +442,9 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||
Name: "example.com:8000",
|
||||
Official: false,
|
||||
},
|
||||
RemoteName: withName("privatebase"),
|
||||
LocalName: withName("example.com:8000/privatebase"),
|
||||
CanonicalName: withName("example.com:8000/privatebase"),
|
||||
RemoteName: "privatebase",
|
||||
LocalName: "example.com:8000/privatebase",
|
||||
CanonicalName: "example.com:8000/privatebase",
|
||||
Official: false,
|
||||
},
|
||||
"localhost/private/moonbase": {
|
||||
|
@ -499,9 +452,9 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||
Name: "localhost",
|
||||
Official: false,
|
||||
},
|
||||
RemoteName: withName("private/moonbase"),
|
||||
LocalName: withName("localhost/private/moonbase"),
|
||||
CanonicalName: withName("localhost/private/moonbase"),
|
||||
RemoteName: "private/moonbase",
|
||||
LocalName: "localhost/private/moonbase",
|
||||
CanonicalName: "localhost/private/moonbase",
|
||||
Official: false,
|
||||
},
|
||||
"localhost/privatebase": {
|
||||
|
@ -509,9 +462,9 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||
Name: "localhost",
|
||||
Official: false,
|
||||
},
|
||||
RemoteName: withName("privatebase"),
|
||||
LocalName: withName("localhost/privatebase"),
|
||||
CanonicalName: withName("localhost/privatebase"),
|
||||
RemoteName: "privatebase",
|
||||
LocalName: "localhost/privatebase",
|
||||
CanonicalName: "localhost/privatebase",
|
||||
Official: false,
|
||||
},
|
||||
IndexName + "/public/moonbase": {
|
||||
|
@ -519,9 +472,9 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||
Name: IndexName,
|
||||
Official: true,
|
||||
},
|
||||
RemoteName: withName("public/moonbase"),
|
||||
LocalName: withName("public/moonbase"),
|
||||
CanonicalName: withName("docker.io/public/moonbase"),
|
||||
RemoteName: "public/moonbase",
|
||||
LocalName: "public/moonbase",
|
||||
CanonicalName: "docker.io/public/moonbase",
|
||||
Official: false,
|
||||
},
|
||||
"index." + IndexName + "/public/moonbase": {
|
||||
|
@ -529,9 +482,9 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||
Name: IndexName,
|
||||
Official: true,
|
||||
},
|
||||
RemoteName: withName("public/moonbase"),
|
||||
LocalName: withName("public/moonbase"),
|
||||
CanonicalName: withName("docker.io/public/moonbase"),
|
||||
RemoteName: "public/moonbase",
|
||||
LocalName: "public/moonbase",
|
||||
CanonicalName: "docker.io/public/moonbase",
|
||||
Official: false,
|
||||
},
|
||||
"ubuntu-12.04-base": {
|
||||
|
@ -539,9 +492,9 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||
Name: IndexName,
|
||||
Official: true,
|
||||
},
|
||||
RemoteName: withName("library/ubuntu-12.04-base"),
|
||||
LocalName: withName("ubuntu-12.04-base"),
|
||||
CanonicalName: withName("docker.io/library/ubuntu-12.04-base"),
|
||||
RemoteName: "library/ubuntu-12.04-base",
|
||||
LocalName: "ubuntu-12.04-base",
|
||||
CanonicalName: "docker.io/library/ubuntu-12.04-base",
|
||||
Official: true,
|
||||
},
|
||||
IndexName + "/ubuntu-12.04-base": {
|
||||
|
@ -549,9 +502,9 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||
Name: IndexName,
|
||||
Official: true,
|
||||
},
|
||||
RemoteName: withName("library/ubuntu-12.04-base"),
|
||||
LocalName: withName("ubuntu-12.04-base"),
|
||||
CanonicalName: withName("docker.io/library/ubuntu-12.04-base"),
|
||||
RemoteName: "library/ubuntu-12.04-base",
|
||||
LocalName: "ubuntu-12.04-base",
|
||||
CanonicalName: "docker.io/library/ubuntu-12.04-base",
|
||||
Official: true,
|
||||
},
|
||||
"index." + IndexName + "/ubuntu-12.04-base": {
|
||||
|
@ -559,9 +512,9 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||
Name: IndexName,
|
||||
Official: true,
|
||||
},
|
||||
RemoteName: withName("library/ubuntu-12.04-base"),
|
||||
LocalName: withName("ubuntu-12.04-base"),
|
||||
CanonicalName: withName("docker.io/library/ubuntu-12.04-base"),
|
||||
RemoteName: "library/ubuntu-12.04-base",
|
||||
LocalName: "ubuntu-12.04-base",
|
||||
CanonicalName: "docker.io/library/ubuntu-12.04-base",
|
||||
Official: true,
|
||||
},
|
||||
}
|
||||
|
@ -577,9 +530,9 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||
t.Error(err)
|
||||
} else {
|
||||
checkEqual(t, repoInfo.Index.Name, expectedRepoInfo.Index.Name, reposName)
|
||||
checkEqual(t, repoInfo.RemoteName.String(), expectedRepoInfo.RemoteName.String(), reposName)
|
||||
checkEqual(t, repoInfo.LocalName.String(), expectedRepoInfo.LocalName.String(), reposName)
|
||||
checkEqual(t, repoInfo.CanonicalName.String(), expectedRepoInfo.CanonicalName.String(), reposName)
|
||||
checkEqual(t, repoInfo.RemoteName(), expectedRepoInfo.RemoteName, reposName)
|
||||
checkEqual(t, repoInfo.Name(), expectedRepoInfo.LocalName, reposName)
|
||||
checkEqual(t, repoInfo.FullName(), expectedRepoInfo.CanonicalName, reposName)
|
||||
checkEqual(t, repoInfo.Index.Official, expectedRepoInfo.Index.Official, reposName)
|
||||
checkEqual(t, repoInfo.Official, expectedRepoInfo.Official, reposName)
|
||||
}
|
||||
|
@ -806,82 +759,6 @@ func TestSearchRepositories(t *testing.T) {
|
|||
assertEqual(t, results.Results[0].StarCount, 42, "Expected 'fakeimage' to have 42 stars")
|
||||
}
|
||||
|
||||
func TestValidRemoteName(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 {
|
||||
repositoryRef, err := reference.WithName(repositoryName)
|
||||
if err != nil {
|
||||
t.Errorf("Repository name should be valid: %v. Error: %v", repositoryName, err)
|
||||
}
|
||||
if err := validateRemoteName(repositoryRef); 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 {
|
||||
repositoryRef, err := reference.ParseNamed(repositoryName)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if err := validateRemoteName(repositoryRef); err == nil {
|
||||
t.Errorf("Repository name should be invalid: %v", repositoryName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTrustedLocation(t *testing.T) {
|
||||
for _, url := range []string{"http://example.com", "https://example.com:7777", "http://docker.io", "http://test.docker.com", "https://fakedocker.com"} {
|
||||
req, _ := http.NewRequest("GET", url, nil)
|
||||
|
|
|
@ -6,10 +6,10 @@ import (
|
|||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/registry/client/auth"
|
||||
"github.com/docker/docker/api/types"
|
||||
registrytypes "github.com/docker/docker/api/types/registry"
|
||||
"github.com/docker/docker/reference"
|
||||
)
|
||||
|
||||
// Service is a registry service. It tracks configuration data such as a list
|
||||
|
|
|
@ -4,14 +4,14 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/pkg/tlsconfig"
|
||||
"github.com/docker/docker/reference"
|
||||
)
|
||||
|
||||
func (s *Service) lookupV1Endpoints(repoName reference.Named) (endpoints []APIEndpoint, err error) {
|
||||
var cfg = tlsconfig.ServerDefault
|
||||
tlsConfig := &cfg
|
||||
nameString := repoName.Name()
|
||||
nameString := repoName.FullName()
|
||||
if strings.HasPrefix(nameString, DefaultNamespace+"/") {
|
||||
endpoints = append(endpoints, APIEndpoint{
|
||||
URL: DefaultV1Registry,
|
||||
|
|
|
@ -4,15 +4,15 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/registry/client/auth"
|
||||
"github.com/docker/docker/pkg/tlsconfig"
|
||||
"github.com/docker/docker/reference"
|
||||
)
|
||||
|
||||
func (s *Service) lookupV2Endpoints(repoName reference.Named) (endpoints []APIEndpoint, err error) {
|
||||
var cfg = tlsconfig.ServerDefault
|
||||
tlsConfig := &cfg
|
||||
nameString := repoName.Name()
|
||||
nameString := repoName.FullName()
|
||||
if strings.HasPrefix(nameString, DefaultNamespace+"/") {
|
||||
// v2 mirrors
|
||||
for _, mirror := range s.Config.Mirrors {
|
||||
|
|
|
@ -19,13 +19,13 @@ import (
|
|||
"strings"
|
||||
|
||||
"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/httputils"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/docker/pkg/tarsum"
|
||||
"github.com/docker/docker/reference"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -312,7 +312,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.Name()
|
||||
repository := repositoryRef.RemoteName()
|
||||
|
||||
if strings.Count(repository, "/") == 0 {
|
||||
// This will be removed once the registry supports auto-resolution on
|
||||
|
@ -350,7 +350,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.Name()
|
||||
repository := repositoryRef.RemoteName()
|
||||
|
||||
if strings.Count(repository, "/") == 0 {
|
||||
// This will be removed once the registry supports auto-resolution on
|
||||
|
@ -403,8 +403,8 @@ func buildEndpointsList(headers []string, indexEp string) ([]string, error) {
|
|||
}
|
||||
|
||||
// GetRepositoryData returns lists of images and endpoints for the repository
|
||||
func (r *Session) GetRepositoryData(remote reference.Named) (*RepositoryData, error) {
|
||||
repositoryTarget := fmt.Sprintf("%srepositories/%s/images", r.indexEndpoint.VersionString(1), remote.Name())
|
||||
func (r *Session) GetRepositoryData(name reference.Named) (*RepositoryData, error) {
|
||||
repositoryTarget := fmt.Sprintf("%srepositories/%s/images", r.indexEndpoint.VersionString(1), name.RemoteName())
|
||||
|
||||
logrus.Debugf("[registry] Calling GET %s", repositoryTarget)
|
||||
|
||||
|
@ -438,7 +438,7 @@ func (r *Session) GetRepositoryData(remote reference.Named) (*RepositoryData, er
|
|||
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, remote.Name(), errBody), res)
|
||||
return nil, httputils.NewHTTPRequestError(fmt.Sprintf("Error: Status %d trying to pull repository %s: %q", res.StatusCode, name.RemoteName(), errBody), res)
|
||||
}
|
||||
|
||||
var endpoints []string
|
||||
|
@ -593,7 +593,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.Name(), tag)
|
||||
path := fmt.Sprintf("repositories/%s/tags/%s", remote.RemoteName(), tag)
|
||||
|
||||
req, err := http.NewRequest("PUT", registry+path, strings.NewReader(revision))
|
||||
if err != nil {
|
||||
|
@ -607,7 +607,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.Name()), res)
|
||||
return httputils.NewHTTPRequestError(fmt.Sprintf("Internal server error: %d trying to push tag %s on %s", res.StatusCode, tag, remote.RemoteName()), res)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -633,7 +633,7 @@ func (r *Session) PushImageJSONIndex(remote reference.Named, imgList []*ImgData,
|
|||
if validate {
|
||||
suffix = "images"
|
||||
}
|
||||
u := fmt.Sprintf("%srepositories/%s/%s", r.indexEndpoint.VersionString(1), remote.Name(), suffix)
|
||||
u := fmt.Sprintf("%srepositories/%s/%s", r.indexEndpoint.VersionString(1), remote.RemoteName(), suffix)
|
||||
logrus.Debugf("[registry] PUT %s", u)
|
||||
logrus.Debugf("Image list pushed to index:\n%s", imgListJSON)
|
||||
headers := map[string][]string{
|
||||
|
@ -671,7 +671,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.Name(), errBody), res)
|
||||
return nil, httputils.NewHTTPRequestError(fmt.Sprintf("Error: Status %d trying to push repository %s: %q", res.StatusCode, remote.RemoteName(), errBody), res)
|
||||
}
|
||||
tokens = res.Header["X-Docker-Token"]
|
||||
logrus.Debugf("Auth token: %v", tokens)
|
||||
|
@ -689,7 +689,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.Name(), errBody), res)
|
||||
return nil, httputils.NewHTTPRequestError(fmt.Sprintf("Error: Status %d trying to push checksums %s: %q", res.StatusCode, remote.RemoteName(), 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, and list of tokens
|
||||
|
@ -60,17 +60,9 @@ const (
|
|||
|
||||
// RepositoryInfo describes a repository
|
||||
type RepositoryInfo struct {
|
||||
reference.Named
|
||||
// Index points to registry information
|
||||
Index *registrytypes.IndexInfo
|
||||
// RemoteName is the remote name of the repository, such as
|
||||
// "library/ubuntu-12.04-base"
|
||||
RemoteName reference.Named
|
||||
// LocalName is the local name of the repository, such as
|
||||
// "ubuntu-12.04-base"
|
||||
LocalName reference.Named
|
||||
// CanonicalName is the canonical name of the repository, such as
|
||||
// "docker.io/library/ubuntu-12.04-base"
|
||||
CanonicalName reference.Named
|
||||
// Official indicates whether the repository is considered official.
|
||||
// If the registry is official, and the normalized name does not
|
||||
// contain a '/' (e.g. "foo"), then it is considered an official repo.
|
||||
|
|
Loading…
Add table
Reference in a new issue