mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Merge pull request #30457 from dmcgowan/distribution-reference-update-2
reference: use distribution reference and remove fork
This commit is contained in:
commit
254fc83cba
104 changed files with 758 additions and 1267 deletions
|
@ -4,9 +4,9 @@ import (
|
|||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
enginetypes "github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/reference"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
|
|
|
@ -7,13 +7,12 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
distreference "github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/server/httputils"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/pkg/streamformatter"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
@ -47,39 +46,27 @@ func parseHeaders(headers http.Header) (map[string][]string, *types.AuthConfig)
|
|||
// be returned.
|
||||
func parseRemoteRef(remote string) (reference.Named, string, error) {
|
||||
// Parse remote reference, supporting remotes with name and tag
|
||||
// NOTE: Using distribution reference to handle references
|
||||
// containing both a name and digest
|
||||
remoteRef, err := distreference.ParseNamed(remote)
|
||||
remoteRef, err := reference.ParseNormalizedNamed(remote)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
var tag string
|
||||
if t, ok := remoteRef.(distreference.Tagged); ok {
|
||||
tag = t.Tag()
|
||||
type canonicalWithTag interface {
|
||||
reference.Canonical
|
||||
Tag() string
|
||||
}
|
||||
|
||||
// Convert distribution reference to docker reference
|
||||
// TODO: remove when docker reference changes reconciled upstream
|
||||
ref, err := reference.WithName(remoteRef.Name())
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
if d, ok := remoteRef.(distreference.Digested); ok {
|
||||
ref, err = reference.WithDigest(ref, d.Digest())
|
||||
if canonical, ok := remoteRef.(canonicalWithTag); ok {
|
||||
remoteRef, err = reference.WithDigest(reference.TrimNamed(remoteRef), canonical.Digest())
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
} else if tag != "" {
|
||||
ref, err = reference.WithTag(ref, tag)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
} else {
|
||||
ref = reference.WithDefaultTag(ref)
|
||||
return remoteRef, canonical.Tag(), nil
|
||||
}
|
||||
|
||||
return ref, tag, nil
|
||||
remoteRef = reference.TagNameOnly(remoteRef)
|
||||
|
||||
return remoteRef, "", nil
|
||||
}
|
||||
|
||||
func (pr *pluginRouter) getPrivileges(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
|
@ -188,24 +175,24 @@ func getName(ref reference.Named, tag, name string) (string, error) {
|
|||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
name = nt.String()
|
||||
name = reference.FamiliarString(nt)
|
||||
} else {
|
||||
name = reference.WithDefaultTag(trimmed).String()
|
||||
name = reference.FamiliarString(reference.TagNameOnly(trimmed))
|
||||
}
|
||||
} else {
|
||||
name = ref.String()
|
||||
name = reference.FamiliarString(ref)
|
||||
}
|
||||
} else {
|
||||
localRef, err := reference.ParseNamed(name)
|
||||
localRef, err := reference.ParseNormalizedNamed(name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if _, ok := localRef.(reference.Canonical); ok {
|
||||
return "", errors.New("cannot use digest in plugin tag")
|
||||
}
|
||||
if distreference.IsNameOnly(localRef) {
|
||||
if reference.IsNameOnly(localRef) {
|
||||
// TODO: log change in name to out stream
|
||||
name = reference.WithDefaultTag(localRef).String()
|
||||
name = reference.FamiliarString(reference.TagNameOnly(localRef))
|
||||
}
|
||||
}
|
||||
return name, nil
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
package reference
|
||||
|
||||
import (
|
||||
distreference "github.com/docker/distribution/reference"
|
||||
)
|
||||
|
||||
// Parse parses the given references and returns the repository and
|
||||
// tag (if present) from it. If there is an error during parsing, it will
|
||||
// return an error.
|
||||
func Parse(ref string) (string, string, error) {
|
||||
distributionRef, err := distreference.ParseNamed(ref)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
tag := GetTagFromNamedRef(distributionRef)
|
||||
return distributionRef.Name(), tag, nil
|
||||
}
|
||||
|
||||
// GetTagFromNamedRef returns a tag from the specified reference.
|
||||
// This function is necessary as long as the docker "server" api makes the distinction between repository
|
||||
// and tags.
|
||||
func GetTagFromNamedRef(ref distreference.Named) string {
|
||||
var tag string
|
||||
switch x := ref.(type) {
|
||||
case distreference.Digested:
|
||||
tag = x.Digest().String()
|
||||
case distreference.NamedTagged:
|
||||
tag = x.Tag()
|
||||
default:
|
||||
tag = "latest"
|
||||
}
|
||||
return tag
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
package reference
|
||||
|
||||
import (
|
||||
_ "crypto/sha256"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParse(t *testing.T) {
|
||||
testCases := []struct {
|
||||
ref string
|
||||
expectedName string
|
||||
expectedTag string
|
||||
expectedError bool
|
||||
}{
|
||||
{
|
||||
ref: "",
|
||||
expectedName: "",
|
||||
expectedTag: "",
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
ref: "repository",
|
||||
expectedName: "repository",
|
||||
expectedTag: "latest",
|
||||
expectedError: false,
|
||||
},
|
||||
{
|
||||
ref: "repository:tag",
|
||||
expectedName: "repository",
|
||||
expectedTag: "tag",
|
||||
expectedError: false,
|
||||
},
|
||||
{
|
||||
ref: "test.com/repository",
|
||||
expectedName: "test.com/repository",
|
||||
expectedTag: "latest",
|
||||
expectedError: false,
|
||||
},
|
||||
{
|
||||
ref: "test.com:5000/test/repository",
|
||||
expectedName: "test.com:5000/test/repository",
|
||||
expectedTag: "latest",
|
||||
expectedError: false,
|
||||
},
|
||||
{
|
||||
ref: "test.com:5000/repo@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
expectedName: "test.com:5000/repo",
|
||||
expectedTag: "sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
expectedError: false,
|
||||
},
|
||||
{
|
||||
ref: "test.com:5000/repo:tag@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
expectedName: "test.com:5000/repo",
|
||||
expectedTag: "sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
expectedError: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range testCases {
|
||||
name, tag, err := Parse(c.ref)
|
||||
if err != nil && c.expectedError {
|
||||
continue
|
||||
} else if err != nil {
|
||||
t.Fatalf("error with %s: %s", c.ref, err.Error())
|
||||
}
|
||||
if name != c.expectedName {
|
||||
t.Fatalf("expected name %s, got %s", c.expectedName, name)
|
||||
}
|
||||
if tag != c.expectedTag {
|
||||
t.Fatalf("expected tag %s, got %s", c.expectedTag, tag)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,11 +9,11 @@ import (
|
|||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/reference"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution/reference"
|
||||
apierrors "github.com/docker/docker/api/errors"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
|
@ -19,7 +20,6 @@ import (
|
|||
"github.com/docker/docker/builder/dockerfile/parser"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/docker/reference"
|
||||
perrors "github.com/pkg/errors"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
@ -178,23 +178,16 @@ func sanitizeRepoAndTags(names []string) ([]reference.Named, error) {
|
|||
continue
|
||||
}
|
||||
|
||||
ref, err := reference.ParseNamed(repo)
|
||||
ref, err := reference.ParseNormalizedNamed(repo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ref = reference.WithDefaultTag(ref)
|
||||
|
||||
if _, isCanonical := ref.(reference.Canonical); isCanonical {
|
||||
return nil, errors.New("build tag cannot contain a digest")
|
||||
}
|
||||
|
||||
if _, isTagged := ref.(reference.NamedTagged); !isTagged {
|
||||
ref, err = reference.WithTag(ref, reference.DefaultTag)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
ref = reference.TagNameOnly(ref)
|
||||
|
||||
nameWithTag := ref.String()
|
||||
|
||||
|
|
|
@ -168,11 +168,7 @@ func createContainer(ctx context.Context, dockerCli *command.DockerCli, config *
|
|||
return nil, err
|
||||
}
|
||||
if named, ok := ref.(reference.Named); ok {
|
||||
if reference.IsNameOnly(named) {
|
||||
namedRef = reference.EnsureTagged(named)
|
||||
} else {
|
||||
namedRef = named
|
||||
}
|
||||
namedRef = reference.TagNameOnly(named)
|
||||
|
||||
if taggedRef, ok := namedRef.(reference.NamedTagged); ok && command.IsTrusted() {
|
||||
var err error
|
||||
|
|
|
@ -94,12 +94,12 @@ func (ctx *DiskUsageContext) Write() {
|
|||
tag := "<none>"
|
||||
if len(i.RepoTags) > 0 && !isDangling(*i) {
|
||||
// Only show the first tag
|
||||
ref, err := reference.ParseNamed(i.RepoTags[0])
|
||||
ref, err := reference.ParseNormalizedNamed(i.RepoTags[0])
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if nt, ok := ref.(reference.NamedTagged); ok {
|
||||
repo = ref.Name()
|
||||
repo = reference.FamiliarName(ref)
|
||||
tag = nt.Tag()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -94,7 +94,7 @@ func imageFormat(ctx ImageContext, images []types.ImageSummary, format func(subC
|
|||
repoTags := map[string][]string{}
|
||||
repoDigests := map[string][]string{}
|
||||
|
||||
for _, refString := range append(image.RepoTags) {
|
||||
for _, refString := range image.RepoTags {
|
||||
ref, err := reference.ParseNormalizedNamed(refString)
|
||||
if err != nil {
|
||||
continue
|
||||
|
@ -104,7 +104,7 @@ func imageFormat(ctx ImageContext, images []types.ImageSummary, format func(subC
|
|||
repoTags[familiarRef] = append(repoTags[familiarRef], nt.Tag())
|
||||
}
|
||||
}
|
||||
for _, refString := range append(image.RepoDigests) {
|
||||
for _, refString := range image.RepoDigests {
|
||||
ref, err := reference.ParseNormalizedNamed(refString)
|
||||
if err != nil {
|
||||
continue
|
||||
|
|
|
@ -5,7 +5,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
distreference "github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/reference"
|
||||
mounttypes "github.com/docker/docker/api/types/mount"
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
"github.com/docker/docker/cli/command/inspect"
|
||||
|
@ -409,11 +409,12 @@ func (c *serviceContext) Replicas() string {
|
|||
func (c *serviceContext) Image() string {
|
||||
c.AddHeader(imageHeader)
|
||||
image := c.service.Spec.TaskTemplate.ContainerSpec.Image
|
||||
if ref, err := distreference.ParseNamed(image); err == nil {
|
||||
// update image string for display
|
||||
namedTagged, ok := ref.(distreference.NamedTagged)
|
||||
if ok {
|
||||
image = namedTagged.Name() + ":" + namedTagged.Tag()
|
||||
if ref, err := reference.ParseNormalizedNamed(image); err == nil {
|
||||
// update image string for display, (strips any digest)
|
||||
if nt, ok := ref.(reference.NamedTagged); ok {
|
||||
if namedTagged, err := reference.WithTag(reference.TrimNamed(nt), nt.Tag()); err == nil {
|
||||
image = reference.FamiliarString(namedTagged)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -397,9 +397,7 @@ func rewriteDockerfileFrom(ctx context.Context, dockerfile io.Reader, translator
|
|||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if reference.IsNameOnly(ref) {
|
||||
ref = reference.EnsureTagged(ref)
|
||||
}
|
||||
ref = reference.TagNameOnly(ref)
|
||||
if ref, ok := ref.(reference.NamedTagged); ok && command.IsTrusted() {
|
||||
trustedRef, err := translator(ctx, ref)
|
||||
if err != nil {
|
||||
|
|
|
@ -42,7 +42,6 @@ func NewPullCommand(dockerCli *command.DockerCli) *cobra.Command {
|
|||
}
|
||||
|
||||
func runPull(dockerCli *command.DockerCli, opts pullOptions) error {
|
||||
var distributionRef reference.Named
|
||||
distributionRef, err := reference.ParseNormalizedNamed(opts.remote)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -52,9 +51,10 @@ func runPull(dockerCli *command.DockerCli, opts pullOptions) error {
|
|||
}
|
||||
|
||||
if !opts.all && reference.IsNameOnly(distributionRef) {
|
||||
taggedRef := reference.EnsureTagged(distributionRef)
|
||||
fmt.Fprintf(dockerCli.Out(), "Using default tag: %s\n", taggedRef.Tag())
|
||||
distributionRef = taggedRef
|
||||
distributionRef = reference.TagNameOnly(distributionRef)
|
||||
if tagged, ok := distributionRef.(reference.Tagged); ok {
|
||||
fmt.Fprintf(dockerCli.Out(), "Using default tag: %s\n", tagged.Tag())
|
||||
}
|
||||
}
|
||||
|
||||
// Resolve the Repository name from fqn to RepositoryInfo
|
||||
|
|
|
@ -129,15 +129,15 @@ func PushTrustedReference(cli *command.DockerCli, repoInfo *registry.RepositoryI
|
|||
|
||||
// Initialize the notary repository with a remotely managed snapshot key
|
||||
if err := repo.Initialize([]string{rootKeyID}, data.CanonicalSnapshotRole); err != nil {
|
||||
return trust.NotaryError(repoInfo.FullName(), err)
|
||||
return trust.NotaryError(repoInfo.Name.Name(), err)
|
||||
}
|
||||
fmt.Fprintf(cli.Out(), "Finished initializing %q\n", repoInfo.FullName())
|
||||
fmt.Fprintf(cli.Out(), "Finished initializing %q\n", repoInfo.Name.Name())
|
||||
err = repo.AddTarget(target, data.CanonicalTargetsRole)
|
||||
case nil:
|
||||
// already initialized and we have successfully downloaded the latest metadata
|
||||
err = addTargetToAllSignableRoles(repo, target)
|
||||
default:
|
||||
return trust.NotaryError(repoInfo.FullName(), err)
|
||||
return trust.NotaryError(repoInfo.Name.Name(), err)
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
|
@ -145,11 +145,11 @@ func PushTrustedReference(cli *command.DockerCli, repoInfo *registry.RepositoryI
|
|||
}
|
||||
|
||||
if err != nil {
|
||||
fmt.Fprintf(cli.Out(), "Failed to sign %q:%s - %s\n", repoInfo.FullName(), tag, err.Error())
|
||||
return trust.NotaryError(repoInfo.FullName(), err)
|
||||
fmt.Fprintf(cli.Out(), "Failed to sign %q:%s - %s\n", repoInfo.Name.Name(), tag, err.Error())
|
||||
return trust.NotaryError(repoInfo.Name.Name(), err)
|
||||
}
|
||||
|
||||
fmt.Fprintf(cli.Out(), "Successfully signed %q:%s\n", repoInfo.FullName(), tag)
|
||||
fmt.Fprintf(cli.Out(), "Successfully signed %q:%s\n", repoInfo.Name.Name(), tag)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -342,12 +342,12 @@ func TrustedReference(ctx context.Context, cli *command.DockerCli, ref reference
|
|||
|
||||
t, err := notaryRepo.GetTargetByName(ref.Tag(), trust.ReleasesRole, data.CanonicalTargetsRole)
|
||||
if err != nil {
|
||||
return nil, trust.NotaryError(repoInfo.FullName(), err)
|
||||
return nil, trust.NotaryError(repoInfo.Name.Name(), err)
|
||||
}
|
||||
// Only list tags in the top level targets role or the releases delegation role - ignore
|
||||
// all other delegation roles
|
||||
if t.Role != trust.ReleasesRole && t.Role != data.CanonicalTargetsRole {
|
||||
return nil, trust.NotaryError(repoInfo.FullName(), fmt.Errorf("No trust data for %s", ref.Tag()))
|
||||
return nil, trust.NotaryError(repoInfo.Name.Name(), fmt.Errorf("No trust data for %s", ref.Tag()))
|
||||
}
|
||||
r, err := convertTarget(t.Target)
|
||||
if err != nil {
|
||||
|
|
|
@ -7,7 +7,6 @@ import (
|
|||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
registrytypes "github.com/docker/docker/api/types/registry"
|
||||
"github.com/docker/docker/cli"
|
||||
"github.com/docker/docker/cli/command"
|
||||
"github.com/docker/docker/cli/command/image"
|
||||
|
@ -54,20 +53,6 @@ func newInstallCommand(dockerCli *command.DockerCli) *cobra.Command {
|
|||
return cmd
|
||||
}
|
||||
|
||||
func getRepoIndexFromUnnormalizedRef(ref reference.Named) (*registrytypes.IndexInfo, error) {
|
||||
named, err := reference.ParseNormalizedNamed(ref.Name())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
repoInfo, err := registry.ParseRepositoryInfo(named)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return repoInfo.Index, nil
|
||||
}
|
||||
|
||||
type pluginRegistryService struct {
|
||||
registry.Service
|
||||
}
|
||||
|
@ -104,9 +89,10 @@ func buildPullConfig(ctx context.Context, dockerCli *command.DockerCli, opts plu
|
|||
|
||||
_, isCanonical := ref.(reference.Canonical)
|
||||
if command.IsTrusted() && !isCanonical {
|
||||
ref = reference.TagNameOnly(ref)
|
||||
nt, ok := ref.(reference.NamedTagged)
|
||||
if !ok {
|
||||
nt = reference.EnsureTagged(ref)
|
||||
return types.PluginInstallOptions{}, fmt.Errorf("invalid name: %s", ref.String())
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
@ -148,7 +134,7 @@ func runInstall(dockerCli *command.DockerCli, opts pluginOptions) error {
|
|||
if _, ok := aref.(reference.Canonical); ok {
|
||||
return fmt.Errorf("invalid name: %s", opts.localName)
|
||||
}
|
||||
localName = reference.FamiliarString(reference.EnsureTagged(aref))
|
||||
localName = reference.FamiliarString(reference.TagNameOnly(aref))
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
|
|
@ -40,10 +40,7 @@ func runPush(dockerCli *command.DockerCli, name string) error {
|
|||
return fmt.Errorf("invalid name: %s", name)
|
||||
}
|
||||
|
||||
taggedRef, ok := named.(reference.NamedTagged)
|
||||
if !ok {
|
||||
taggedRef = reference.EnsureTagged(named)
|
||||
}
|
||||
named = reference.TagNameOnly(named)
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
|
@ -58,7 +55,7 @@ func runPush(dockerCli *command.DockerCli, name string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
responseBody, err := dockerCli.Client().PluginPush(ctx, reference.FamiliarString(taggedRef), encodedAuth)
|
||||
responseBody, err := dockerCli.Client().PluginPush(ctx, reference.FamiliarString(named), encodedAuth)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -5,10 +5,10 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/cli"
|
||||
"github.com/docker/docker/cli/command"
|
||||
"github.com/docker/docker/pkg/jsonmessage"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
@ -49,19 +49,19 @@ func runUpgrade(dockerCli *command.DockerCli, opts pluginOptions) error {
|
|||
if opts.remote == "" {
|
||||
opts.remote = p.PluginReference
|
||||
}
|
||||
remote, err := reference.ParseNamed(opts.remote)
|
||||
remote, err := reference.ParseNormalizedNamed(opts.remote)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error parsing remote upgrade image reference")
|
||||
}
|
||||
remote = reference.WithDefaultTag(remote)
|
||||
remote = reference.TagNameOnly(remote)
|
||||
|
||||
old, err := reference.ParseNamed(p.PluginReference)
|
||||
old, err := reference.ParseNormalizedNamed(p.PluginReference)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error parsing current image reference")
|
||||
}
|
||||
old = reference.WithDefaultTag(old)
|
||||
old = reference.TagNameOnly(old)
|
||||
|
||||
fmt.Fprintf(dockerCli.Out(), "Upgrading plugin %s from %s to %s\n", p.Name, old, remote)
|
||||
fmt.Fprintf(dockerCli.Out(), "Upgrading plugin %s from %s to %s\n", p.Name, reference.FamiliarString(old), reference.FamiliarString(remote))
|
||||
if !opts.skipRemoteCheck && remote.String() != old.String() {
|
||||
if !command.PromptForConfirmation(dockerCli.In(), dockerCli.Out(), "Plugin images do not match, are you sure?") {
|
||||
return errors.New("canceling upgrade request")
|
||||
|
|
|
@ -33,10 +33,12 @@ func resolveServiceImageDigest(dockerCli *command.DockerCli, service *swarm.Serv
|
|||
namedRef, ok := ref.(reference.Named)
|
||||
if !ok {
|
||||
return errors.New("failed to resolve image digest using content trust: reference is not named")
|
||||
|
||||
}
|
||||
|
||||
taggedRef := reference.EnsureTagged(namedRef)
|
||||
namedRef = reference.TagNameOnly(namedRef)
|
||||
taggedRef, ok := namedRef.(reference.NamedTagged)
|
||||
if !ok {
|
||||
return errors.New("failed to resolve image digest using content trust: reference is not tagged")
|
||||
}
|
||||
|
||||
resolvedImage, err := trustedResolveDigest(context.Background(), dockerCli, taggedRef)
|
||||
if err != nil {
|
||||
|
@ -65,12 +67,12 @@ func trustedResolveDigest(ctx context.Context, cli *command.DockerCli, ref refer
|
|||
|
||||
t, err := notaryRepo.GetTargetByName(ref.Tag(), trust.ReleasesRole, data.CanonicalTargetsRole)
|
||||
if err != nil {
|
||||
return nil, trust.NotaryError(repoInfo.FullName(), err)
|
||||
return nil, trust.NotaryError(repoInfo.Name.Name(), err)
|
||||
}
|
||||
// Only get the tag if it's in the top level targets role or the releases delegation role
|
||||
// ignore it if it's in any other delegation roles
|
||||
if t.Role != trust.ReleasesRole && t.Role != data.CanonicalTargetsRole {
|
||||
return nil, trust.NotaryError(repoInfo.FullName(), fmt.Errorf("No trust data for %s", reference.FamiliarString(ref)))
|
||||
return nil, trust.NotaryError(repoInfo.Name.Name(), fmt.Errorf("No trust data for %s", reference.FamiliarString(ref)))
|
||||
}
|
||||
|
||||
logrus.Debugf("retrieving target for %s role\n", t.Role)
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
distreference "github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
"github.com/docker/docker/cli/command"
|
||||
"github.com/docker/docker/cli/command/idresolver"
|
||||
|
@ -129,13 +129,15 @@ func print(out io.Writer, ctx context.Context, tasks []swarm.Task, resolver *idr
|
|||
|
||||
image := task.Spec.ContainerSpec.Image
|
||||
if !noTrunc {
|
||||
ref, err := distreference.ParseNamed(image)
|
||||
ref, err := reference.ParseNormalizedNamed(image)
|
||||
if err == nil {
|
||||
// update image string for display
|
||||
namedTagged, ok := ref.(distreference.NamedTagged)
|
||||
if ok {
|
||||
image = namedTagged.Name() + ":" + namedTagged.Tag()
|
||||
// update image string for display, (strips any digest)
|
||||
if nt, ok := ref.(reference.NamedTagged); ok {
|
||||
if namedTagged, err := reference.WithTag(reference.TrimNamed(nt), nt.Tag()); err == nil {
|
||||
image = reference.FamiliarString(namedTagged)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -148,7 +148,7 @@ func GetNotaryRepository(streams command.Streams, repoInfo *registry.RepositoryI
|
|||
}
|
||||
|
||||
scope := auth.RepositoryScope{
|
||||
Repository: repoInfo.FullName(),
|
||||
Repository: repoInfo.Name.Name(),
|
||||
Actions: actions,
|
||||
Class: repoInfo.Class,
|
||||
}
|
||||
|
@ -166,7 +166,7 @@ func GetNotaryRepository(streams command.Streams, repoInfo *registry.RepositoryI
|
|||
|
||||
return client.NewNotaryRepository(
|
||||
trustDirectory(),
|
||||
repoInfo.FullName(),
|
||||
repoInfo.Name.Name(),
|
||||
server,
|
||||
tr,
|
||||
getPassphraseRetriever(streams),
|
||||
|
|
|
@ -5,9 +5,8 @@ import (
|
|||
"errors"
|
||||
"net/url"
|
||||
|
||||
distreference "github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/reference"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
|
@ -15,17 +14,20 @@ import (
|
|||
func (cli *Client) ContainerCommit(ctx context.Context, container string, options types.ContainerCommitOptions) (types.IDResponse, error) {
|
||||
var repository, tag string
|
||||
if options.Reference != "" {
|
||||
distributionRef, err := distreference.ParseNamed(options.Reference)
|
||||
ref, err := reference.ParseNormalizedNamed(options.Reference)
|
||||
if err != nil {
|
||||
return types.IDResponse{}, err
|
||||
}
|
||||
|
||||
if _, isCanonical := distributionRef.(distreference.Canonical); isCanonical {
|
||||
if _, isCanonical := ref.(reference.Canonical); isCanonical {
|
||||
return types.IDResponse{}, errors.New("refusing to create a tag with a digest reference")
|
||||
}
|
||||
ref = reference.TagNameOnly(ref)
|
||||
|
||||
tag = reference.GetTagFromNamedRef(distributionRef)
|
||||
repository = distributionRef.Name()
|
||||
if tagged, ok := ref.(reference.Tagged); ok {
|
||||
tag = tagged.Tag()
|
||||
}
|
||||
repository = reference.FamiliarName(ref)
|
||||
}
|
||||
|
||||
query := url.Values{}
|
||||
|
|
|
@ -6,21 +6,21 @@ import (
|
|||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/reference"
|
||||
)
|
||||
|
||||
// ImageCreate creates a new image based in the parent options.
|
||||
// It returns the JSON content in the response body.
|
||||
func (cli *Client) ImageCreate(ctx context.Context, parentReference string, options types.ImageCreateOptions) (io.ReadCloser, error) {
|
||||
repository, tag, err := reference.Parse(parentReference)
|
||||
ref, err := reference.ParseNormalizedNamed(parentReference)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
query := url.Values{}
|
||||
query.Set("fromImage", repository)
|
||||
query.Set("tag", tag)
|
||||
query.Set("fromImage", reference.FamiliarName(ref))
|
||||
query.Set("tag", getAPITagFromNamedRef(ref))
|
||||
resp, err := cli.tryImageCreate(ctx, query, options.RegistryAuth)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -15,7 +15,7 @@ import (
|
|||
func (cli *Client) ImageImport(ctx context.Context, source types.ImageImportSource, ref string, options types.ImageImportOptions) (io.ReadCloser, error) {
|
||||
if ref != "" {
|
||||
//Check if the given image name can be resolved
|
||||
if _, err := reference.ParseNamed(ref); err != nil {
|
||||
if _, err := reference.ParseNormalizedNamed(ref); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,8 +7,8 @@ import (
|
|||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/reference"
|
||||
)
|
||||
|
||||
// ImagePull requests the docker host to pull an image from a remote registry.
|
||||
|
@ -19,16 +19,16 @@ import (
|
|||
// FIXME(vdemeester): there is currently used in a few way in docker/docker
|
||||
// - if not in trusted content, ref is used to pass the whole reference, and tag is empty
|
||||
// - if in trusted content, ref is used to pass the reference name, and tag for the digest
|
||||
func (cli *Client) ImagePull(ctx context.Context, ref string, options types.ImagePullOptions) (io.ReadCloser, error) {
|
||||
repository, tag, err := reference.Parse(ref)
|
||||
func (cli *Client) ImagePull(ctx context.Context, refStr string, options types.ImagePullOptions) (io.ReadCloser, error) {
|
||||
ref, err := reference.ParseNormalizedNamed(refStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
query := url.Values{}
|
||||
query.Set("fromImage", repository)
|
||||
if tag != "" && !options.All {
|
||||
query.Set("tag", tag)
|
||||
query.Set("fromImage", reference.FamiliarName(ref))
|
||||
if !options.All {
|
||||
query.Set("tag", getAPITagFromNamedRef(ref))
|
||||
}
|
||||
|
||||
resp, err := cli.tryImageCreate(ctx, query, options.RegistryAuth)
|
||||
|
@ -44,3 +44,18 @@ func (cli *Client) ImagePull(ctx context.Context, ref string, options types.Imag
|
|||
}
|
||||
return resp.body, nil
|
||||
}
|
||||
|
||||
// getAPITagFromNamedRef returns a tag from the specified reference.
|
||||
// This function is necessary as long as the docker "server" api expects
|
||||
// digests to be sent as tags and makes a distinction between the name
|
||||
// and tag/digest part of a reference.
|
||||
func getAPITagFromNamedRef(ref reference.Named) string {
|
||||
if digested, ok := ref.(reference.Digested); ok {
|
||||
return digested.Digest().String()
|
||||
}
|
||||
ref = reference.TagNameOnly(ref)
|
||||
if tagged, ok := ref.(reference.Tagged); ok {
|
||||
return tagged.Tag()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ func TestImagePullReferenceParseError(t *testing.T) {
|
|||
}
|
||||
// An empty reference is an invalid reference
|
||||
_, err := client.ImagePull(context.Background(), "", types.ImagePullOptions{})
|
||||
if err == nil || err.Error() != "repository name must have at least one component" {
|
||||
if err == nil || !strings.Contains(err.Error(), "invalid reference format") {
|
||||
t.Fatalf("expected an error, got %v", err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
distreference "github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
)
|
||||
|
||||
|
@ -16,31 +16,33 @@ import (
|
|||
// It executes the privileged function if the operation is unauthorized
|
||||
// and it tries one more time.
|
||||
// It's up to the caller to handle the io.ReadCloser and close it properly.
|
||||
func (cli *Client) ImagePush(ctx context.Context, ref string, options types.ImagePushOptions) (io.ReadCloser, error) {
|
||||
distributionRef, err := distreference.ParseNamed(ref)
|
||||
func (cli *Client) ImagePush(ctx context.Context, image string, options types.ImagePushOptions) (io.ReadCloser, error) {
|
||||
ref, err := reference.ParseNormalizedNamed(image)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, isCanonical := distributionRef.(distreference.Canonical); isCanonical {
|
||||
if _, isCanonical := ref.(reference.Canonical); isCanonical {
|
||||
return nil, errors.New("cannot push a digest reference")
|
||||
}
|
||||
|
||||
var tag = ""
|
||||
if nameTaggedRef, isNamedTagged := distributionRef.(distreference.NamedTagged); isNamedTagged {
|
||||
tag := ""
|
||||
name := reference.FamiliarName(ref)
|
||||
|
||||
if nameTaggedRef, isNamedTagged := ref.(reference.NamedTagged); isNamedTagged {
|
||||
tag = nameTaggedRef.Tag()
|
||||
}
|
||||
|
||||
query := url.Values{}
|
||||
query.Set("tag", tag)
|
||||
|
||||
resp, err := cli.tryImagePush(ctx, distributionRef.Name(), query, options.RegistryAuth)
|
||||
resp, err := cli.tryImagePush(ctx, name, query, options.RegistryAuth)
|
||||
if resp.statusCode == http.StatusUnauthorized && options.PrivilegeFunc != nil {
|
||||
newAuthHeader, privilegeErr := options.PrivilegeFunc()
|
||||
if privilegeErr != nil {
|
||||
return nil, privilegeErr
|
||||
}
|
||||
resp, err = cli.tryImagePush(ctx, distributionRef.Name(), query, newAuthHeader)
|
||||
resp, err = cli.tryImagePush(ctx, name, query, newAuthHeader)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -21,7 +21,7 @@ func TestImagePushReferenceError(t *testing.T) {
|
|||
}
|
||||
// An empty reference is an invalid reference
|
||||
_, err := client.ImagePush(context.Background(), "", types.ImagePushOptions{})
|
||||
if err == nil || err.Error() != "repository name must have at least one component" {
|
||||
if err == nil || !strings.Contains(err.Error(), "invalid reference format") {
|
||||
t.Fatalf("expected an error, got %v", err)
|
||||
}
|
||||
// An canonical reference cannot be pushed
|
||||
|
|
|
@ -3,32 +3,33 @@ package client
|
|||
import (
|
||||
"net/url"
|
||||
|
||||
distreference "github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types/reference"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// ImageTag tags an image in the docker host
|
||||
func (cli *Client) ImageTag(ctx context.Context, source, target string) error {
|
||||
if _, err := distreference.ParseNamed(source); err != nil {
|
||||
if _, err := reference.ParseNormalizedNamed(source); err != nil {
|
||||
return errors.Wrapf(err, "Error parsing reference: %q is not a valid repository/tag", source)
|
||||
}
|
||||
|
||||
distributionRef, err := distreference.ParseNamed(target)
|
||||
ref, err := reference.ParseNormalizedNamed(target)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Error parsing reference: %q is not a valid repository/tag", target)
|
||||
}
|
||||
|
||||
if _, isCanonical := distributionRef.(distreference.Canonical); isCanonical {
|
||||
if _, isCanonical := ref.(reference.Canonical); isCanonical {
|
||||
return errors.New("refusing to create a tag with a digest reference")
|
||||
}
|
||||
|
||||
tag := reference.GetTagFromNamedRef(distributionRef)
|
||||
ref = reference.TagNameOnly(ref)
|
||||
|
||||
query := url.Values{}
|
||||
query.Set("repo", distributionRef.Name())
|
||||
query.Set("tag", tag)
|
||||
query.Set("repo", reference.FamiliarName(ref))
|
||||
if tagged, ok := ref.(reference.Tagged); ok {
|
||||
query.Set("tag", tagged.Tag())
|
||||
}
|
||||
|
||||
resp, err := cli.post(ctx, "/images/"+source+"/tag", query, nil, nil)
|
||||
ensureReaderClosed(resp)
|
||||
|
|
|
@ -15,7 +15,7 @@ import (
|
|||
// PluginInstall installs a plugin
|
||||
func (cli *Client) PluginInstall(ctx context.Context, name string, options types.PluginInstallOptions) (rc io.ReadCloser, err error) {
|
||||
query := url.Values{}
|
||||
if _, err := reference.ParseNamed(options.RemoteRef); err != nil {
|
||||
if _, err := reference.ParseNormalizedNamed(options.RemoteRef); err != nil {
|
||||
return nil, errors.Wrap(err, "invalid remote reference")
|
||||
}
|
||||
query.Set("remote", options.RemoteRef)
|
||||
|
|
|
@ -14,7 +14,7 @@ import (
|
|||
// PluginUpgrade upgrades a plugin
|
||||
func (cli *Client) PluginUpgrade(ctx context.Context, name string, options types.PluginInstallOptions) (rc io.ReadCloser, err error) {
|
||||
query := url.Values{}
|
||||
if _, err := reference.ParseNamed(options.RemoteRef); err != nil {
|
||||
if _, err := reference.ParseNormalizedNamed(options.RemoteRef); err != nil {
|
||||
return nil, errors.Wrap(err, "invalid remote reference")
|
||||
}
|
||||
query.Set("remote", options.RemoteRef)
|
||||
|
|
|
@ -52,7 +52,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
distreference "github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/reference"
|
||||
apierrors "github.com/docker/docker/api/errors"
|
||||
apitypes "github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
|
@ -66,13 +66,11 @@ import (
|
|||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/pkg/signal"
|
||||
"github.com/docker/docker/pkg/stdcopy"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/docker/docker/runconfig"
|
||||
swarmapi "github.com/docker/swarmkit/api"
|
||||
"github.com/docker/swarmkit/manager/encryption"
|
||||
swarmnode "github.com/docker/swarmkit/node"
|
||||
gogotypes "github.com/gogo/protobuf/types"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
@ -829,50 +827,46 @@ func (c *Cluster) GetServices(options apitypes.ServiceListOptions) ([]types.Serv
|
|||
}
|
||||
|
||||
// imageWithDigestString takes an image such as name or name:tag
|
||||
// and returns the image pinned to a digest, such as name@sha256:34234...
|
||||
// Due to the difference between the docker/docker/reference, and the
|
||||
// docker/distribution/reference packages, we're parsing the image twice.
|
||||
// As the two packages converge, this function should be simplified.
|
||||
// TODO(nishanttotla): After the packages converge, the function must
|
||||
// convert distreference.Named -> distreference.Canonical, and the logic simplified.
|
||||
// and returns the image pinned to a digest, such as name@sha256:34234
|
||||
func (c *Cluster) imageWithDigestString(ctx context.Context, image string, authConfig *apitypes.AuthConfig) (string, error) {
|
||||
if _, err := digest.Parse(image); err == nil {
|
||||
return "", errors.New("image reference is an image ID")
|
||||
}
|
||||
ref, err := distreference.ParseNamed(image)
|
||||
ref, err := reference.ParseAnyReference(image)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
namedRef, ok := ref.(reference.Named)
|
||||
if !ok {
|
||||
if _, ok := ref.(reference.Digested); ok {
|
||||
return "", errors.New("image reference is an image ID")
|
||||
}
|
||||
return "", errors.Errorf("unknown image reference format: %s", image)
|
||||
}
|
||||
// only query registry if not a canonical reference (i.e. with digest)
|
||||
if _, ok := ref.(distreference.Canonical); !ok {
|
||||
// create a docker/docker/reference Named object because GetRepository needs it
|
||||
dockerRef, err := reference.ParseNamed(image)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
dockerRef = reference.WithDefaultTag(dockerRef)
|
||||
namedTaggedRef, ok := dockerRef.(reference.NamedTagged)
|
||||
if _, ok := namedRef.(reference.Canonical); !ok {
|
||||
namedRef = reference.TagNameOnly(namedRef)
|
||||
|
||||
taggedRef, ok := namedRef.(reference.NamedTagged)
|
||||
if !ok {
|
||||
return "", errors.New("unable to cast image to NamedTagged reference object")
|
||||
return "", errors.Errorf("image reference not tagged: %s", image)
|
||||
}
|
||||
|
||||
repo, _, err := c.config.Backend.GetRepository(ctx, namedTaggedRef, authConfig)
|
||||
repo, _, err := c.config.Backend.GetRepository(ctx, taggedRef, authConfig)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
dscrptr, err := repo.Tags(ctx).Get(ctx, namedTaggedRef.Tag())
|
||||
dscrptr, err := repo.Tags(ctx).Get(ctx, taggedRef.Tag())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
namedDigestedRef, err := distreference.WithDigest(distreference.EnsureTagged(ref), dscrptr.Digest)
|
||||
namedDigestedRef, err := reference.WithDigest(taggedRef, dscrptr.Digest)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return namedDigestedRef.String(), nil
|
||||
// return familiar form until interface updated to return type
|
||||
return reference.FamiliarString(namedDigestedRef), nil
|
||||
}
|
||||
// reference already contains a digest, so just return it
|
||||
return ref.String(), nil
|
||||
return reference.FamiliarString(ref), nil
|
||||
}
|
||||
|
||||
// CreateService creates a new service in a managed swarm cluster.
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/docker/distribution"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
|
@ -14,7 +15,6 @@ import (
|
|||
swarmtypes "github.com/docker/docker/api/types/swarm"
|
||||
clustertypes "github.com/docker/docker/daemon/cluster/provider"
|
||||
"github.com/docker/docker/plugin"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/docker/libnetwork"
|
||||
"github.com/docker/libnetwork/cluster"
|
||||
networktypes "github.com/docker/libnetwork/types"
|
||||
|
|
|
@ -12,13 +12,13 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
containertypes "github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/events"
|
||||
"github.com/docker/docker/daemon/cluster/convert"
|
||||
executorpkg "github.com/docker/docker/daemon/cluster/executor"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/docker/libnetwork"
|
||||
"github.com/docker/swarmkit/agent/exec"
|
||||
"github.com/docker/swarmkit/api"
|
||||
|
@ -61,7 +61,7 @@ func (c *containerAdapter) pullImage(ctx context.Context) error {
|
|||
|
||||
// Skip pulling if the image is referenced by digest and already
|
||||
// exists locally.
|
||||
named, err := reference.ParseNamed(spec.Image)
|
||||
named, err := reference.ParseNormalizedNamed(spec.Image)
|
||||
if err == nil {
|
||||
if _, ok := named.(reference.Canonical); ok {
|
||||
_, err := c.backend.LookupImage(spec.Image)
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
|
||||
"github.com/Sirupsen/logrus"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
enginecontainer "github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/events"
|
||||
|
@ -18,7 +19,6 @@ import (
|
|||
"github.com/docker/docker/api/types/network"
|
||||
volumetypes "github.com/docker/docker/api/types/volume"
|
||||
clustertypes "github.com/docker/docker/daemon/cluster/provider"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/docker/go-connections/nat"
|
||||
"github.com/docker/swarmkit/agent/exec"
|
||||
"github.com/docker/swarmkit/api"
|
||||
|
@ -132,11 +132,11 @@ func (c *containerConfig) name() string {
|
|||
|
||||
func (c *containerConfig) image() string {
|
||||
raw := c.spec().Image
|
||||
ref, err := reference.ParseNamed(raw)
|
||||
ref, err := reference.ParseNormalizedNamed(raw)
|
||||
if err != nil {
|
||||
return raw
|
||||
}
|
||||
return reference.WithDefaultTag(ref).String()
|
||||
return reference.FamiliarString(reference.TagNameOnly(ref))
|
||||
}
|
||||
|
||||
func (c *containerConfig) portBindings() nat.PortMap {
|
||||
|
|
|
@ -2,12 +2,12 @@ package daemon
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types/backend"
|
||||
containertypes "github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/builder/dockerfile"
|
||||
|
@ -16,7 +16,7 @@ import (
|
|||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// merge merges two Config, the image container configuration (defaults values),
|
||||
|
@ -128,7 +128,7 @@ func (daemon *Daemon) Commit(name string, c *backend.ContainerCommitConfig) (str
|
|||
|
||||
// It is not possible to commit a running container on Windows and on Solaris.
|
||||
if (runtime.GOOS == "windows" || runtime.GOOS == "solaris") && container.IsRunning() {
|
||||
return "", fmt.Errorf("%+v does not support commit of a running container", runtime.GOOS)
|
||||
return "", errors.Errorf("%+v does not support commit of a running container", runtime.GOOS)
|
||||
}
|
||||
|
||||
if c.Pause && !container.IsPaused() {
|
||||
|
@ -228,10 +228,13 @@ func (daemon *Daemon) Commit(name string, c *backend.ContainerCommitConfig) (str
|
|||
|
||||
imageRef := ""
|
||||
if c.Repo != "" {
|
||||
newTag, err := reference.WithName(c.Repo) // todo: should move this to API layer
|
||||
newTag, err := reference.ParseNormalizedNamed(c.Repo) // todo: should move this to API layer
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if !reference.IsNameOnly(newTag) {
|
||||
return "", errors.Errorf("unexpected repository name: %s", c.Repo)
|
||||
}
|
||||
if c.Tag != "" {
|
||||
if newTag, err = reference.WithTag(newTag, c.Tag); err != nil {
|
||||
return "", err
|
||||
|
@ -240,7 +243,7 @@ func (daemon *Daemon) Commit(name string, c *backend.ContainerCommitConfig) (str
|
|||
if err := daemon.TagImageWithReference(id, newTag); err != nil {
|
||||
return "", err
|
||||
}
|
||||
imageRef = newTag.String()
|
||||
imageRef = reference.FamiliarString(newTag)
|
||||
}
|
||||
|
||||
attributes := map[string]string{
|
||||
|
|
|
@ -46,7 +46,7 @@ import (
|
|||
"github.com/docker/docker/pkg/system"
|
||||
"github.com/docker/docker/pkg/truncindex"
|
||||
"github.com/docker/docker/plugin"
|
||||
"github.com/docker/docker/reference"
|
||||
refstore "github.com/docker/docker/reference"
|
||||
"github.com/docker/docker/registry"
|
||||
"github.com/docker/docker/runconfig"
|
||||
volumedrivers "github.com/docker/docker/volume/drivers"
|
||||
|
@ -76,7 +76,7 @@ type Daemon struct {
|
|||
repository string
|
||||
containers container.Store
|
||||
execCommands *exec.Store
|
||||
referenceStore reference.Store
|
||||
referenceStore refstore.Store
|
||||
downloadManager *xfer.LayerDownloadManager
|
||||
uploadManager *xfer.LayerUploadManager
|
||||
distributionMetadataStore dmetadata.Store
|
||||
|
@ -637,7 +637,7 @@ func NewDaemon(config *Config, registryService registry.Service, containerdRemot
|
|||
|
||||
eventsService := events.New()
|
||||
|
||||
referenceStore, err := reference.NewReferenceStore(filepath.Join(imageRoot, "repositories.json"))
|
||||
referenceStore, err := refstore.NewReferenceStore(filepath.Join(imageRoot, "repositories.json"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Couldn't create Tag store repositories: %s", err)
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ import (
|
|||
"github.com/docker/docker/pkg/idtools"
|
||||
"github.com/docker/docker/pkg/parsers/kernel"
|
||||
"github.com/docker/docker/pkg/sysinfo"
|
||||
"github.com/docker/docker/reference"
|
||||
refstore "github.com/docker/docker/reference"
|
||||
"github.com/docker/libnetwork"
|
||||
nwconfig "github.com/docker/libnetwork/config"
|
||||
"github.com/docker/libnetwork/drivers/solaris/bridge"
|
||||
|
@ -491,7 +491,7 @@ func (daemon *Daemon) conditionalUnmountOnCleanup(container *container.Container
|
|||
return daemon.Unmount(container)
|
||||
}
|
||||
|
||||
func restoreCustomImage(is image.Store, ls layer.Store, rs reference.Store) error {
|
||||
func restoreCustomImage(is image.Store, ls layer.Store, rs refstore.Store) error {
|
||||
// Solaris has no custom images to register
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -2,29 +2,13 @@ package daemon
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/api/errors"
|
||||
"github.com/docker/docker/reference"
|
||||
)
|
||||
|
||||
func (d *Daemon) imageNotExistToErrcode(err error) error {
|
||||
if dne, isDNE := err.(ErrImageDoesNotExist); isDNE {
|
||||
if strings.Contains(dne.RefOrID, "@") {
|
||||
e := fmt.Errorf("No such image: %s", dne.RefOrID)
|
||||
return errors.NewRequestNotFoundError(e)
|
||||
}
|
||||
tag := reference.DefaultTag
|
||||
ref, err := reference.ParseNamed(dne.RefOrID)
|
||||
if err != nil {
|
||||
e := fmt.Errorf("No such image: %s:%s", dne.RefOrID, tag)
|
||||
return errors.NewRequestNotFoundError(e)
|
||||
}
|
||||
if tagged, isTagged := ref.(reference.NamedTagged); isTagged {
|
||||
tag = tagged.Tag()
|
||||
}
|
||||
e := fmt.Errorf("No such image: %s:%s", ref.Name(), tag)
|
||||
return errors.NewRequestNotFoundError(e)
|
||||
return errors.NewRequestNotFoundError(dne)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package events
|
||||
|
||||
import (
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types/events"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/reference"
|
||||
)
|
||||
|
||||
// Filter can filter out docker events from a stream
|
||||
|
@ -102,9 +102,9 @@ func (ef *Filter) matchImage(ev events.Message) bool {
|
|||
}
|
||||
|
||||
func stripTag(image string) string {
|
||||
ref, err := reference.ParseNamed(image)
|
||||
ref, err := reference.ParseNormalizedNamed(image)
|
||||
if err != nil {
|
||||
return image
|
||||
}
|
||||
return ref.Name()
|
||||
return reference.FamiliarName(ref)
|
||||
}
|
||||
|
|
|
@ -3,45 +3,55 @@ package daemon
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/builder"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/docker/reference"
|
||||
)
|
||||
|
||||
// ErrImageDoesNotExist is error returned when no image can be found for a reference.
|
||||
type ErrImageDoesNotExist struct {
|
||||
RefOrID string
|
||||
ref reference.Reference
|
||||
}
|
||||
|
||||
func (e ErrImageDoesNotExist) Error() string {
|
||||
return fmt.Sprintf("no such id: %s", e.RefOrID)
|
||||
ref := e.ref
|
||||
if named, ok := ref.(reference.Named); ok {
|
||||
ref = reference.TagNameOnly(named)
|
||||
}
|
||||
return fmt.Sprintf("No such image: %s", reference.FamiliarString(ref))
|
||||
}
|
||||
|
||||
// GetImageID returns an image ID corresponding to the image referred to by
|
||||
// refOrID.
|
||||
func (daemon *Daemon) GetImageID(refOrID string) (image.ID, error) {
|
||||
id, ref, err := reference.ParseIDOrReference(refOrID)
|
||||
ref, err := reference.ParseAnyReference(refOrID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if id != "" {
|
||||
if _, err := daemon.imageStore.Get(image.IDFromDigest(id)); err != nil {
|
||||
return "", ErrImageDoesNotExist{refOrID}
|
||||
namedRef, ok := ref.(reference.Named)
|
||||
if !ok {
|
||||
digested, ok := ref.(reference.Digested)
|
||||
if !ok {
|
||||
return "", ErrImageDoesNotExist{ref}
|
||||
}
|
||||
return image.IDFromDigest(id), nil
|
||||
id := image.IDFromDigest(digested.Digest())
|
||||
if _, err := daemon.imageStore.Get(id); err != nil {
|
||||
return "", ErrImageDoesNotExist{ref}
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
|
||||
if id, err := daemon.referenceStore.Get(ref); err == nil {
|
||||
if id, err := daemon.referenceStore.Get(namedRef); err == nil {
|
||||
return image.IDFromDigest(id), nil
|
||||
}
|
||||
|
||||
// deprecated: repo:shortid https://github.com/docker/docker/pull/799
|
||||
if tagged, ok := ref.(reference.NamedTagged); ok {
|
||||
if tagged, ok := namedRef.(reference.Tagged); ok {
|
||||
if tag := tagged.Tag(); stringid.IsShortID(stringid.TruncateID(tag)) {
|
||||
if id, err := daemon.imageStore.Search(tag); err == nil {
|
||||
for _, namedRef := range daemon.referenceStore.References(id.Digest()) {
|
||||
if namedRef.Name() == ref.Name() {
|
||||
for _, storeRef := range daemon.referenceStore.References(id.Digest()) {
|
||||
if storeRef.Name() == namedRef.Name() {
|
||||
return id, nil
|
||||
}
|
||||
}
|
||||
|
@ -54,7 +64,7 @@ func (daemon *Daemon) GetImageID(refOrID string) (image.ID, error) {
|
|||
return id, nil
|
||||
}
|
||||
|
||||
return "", ErrImageDoesNotExist{refOrID}
|
||||
return "", ErrImageDoesNotExist{ref}
|
||||
}
|
||||
|
||||
// GetImage returns an image corresponding to the image referred to by refOrID.
|
||||
|
|
|
@ -5,12 +5,12 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/errors"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/container"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/docker/reference"
|
||||
)
|
||||
|
||||
type conflictType int
|
||||
|
@ -89,7 +89,7 @@ func (daemon *Daemon) ImageDelete(imageRef string, force, prune bool) ([]types.I
|
|||
}
|
||||
}
|
||||
|
||||
parsedRef, err := reference.ParseNamed(imageRef)
|
||||
parsedRef, err := reference.ParseNormalizedNamed(imageRef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -99,7 +99,7 @@ func (daemon *Daemon) ImageDelete(imageRef string, force, prune bool) ([]types.I
|
|||
return nil, err
|
||||
}
|
||||
|
||||
untaggedRecord := types.ImageDeleteResponseItem{Untagged: parsedRef.String()}
|
||||
untaggedRecord := types.ImageDeleteResponseItem{Untagged: reference.FamiliarString(parsedRef)}
|
||||
|
||||
daemon.LogImageEvent(imgID.String(), imgID.String(), "untag")
|
||||
records = append(records, untaggedRecord)
|
||||
|
@ -126,7 +126,7 @@ func (daemon *Daemon) ImageDelete(imageRef string, force, prune bool) ([]types.I
|
|||
return records, err
|
||||
}
|
||||
|
||||
untaggedRecord := types.ImageDeleteResponseItem{Untagged: repoRef.String()}
|
||||
untaggedRecord := types.ImageDeleteResponseItem{Untagged: reference.FamiliarString(repoRef)}
|
||||
records = append(records, untaggedRecord)
|
||||
} else {
|
||||
remainingRefs = append(remainingRefs, repoRef)
|
||||
|
@ -162,7 +162,7 @@ func (daemon *Daemon) ImageDelete(imageRef string, force, prune bool) ([]types.I
|
|||
return nil, err
|
||||
}
|
||||
|
||||
untaggedRecord := types.ImageDeleteResponseItem{Untagged: parsedRef.String()}
|
||||
untaggedRecord := types.ImageDeleteResponseItem{Untagged: reference.FamiliarString(parsedRef)}
|
||||
|
||||
daemon.LogImageEvent(imgID.String(), imgID.String(), "untag")
|
||||
records = append(records, untaggedRecord)
|
||||
|
@ -232,7 +232,8 @@ func (daemon *Daemon) getContainerUsingImage(imageID image.ID) *container.Contai
|
|||
// optional tag or digest reference. If tag or digest is omitted, the default
|
||||
// tag is used. Returns the resolved image reference and an error.
|
||||
func (daemon *Daemon) removeImageRef(ref reference.Named) (reference.Named, error) {
|
||||
ref = reference.WithDefaultTag(ref)
|
||||
ref = reference.TagNameOnly(ref)
|
||||
|
||||
// Ignore the boolean value returned, as far as we're concerned, this
|
||||
// is an idempotent operation and it's okay if the reference didn't
|
||||
// exist in the first place.
|
||||
|
@ -255,7 +256,7 @@ func (daemon *Daemon) removeAllReferencesToImageID(imgID image.ID, records *[]ty
|
|||
return err
|
||||
}
|
||||
|
||||
untaggedRecord := types.ImageDeleteResponseItem{Untagged: parsedRef.String()}
|
||||
untaggedRecord := types.ImageDeleteResponseItem{Untagged: reference.FamiliarString(parsedRef)}
|
||||
|
||||
daemon.LogImageEvent(imgID.String(), imgID.String(), "untag")
|
||||
*records = append(*records, untaggedRecord)
|
||||
|
|
|
@ -4,9 +4,9 @@ import (
|
|||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types/image"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/docker/docker/reference"
|
||||
)
|
||||
|
||||
// ImageHistory returns a slice of ImageHistory structures for the specified image
|
||||
|
@ -64,7 +64,7 @@ func (daemon *Daemon) ImageHistory(name string) ([]*image.HistoryResponseItem, e
|
|||
var tags []string
|
||||
for _, r := range daemon.referenceStore.References(id.Digest()) {
|
||||
if _, ok := r.(reference.NamedTagged); ok {
|
||||
tags = append(tags, r.String())
|
||||
tags = append(tags, reference.FamiliarString(r))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,9 +3,9 @@ package daemon
|
|||
import (
|
||||
"time"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
|
@ -23,9 +23,9 @@ func (daemon *Daemon) LookupImage(name string) (*types.ImageInspect, error) {
|
|||
for _, ref := range refs {
|
||||
switch ref.(type) {
|
||||
case reference.NamedTagged:
|
||||
repoTags = append(repoTags, ref.String())
|
||||
repoTags = append(repoTags, reference.FamiliarString(ref))
|
||||
case reference.Canonical:
|
||||
repoDigests = append(repoDigests, ref.String())
|
||||
repoDigests = append(repoDigests, reference.FamiliarString(ref))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,12 +5,12 @@ import (
|
|||
"strings"
|
||||
|
||||
dist "github.com/docker/distribution"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/builder"
|
||||
"github.com/docker/docker/distribution"
|
||||
progressutils "github.com/docker/docker/distribution/utils"
|
||||
"github.com/docker/docker/pkg/progress"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/docker/docker/registry"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"golang.org/x/net/context"
|
||||
|
@ -24,7 +24,7 @@ func (daemon *Daemon) PullImage(ctx context.Context, image, tag string, metaHead
|
|||
// compatibility.
|
||||
image = strings.TrimSuffix(image, ":")
|
||||
|
||||
ref, err := reference.ParseNamed(image)
|
||||
ref, err := reference.ParseNormalizedNamed(image)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -48,11 +48,11 @@ func (daemon *Daemon) PullImage(ctx context.Context, image, tag string, metaHead
|
|||
|
||||
// PullOnBuild tells Docker to pull image referenced by `name`.
|
||||
func (daemon *Daemon) PullOnBuild(ctx context.Context, name string, authConfigs map[string]types.AuthConfig, output io.Writer) (builder.Image, error) {
|
||||
ref, err := reference.ParseNamed(name)
|
||||
ref, err := reference.ParseNormalizedNamed(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ref = reference.WithDefaultTag(ref)
|
||||
ref = reference.TagNameOnly(ref)
|
||||
|
||||
pullRegistryAuth := &types.AuthConfig{}
|
||||
if len(authConfigs) > 0 {
|
||||
|
@ -118,12 +118,12 @@ func (daemon *Daemon) GetRepository(ctx context.Context, ref reference.NamedTagg
|
|||
return nil, false, err
|
||||
}
|
||||
// makes sure name is not empty or `scratch`
|
||||
if err := distribution.ValidateRepoName(repoInfo.Name()); err != nil {
|
||||
if err := distribution.ValidateRepoName(repoInfo.Name); err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
// get endpoints
|
||||
endpoints, err := daemon.RegistryService.LookupPullEndpoints(repoInfo.Hostname())
|
||||
endpoints, err := daemon.RegistryService.LookupPullEndpoints(reference.Domain(repoInfo.Name))
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
|
|
|
@ -4,17 +4,17 @@ import (
|
|||
"io"
|
||||
|
||||
"github.com/docker/distribution/manifest/schema2"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/distribution"
|
||||
progressutils "github.com/docker/docker/distribution/utils"
|
||||
"github.com/docker/docker/pkg/progress"
|
||||
"github.com/docker/docker/reference"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// PushImage initiates a push operation on the repository named localName.
|
||||
func (daemon *Daemon) PushImage(ctx context.Context, image, tag string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
|
||||
ref, err := reference.ParseNamed(image)
|
||||
ref, err := reference.ParseNormalizedNamed(image)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package daemon
|
||||
|
||||
import (
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/reference"
|
||||
)
|
||||
|
||||
// TagImage creates the tag specified by newTag, pointing to the image named
|
||||
|
@ -13,12 +13,12 @@ func (daemon *Daemon) TagImage(imageName, repository, tag string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
newTag, err := reference.WithName(repository)
|
||||
newTag, err := reference.ParseNormalizedNamed(repository)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if tag != "" {
|
||||
if newTag, err = reference.WithTag(newTag, tag); err != nil {
|
||||
if newTag, err = reference.WithTag(reference.TrimNamed(newTag), tag); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,6 @@ func (daemon *Daemon) TagImageWithReference(imageID image.ID, newTag reference.N
|
|||
return err
|
||||
}
|
||||
|
||||
daemon.LogImageEvent(imageID.String(), newTag.String(), "tag")
|
||||
daemon.LogImageEvent(imageID.String(), reference.FamiliarString(newTag), "tag")
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -135,7 +135,7 @@ func (daemon *Daemon) Images(imageFilters filters.Args, all bool, withExtraAttrs
|
|||
var found bool
|
||||
var matchErr error
|
||||
for _, pattern := range imageFilters.Get("reference") {
|
||||
found, matchErr = reference.Match(pattern, ref)
|
||||
found, matchErr = reference.FamiliarMatch(pattern, ref)
|
||||
if matchErr != nil {
|
||||
return nil, matchErr
|
||||
}
|
||||
|
@ -145,10 +145,10 @@ func (daemon *Daemon) Images(imageFilters filters.Args, all bool, withExtraAttrs
|
|||
}
|
||||
}
|
||||
if _, ok := ref.(reference.Canonical); ok {
|
||||
newImage.RepoDigests = append(newImage.RepoDigests, ref.String())
|
||||
newImage.RepoDigests = append(newImage.RepoDigests, reference.FamiliarString(ref))
|
||||
}
|
||||
if _, ok := ref.(reference.NamedTagged); ok {
|
||||
newImage.RepoTags = append(newImage.RepoTags, ref.String())
|
||||
newImage.RepoTags = append(newImage.RepoTags, reference.FamiliarString(ref))
|
||||
}
|
||||
}
|
||||
if newImage.RepoDigests == nil && newImage.RepoTags == nil {
|
||||
|
|
|
@ -2,13 +2,13 @@ package daemon
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/builder/dockerfile"
|
||||
"github.com/docker/docker/dockerversion"
|
||||
|
@ -18,7 +18,7 @@ import (
|
|||
"github.com/docker/docker/pkg/httputils"
|
||||
"github.com/docker/docker/pkg/progress"
|
||||
"github.com/docker/docker/pkg/streamformatter"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// ImportImage imports an image, getting the archived layer data either from
|
||||
|
@ -35,11 +35,10 @@ func (daemon *Daemon) ImportImage(src string, repository, tag string, msg string
|
|||
|
||||
if repository != "" {
|
||||
var err error
|
||||
newRef, err = reference.ParseNamed(repository)
|
||||
newRef, err = reference.ParseNormalizedNamed(repository)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, isCanonical := newRef.(reference.Canonical); isCanonical {
|
||||
return errors.New("cannot import digest reference")
|
||||
}
|
||||
|
|
|
@ -6,13 +6,13 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
timetypes "github.com/docker/docker/api/types/time"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/docker/docker/pkg/directory"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/docker/docker/runconfig"
|
||||
"github.com/docker/docker/volume"
|
||||
"github.com/docker/libnetwork"
|
||||
|
|
|
@ -14,7 +14,7 @@ import (
|
|||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/docker/docker/pkg/progress"
|
||||
"github.com/docker/docker/reference"
|
||||
refstore "github.com/docker/docker/reference"
|
||||
"github.com/docker/docker/registry"
|
||||
"github.com/docker/libtrust"
|
||||
"github.com/opencontainers/go-digest"
|
||||
|
@ -44,7 +44,7 @@ type Config struct {
|
|||
ImageStore ImageConfigStore
|
||||
// ReferenceStore manages tags. This value is optional, when excluded
|
||||
// content will not be tagged.
|
||||
ReferenceStore reference.Store
|
||||
ReferenceStore refstore.Store
|
||||
// RequireSchema2 ensures that only schema2 manifests are used.
|
||||
RequireSchema2 bool
|
||||
}
|
||||
|
|
|
@ -7,12 +7,12 @@ import (
|
|||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/registry/api/errcode"
|
||||
"github.com/docker/distribution/registry/api/v2"
|
||||
"github.com/docker/distribution/registry/client"
|
||||
"github.com/docker/distribution/registry/client/auth"
|
||||
"github.com/docker/docker/distribution/xfer"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
|
@ -78,11 +78,11 @@ func TranslatePullError(err error, ref reference.Named) error {
|
|||
switch v.Code {
|
||||
case errcode.ErrorCodeDenied:
|
||||
// ErrorCodeDenied is used when access to the repository was denied
|
||||
newErr = errors.Errorf("repository %s not found: does not exist or no pull access", ref.Name())
|
||||
newErr = errors.Errorf("repository %s not found: does not exist or no pull access", reference.FamiliarName(ref))
|
||||
case v2.ErrorCodeManifestUnknown:
|
||||
newErr = errors.Errorf("manifest for %s not found", ref.String())
|
||||
newErr = errors.Errorf("manifest for %s not found", reference.FamiliarString(ref))
|
||||
case v2.ErrorCodeNameUnknown:
|
||||
newErr = errors.Errorf("repository %s not found", ref.Name())
|
||||
newErr = errors.Errorf("repository %s not found", reference.FamiliarName(ref))
|
||||
}
|
||||
if newErr != nil {
|
||||
logrus.Infof("Translating %q to %q", err, newErr)
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
package distribution
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api"
|
||||
"github.com/docker/docker/distribution/metadata"
|
||||
"github.com/docker/docker/pkg/progress"
|
||||
"github.com/docker/docker/reference"
|
||||
refstore "github.com/docker/docker/reference"
|
||||
"github.com/docker/docker/registry"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"golang.org/x/net/context"
|
||||
|
@ -56,12 +56,12 @@ func Pull(ctx context.Context, ref reference.Named, imagePullConfig *ImagePullCo
|
|||
return err
|
||||
}
|
||||
|
||||
// makes sure name is not empty or `scratch`
|
||||
if err := ValidateRepoName(repoInfo.Name()); err != nil {
|
||||
// makes sure name is not `scratch`
|
||||
if err := ValidateRepoName(repoInfo.Name); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
endpoints, err := imagePullConfig.RegistryService.LookupPullEndpoints(repoInfo.Hostname())
|
||||
endpoints, err := imagePullConfig.RegistryService.LookupPullEndpoints(reference.Domain(repoInfo.Name))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -105,7 +105,7 @@ func Pull(ctx context.Context, ref reference.Named, imagePullConfig *ImagePullCo
|
|||
}
|
||||
}
|
||||
|
||||
logrus.Debugf("Trying to pull %s from %s %s", repoInfo.Name(), endpoint.URL, endpoint.Version)
|
||||
logrus.Debugf("Trying to pull %s from %s %s", reference.FamiliarName(repoInfo.Name), endpoint.URL, endpoint.Version)
|
||||
|
||||
puller, err := newPuller(endpoint, repoInfo, imagePullConfig)
|
||||
if err != nil {
|
||||
|
@ -147,12 +147,12 @@ func Pull(ctx context.Context, ref reference.Named, imagePullConfig *ImagePullCo
|
|||
return TranslatePullError(err, ref)
|
||||
}
|
||||
|
||||
imagePullConfig.ImageEventLogger(ref.String(), repoInfo.Name(), "pull")
|
||||
imagePullConfig.ImageEventLogger(reference.FamiliarString(ref), reference.FamiliarName(repoInfo.Name), "pull")
|
||||
return nil
|
||||
}
|
||||
|
||||
if lastErr == nil {
|
||||
lastErr = fmt.Errorf("no endpoints found for %s", ref.String())
|
||||
lastErr = fmt.Errorf("no endpoints found for %s", reference.FamiliarString(ref))
|
||||
}
|
||||
|
||||
return TranslatePullError(lastErr, ref)
|
||||
|
@ -171,17 +171,14 @@ func writeStatus(requestedTag string, out progress.Output, layersDownloaded bool
|
|||
}
|
||||
|
||||
// ValidateRepoName validates the name of a repository.
|
||||
func ValidateRepoName(name string) error {
|
||||
if name == "" {
|
||||
return errors.New("Repository name can't be empty")
|
||||
}
|
||||
if name == api.NoBaseImageSpecifier {
|
||||
func ValidateRepoName(name reference.Named) error {
|
||||
if reference.FamiliarName(name) == api.NoBaseImageSpecifier {
|
||||
return fmt.Errorf("'%s' is a reserved name", api.NoBaseImageSpecifier)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func addDigestReference(store reference.Store, ref reference.Named, dgst digest.Digest, id digest.Digest) error {
|
||||
func addDigestReference(store refstore.Store, ref reference.Named, dgst digest.Digest, id digest.Digest) error {
|
||||
dgstRef, err := reference.WithDigest(reference.TrimNamed(ref), dgst)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -193,7 +190,7 @@ func addDigestReference(store reference.Store, ref reference.Named, dgst digest.
|
|||
logrus.Errorf("Image ID for digest %s changed from %s to %s, cannot update", dgst.String(), oldTagID, id)
|
||||
}
|
||||
return nil
|
||||
} else if err != reference.ErrDoesNotExist {
|
||||
} else if err != refstore.ErrDoesNotExist {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/registry/client/transport"
|
||||
"github.com/docker/docker/distribution/metadata"
|
||||
"github.com/docker/docker/distribution/xfer"
|
||||
|
@ -22,7 +23,6 @@ import (
|
|||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/pkg/progress"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/docker/docker/registry"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
@ -67,23 +67,23 @@ func (p *v1Puller) Pull(ctx context.Context, ref reference.Named) error {
|
|||
// TODO(dmcgowan): Check if should fallback
|
||||
return err
|
||||
}
|
||||
progress.Message(p.config.ProgressOutput, "", p.repoInfo.FullName()+": this image was pulled from a legacy registry. Important: This registry version will not be supported in future versions of docker.")
|
||||
progress.Message(p.config.ProgressOutput, "", p.repoInfo.Name.Name()+": this image was pulled from a legacy registry. Important: This registry version will not be supported in future versions of docker.")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *v1Puller) pullRepository(ctx context.Context, ref reference.Named) error {
|
||||
progress.Message(p.config.ProgressOutput, "", "Pulling repository "+p.repoInfo.FullName())
|
||||
progress.Message(p.config.ProgressOutput, "", "Pulling repository "+p.repoInfo.Name.Name())
|
||||
|
||||
tagged, isTagged := ref.(reference.NamedTagged)
|
||||
|
||||
repoData, err := p.session.GetRepositoryData(p.repoInfo)
|
||||
repoData, err := p.session.GetRepositoryData(p.repoInfo.Name)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "HTTP code: 404") {
|
||||
if isTagged {
|
||||
return fmt.Errorf("Error: image %s:%s not found", p.repoInfo.RemoteName(), tagged.Tag())
|
||||
return fmt.Errorf("Error: image %s:%s not found", reference.Path(p.repoInfo.Name), tagged.Tag())
|
||||
}
|
||||
return fmt.Errorf("Error: image %s not found", p.repoInfo.RemoteName())
|
||||
return fmt.Errorf("Error: image %s not found", reference.Path(p.repoInfo.Name))
|
||||
}
|
||||
// Unexpected HTTP error
|
||||
return err
|
||||
|
@ -92,13 +92,13 @@ func (p *v1Puller) pullRepository(ctx context.Context, ref reference.Named) erro
|
|||
logrus.Debug("Retrieving the tag list")
|
||||
var tagsList map[string]string
|
||||
if !isTagged {
|
||||
tagsList, err = p.session.GetRemoteTags(repoData.Endpoints, p.repoInfo)
|
||||
tagsList, err = p.session.GetRemoteTags(repoData.Endpoints, p.repoInfo.Name)
|
||||
} else {
|
||||
var tagID string
|
||||
tagsList = make(map[string]string)
|
||||
tagID, err = p.session.GetRemoteTag(repoData.Endpoints, p.repoInfo, tagged.Tag())
|
||||
tagID, err = p.session.GetRemoteTag(repoData.Endpoints, p.repoInfo.Name, tagged.Tag())
|
||||
if err == registry.ErrRepoNotFound {
|
||||
return fmt.Errorf("Tag %s not found in repository %s", tagged.Tag(), p.repoInfo.FullName())
|
||||
return fmt.Errorf("Tag %s not found in repository %s", tagged.Tag(), p.repoInfo.Name.Name())
|
||||
}
|
||||
tagsList[tagged.Tag()] = tagID
|
||||
}
|
||||
|
@ -127,7 +127,7 @@ func (p *v1Puller) pullRepository(ctx context.Context, ref reference.Named) erro
|
|||
}
|
||||
}
|
||||
|
||||
writeStatus(ref.String(), p.config.ProgressOutput, layersDownloaded)
|
||||
writeStatus(reference.FamiliarString(ref), p.config.ProgressOutput, layersDownloaded)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -137,7 +137,7 @@ func (p *v1Puller) downloadImage(ctx context.Context, repoData *registry.Reposit
|
|||
return nil
|
||||
}
|
||||
|
||||
localNameRef, err := reference.WithTag(p.repoInfo, img.Tag)
|
||||
localNameRef, err := reference.WithTag(p.repoInfo.Name, img.Tag)
|
||||
if err != nil {
|
||||
retErr := fmt.Errorf("Image (id: %s) has invalid tag: %s", img.ID, img.Tag)
|
||||
logrus.Debug(retErr.Error())
|
||||
|
@ -148,15 +148,15 @@ func (p *v1Puller) downloadImage(ctx context.Context, repoData *registry.Reposit
|
|||
return err
|
||||
}
|
||||
|
||||
progress.Updatef(p.config.ProgressOutput, stringid.TruncateID(img.ID), "Pulling image (%s) from %s", img.Tag, p.repoInfo.FullName())
|
||||
progress.Updatef(p.config.ProgressOutput, stringid.TruncateID(img.ID), "Pulling image (%s) from %s", img.Tag, p.repoInfo.Name.Name())
|
||||
success := false
|
||||
var lastErr error
|
||||
for _, ep := range p.repoInfo.Index.Mirrors {
|
||||
ep += "v1/"
|
||||
progress.Updatef(p.config.ProgressOutput, stringid.TruncateID(img.ID), fmt.Sprintf("Pulling image (%s) from %s, mirror: %s", img.Tag, p.repoInfo.FullName(), ep))
|
||||
progress.Updatef(p.config.ProgressOutput, stringid.TruncateID(img.ID), fmt.Sprintf("Pulling image (%s) from %s, mirror: %s", img.Tag, p.repoInfo.Name.Name(), ep))
|
||||
if err = p.pullImage(ctx, img.ID, ep, localNameRef, layersDownloaded); err != nil {
|
||||
// Don't report errors when pulling from mirrors.
|
||||
logrus.Debugf("Error pulling image (%s) from %s, mirror: %s, %s", img.Tag, p.repoInfo.FullName(), ep, err)
|
||||
logrus.Debugf("Error pulling image (%s) from %s, mirror: %s, %s", img.Tag, p.repoInfo.Name.Name(), ep, err)
|
||||
continue
|
||||
}
|
||||
success = true
|
||||
|
@ -164,12 +164,12 @@ func (p *v1Puller) downloadImage(ctx context.Context, repoData *registry.Reposit
|
|||
}
|
||||
if !success {
|
||||
for _, ep := range repoData.Endpoints {
|
||||
progress.Updatef(p.config.ProgressOutput, stringid.TruncateID(img.ID), "Pulling image (%s) from %s, endpoint: %s", img.Tag, p.repoInfo.FullName(), ep)
|
||||
progress.Updatef(p.config.ProgressOutput, stringid.TruncateID(img.ID), "Pulling image (%s) from %s, endpoint: %s", img.Tag, p.repoInfo.Name.Name(), ep)
|
||||
if err = p.pullImage(ctx, img.ID, ep, localNameRef, layersDownloaded); err != nil {
|
||||
// It's not ideal that only the last error is returned, it would be better to concatenate the errors.
|
||||
// As the error is also given to the output stream the user will see the error.
|
||||
lastErr = err
|
||||
progress.Updatef(p.config.ProgressOutput, stringid.TruncateID(img.ID), "Error pulling image (%s) from %s, endpoint: %s, %s", img.Tag, p.repoInfo.FullName(), ep, err)
|
||||
progress.Updatef(p.config.ProgressOutput, stringid.TruncateID(img.ID), "Error pulling image (%s) from %s, endpoint: %s, %s", img.Tag, p.repoInfo.Name.Name(), ep, err)
|
||||
continue
|
||||
}
|
||||
success = true
|
||||
|
@ -177,7 +177,7 @@ func (p *v1Puller) downloadImage(ctx context.Context, repoData *registry.Reposit
|
|||
}
|
||||
}
|
||||
if !success {
|
||||
err := fmt.Errorf("Error pulling image (%s) from %s, %v", img.Tag, p.repoInfo.FullName(), lastErr)
|
||||
err := fmt.Errorf("Error pulling image (%s) from %s, %v", img.Tag, p.repoInfo.Name.Name(), lastErr)
|
||||
progress.Update(p.config.ProgressOutput, stringid.TruncateID(img.ID), err.Error())
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ import (
|
|||
"github.com/docker/distribution/manifest/manifestlist"
|
||||
"github.com/docker/distribution/manifest/schema1"
|
||||
"github.com/docker/distribution/manifest/schema2"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/registry/api/errcode"
|
||||
"github.com/docker/distribution/registry/client/auth"
|
||||
"github.com/docker/distribution/registry/client/transport"
|
||||
|
@ -26,7 +27,7 @@ import (
|
|||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/pkg/progress"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/docker/reference"
|
||||
refstore "github.com/docker/docker/reference"
|
||||
"github.com/docker/docker/registry"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"golang.org/x/net/context"
|
||||
|
@ -124,7 +125,7 @@ func (p *v2Puller) pullV2Repository(ctx context.Context, ref reference.Named) (e
|
|||
}
|
||||
}
|
||||
|
||||
writeStatus(ref.String(), p.config.ProgressOutput, layersDownloaded)
|
||||
writeStatus(reference.FamiliarString(ref), p.config.ProgressOutput, layersDownloaded)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -317,7 +318,7 @@ func (ld *v2LayerDescriptor) truncateDownloadFile() error {
|
|||
|
||||
func (ld *v2LayerDescriptor) Registered(diffID layer.DiffID) {
|
||||
// Cache mapping from this layer's DiffID to the blobsum
|
||||
ld.V2MetadataService.Add(diffID, metadata.V2Metadata{Digest: ld.digest, SourceRepository: ld.repoInfo.FullName()})
|
||||
ld.V2MetadataService.Add(diffID, metadata.V2Metadata{Digest: ld.digest, SourceRepository: ld.repoInfo.Name.Name()})
|
||||
}
|
||||
|
||||
func (p *v2Puller) pullV2Tag(ctx context.Context, ref reference.Named) (tagUpdated bool, err error) {
|
||||
|
@ -343,7 +344,7 @@ func (p *v2Puller) pullV2Tag(ctx context.Context, ref reference.Named) (tagUpdat
|
|||
}
|
||||
tagOrDigest = digested.Digest().String()
|
||||
} else {
|
||||
return false, fmt.Errorf("internal error: reference has neither a tag nor a digest: %s", ref.String())
|
||||
return false, fmt.Errorf("internal error: reference has neither a tag nor a digest: %s", reference.FamiliarString(ref))
|
||||
}
|
||||
|
||||
if manifest == nil {
|
||||
|
@ -371,8 +372,8 @@ func (p *v2Puller) pullV2Tag(ctx context.Context, ref reference.Named) (tagUpdat
|
|||
// the other side speaks the v2 protocol.
|
||||
p.confirmedV2 = true
|
||||
|
||||
logrus.Debugf("Pulling ref from V2 registry: %s", ref.String())
|
||||
progress.Message(p.config.ProgressOutput, tagOrDigest, "Pulling from "+p.repo.Named().Name())
|
||||
logrus.Debugf("Pulling ref from V2 registry: %s", reference.FamiliarString(ref))
|
||||
progress.Message(p.config.ProgressOutput, tagOrDigest, "Pulling from "+reference.FamiliarName(p.repo.Named()))
|
||||
|
||||
var (
|
||||
id digest.Digest
|
||||
|
@ -410,7 +411,7 @@ func (p *v2Puller) pullV2Tag(ctx context.Context, ref reference.Named) (tagUpdat
|
|||
if oldTagID == id {
|
||||
return false, addDigestReference(p.config.ReferenceStore, ref, manifestDigest, id)
|
||||
}
|
||||
} else if err != reference.ErrDoesNotExist {
|
||||
} else if err != refstore.ErrDoesNotExist {
|
||||
return false, err
|
||||
}
|
||||
|
||||
|
@ -802,13 +803,13 @@ func verifySchema1Manifest(signedManifest *schema1.SignedManifest, ref reference
|
|||
m = &signedManifest.Manifest
|
||||
|
||||
if m.SchemaVersion != 1 {
|
||||
return nil, fmt.Errorf("unsupported schema version %d for %q", m.SchemaVersion, ref.String())
|
||||
return nil, fmt.Errorf("unsupported schema version %d for %q", m.SchemaVersion, reference.FamiliarString(ref))
|
||||
}
|
||||
if len(m.FSLayers) != len(m.History) {
|
||||
return nil, fmt.Errorf("length of history not equal to number of layers for %q", ref.String())
|
||||
return nil, fmt.Errorf("length of history not equal to number of layers for %q", reference.FamiliarString(ref))
|
||||
}
|
||||
if len(m.FSLayers) == 0 {
|
||||
return nil, fmt.Errorf("no FSLayers in manifest for %q", ref.String())
|
||||
return nil, fmt.Errorf("no FSLayers in manifest for %q", reference.FamiliarString(ref))
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/docker/distribution/manifest/schema1"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/opencontainers/go-digest"
|
||||
)
|
||||
|
||||
|
@ -113,7 +113,7 @@ func TestValidateManifest(t *testing.T) {
|
|||
if runtime.GOOS == "windows" {
|
||||
t.Skip("Needs fixing on Windows")
|
||||
}
|
||||
expectedDigest, err := reference.ParseNamed("repo@sha256:02fee8c3220ba806531f606525eceb83f4feb654f62b207191b1c9209188dedd")
|
||||
expectedDigest, err := reference.ParseNormalizedNamed("repo@sha256:02fee8c3220ba806531f606525eceb83f4feb654f62b207191b1c9209188dedd")
|
||||
if err != nil {
|
||||
t.Fatal("could not parse reference")
|
||||
}
|
||||
|
|
|
@ -7,9 +7,9 @@ import (
|
|||
"io"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/distribution/metadata"
|
||||
"github.com/docker/docker/pkg/progress"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/docker/docker/registry"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
@ -64,16 +64,16 @@ func Push(ctx context.Context, ref reference.Named, imagePushConfig *ImagePushCo
|
|||
return err
|
||||
}
|
||||
|
||||
endpoints, err := imagePushConfig.RegistryService.LookupPushEndpoints(repoInfo.Hostname())
|
||||
endpoints, err := imagePushConfig.RegistryService.LookupPushEndpoints(reference.Domain(repoInfo.Name))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
progress.Messagef(imagePushConfig.ProgressOutput, "", "The push refers to a repository [%s]", repoInfo.FullName())
|
||||
progress.Messagef(imagePushConfig.ProgressOutput, "", "The push refers to a repository [%s]", repoInfo.Name.Name())
|
||||
|
||||
associations := imagePushConfig.ReferenceStore.ReferencesByName(repoInfo)
|
||||
associations := imagePushConfig.ReferenceStore.ReferencesByName(repoInfo.Name)
|
||||
if len(associations) == 0 {
|
||||
return fmt.Errorf("An image does not exist locally with the tag: %s", repoInfo.Name())
|
||||
return fmt.Errorf("An image does not exist locally with the tag: %s", reference.FamiliarName(repoInfo.Name))
|
||||
}
|
||||
|
||||
var (
|
||||
|
@ -106,7 +106,7 @@ func Push(ctx context.Context, ref reference.Named, imagePushConfig *ImagePushCo
|
|||
}
|
||||
}
|
||||
|
||||
logrus.Debugf("Trying to push %s to %s %s", repoInfo.FullName(), endpoint.URL, endpoint.Version)
|
||||
logrus.Debugf("Trying to push %s to %s %s", repoInfo.Name.Name(), endpoint.URL, endpoint.Version)
|
||||
|
||||
pusher, err := NewPusher(ref, endpoint, repoInfo, imagePushConfig)
|
||||
if err != nil {
|
||||
|
@ -135,12 +135,12 @@ func Push(ctx context.Context, ref reference.Named, imagePushConfig *ImagePushCo
|
|||
return err
|
||||
}
|
||||
|
||||
imagePushConfig.ImageEventLogger(ref.String(), repoInfo.Name(), "push")
|
||||
imagePushConfig.ImageEventLogger(reference.FamiliarString(ref), reference.FamiliarName(repoInfo.Name), "push")
|
||||
return nil
|
||||
}
|
||||
|
||||
if lastErr == nil {
|
||||
lastErr = fmt.Errorf("no endpoints found for %s", repoInfo.FullName())
|
||||
lastErr = fmt.Errorf("no endpoints found for %s", repoInfo.Name.Name())
|
||||
}
|
||||
return lastErr
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"sync"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/registry/client/transport"
|
||||
"github.com/docker/docker/distribution/metadata"
|
||||
"github.com/docker/docker/dockerversion"
|
||||
|
@ -14,7 +15,6 @@ import (
|
|||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/pkg/progress"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/docker/docker/registry"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"golang.org/x/net/context"
|
||||
|
@ -356,8 +356,8 @@ func (p *v1Pusher) pushImageToEndpoint(ctx context.Context, endpoint string, ima
|
|||
}
|
||||
if topImage, isTopImage := img.(*v1TopImage); isTopImage {
|
||||
for _, tag := range tags[topImage.imageID] {
|
||||
progress.Messagef(p.config.ProgressOutput, "", "Pushing tag for rev [%s] on {%s}", stringid.TruncateID(v1ID), endpoint+"repositories/"+p.repoInfo.RemoteName()+"/tags/"+tag)
|
||||
if err := p.session.PushRegistryTag(p.repoInfo, v1ID, tag, endpoint); err != nil {
|
||||
progress.Messagef(p.config.ProgressOutput, "", "Pushing tag for rev [%s] on {%s}", stringid.TruncateID(v1ID), endpoint+"repositories/"+reference.Path(p.repoInfo.Name)+"/tags/"+tag)
|
||||
if err := p.session.PushRegistryTag(p.repoInfo.Name, v1ID, tag, endpoint); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -385,7 +385,7 @@ func (p *v1Pusher) pushRepository(ctx context.Context) error {
|
|||
|
||||
// Register all the images in a repository with the registry
|
||||
// If an image is not in this list it will not be associated with the repository
|
||||
repoData, err := p.session.PushImageJSONIndex(p.repoInfo, imageIndex, false, nil)
|
||||
repoData, err := p.session.PushImageJSONIndex(p.repoInfo.Name, imageIndex, false, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -395,7 +395,7 @@ func (p *v1Pusher) pushRepository(ctx context.Context) error {
|
|||
return err
|
||||
}
|
||||
}
|
||||
_, err = p.session.PushImageJSONIndex(p.repoInfo, imageIndex, true, repoData.Endpoints)
|
||||
_, err = p.session.PushImageJSONIndex(p.repoInfo.Name, imageIndex, true, repoData.Endpoints)
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ import (
|
|||
"github.com/docker/distribution"
|
||||
"github.com/docker/distribution/manifest/schema1"
|
||||
"github.com/docker/distribution/manifest/schema2"
|
||||
distreference "github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/registry/client"
|
||||
apitypes "github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/distribution/metadata"
|
||||
|
@ -24,7 +24,6 @@ import (
|
|||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/pkg/progress"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/docker/docker/registry"
|
||||
"github.com/opencontainers/go-digest"
|
||||
)
|
||||
|
@ -83,7 +82,7 @@ func (p *v2Pusher) pushV2Repository(ctx context.Context) (err error) {
|
|||
if namedTagged, isNamedTagged := p.ref.(reference.NamedTagged); isNamedTagged {
|
||||
imageID, err := p.config.ReferenceStore.Get(p.ref)
|
||||
if err != nil {
|
||||
return fmt.Errorf("tag does not exist: %s", p.ref.String())
|
||||
return fmt.Errorf("tag does not exist: %s", reference.FamiliarString(p.ref))
|
||||
}
|
||||
|
||||
return p.pushV2Tag(ctx, namedTagged, imageID)
|
||||
|
@ -105,23 +104,23 @@ func (p *v2Pusher) pushV2Repository(ctx context.Context) (err error) {
|
|||
}
|
||||
|
||||
if pushed == 0 {
|
||||
return fmt.Errorf("no tags to push for %s", p.repoInfo.Name())
|
||||
return fmt.Errorf("no tags to push for %s", reference.FamiliarName(p.repoInfo.Name))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *v2Pusher) pushV2Tag(ctx context.Context, ref reference.NamedTagged, id digest.Digest) error {
|
||||
logrus.Debugf("Pushing repository: %s", ref.String())
|
||||
logrus.Debugf("Pushing repository: %s", reference.FamiliarString(ref))
|
||||
|
||||
imgConfig, err := p.config.ImageStore.Get(id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not find image from tag %s: %v", ref.String(), err)
|
||||
return fmt.Errorf("could not find image from tag %s: %v", reference.FamiliarString(ref), err)
|
||||
}
|
||||
|
||||
rootfs, err := p.config.ImageStore.RootFSFromConfig(imgConfig)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to get rootfs for image %s: %s", ref.String(), err)
|
||||
return fmt.Errorf("unable to get rootfs for image %s: %s", reference.FamiliarString(ref), err)
|
||||
}
|
||||
|
||||
l, err := p.config.LayerStore.Get(rootfs.ChainID())
|
||||
|
@ -140,7 +139,7 @@ func (p *v2Pusher) pushV2Tag(ctx context.Context, ref reference.NamedTagged, id
|
|||
descriptorTemplate := v2PushDescriptor{
|
||||
v2MetadataService: p.v2MetadataService,
|
||||
hmacKey: hmacKey,
|
||||
repoInfo: p.repoInfo,
|
||||
repoInfo: p.repoInfo.Name,
|
||||
ref: p.ref,
|
||||
repo: p.repo,
|
||||
pushState: &p.pushState,
|
||||
|
@ -181,7 +180,7 @@ func (p *v2Pusher) pushV2Tag(ctx context.Context, ref reference.NamedTagged, id
|
|||
|
||||
logrus.Warnf("failed to upload schema2 manifest: %v - falling back to schema1", err)
|
||||
|
||||
manifestRef, err := distreference.WithTag(p.repo.Named(), ref.Tag())
|
||||
manifestRef, err := reference.WithTag(p.repo.Named(), ref.Tag())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -248,7 +247,7 @@ type v2PushDescriptor struct {
|
|||
}
|
||||
|
||||
func (pd *v2PushDescriptor) Key() string {
|
||||
return "v2push:" + pd.ref.FullName() + " " + pd.layer.DiffID().String()
|
||||
return "v2push:" + pd.ref.Name() + " " + pd.layer.DiffID().String()
|
||||
}
|
||||
|
||||
func (pd *v2PushDescriptor) ID() string {
|
||||
|
@ -304,23 +303,22 @@ func (pd *v2PushDescriptor) Upload(ctx context.Context, progressOutput progress.
|
|||
createOpts := []distribution.BlobCreateOption{}
|
||||
|
||||
if len(mountCandidate.SourceRepository) > 0 {
|
||||
namedRef, err := reference.WithName(mountCandidate.SourceRepository)
|
||||
namedRef, err := reference.ParseNormalizedNamed(mountCandidate.SourceRepository)
|
||||
if err != nil {
|
||||
logrus.Errorf("failed to parse source repository reference %v: %v", namedRef.String(), err)
|
||||
logrus.Errorf("failed to parse source repository reference %v: %v", reference.FamiliarString(namedRef), err)
|
||||
pd.v2MetadataService.Remove(mountCandidate)
|
||||
continue
|
||||
}
|
||||
|
||||
// TODO (brianbland): We need to construct a reference where the Name is
|
||||
// only the full remote name, so clean this up when distribution has a
|
||||
// richer reference package
|
||||
remoteRef, err := distreference.WithName(namedRef.RemoteName())
|
||||
// Candidates are always under same domain, create remote reference
|
||||
// with only path to set mount from with
|
||||
remoteRef, err := reference.WithName(reference.Path(namedRef))
|
||||
if err != nil {
|
||||
logrus.Errorf("failed to make remote reference out of %q: %v", namedRef.RemoteName(), namedRef.RemoteName())
|
||||
logrus.Errorf("failed to make remote reference out of %q: %v", reference.Path(namedRef), err)
|
||||
continue
|
||||
}
|
||||
|
||||
canonicalRef, err := distreference.WithDigest(distreference.TrimNamed(remoteRef), mountCandidate.Digest)
|
||||
canonicalRef, err := reference.WithDigest(reference.TrimNamed(remoteRef), mountCandidate.Digest)
|
||||
if err != nil {
|
||||
logrus.Errorf("failed to make canonical reference: %v", err)
|
||||
continue
|
||||
|
@ -347,7 +345,7 @@ func (pd *v2PushDescriptor) Upload(ctx context.Context, progressOutput progress.
|
|||
// Cache mapping from this layer's DiffID to the blobsum
|
||||
if err := pd.v2MetadataService.TagAndAdd(diffID, pd.hmacKey, metadata.V2Metadata{
|
||||
Digest: err.Descriptor.Digest,
|
||||
SourceRepository: pd.repoInfo.FullName(),
|
||||
SourceRepository: pd.repoInfo.Name(),
|
||||
}); err != nil {
|
||||
return distribution.Descriptor{}, xfer.DoNotRetry{Err: err}
|
||||
}
|
||||
|
@ -455,7 +453,7 @@ func (pd *v2PushDescriptor) uploadUsingSession(
|
|||
// Cache mapping from this layer's DiffID to the blobsum
|
||||
if err := pd.v2MetadataService.TagAndAdd(diffID, pd.hmacKey, metadata.V2Metadata{
|
||||
Digest: pushDigest,
|
||||
SourceRepository: pd.repoInfo.FullName(),
|
||||
SourceRepository: pd.repoInfo.Name(),
|
||||
}); err != nil {
|
||||
return distribution.Descriptor{}, xfer.DoNotRetry{Err: err}
|
||||
}
|
||||
|
@ -490,7 +488,7 @@ func (pd *v2PushDescriptor) layerAlreadyExists(
|
|||
// filter the metadata
|
||||
candidates := []metadata.V2Metadata{}
|
||||
for _, meta := range v2Metadata {
|
||||
if len(meta.SourceRepository) > 0 && !checkOtherRepositories && meta.SourceRepository != pd.repoInfo.FullName() {
|
||||
if len(meta.SourceRepository) > 0 && !checkOtherRepositories && meta.SourceRepository != pd.repoInfo.Name() {
|
||||
continue
|
||||
}
|
||||
candidates = append(candidates, meta)
|
||||
|
@ -521,16 +519,16 @@ func (pd *v2PushDescriptor) layerAlreadyExists(
|
|||
attempts:
|
||||
for _, dgst := range layerDigests {
|
||||
meta := digestToMetadata[dgst]
|
||||
logrus.Debugf("Checking for presence of layer %s (%s) in %s", diffID, dgst, pd.repoInfo.FullName())
|
||||
logrus.Debugf("Checking for presence of layer %s (%s) in %s", diffID, dgst, pd.repoInfo.Name())
|
||||
desc, err = pd.repo.Blobs(ctx).Stat(ctx, dgst)
|
||||
pd.checkedDigests[meta.Digest] = struct{}{}
|
||||
switch err {
|
||||
case nil:
|
||||
if m, ok := digestToMetadata[desc.Digest]; !ok || m.SourceRepository != pd.repoInfo.FullName() || !metadata.CheckV2MetadataHMAC(m, pd.hmacKey) {
|
||||
if m, ok := digestToMetadata[desc.Digest]; !ok || m.SourceRepository != pd.repoInfo.Name() || !metadata.CheckV2MetadataHMAC(m, pd.hmacKey) {
|
||||
// cache mapping from this layer's DiffID to the blobsum
|
||||
if err := pd.v2MetadataService.TagAndAdd(diffID, pd.hmacKey, metadata.V2Metadata{
|
||||
Digest: desc.Digest,
|
||||
SourceRepository: pd.repoInfo.FullName(),
|
||||
SourceRepository: pd.repoInfo.Name(),
|
||||
}); err != nil {
|
||||
return distribution.Descriptor{}, false, xfer.DoNotRetry{Err: err}
|
||||
}
|
||||
|
@ -539,12 +537,12 @@ attempts:
|
|||
exists = true
|
||||
break attempts
|
||||
case distribution.ErrBlobUnknown:
|
||||
if meta.SourceRepository == pd.repoInfo.FullName() {
|
||||
if meta.SourceRepository == pd.repoInfo.Name() {
|
||||
// remove the mapping to the target repository
|
||||
pd.v2MetadataService.Remove(*meta)
|
||||
}
|
||||
default:
|
||||
logrus.WithError(err).Debugf("Failed to check for presence of layer %s (%s) in %s", diffID, dgst, pd.repoInfo.FullName())
|
||||
logrus.WithError(err).Debugf("Failed to check for presence of layer %s (%s) in %s", diffID, dgst, pd.repoInfo.Name())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -598,11 +596,11 @@ func getRepositoryMountCandidates(
|
|||
candidates := []metadata.V2Metadata{}
|
||||
for _, meta := range v2Metadata {
|
||||
sourceRepo, err := reference.ParseNamed(meta.SourceRepository)
|
||||
if err != nil || repoInfo.Hostname() != sourceRepo.Hostname() {
|
||||
if err != nil || reference.Domain(repoInfo) != reference.Domain(sourceRepo) {
|
||||
continue
|
||||
}
|
||||
// target repository is not a viable candidate
|
||||
if meta.SourceRepository == repoInfo.FullName() {
|
||||
if meta.SourceRepository == repoInfo.Name() {
|
||||
continue
|
||||
}
|
||||
candidates = append(candidates, meta)
|
||||
|
@ -653,7 +651,7 @@ func sortV2MetadataByLikenessAndAge(repoInfo reference.Named, hmacKey []byte, ma
|
|||
sort.Stable(byLikeness{
|
||||
arr: marr,
|
||||
hmacKey: hmacKey,
|
||||
pathComponents: getPathComponents(repoInfo.FullName()),
|
||||
pathComponents: getPathComponents(repoInfo.Name()),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -670,11 +668,6 @@ func numOfMatchingPathComponents(pth string, matchComponents []string) int {
|
|||
}
|
||||
|
||||
func getPathComponents(path string) []string {
|
||||
// make sure to add docker.io/ prefix to the path
|
||||
named, err := reference.ParseNamed(path)
|
||||
if err == nil {
|
||||
path = named.FullName()
|
||||
}
|
||||
return strings.Split(path, "/")
|
||||
}
|
||||
|
||||
|
|
|
@ -8,11 +8,10 @@ import (
|
|||
"github.com/docker/distribution"
|
||||
"github.com/docker/distribution/context"
|
||||
"github.com/docker/distribution/manifest/schema2"
|
||||
distreference "github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/distribution/metadata"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/docker/docker/pkg/progress"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/opencontainers/go-digest"
|
||||
)
|
||||
|
||||
|
@ -43,8 +42,8 @@ func TestGetRepositoryMountCandidates(t *testing.T) {
|
|||
name: "one item matching",
|
||||
targetRepo: "busybox",
|
||||
maxCandidates: -1,
|
||||
metadata: []metadata.V2Metadata{taggedMetadata("hash", "1", "hello-world")},
|
||||
candidates: []metadata.V2Metadata{taggedMetadata("hash", "1", "hello-world")},
|
||||
metadata: []metadata.V2Metadata{taggedMetadata("hash", "1", "docker.io/library/hello-world")},
|
||||
candidates: []metadata.V2Metadata{taggedMetadata("hash", "1", "docker.io/library/hello-world")},
|
||||
},
|
||||
{
|
||||
name: "allow missing SourceRepository",
|
||||
|
@ -63,13 +62,13 @@ func TestGetRepositoryMountCandidates(t *testing.T) {
|
|||
maxCandidates: -1,
|
||||
metadata: []metadata.V2Metadata{
|
||||
{Digest: digest.Digest("1"), SourceRepository: "docker.io/user/foo"},
|
||||
{Digest: digest.Digest("3"), SourceRepository: "user/bar"},
|
||||
{Digest: digest.Digest("2"), SourceRepository: "app"},
|
||||
{Digest: digest.Digest("3"), SourceRepository: "docker.io/user/bar"},
|
||||
{Digest: digest.Digest("2"), SourceRepository: "docker.io/library/app"},
|
||||
},
|
||||
candidates: []metadata.V2Metadata{
|
||||
{Digest: digest.Digest("3"), SourceRepository: "user/bar"},
|
||||
{Digest: digest.Digest("3"), SourceRepository: "docker.io/user/bar"},
|
||||
{Digest: digest.Digest("1"), SourceRepository: "docker.io/user/foo"},
|
||||
{Digest: digest.Digest("2"), SourceRepository: "app"},
|
||||
{Digest: digest.Digest("2"), SourceRepository: "docker.io/library/app"},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -78,10 +77,10 @@ func TestGetRepositoryMountCandidates(t *testing.T) {
|
|||
targetRepo: "127.0.0.1/foo/bar",
|
||||
maxCandidates: -1,
|
||||
metadata: []metadata.V2Metadata{
|
||||
taggedMetadata("hash", "1", "hello-world"),
|
||||
taggedMetadata("hash", "1", "docker.io/library/hello-world"),
|
||||
taggedMetadata("efgh", "2", "127.0.0.1/hello-world"),
|
||||
taggedMetadata("abcd", "3", "busybox"),
|
||||
taggedMetadata("hash", "4", "busybox"),
|
||||
taggedMetadata("abcd", "3", "docker.io/library/busybox"),
|
||||
taggedMetadata("hash", "4", "docker.io/library/busybox"),
|
||||
taggedMetadata("hash", "5", "127.0.0.1/foo"),
|
||||
taggedMetadata("hash", "6", "127.0.0.1/bar"),
|
||||
taggedMetadata("efgh", "7", "127.0.0.1/foo/bar"),
|
||||
|
@ -105,23 +104,25 @@ func TestGetRepositoryMountCandidates(t *testing.T) {
|
|||
targetRepo: "user/app",
|
||||
maxCandidates: 3,
|
||||
metadata: []metadata.V2Metadata{
|
||||
taggedMetadata("abcd", "1", "user/app1"),
|
||||
taggedMetadata("abcd", "2", "user/app/base"),
|
||||
taggedMetadata("hash", "3", "user/app"),
|
||||
taggedMetadata("abcd", "1", "docker.io/user/app1"),
|
||||
taggedMetadata("abcd", "2", "docker.io/user/app/base"),
|
||||
taggedMetadata("hash", "3", "docker.io/user/app"),
|
||||
taggedMetadata("abcd", "4", "127.0.0.1/user/app"),
|
||||
taggedMetadata("hash", "5", "user/foo"),
|
||||
taggedMetadata("hash", "6", "app/bar"),
|
||||
taggedMetadata("hash", "5", "docker.io/user/foo"),
|
||||
taggedMetadata("hash", "6", "docker.io/app/bar"),
|
||||
},
|
||||
candidates: []metadata.V2Metadata{
|
||||
// first by matching hash
|
||||
taggedMetadata("abcd", "2", "user/app/base"),
|
||||
taggedMetadata("abcd", "1", "user/app1"),
|
||||
taggedMetadata("abcd", "2", "docker.io/user/app/base"),
|
||||
taggedMetadata("abcd", "1", "docker.io/user/app1"),
|
||||
// then by longest matching prefix
|
||||
taggedMetadata("hash", "3", "user/app"),
|
||||
// "docker.io/usr/app" is excluded since candidates must
|
||||
// be from a different repository
|
||||
taggedMetadata("hash", "5", "docker.io/user/foo"),
|
||||
},
|
||||
},
|
||||
} {
|
||||
repoInfo, err := reference.ParseNamed(tc.targetRepo)
|
||||
repoInfo, err := reference.ParseNormalizedNamed(tc.targetRepo)
|
||||
if err != nil {
|
||||
t.Fatalf("[%s] failed to parse reference name: %v", tc.name, err)
|
||||
}
|
||||
|
@ -204,10 +205,13 @@ func TestLayerAlreadyExists(t *testing.T) {
|
|||
{Digest: digest.Digest("apple"), SourceRepository: "docker.io/library/hello-world"},
|
||||
{Digest: digest.Digest("orange"), SourceRepository: "docker.io/busybox/subapp"},
|
||||
{Digest: digest.Digest("pear"), SourceRepository: "docker.io/busybox"},
|
||||
{Digest: digest.Digest("plum"), SourceRepository: "busybox"},
|
||||
{Digest: digest.Digest("plum"), SourceRepository: "docker.io/library/busybox"},
|
||||
{Digest: digest.Digest("banana"), SourceRepository: "127.0.0.1/busybox"},
|
||||
},
|
||||
expectedRequests: []string{"plum", "pear", "apple", "orange", "banana"},
|
||||
expectedRequests: []string{"plum", "apple", "pear", "orange", "banana"},
|
||||
expectedRemovals: []metadata.V2Metadata{
|
||||
{Digest: digest.Digest("plum"), SourceRepository: "docker.io/library/busybox"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "find existing blob",
|
||||
|
@ -374,7 +378,7 @@ func TestLayerAlreadyExists(t *testing.T) {
|
|||
},
|
||||
},
|
||||
} {
|
||||
repoInfo, err := reference.ParseNamed(tc.targetRepo)
|
||||
repoInfo, err := reference.ParseNormalizedNamed(tc.targetRepo)
|
||||
if err != nil {
|
||||
t.Fatalf("[%s] failed to parse reference name: %v", tc.name, err)
|
||||
}
|
||||
|
@ -476,7 +480,7 @@ type mockRepo struct {
|
|||
|
||||
var _ distribution.Repository = &mockRepo{}
|
||||
|
||||
func (m *mockRepo) Named() distreference.Named {
|
||||
func (m *mockRepo) Named() reference.Named {
|
||||
m.t.Fatalf("Named() not implemented")
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
|
||||
"github.com/docker/distribution"
|
||||
"github.com/docker/distribution/manifest/schema2"
|
||||
distreference "github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/registry/client"
|
||||
"github.com/docker/distribution/registry/client/auth"
|
||||
"github.com/docker/distribution/registry/client/transport"
|
||||
|
@ -55,10 +55,10 @@ func init() {
|
|||
// providing timeout settings and authentication support, and also verifies the
|
||||
// remote API version.
|
||||
func NewV2Repository(ctx context.Context, repoInfo *registry.RepositoryInfo, endpoint registry.APIEndpoint, metaHeaders http.Header, authConfig *types.AuthConfig, actions ...string) (repo distribution.Repository, foundVersion bool, err error) {
|
||||
repoName := repoInfo.FullName()
|
||||
repoName := repoInfo.Name.Name()
|
||||
// If endpoint does not support CanonicalName, use the RemoteName instead
|
||||
if endpoint.TrimHostname {
|
||||
repoName = repoInfo.RemoteName()
|
||||
repoName = reference.Path(repoInfo.Name)
|
||||
}
|
||||
|
||||
direct := &net.Dialer{
|
||||
|
@ -122,7 +122,7 @@ func NewV2Repository(ctx context.Context, repoInfo *registry.RepositoryInfo, end
|
|||
}
|
||||
tr := transport.NewTransport(base, modifiers...)
|
||||
|
||||
repoNameRef, err := distreference.ParseNamed(repoName)
|
||||
repoNameRef, err := reference.WithName(repoName)
|
||||
if err != nil {
|
||||
return nil, foundVersion, fallbackError{
|
||||
err: err,
|
||||
|
|
|
@ -12,11 +12,11 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
registrytypes "github.com/docker/docker/api/types/registry"
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/docker/docker/registry"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
@ -61,9 +61,9 @@ func testTokenPassThru(t *testing.T, ts *httptest.Server) {
|
|||
TrimHostname: false,
|
||||
TLSConfig: nil,
|
||||
}
|
||||
n, _ := reference.ParseNamed("testremotename")
|
||||
n, _ := reference.ParseNormalizedNamed("testremotename")
|
||||
repoInfo := ®istry.RepositoryInfo{
|
||||
Named: n,
|
||||
Name: n,
|
||||
Index: ®istrytypes.IndexInfo{
|
||||
Name: "testrepo",
|
||||
Mirrors: nil,
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/image/v1"
|
||||
"github.com/docker/docker/layer"
|
||||
|
@ -21,7 +22,6 @@ import (
|
|||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/docker/pkg/symlink"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/opencontainers/go-digest"
|
||||
)
|
||||
|
||||
|
@ -117,7 +117,7 @@ func (l *tarexporter) Load(inTar io.ReadCloser, outStream io.Writer, quiet bool)
|
|||
|
||||
imageRefCount = 0
|
||||
for _, repoTag := range m.RepoTags {
|
||||
named, err := reference.ParseNamed(repoTag)
|
||||
named, err := reference.ParseNormalizedNamed(repoTag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -126,7 +126,7 @@ func (l *tarexporter) Load(inTar io.ReadCloser, outStream io.Writer, quiet bool)
|
|||
return fmt.Errorf("invalid tag %q", repoTag)
|
||||
}
|
||||
l.setLoadedTag(ref, imgID.Digest(), outStream)
|
||||
outStream.Write([]byte(fmt.Sprintf("Loaded image: %s\n", ref)))
|
||||
outStream.Write([]byte(fmt.Sprintf("Loaded image: %s\n", reference.FamiliarString(ref))))
|
||||
imageRefCount++
|
||||
}
|
||||
|
||||
|
@ -201,7 +201,7 @@ func (l *tarexporter) loadLayer(filename string, rootFS image.RootFS, id string,
|
|||
|
||||
func (l *tarexporter) setLoadedTag(ref reference.NamedTagged, imgID digest.Digest, outStream io.Writer) error {
|
||||
if prevID, err := l.rs.Get(ref); err == nil && prevID != imgID {
|
||||
fmt.Fprintf(outStream, "The image %s already exists, renaming the old one with ID %s to empty string\n", ref.String(), string(prevID)) // todo: this message is wrong in case of multiple tags
|
||||
fmt.Fprintf(outStream, "The image %s already exists, renaming the old one with ID %s to empty string\n", reference.FamiliarString(ref), string(prevID)) // todo: this message is wrong in case of multiple tags
|
||||
}
|
||||
|
||||
if err := l.rs.AddTag(ref, imgID, true); err != nil {
|
||||
|
@ -249,7 +249,7 @@ func (l *tarexporter) legacyLoad(tmpDir string, outStream io.Writer, progressOut
|
|||
if !ok {
|
||||
return fmt.Errorf("invalid target ID: %v", oldID)
|
||||
}
|
||||
named, err := reference.WithName(name)
|
||||
named, err := reference.ParseNormalizedNamed(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -10,12 +10,12 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/docker/distribution"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/image/v1"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
@ -51,16 +51,12 @@ func (l *tarexporter) parseNames(names []string) (map[image.ID]*imageDescriptor,
|
|||
}
|
||||
|
||||
if ref != nil {
|
||||
var tagged reference.NamedTagged
|
||||
if _, ok := ref.(reference.Canonical); ok {
|
||||
return
|
||||
}
|
||||
var ok bool
|
||||
if tagged, ok = ref.(reference.NamedTagged); !ok {
|
||||
var err error
|
||||
if tagged, err = reference.WithTag(ref, reference.DefaultTag); err != nil {
|
||||
return
|
||||
}
|
||||
tagged, ok := reference.TagNameOnly(ref).(reference.NamedTagged)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
for _, t := range imgDescr[id].refs {
|
||||
|
@ -73,19 +69,26 @@ func (l *tarexporter) parseNames(names []string) (map[image.ID]*imageDescriptor,
|
|||
}
|
||||
|
||||
for _, name := range names {
|
||||
id, ref, err := reference.ParseIDOrReference(name)
|
||||
ref, err := reference.ParseAnyReference(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if id != "" {
|
||||
_, err := l.is.Get(image.IDFromDigest(id))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
namedRef, ok := ref.(reference.Named)
|
||||
if !ok {
|
||||
// Check if digest ID reference
|
||||
if digested, ok := ref.(reference.Digested); ok {
|
||||
id := image.IDFromDigest(digested.Digest())
|
||||
_, err := l.is.Get(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
addAssoc(id, nil)
|
||||
continue
|
||||
}
|
||||
addAssoc(image.IDFromDigest(id), nil)
|
||||
continue
|
||||
return nil, errors.Errorf("invalid reference: %v", name)
|
||||
}
|
||||
if ref.Name() == string(digest.Canonical) {
|
||||
|
||||
if reference.FamiliarName(namedRef) == string(digest.Canonical) {
|
||||
imgID, err := l.is.Search(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -93,8 +96,8 @@ func (l *tarexporter) parseNames(names []string) (map[image.ID]*imageDescriptor,
|
|||
addAssoc(imgID, nil)
|
||||
continue
|
||||
}
|
||||
if reference.IsNameOnly(ref) {
|
||||
assocs := l.rs.ReferencesByName(ref)
|
||||
if reference.IsNameOnly(namedRef) {
|
||||
assocs := l.rs.ReferencesByName(namedRef)
|
||||
for _, assoc := range assocs {
|
||||
addAssoc(image.IDFromDigest(assoc.ID), assoc.Ref)
|
||||
}
|
||||
|
@ -107,11 +110,11 @@ func (l *tarexporter) parseNames(names []string) (map[image.ID]*imageDescriptor,
|
|||
}
|
||||
continue
|
||||
}
|
||||
id, err = l.rs.Get(ref)
|
||||
id, err := l.rs.Get(namedRef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
addAssoc(image.IDFromDigest(id), ref)
|
||||
addAssoc(image.IDFromDigest(id), namedRef)
|
||||
|
||||
}
|
||||
return imgDescr, nil
|
||||
|
@ -144,11 +147,12 @@ func (s *saveSession) save(outStream io.Writer) error {
|
|||
var layers []string
|
||||
|
||||
for _, ref := range imageDescr.refs {
|
||||
if _, ok := reposLegacy[ref.Name()]; !ok {
|
||||
reposLegacy[ref.Name()] = make(map[string]string)
|
||||
familiarName := reference.FamiliarName(ref)
|
||||
if _, ok := reposLegacy[familiarName]; !ok {
|
||||
reposLegacy[familiarName] = make(map[string]string)
|
||||
}
|
||||
reposLegacy[ref.Name()][ref.Tag()] = imageDescr.layers[len(imageDescr.layers)-1]
|
||||
repoTags = append(repoTags, ref.String())
|
||||
reposLegacy[familiarName][ref.Tag()] = imageDescr.layers[len(imageDescr.layers)-1]
|
||||
repoTags = append(repoTags, reference.FamiliarString(ref))
|
||||
}
|
||||
|
||||
for _, l := range imageDescr.layers {
|
||||
|
|
|
@ -4,7 +4,7 @@ import (
|
|||
"github.com/docker/distribution"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/docker/docker/reference"
|
||||
refstore "github.com/docker/docker/reference"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -26,7 +26,7 @@ type manifestItem struct {
|
|||
type tarexporter struct {
|
||||
is image.Store
|
||||
ls layer.Store
|
||||
rs reference.Store
|
||||
rs refstore.Store
|
||||
loggerImgEvent LogImageEvent
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,7 @@ type LogImageEvent interface {
|
|||
}
|
||||
|
||||
// NewTarExporter returns new Exporter for tar packages
|
||||
func NewTarExporter(is image.Store, ls layer.Store, rs reference.Store, loggerImgEvent LogImageEvent) image.Exporter {
|
||||
func NewTarExporter(is image.Store, ls layer.Store, rs refstore.Store, loggerImgEvent LogImageEvent) image.Exporter {
|
||||
return &tarexporter{
|
||||
is: is,
|
||||
ls: ls,
|
||||
|
|
|
@ -335,7 +335,7 @@ func (s *DockerSuite) TestImagesFormat(c *check.C) {
|
|||
expected := []string{"myimage", "myimage"}
|
||||
var names []string
|
||||
names = append(names, lines...)
|
||||
c.Assert(expected, checker.DeepEquals, names, check.Commentf("Expected array with truncated names: %v, got: %v", expected, names))
|
||||
c.Assert(names, checker.DeepEquals, expected, check.Commentf("Expected array with truncated names: %v, got: %v", expected, names))
|
||||
}
|
||||
|
||||
// ImagesDefaultFormatAndQuiet
|
||||
|
|
|
@ -14,12 +14,13 @@ import (
|
|||
"encoding/json"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/distribution/metadata"
|
||||
"github.com/docker/docker/image"
|
||||
imagev1 "github.com/docker/docker/image/v1"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/reference"
|
||||
refstore "github.com/docker/docker/reference"
|
||||
"github.com/opencontainers/go-digest"
|
||||
)
|
||||
|
||||
|
@ -56,7 +57,7 @@ var (
|
|||
|
||||
// Migrate takes an old graph directory and transforms the metadata into the
|
||||
// new format.
|
||||
func Migrate(root, driverName string, ls layer.Store, is image.Store, rs reference.Store, ms metadata.Store) error {
|
||||
func Migrate(root, driverName string, ls layer.Store, is image.Store, rs refstore.Store, ms metadata.Store) error {
|
||||
graphDir := filepath.Join(root, graphDirName)
|
||||
if _, err := os.Lstat(graphDir); os.IsNotExist(err) {
|
||||
return nil
|
||||
|
@ -322,11 +323,15 @@ func migrateRefs(root, driverName string, rs refAdder, mappings map[string]image
|
|||
for name, repo := range repos.Repositories {
|
||||
for tag, id := range repo {
|
||||
if strongID, exists := mappings[id]; exists {
|
||||
ref, err := reference.WithName(name)
|
||||
ref, err := reference.ParseNormalizedNamed(name)
|
||||
if err != nil {
|
||||
logrus.Errorf("migrate tags: invalid name %q, %q", name, err)
|
||||
continue
|
||||
}
|
||||
if !reference.IsNameOnly(ref) {
|
||||
logrus.Errorf("migrate tags: invalid name %q, unexpected tag or digest", name)
|
||||
continue
|
||||
}
|
||||
if dgst, err := digest.Parse(tag); err == nil {
|
||||
canonical, err := reference.WithDigest(reference.TrimNamed(ref), dgst)
|
||||
if err != nil {
|
||||
|
@ -334,7 +339,7 @@ func migrateRefs(root, driverName string, rs refAdder, mappings map[string]image
|
|||
continue
|
||||
}
|
||||
if err := rs.AddDigest(canonical, strongID.Digest(), false); err != nil {
|
||||
logrus.Errorf("can't migrate digest %q for %q, err: %q", ref.String(), strongID, err)
|
||||
logrus.Errorf("can't migrate digest %q for %q, err: %q", reference.FamiliarString(ref), strongID, err)
|
||||
}
|
||||
} else {
|
||||
tagRef, err := reference.WithTag(ref, tag)
|
||||
|
@ -343,7 +348,7 @@ func migrateRefs(root, driverName string, rs refAdder, mappings map[string]image
|
|||
continue
|
||||
}
|
||||
if err := rs.AddTag(tagRef, strongID.Digest(), false); err != nil {
|
||||
logrus.Errorf("can't migrate tag %q for %q, err: %q", ref.String(), strongID, err)
|
||||
logrus.Errorf("can't migrate tag %q for %q, err: %q", reference.FamiliarString(ref), strongID, err)
|
||||
}
|
||||
}
|
||||
logrus.Infof("migrated tag %s:%s to point to %s", name, tag, strongID)
|
||||
|
|
|
@ -13,10 +13,10 @@ import (
|
|||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/distribution/metadata"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/opencontainers/go-digest"
|
||||
)
|
||||
|
||||
|
@ -40,9 +40,9 @@ func TestMigrateRefs(t *testing.T) {
|
|||
}
|
||||
|
||||
expected := map[string]string{
|
||||
"busybox:latest": "sha256:fcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9",
|
||||
"busybox@sha256:16a2a52884c2a9481ed267c2d46483eac7693b813a63132368ab098a71303f8a": "sha256:fcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9",
|
||||
"registry:2": "sha256:2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae",
|
||||
"docker.io/library/busybox:latest": "sha256:fcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9",
|
||||
"docker.io/library/busybox@sha256:16a2a52884c2a9481ed267c2d46483eac7693b813a63132368ab098a71303f8a": "sha256:fcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9",
|
||||
"docker.io/library/registry:2": "sha256:2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae",
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(expected, ta.refs) {
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution/manifest/schema2"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/distribution"
|
||||
|
@ -30,7 +31,7 @@ import (
|
|||
"github.com/docker/docker/pkg/pools"
|
||||
"github.com/docker/docker/pkg/progress"
|
||||
"github.com/docker/docker/plugin/v2"
|
||||
"github.com/docker/docker/reference"
|
||||
refstore "github.com/docker/docker/reference"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/net/context"
|
||||
|
@ -232,11 +233,11 @@ func (pm *Manager) Upgrade(ctx context.Context, ref reference.Named, name string
|
|||
defer pm.muGC.RUnlock()
|
||||
|
||||
// revalidate because Pull is public
|
||||
nameref, err := reference.ParseNamed(name)
|
||||
nameref, err := reference.ParseNormalizedNamed(name)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to parse %q", name)
|
||||
}
|
||||
name = reference.WithDefaultTag(nameref).String()
|
||||
name = reference.FamiliarString(reference.TagNameOnly(nameref))
|
||||
|
||||
tmpRootFSDir, err := ioutil.TempDir(pm.tmpDir(), ".rootfs")
|
||||
defer os.RemoveAll(tmpRootFSDir)
|
||||
|
@ -277,11 +278,11 @@ func (pm *Manager) Pull(ctx context.Context, ref reference.Named, name string, m
|
|||
defer pm.muGC.RUnlock()
|
||||
|
||||
// revalidate because Pull is public
|
||||
nameref, err := reference.ParseNamed(name)
|
||||
nameref, err := reference.ParseNormalizedNamed(name)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to parse %q", name)
|
||||
}
|
||||
name = reference.WithDefaultTag(nameref).String()
|
||||
name = reference.FamiliarString(reference.TagNameOnly(nameref))
|
||||
|
||||
if err := pm.config.Store.validateName(name); err != nil {
|
||||
return err
|
||||
|
@ -370,7 +371,7 @@ func (pm *Manager) Push(ctx context.Context, name string, metaHeader http.Header
|
|||
return err
|
||||
}
|
||||
|
||||
ref, err := reference.ParseNamed(p.Name())
|
||||
ref, err := reference.ParseNormalizedNamed(p.Name())
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "plugin has invalid name %v for push", p.Name())
|
||||
}
|
||||
|
@ -448,8 +449,8 @@ func (r *pluginReference) References(id digest.Digest) []reference.Named {
|
|||
return []reference.Named{r.name}
|
||||
}
|
||||
|
||||
func (r *pluginReference) ReferencesByName(ref reference.Named) []reference.Association {
|
||||
return []reference.Association{
|
||||
func (r *pluginReference) ReferencesByName(ref reference.Named) []refstore.Association {
|
||||
return []refstore.Association{
|
||||
{
|
||||
Ref: r.name,
|
||||
ID: r.pluginID,
|
||||
|
@ -459,7 +460,7 @@ func (r *pluginReference) ReferencesByName(ref reference.Named) []reference.Asso
|
|||
|
||||
func (r *pluginReference) Get(ref reference.Named) (digest.Digest, error) {
|
||||
if r.name.String() != ref.String() {
|
||||
return digest.Digest(""), reference.ErrDoesNotExist
|
||||
return digest.Digest(""), refstore.ErrDoesNotExist
|
||||
}
|
||||
return r.pluginID, nil
|
||||
}
|
||||
|
@ -664,15 +665,14 @@ func (pm *Manager) CreateFromContext(ctx context.Context, tarCtx io.ReadCloser,
|
|||
pm.muGC.RLock()
|
||||
defer pm.muGC.RUnlock()
|
||||
|
||||
ref, err := reference.ParseNamed(options.RepoName)
|
||||
ref, err := reference.ParseNormalizedNamed(options.RepoName)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to parse reference %v", options.RepoName)
|
||||
}
|
||||
if _, ok := ref.(reference.Canonical); ok {
|
||||
return errors.Errorf("canonical references are not permitted")
|
||||
}
|
||||
taggedRef := reference.WithDefaultTag(ref)
|
||||
name := taggedRef.String()
|
||||
name := reference.FamiliarString(reference.TagNameOnly(ref))
|
||||
|
||||
if err := pm.config.Store.validateName(name); err != nil { // fast check, real check is in createPlugin()
|
||||
return err
|
||||
|
@ -754,7 +754,7 @@ func (pm *Manager) CreateFromContext(ctx context.Context, tarCtx io.ReadCloser,
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.PluginObj.PluginReference = taggedRef.String()
|
||||
p.PluginObj.PluginReference = name
|
||||
|
||||
pm.config.LogPluginEvent(p.PluginObj.ID, name, "create")
|
||||
|
||||
|
|
|
@ -7,9 +7,9 @@ import (
|
|||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/reference"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
|
|
|
@ -5,10 +5,10 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/pkg/plugingetter"
|
||||
"github.com/docker/docker/pkg/plugins"
|
||||
"github.com/docker/docker/plugin/v2"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
|
@ -230,19 +230,19 @@ func (ps *Store) resolvePluginID(idOrName string) (string, error) {
|
|||
return idOrName, nil
|
||||
}
|
||||
|
||||
ref, err := reference.ParseNamed(idOrName)
|
||||
ref, err := reference.ParseNormalizedNamed(idOrName)
|
||||
if err != nil {
|
||||
return "", errors.WithStack(ErrNotFound(idOrName))
|
||||
}
|
||||
if _, ok := ref.(reference.Canonical); ok {
|
||||
logrus.Warnf("canonical references cannot be resolved: %v", ref.String())
|
||||
logrus.Warnf("canonical references cannot be resolved: %v", reference.FamiliarString(ref))
|
||||
return "", errors.WithStack(ErrNotFound(idOrName))
|
||||
}
|
||||
|
||||
fullRef := reference.WithDefaultTag(ref)
|
||||
ref = reference.TagNameOnly(ref)
|
||||
|
||||
for _, p := range ps.plugins {
|
||||
if p.PluginObj.Name == fullRef.String() {
|
||||
if p.PluginObj.Name == reference.FamiliarString(ref) {
|
||||
return p.PluginObj.ID, nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,194 +0,0 @@
|
|||
package reference
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
distreference "github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultTag defines the default tag used when performing images related actions and no tag or digest is specified
|
||||
DefaultTag = "latest"
|
||||
// DefaultHostname is the default built-in hostname
|
||||
DefaultHostname = "docker.io"
|
||||
// LegacyDefaultHostname is automatically converted to DefaultHostname
|
||||
LegacyDefaultHostname = "index.docker.io"
|
||||
// DefaultRepoPrefix is the prefix used for default repositories in default host
|
||||
DefaultRepoPrefix = "library/"
|
||||
)
|
||||
|
||||
// Named is an object with a full name
|
||||
type Named interface {
|
||||
// Name returns normalized repository name, like "ubuntu".
|
||||
Name() string
|
||||
// String returns full reference, like "ubuntu@sha256:abcdef..."
|
||||
String() string
|
||||
// FullName returns full repository name with hostname, like "docker.io/library/ubuntu"
|
||||
FullName() string
|
||||
// Hostname returns hostname for the reference, like "docker.io"
|
||||
Hostname() string
|
||||
// RemoteName returns the repository component of the full name, like "library/ubuntu"
|
||||
RemoteName() string
|
||||
}
|
||||
|
||||
// NamedTagged is an object including a name and tag.
|
||||
type NamedTagged interface {
|
||||
Named
|
||||
Tag() string
|
||||
}
|
||||
|
||||
// Canonical reference is an object with a fully unique
|
||||
// name including a name with hostname and digest
|
||||
type Canonical interface {
|
||||
Named
|
||||
Digest() digest.Digest
|
||||
}
|
||||
|
||||
// ParseNamed parses s and returns a syntactically valid reference implementing
|
||||
// the Named interface. The reference must have a name, otherwise an error is
|
||||
// returned.
|
||||
// If an error was encountered it is returned, along with a nil Reference.
|
||||
func ParseNamed(s string) (Named, error) {
|
||||
named, err := distreference.ParseNormalizedNamed(s)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to parse reference %q", s)
|
||||
}
|
||||
if err := validateName(distreference.FamiliarName(named)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Ensure returned reference cannot have tag and digest
|
||||
if canonical, isCanonical := named.(distreference.Canonical); isCanonical {
|
||||
r, err := distreference.WithDigest(distreference.TrimNamed(named), canonical.Digest())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &canonicalRef{namedRef{r}}, nil
|
||||
}
|
||||
if tagged, isTagged := named.(distreference.NamedTagged); isTagged {
|
||||
r, err := distreference.WithTag(distreference.TrimNamed(named), tagged.Tag())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &taggedRef{namedRef{r}}, nil
|
||||
}
|
||||
|
||||
return &namedRef{named}, nil
|
||||
}
|
||||
|
||||
// TrimNamed removes any tag or digest from the named reference
|
||||
func TrimNamed(ref Named) Named {
|
||||
return &namedRef{distreference.TrimNamed(ref)}
|
||||
}
|
||||
|
||||
// WithName returns a named object representing the given string. If the input
|
||||
// is invalid ErrReferenceInvalidFormat will be returned.
|
||||
func WithName(name string) (Named, error) {
|
||||
r, err := distreference.ParseNormalizedNamed(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := validateName(distreference.FamiliarName(r)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !distreference.IsNameOnly(r) {
|
||||
return nil, distreference.ErrReferenceInvalidFormat
|
||||
}
|
||||
return &namedRef{r}, nil
|
||||
}
|
||||
|
||||
// WithTag combines the name from "name" and the tag from "tag" to form a
|
||||
// reference incorporating both the name and the tag.
|
||||
func WithTag(name Named, tag string) (NamedTagged, error) {
|
||||
r, err := distreference.WithTag(name, tag)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &taggedRef{namedRef{r}}, nil
|
||||
}
|
||||
|
||||
// WithDigest combines the name from "name" and the digest from "digest" to form
|
||||
// a reference incorporating both the name and the digest.
|
||||
func WithDigest(name Named, digest digest.Digest) (Canonical, error) {
|
||||
r, err := distreference.WithDigest(name, digest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &canonicalRef{namedRef{r}}, nil
|
||||
}
|
||||
|
||||
type namedRef struct {
|
||||
distreference.Named
|
||||
}
|
||||
type taggedRef struct {
|
||||
namedRef
|
||||
}
|
||||
type canonicalRef struct {
|
||||
namedRef
|
||||
}
|
||||
|
||||
func (r *namedRef) Name() string {
|
||||
return distreference.FamiliarName(r.Named)
|
||||
}
|
||||
|
||||
func (r *namedRef) String() string {
|
||||
return distreference.FamiliarString(r.Named)
|
||||
}
|
||||
|
||||
func (r *namedRef) FullName() string {
|
||||
return r.Named.Name()
|
||||
}
|
||||
func (r *namedRef) Hostname() string {
|
||||
return distreference.Domain(r.Named)
|
||||
}
|
||||
func (r *namedRef) RemoteName() string {
|
||||
return distreference.Path(r.Named)
|
||||
}
|
||||
func (r *taggedRef) Tag() string {
|
||||
return r.namedRef.Named.(distreference.NamedTagged).Tag()
|
||||
}
|
||||
func (r *canonicalRef) Digest() digest.Digest {
|
||||
return r.namedRef.Named.(distreference.Canonical).Digest()
|
||||
}
|
||||
|
||||
// WithDefaultTag adds a default tag to a reference if it only has a repo name.
|
||||
func WithDefaultTag(ref Named) Named {
|
||||
if IsNameOnly(ref) {
|
||||
ref, _ = WithTag(ref, DefaultTag)
|
||||
}
|
||||
return ref
|
||||
}
|
||||
|
||||
// IsNameOnly returns true if reference only contains a repo name.
|
||||
func IsNameOnly(ref Named) bool {
|
||||
if _, ok := ref.(NamedTagged); ok {
|
||||
return false
|
||||
}
|
||||
if _, ok := ref.(Canonical); ok {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// ParseIDOrReference parses string for an image ID or a reference. ID can be
|
||||
// without a default prefix.
|
||||
func ParseIDOrReference(idOrRef string) (digest.Digest, Named, error) {
|
||||
if err := stringid.ValidateID(idOrRef); err == nil {
|
||||
idOrRef = "sha256:" + idOrRef
|
||||
}
|
||||
if dgst, err := digest.Parse(idOrRef); err == nil {
|
||||
return dgst, nil, nil
|
||||
}
|
||||
ref, err := ParseNamed(idOrRef)
|
||||
return "", ref, err
|
||||
}
|
||||
|
||||
func validateName(name string) error {
|
||||
if err := stringid.ValidateID(name); err == nil {
|
||||
return fmt.Errorf("Invalid repository name (%s), cannot specify 64-byte hexadecimal strings", name)
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -1,275 +0,0 @@
|
|||
package reference
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/opencontainers/go-digest"
|
||||
)
|
||||
|
||||
func TestValidateReferenceName(t *testing.T) {
|
||||
validRepoNames := []string{
|
||||
"docker/docker",
|
||||
"library/debian",
|
||||
"debian",
|
||||
"docker.io/docker/docker",
|
||||
"docker.io/library/debian",
|
||||
"docker.io/debian",
|
||||
"index.docker.io/docker/docker",
|
||||
"index.docker.io/library/debian",
|
||||
"index.docker.io/debian",
|
||||
"127.0.0.1:5000/docker/docker",
|
||||
"127.0.0.1:5000/library/debian",
|
||||
"127.0.0.1:5000/debian",
|
||||
"thisisthesongthatneverendsitgoesonandonandonthisisthesongthatnev",
|
||||
}
|
||||
invalidRepoNames := []string{
|
||||
"https://github.com/docker/docker",
|
||||
"docker/Docker",
|
||||
"-docker",
|
||||
"-docker/docker",
|
||||
"-docker.io/docker/docker",
|
||||
"docker///docker",
|
||||
"docker.io/docker/Docker",
|
||||
"docker.io/docker///docker",
|
||||
"1a3f5e7d9c1b3a5f7e9d1c3b5a7f9e1d3c5b7a9f1e3d5d7c9b1a3f5e7d9c1b3a",
|
||||
"docker.io/1a3f5e7d9c1b3a5f7e9d1c3b5a7f9e1d3c5b7a9f1e3d5d7c9b1a3f5e7d9c1b3a",
|
||||
}
|
||||
|
||||
for _, name := range invalidRepoNames {
|
||||
_, err := ParseNamed(name)
|
||||
if err == nil {
|
||||
t.Fatalf("Expected invalid repo name for %q", name)
|
||||
}
|
||||
}
|
||||
|
||||
for _, name := range validRepoNames {
|
||||
_, err := ParseNamed(name)
|
||||
if err != nil {
|
||||
t.Fatalf("Error parsing repo name %s, got: %q", name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateRemoteName(t *testing.T) {
|
||||
validRepositoryNames := []string{
|
||||
// Sanity check.
|
||||
"docker/docker",
|
||||
|
||||
// Allow 64-character non-hexadecimal names (hexadecimal names are forbidden).
|
||||
"thisisthesongthatneverendsitgoesonandonandonthisisthesongthatnev",
|
||||
|
||||
// Allow embedded hyphens.
|
||||
"docker-rules/docker",
|
||||
|
||||
// Allow multiple hyphens as well.
|
||||
"docker---rules/docker",
|
||||
|
||||
//Username doc and image name docker being tested.
|
||||
"doc/docker",
|
||||
|
||||
// single character names are now allowed.
|
||||
"d/docker",
|
||||
"jess/t",
|
||||
|
||||
// Consecutive underscores.
|
||||
"dock__er/docker",
|
||||
}
|
||||
for _, repositoryName := range validRepositoryNames {
|
||||
_, err := ParseNamed(repositoryName)
|
||||
if err != nil {
|
||||
t.Errorf("Repository name should be valid: %v. Error: %v", repositoryName, err)
|
||||
}
|
||||
}
|
||||
|
||||
invalidRepositoryNames := []string{
|
||||
// Disallow capital letters.
|
||||
"docker/Docker",
|
||||
|
||||
// Only allow one slash.
|
||||
"docker///docker",
|
||||
|
||||
// Disallow 64-character hexadecimal.
|
||||
"1a3f5e7d9c1b3a5f7e9d1c3b5a7f9e1d3c5b7a9f1e3d5d7c9b1a3f5e7d9c1b3a",
|
||||
|
||||
// Disallow leading and trailing hyphens in namespace.
|
||||
"-docker/docker",
|
||||
"docker-/docker",
|
||||
"-docker-/docker",
|
||||
|
||||
// Don't allow underscores everywhere (as opposed to hyphens).
|
||||
"____/____",
|
||||
|
||||
"_docker/_docker",
|
||||
|
||||
// Disallow consecutive periods.
|
||||
"dock..er/docker",
|
||||
"dock_.er/docker",
|
||||
"dock-.er/docker",
|
||||
|
||||
// No repository.
|
||||
"docker/",
|
||||
|
||||
//namespace too long
|
||||
"this_is_not_a_valid_namespace_because_its_lenth_is_greater_than_255_this_is_not_a_valid_namespace_because_its_lenth_is_greater_than_255_this_is_not_a_valid_namespace_because_its_lenth_is_greater_than_255_this_is_not_a_valid_namespace_because_its_lenth_is_greater_than_255/docker",
|
||||
}
|
||||
for _, repositoryName := range invalidRepositoryNames {
|
||||
if _, err := ParseNamed(repositoryName); err == nil {
|
||||
t.Errorf("Repository name should be invalid: %v", repositoryName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseRepositoryInfo(t *testing.T) {
|
||||
type tcase struct {
|
||||
RemoteName, NormalizedName, FullName, AmbiguousName, Hostname string
|
||||
}
|
||||
|
||||
tcases := []tcase{
|
||||
{
|
||||
RemoteName: "fooo/bar",
|
||||
NormalizedName: "fooo/bar",
|
||||
FullName: "docker.io/fooo/bar",
|
||||
AmbiguousName: "index.docker.io/fooo/bar",
|
||||
Hostname: "docker.io",
|
||||
},
|
||||
{
|
||||
RemoteName: "library/ubuntu",
|
||||
NormalizedName: "ubuntu",
|
||||
FullName: "docker.io/library/ubuntu",
|
||||
AmbiguousName: "library/ubuntu",
|
||||
Hostname: "docker.io",
|
||||
},
|
||||
{
|
||||
RemoteName: "nonlibrary/ubuntu",
|
||||
NormalizedName: "nonlibrary/ubuntu",
|
||||
FullName: "docker.io/nonlibrary/ubuntu",
|
||||
AmbiguousName: "",
|
||||
Hostname: "docker.io",
|
||||
},
|
||||
{
|
||||
RemoteName: "other/library",
|
||||
NormalizedName: "other/library",
|
||||
FullName: "docker.io/other/library",
|
||||
AmbiguousName: "",
|
||||
Hostname: "docker.io",
|
||||
},
|
||||
{
|
||||
RemoteName: "private/moonbase",
|
||||
NormalizedName: "127.0.0.1:8000/private/moonbase",
|
||||
FullName: "127.0.0.1:8000/private/moonbase",
|
||||
AmbiguousName: "",
|
||||
Hostname: "127.0.0.1:8000",
|
||||
},
|
||||
{
|
||||
RemoteName: "privatebase",
|
||||
NormalizedName: "127.0.0.1:8000/privatebase",
|
||||
FullName: "127.0.0.1:8000/privatebase",
|
||||
AmbiguousName: "",
|
||||
Hostname: "127.0.0.1:8000",
|
||||
},
|
||||
{
|
||||
RemoteName: "private/moonbase",
|
||||
NormalizedName: "example.com/private/moonbase",
|
||||
FullName: "example.com/private/moonbase",
|
||||
AmbiguousName: "",
|
||||
Hostname: "example.com",
|
||||
},
|
||||
{
|
||||
RemoteName: "privatebase",
|
||||
NormalizedName: "example.com/privatebase",
|
||||
FullName: "example.com/privatebase",
|
||||
AmbiguousName: "",
|
||||
Hostname: "example.com",
|
||||
},
|
||||
{
|
||||
RemoteName: "private/moonbase",
|
||||
NormalizedName: "example.com:8000/private/moonbase",
|
||||
FullName: "example.com:8000/private/moonbase",
|
||||
AmbiguousName: "",
|
||||
Hostname: "example.com:8000",
|
||||
},
|
||||
{
|
||||
RemoteName: "privatebasee",
|
||||
NormalizedName: "example.com:8000/privatebasee",
|
||||
FullName: "example.com:8000/privatebasee",
|
||||
AmbiguousName: "",
|
||||
Hostname: "example.com:8000",
|
||||
},
|
||||
{
|
||||
RemoteName: "library/ubuntu-12.04-base",
|
||||
NormalizedName: "ubuntu-12.04-base",
|
||||
FullName: "docker.io/library/ubuntu-12.04-base",
|
||||
AmbiguousName: "index.docker.io/library/ubuntu-12.04-base",
|
||||
Hostname: "docker.io",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tcase := range tcases {
|
||||
refStrings := []string{tcase.NormalizedName, tcase.FullName}
|
||||
if tcase.AmbiguousName != "" {
|
||||
refStrings = append(refStrings, tcase.AmbiguousName)
|
||||
}
|
||||
|
||||
var refs []Named
|
||||
for _, r := range refStrings {
|
||||
named, err := ParseNamed(r)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
refs = append(refs, named)
|
||||
named, err = WithName(r)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
refs = append(refs, named)
|
||||
}
|
||||
|
||||
for _, r := range refs {
|
||||
if expected, actual := tcase.NormalizedName, r.Name(); expected != actual {
|
||||
t.Fatalf("Invalid normalized reference for %q. Expected %q, got %q", r, expected, actual)
|
||||
}
|
||||
if expected, actual := tcase.FullName, r.FullName(); expected != actual {
|
||||
t.Fatalf("Invalid fullName for %q. Expected %q, got %q", r, expected, actual)
|
||||
}
|
||||
if expected, actual := tcase.Hostname, r.Hostname(); expected != actual {
|
||||
t.Fatalf("Invalid hostname for %q. Expected %q, got %q", r, expected, actual)
|
||||
}
|
||||
if expected, actual := tcase.RemoteName, r.RemoteName(); expected != actual {
|
||||
t.Fatalf("Invalid remoteName for %q. Expected %q, got %q", r, expected, actual)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseReferenceWithTagAndDigest(t *testing.T) {
|
||||
ref, err := ParseNamed("busybox:latest@sha256:86e0e091d0da6bde2456dbb48306f3956bbeb2eae1b5b9a43045843f69fe4aaa")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, isTagged := ref.(NamedTagged); isTagged {
|
||||
t.Fatalf("Reference from %q should not support tag", ref)
|
||||
}
|
||||
if _, isCanonical := ref.(Canonical); !isCanonical {
|
||||
t.Fatalf("Reference from %q should not support digest", ref)
|
||||
}
|
||||
if expected, actual := "busybox@sha256:86e0e091d0da6bde2456dbb48306f3956bbeb2eae1b5b9a43045843f69fe4aaa", ref.String(); actual != expected {
|
||||
t.Fatalf("Invalid parsed reference for %q: expected %q, got %q", ref, expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvalidReferenceComponents(t *testing.T) {
|
||||
if _, err := WithName("-foo"); err == nil {
|
||||
t.Fatal("Expected WithName to detect invalid name")
|
||||
}
|
||||
ref, err := WithName("busybox")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := WithTag(ref, "-foo"); err == nil {
|
||||
t.Fatal("Expected WithName to detect invalid tag")
|
||||
}
|
||||
if _, err := WithDigest(ref, digest.Digest("foo")); err == nil {
|
||||
t.Fatal("Expected WithName to detect invalid digest")
|
||||
}
|
||||
}
|
|
@ -9,6 +9,7 @@ import (
|
|||
"sort"
|
||||
"sync"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/opencontainers/go-digest"
|
||||
)
|
||||
|
@ -21,18 +22,18 @@ var (
|
|||
|
||||
// An Association is a tuple associating a reference with an image ID.
|
||||
type Association struct {
|
||||
Ref Named
|
||||
Ref reference.Named
|
||||
ID digest.Digest
|
||||
}
|
||||
|
||||
// Store provides the set of methods which can operate on a tag store.
|
||||
type Store interface {
|
||||
References(id digest.Digest) []Named
|
||||
ReferencesByName(ref Named) []Association
|
||||
AddTag(ref Named, id digest.Digest, force bool) error
|
||||
AddDigest(ref Canonical, id digest.Digest, force bool) error
|
||||
Delete(ref Named) (bool, error)
|
||||
Get(ref Named) (digest.Digest, error)
|
||||
References(id digest.Digest) []reference.Named
|
||||
ReferencesByName(ref reference.Named) []Association
|
||||
AddTag(ref reference.Named, id digest.Digest, force bool) error
|
||||
AddDigest(ref reference.Canonical, id digest.Digest, force bool) error
|
||||
Delete(ref reference.Named) (bool, error)
|
||||
Get(ref reference.Named) (digest.Digest, error)
|
||||
}
|
||||
|
||||
type store struct {
|
||||
|
@ -44,24 +45,28 @@ type store struct {
|
|||
Repositories map[string]repository
|
||||
// referencesByIDCache is a cache of references indexed by ID, to speed
|
||||
// up References.
|
||||
referencesByIDCache map[digest.Digest]map[string]Named
|
||||
referencesByIDCache map[digest.Digest]map[string]reference.Named
|
||||
}
|
||||
|
||||
// Repository maps tags to digests. The key is a stringified Reference,
|
||||
// including the repository name.
|
||||
type repository map[string]digest.Digest
|
||||
|
||||
type lexicalRefs []Named
|
||||
type lexicalRefs []reference.Named
|
||||
|
||||
func (a lexicalRefs) Len() int { return len(a) }
|
||||
func (a lexicalRefs) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
func (a lexicalRefs) Less(i, j int) bool { return a[i].String() < a[j].String() }
|
||||
func (a lexicalRefs) Len() int { return len(a) }
|
||||
func (a lexicalRefs) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
func (a lexicalRefs) Less(i, j int) bool {
|
||||
return a[i].String() < a[j].String()
|
||||
}
|
||||
|
||||
type lexicalAssociations []Association
|
||||
|
||||
func (a lexicalAssociations) Len() int { return len(a) }
|
||||
func (a lexicalAssociations) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
func (a lexicalAssociations) Less(i, j int) bool { return a[i].Ref.String() < a[j].Ref.String() }
|
||||
func (a lexicalAssociations) Len() int { return len(a) }
|
||||
func (a lexicalAssociations) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
func (a lexicalAssociations) Less(i, j int) bool {
|
||||
return a[i].Ref.String() < a[j].Ref.String()
|
||||
}
|
||||
|
||||
// NewReferenceStore creates a new reference store, tied to a file path where
|
||||
// the set of references are serialized in JSON format.
|
||||
|
@ -74,7 +79,7 @@ func NewReferenceStore(jsonPath string) (Store, error) {
|
|||
store := &store{
|
||||
jsonPath: abspath,
|
||||
Repositories: make(map[string]repository),
|
||||
referencesByIDCache: make(map[digest.Digest]map[string]Named),
|
||||
referencesByIDCache: make(map[digest.Digest]map[string]reference.Named),
|
||||
}
|
||||
// Load the json file if it exists, otherwise create it.
|
||||
if err := store.reload(); os.IsNotExist(err) {
|
||||
|
@ -89,43 +94,45 @@ func NewReferenceStore(jsonPath string) (Store, error) {
|
|||
|
||||
// AddTag adds a tag reference to the store. If force is set to true, existing
|
||||
// references can be overwritten. This only works for tags, not digests.
|
||||
func (store *store) AddTag(ref Named, id digest.Digest, force bool) error {
|
||||
if _, isCanonical := ref.(Canonical); isCanonical {
|
||||
func (store *store) AddTag(ref reference.Named, id digest.Digest, force bool) error {
|
||||
if _, isCanonical := ref.(reference.Canonical); isCanonical {
|
||||
return errors.New("refusing to create a tag with a digest reference")
|
||||
}
|
||||
return store.addReference(WithDefaultTag(ref), id, force)
|
||||
return store.addReference(reference.TagNameOnly(ref), id, force)
|
||||
}
|
||||
|
||||
// AddDigest adds a digest reference to the store.
|
||||
func (store *store) AddDigest(ref Canonical, id digest.Digest, force bool) error {
|
||||
func (store *store) AddDigest(ref reference.Canonical, id digest.Digest, force bool) error {
|
||||
return store.addReference(ref, id, force)
|
||||
}
|
||||
|
||||
func (store *store) addReference(ref Named, id digest.Digest, force bool) error {
|
||||
if ref.Name() == string(digest.Canonical) {
|
||||
func (store *store) addReference(ref reference.Named, id digest.Digest, force bool) error {
|
||||
refName := reference.FamiliarName(ref)
|
||||
refStr := reference.FamiliarString(ref)
|
||||
|
||||
if refName == string(digest.Canonical) {
|
||||
return errors.New("refusing to create an ambiguous tag using digest algorithm as name")
|
||||
}
|
||||
|
||||
store.mu.Lock()
|
||||
defer store.mu.Unlock()
|
||||
|
||||
repository, exists := store.Repositories[ref.Name()]
|
||||
repository, exists := store.Repositories[refName]
|
||||
if !exists || repository == nil {
|
||||
repository = make(map[string]digest.Digest)
|
||||
store.Repositories[ref.Name()] = repository
|
||||
store.Repositories[refName] = repository
|
||||
}
|
||||
|
||||
refStr := ref.String()
|
||||
oldID, exists := repository[refStr]
|
||||
|
||||
if exists {
|
||||
// force only works for tags
|
||||
if digested, isDigest := ref.(Canonical); isDigest {
|
||||
if digested, isDigest := ref.(reference.Canonical); isDigest {
|
||||
return fmt.Errorf("Cannot overwrite digest %s", digested.Digest().String())
|
||||
}
|
||||
|
||||
if !force {
|
||||
return fmt.Errorf("Conflict: Tag %s is already set to image %s, if you want to replace it, please use -f option", ref.String(), oldID.String())
|
||||
return fmt.Errorf("Conflict: Tag %s is already set to image %s, if you want to replace it, please use -f option", refStr, oldID.String())
|
||||
}
|
||||
|
||||
if store.referencesByIDCache[oldID] != nil {
|
||||
|
@ -138,7 +145,7 @@ func (store *store) addReference(ref Named, id digest.Digest, force bool) error
|
|||
|
||||
repository[refStr] = id
|
||||
if store.referencesByIDCache[id] == nil {
|
||||
store.referencesByIDCache[id] = make(map[string]Named)
|
||||
store.referencesByIDCache[id] = make(map[string]reference.Named)
|
||||
}
|
||||
store.referencesByIDCache[id][refStr] = ref
|
||||
|
||||
|
@ -147,24 +154,24 @@ func (store *store) addReference(ref Named, id digest.Digest, force bool) error
|
|||
|
||||
// Delete deletes a reference from the store. It returns true if a deletion
|
||||
// happened, or false otherwise.
|
||||
func (store *store) Delete(ref Named) (bool, error) {
|
||||
ref = WithDefaultTag(ref)
|
||||
func (store *store) Delete(ref reference.Named) (bool, error) {
|
||||
ref = reference.TagNameOnly(ref)
|
||||
|
||||
refName := reference.FamiliarName(ref)
|
||||
refStr := reference.FamiliarString(ref)
|
||||
|
||||
store.mu.Lock()
|
||||
defer store.mu.Unlock()
|
||||
|
||||
repoName := ref.Name()
|
||||
|
||||
repository, exists := store.Repositories[repoName]
|
||||
repository, exists := store.Repositories[refName]
|
||||
if !exists {
|
||||
return false, ErrDoesNotExist
|
||||
}
|
||||
|
||||
refStr := ref.String()
|
||||
if id, exists := repository[refStr]; exists {
|
||||
delete(repository, refStr)
|
||||
if len(repository) == 0 {
|
||||
delete(store.Repositories, repoName)
|
||||
delete(store.Repositories, refName)
|
||||
}
|
||||
if store.referencesByIDCache[id] != nil {
|
||||
delete(store.referencesByIDCache[id], refStr)
|
||||
|
@ -179,18 +186,34 @@ func (store *store) Delete(ref Named) (bool, error) {
|
|||
}
|
||||
|
||||
// Get retrieves an item from the store by reference
|
||||
func (store *store) Get(ref Named) (digest.Digest, error) {
|
||||
ref = WithDefaultTag(ref)
|
||||
func (store *store) Get(ref reference.Named) (digest.Digest, error) {
|
||||
if canonical, ok := ref.(reference.Canonical); ok {
|
||||
// If reference contains both tag and digest, only
|
||||
// lookup by digest as it takes precendent over
|
||||
// tag, until tag/digest combos are stored.
|
||||
if _, ok := ref.(reference.Tagged); ok {
|
||||
var err error
|
||||
ref, err = reference.WithDigest(reference.TrimNamed(canonical), canonical.Digest())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ref = reference.TagNameOnly(ref)
|
||||
}
|
||||
|
||||
refName := reference.FamiliarName(ref)
|
||||
refStr := reference.FamiliarString(ref)
|
||||
|
||||
store.mu.RLock()
|
||||
defer store.mu.RUnlock()
|
||||
|
||||
repository, exists := store.Repositories[ref.Name()]
|
||||
repository, exists := store.Repositories[refName]
|
||||
if !exists || repository == nil {
|
||||
return "", ErrDoesNotExist
|
||||
}
|
||||
|
||||
id, exists := repository[ref.String()]
|
||||
id, exists := repository[refStr]
|
||||
if !exists {
|
||||
return "", ErrDoesNotExist
|
||||
}
|
||||
|
@ -200,7 +223,7 @@ func (store *store) Get(ref Named) (digest.Digest, error) {
|
|||
|
||||
// References returns a slice of references to the given ID. The slice
|
||||
// will be nil if there are no references to this ID.
|
||||
func (store *store) References(id digest.Digest) []Named {
|
||||
func (store *store) References(id digest.Digest) []reference.Named {
|
||||
store.mu.RLock()
|
||||
defer store.mu.RUnlock()
|
||||
|
||||
|
@ -208,7 +231,7 @@ func (store *store) References(id digest.Digest) []Named {
|
|||
// 1) We must not return a mutable
|
||||
// 2) It would be ugly to expose the extraneous map keys to callers.
|
||||
|
||||
var references []Named
|
||||
var references []reference.Named
|
||||
for _, ref := range store.referencesByIDCache[id] {
|
||||
references = append(references, ref)
|
||||
}
|
||||
|
@ -221,18 +244,20 @@ func (store *store) References(id digest.Digest) []Named {
|
|||
// ReferencesByName returns the references for a given repository name.
|
||||
// If there are no references known for this repository name,
|
||||
// ReferencesByName returns nil.
|
||||
func (store *store) ReferencesByName(ref Named) []Association {
|
||||
func (store *store) ReferencesByName(ref reference.Named) []Association {
|
||||
refName := reference.FamiliarName(ref)
|
||||
|
||||
store.mu.RLock()
|
||||
defer store.mu.RUnlock()
|
||||
|
||||
repository, exists := store.Repositories[ref.Name()]
|
||||
repository, exists := store.Repositories[refName]
|
||||
if !exists {
|
||||
return nil
|
||||
}
|
||||
|
||||
var associations []Association
|
||||
for refStr, refID := range repository {
|
||||
ref, err := ParseNamed(refStr)
|
||||
ref, err := reference.ParseNormalizedNamed(refStr)
|
||||
if err != nil {
|
||||
// Should never happen
|
||||
return nil
|
||||
|
@ -270,13 +295,13 @@ func (store *store) reload() error {
|
|||
|
||||
for _, repository := range store.Repositories {
|
||||
for refStr, refID := range repository {
|
||||
ref, err := ParseNamed(refStr)
|
||||
ref, err := reference.ParseNormalizedNamed(refStr)
|
||||
if err != nil {
|
||||
// Should never happen
|
||||
continue
|
||||
}
|
||||
if store.referencesByIDCache[refID] == nil {
|
||||
store.referencesByIDCache[refID] = make(map[string]Named)
|
||||
store.referencesByIDCache[refID] = make(map[string]reference.Named)
|
||||
}
|
||||
store.referencesByIDCache[refID][refStr] = ref
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/opencontainers/go-digest"
|
||||
)
|
||||
|
||||
|
@ -45,7 +46,7 @@ func TestLoad(t *testing.T) {
|
|||
}
|
||||
|
||||
for refStr, expectedID := range saveLoadTestCases {
|
||||
ref, err := ParseNamed(refStr)
|
||||
ref, err := reference.ParseNormalizedNamed(refStr)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to parse reference: %v", err)
|
||||
}
|
||||
|
@ -74,11 +75,11 @@ func TestSave(t *testing.T) {
|
|||
}
|
||||
|
||||
for refStr, id := range saveLoadTestCases {
|
||||
ref, err := ParseNamed(refStr)
|
||||
ref, err := reference.ParseNormalizedNamed(refStr)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to parse reference: %v", err)
|
||||
}
|
||||
if canonical, ok := ref.(Canonical); ok {
|
||||
if canonical, ok := ref.(reference.Canonical); ok {
|
||||
err = store.AddDigest(canonical, id, false)
|
||||
if err != nil {
|
||||
t.Fatalf("could not add digest reference %s: %v", refStr, err)
|
||||
|
@ -120,7 +121,7 @@ func TestAddDeleteGet(t *testing.T) {
|
|||
testImageID3 := digest.Digest("sha256:9655aef5fd742a1b4e1b7b163aa9f1c76c186304bf39102283d80927c916ca9e")
|
||||
|
||||
// Try adding a reference with no tag or digest
|
||||
nameOnly, err := WithName("username/repo")
|
||||
nameOnly, err := reference.ParseNormalizedNamed("username/repo")
|
||||
if err != nil {
|
||||
t.Fatalf("could not parse reference: %v", err)
|
||||
}
|
||||
|
@ -129,7 +130,7 @@ func TestAddDeleteGet(t *testing.T) {
|
|||
}
|
||||
|
||||
// Add a few references
|
||||
ref1, err := ParseNamed("username/repo1:latest")
|
||||
ref1, err := reference.ParseNormalizedNamed("username/repo1:latest")
|
||||
if err != nil {
|
||||
t.Fatalf("could not parse reference: %v", err)
|
||||
}
|
||||
|
@ -137,7 +138,7 @@ func TestAddDeleteGet(t *testing.T) {
|
|||
t.Fatalf("error adding to store: %v", err)
|
||||
}
|
||||
|
||||
ref2, err := ParseNamed("username/repo1:old")
|
||||
ref2, err := reference.ParseNormalizedNamed("username/repo1:old")
|
||||
if err != nil {
|
||||
t.Fatalf("could not parse reference: %v", err)
|
||||
}
|
||||
|
@ -145,7 +146,7 @@ func TestAddDeleteGet(t *testing.T) {
|
|||
t.Fatalf("error adding to store: %v", err)
|
||||
}
|
||||
|
||||
ref3, err := ParseNamed("username/repo1:alias")
|
||||
ref3, err := reference.ParseNormalizedNamed("username/repo1:alias")
|
||||
if err != nil {
|
||||
t.Fatalf("could not parse reference: %v", err)
|
||||
}
|
||||
|
@ -153,7 +154,7 @@ func TestAddDeleteGet(t *testing.T) {
|
|||
t.Fatalf("error adding to store: %v", err)
|
||||
}
|
||||
|
||||
ref4, err := ParseNamed("username/repo2:latest")
|
||||
ref4, err := reference.ParseNormalizedNamed("username/repo2:latest")
|
||||
if err != nil {
|
||||
t.Fatalf("could not parse reference: %v", err)
|
||||
}
|
||||
|
@ -161,11 +162,11 @@ func TestAddDeleteGet(t *testing.T) {
|
|||
t.Fatalf("error adding to store: %v", err)
|
||||
}
|
||||
|
||||
ref5, err := ParseNamed("username/repo3@sha256:58153dfb11794fad694460162bf0cb0a4fa710cfa3f60979c177d920813e267c")
|
||||
ref5, err := reference.ParseNormalizedNamed("username/repo3@sha256:58153dfb11794fad694460162bf0cb0a4fa710cfa3f60979c177d920813e267c")
|
||||
if err != nil {
|
||||
t.Fatalf("could not parse reference: %v", err)
|
||||
}
|
||||
if err = store.AddDigest(ref5.(Canonical), testImageID2, false); err != nil {
|
||||
if err = store.AddDigest(ref5.(reference.Canonical), testImageID2, false); err != nil {
|
||||
t.Fatalf("error adding to store: %v", err)
|
||||
}
|
||||
|
||||
|
@ -228,7 +229,7 @@ func TestAddDeleteGet(t *testing.T) {
|
|||
}
|
||||
|
||||
// Get should return ErrDoesNotExist for a nonexistent repo
|
||||
nonExistRepo, err := ParseNamed("username/nonexistrepo:latest")
|
||||
nonExistRepo, err := reference.ParseNormalizedNamed("username/nonexistrepo:latest")
|
||||
if err != nil {
|
||||
t.Fatalf("could not parse reference: %v", err)
|
||||
}
|
||||
|
@ -237,7 +238,7 @@ func TestAddDeleteGet(t *testing.T) {
|
|||
}
|
||||
|
||||
// Get should return ErrDoesNotExist for a nonexistent tag
|
||||
nonExistTag, err := ParseNamed("username/repo1:nonexist")
|
||||
nonExistTag, err := reference.ParseNormalizedNamed("username/repo1:nonexist")
|
||||
if err != nil {
|
||||
t.Fatalf("could not parse reference: %v", err)
|
||||
}
|
||||
|
@ -263,7 +264,7 @@ func TestAddDeleteGet(t *testing.T) {
|
|||
}
|
||||
|
||||
// Check ReferencesByName
|
||||
repoName, err := WithName("username/repo1")
|
||||
repoName, err := reference.ParseNormalizedNamed("username/repo1")
|
||||
if err != nil {
|
||||
t.Fatalf("could not parse reference: %v", err)
|
||||
}
|
||||
|
@ -334,7 +335,7 @@ func TestInvalidTags(t *testing.T) {
|
|||
id := digest.Digest("sha256:470022b8af682154f57a2163d030eb369549549cba00edc69e1b99b46bb924d6")
|
||||
|
||||
// sha256 as repo name
|
||||
ref, err := ParseNamed("sha256:abc")
|
||||
ref, err := reference.ParseNormalizedNamed("sha256:abc")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -344,7 +345,7 @@ func TestInvalidTags(t *testing.T) {
|
|||
}
|
||||
|
||||
// setting digest as a tag
|
||||
ref, err = ParseNamed("registry@sha256:367eb40fd0330a7e464777121e39d2f5b3e8e23a1e159342e53ab05c9e4d94e6")
|
||||
ref, err = reference.ParseNormalizedNamed("registry@sha256:367eb40fd0330a7e464777121e39d2f5b3e8e23a1e159342e53ab05c9e4d94e6")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ import (
|
|||
"github.com/docker/distribution/reference"
|
||||
registrytypes "github.com/docker/docker/api/types/registry"
|
||||
"github.com/docker/docker/opts"
|
||||
forkedref "github.com/docker/docker/reference"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
@ -271,8 +270,9 @@ func ValidateMirror(val string) (string, error) {
|
|||
|
||||
// ValidateIndexName validates an index name.
|
||||
func ValidateIndexName(val string) (string, error) {
|
||||
if val == forkedref.LegacyDefaultHostname {
|
||||
val = forkedref.DefaultHostname
|
||||
// TODO: upstream this to check to reference package
|
||||
if val == "index.docker.io" {
|
||||
val = "docker.io"
|
||||
}
|
||||
if strings.HasPrefix(val, "-") || strings.HasSuffix(val, "-") {
|
||||
return "", fmt.Errorf("Invalid index name (%s). Cannot begin or end with a hyphen.", val)
|
||||
|
@ -328,13 +328,8 @@ func newRepositoryInfo(config *serviceConfig, name reference.Named) (*Repository
|
|||
}
|
||||
official := !strings.ContainsRune(reference.FamiliarName(name), '/')
|
||||
|
||||
// TODO: remove used of forked reference package
|
||||
nameref, err := forkedref.ParseNamed(name.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &RepositoryInfo{
|
||||
Named: nameref,
|
||||
Name: reference.TrimNamed(name),
|
||||
Index: index,
|
||||
Official: official,
|
||||
}, nil
|
||||
|
|
|
@ -17,8 +17,8 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
registrytypes "github.com/docker/docker/api/types/registry"
|
||||
"github.com/docker/docker/reference"
|
||||
"github.com/gorilla/mux"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
|
|
|
@ -14,7 +14,6 @@ import (
|
|||
"github.com/docker/distribution/registry/client/transport"
|
||||
"github.com/docker/docker/api/types"
|
||||
registrytypes "github.com/docker/docker/api/types/registry"
|
||||
forkedref "github.com/docker/docker/reference"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -202,7 +201,7 @@ func TestGetRemoteImageLayer(t *testing.T) {
|
|||
|
||||
func TestGetRemoteTag(t *testing.T) {
|
||||
r := spawnTestRegistrySession(t)
|
||||
repoRef, err := forkedref.ParseNamed(REPO)
|
||||
repoRef, err := reference.ParseNormalizedNamed(REPO)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -212,7 +211,7 @@ func TestGetRemoteTag(t *testing.T) {
|
|||
}
|
||||
assertEqual(t, tag, imageID, "Expected tag test to map to "+imageID)
|
||||
|
||||
bazRef, err := forkedref.ParseNamed("foo42/baz")
|
||||
bazRef, err := reference.ParseNormalizedNamed("foo42/baz")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -224,7 +223,7 @@ func TestGetRemoteTag(t *testing.T) {
|
|||
|
||||
func TestGetRemoteTags(t *testing.T) {
|
||||
r := spawnTestRegistrySession(t)
|
||||
repoRef, err := forkedref.ParseNamed(REPO)
|
||||
repoRef, err := reference.ParseNormalizedNamed(REPO)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -236,7 +235,7 @@ func TestGetRemoteTags(t *testing.T) {
|
|||
assertEqual(t, tags["latest"], imageID, "Expected tag latest to map to "+imageID)
|
||||
assertEqual(t, tags["test"], imageID, "Expected tag test to map to "+imageID)
|
||||
|
||||
bazRef, err := forkedref.ParseNamed("foo42/baz")
|
||||
bazRef, err := reference.ParseNormalizedNamed("foo42/baz")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -253,7 +252,7 @@ func TestGetRepositoryData(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
host := "http://" + parsedURL.Host + "/v1/"
|
||||
repoRef, err := forkedref.ParseNamed(REPO)
|
||||
repoRef, err := reference.ParseNormalizedNamed(REPO)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -516,9 +515,9 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||
t.Error(err)
|
||||
} else {
|
||||
checkEqual(t, repoInfo.Index.Name, expectedRepoInfo.Index.Name, reposName)
|
||||
checkEqual(t, repoInfo.RemoteName(), expectedRepoInfo.RemoteName, reposName)
|
||||
checkEqual(t, repoInfo.Name(), expectedRepoInfo.LocalName, reposName)
|
||||
checkEqual(t, repoInfo.FullName(), expectedRepoInfo.CanonicalName, reposName)
|
||||
checkEqual(t, reference.Path(repoInfo.Name), expectedRepoInfo.RemoteName, reposName)
|
||||
checkEqual(t, reference.FamiliarName(repoInfo.Name), expectedRepoInfo.LocalName, reposName)
|
||||
checkEqual(t, repoInfo.Name.Name(), expectedRepoInfo.CanonicalName, reposName)
|
||||
checkEqual(t, repoInfo.Index.Official, expectedRepoInfo.Index.Official, reposName)
|
||||
checkEqual(t, repoInfo.Official, expectedRepoInfo.Official, reposName)
|
||||
}
|
||||
|
@ -689,7 +688,7 @@ func TestMirrorEndpointLookup(t *testing.T) {
|
|||
|
||||
func TestPushRegistryTag(t *testing.T) {
|
||||
r := spawnTestRegistrySession(t)
|
||||
repoRef, err := forkedref.ParseNamed(REPO)
|
||||
repoRef, err := reference.ParseNormalizedNamed(REPO)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -711,7 +710,7 @@ func TestPushImageJSONIndex(t *testing.T) {
|
|||
Checksum: "sha256:bea7bf2e4bacd479344b737328db47b18880d09096e6674165533aa994f5e9f2",
|
||||
},
|
||||
}
|
||||
repoRef, err := forkedref.ParseNamed(REPO)
|
||||
repoRef, err := reference.ParseNormalizedNamed(REPO)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/distribution/registry/api/errcode"
|
||||
"github.com/docker/docker/api/types"
|
||||
registrytypes "github.com/docker/docker/api/types/registry"
|
||||
|
@ -26,7 +27,6 @@ import (
|
|||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/docker/pkg/tarsum"
|
||||
"github.com/docker/docker/reference"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -324,7 +324,7 @@ func (r *Session) GetRemoteImageLayer(imgID, registry string, imgSize int64) (io
|
|||
// argument, and returns data from the first one that answers the query
|
||||
// successfully.
|
||||
func (r *Session) GetRemoteTag(registries []string, repositoryRef reference.Named, askedTag string) (string, error) {
|
||||
repository := repositoryRef.RemoteName()
|
||||
repository := reference.Path(repositoryRef)
|
||||
|
||||
if strings.Count(repository, "/") == 0 {
|
||||
// This will be removed once the registry supports auto-resolution on
|
||||
|
@ -362,7 +362,7 @@ func (r *Session) GetRemoteTag(registries []string, repositoryRef reference.Name
|
|||
// the first one that answers the query successfully. It returns a map with
|
||||
// tag names as the keys and image IDs as the values.
|
||||
func (r *Session) GetRemoteTags(registries []string, repositoryRef reference.Named) (map[string]string, error) {
|
||||
repository := repositoryRef.RemoteName()
|
||||
repository := reference.Path(repositoryRef)
|
||||
|
||||
if strings.Count(repository, "/") == 0 {
|
||||
// This will be removed once the registry supports auto-resolution on
|
||||
|
@ -416,7 +416,7 @@ func buildEndpointsList(headers []string, indexEp string) ([]string, error) {
|
|||
|
||||
// GetRepositoryData returns lists of images and endpoints for the repository
|
||||
func (r *Session) GetRepositoryData(name reference.Named) (*RepositoryData, error) {
|
||||
repositoryTarget := fmt.Sprintf("%srepositories/%s/images", r.indexEndpoint.String(), name.RemoteName())
|
||||
repositoryTarget := fmt.Sprintf("%srepositories/%s/images", r.indexEndpoint.String(), reference.Path(name))
|
||||
|
||||
logrus.Debugf("[registry] Calling GET %s", repositoryTarget)
|
||||
|
||||
|
@ -450,7 +450,7 @@ func (r *Session) GetRepositoryData(name reference.Named) (*RepositoryData, erro
|
|||
if err != nil {
|
||||
logrus.Debugf("Error reading response body: %s", err)
|
||||
}
|
||||
return nil, httputils.NewHTTPRequestError(fmt.Sprintf("Error: Status %d trying to pull repository %s: %q", res.StatusCode, name.RemoteName(), errBody), res)
|
||||
return nil, httputils.NewHTTPRequestError(fmt.Sprintf("Error: Status %d trying to pull repository %s: %q", res.StatusCode, reference.Path(name), errBody), res)
|
||||
}
|
||||
|
||||
var endpoints []string
|
||||
|
@ -605,7 +605,7 @@ func (r *Session) PushImageLayerRegistry(imgID string, layer io.Reader, registry
|
|||
func (r *Session) PushRegistryTag(remote reference.Named, revision, tag, registry string) error {
|
||||
// "jsonify" the string
|
||||
revision = "\"" + revision + "\""
|
||||
path := fmt.Sprintf("repositories/%s/tags/%s", remote.RemoteName(), tag)
|
||||
path := fmt.Sprintf("repositories/%s/tags/%s", reference.Path(remote), tag)
|
||||
|
||||
req, err := http.NewRequest("PUT", registry+path, strings.NewReader(revision))
|
||||
if err != nil {
|
||||
|
@ -619,7 +619,7 @@ func (r *Session) PushRegistryTag(remote reference.Named, revision, tag, registr
|
|||
}
|
||||
res.Body.Close()
|
||||
if res.StatusCode != 200 && res.StatusCode != 201 {
|
||||
return httputils.NewHTTPRequestError(fmt.Sprintf("Internal server error: %d trying to push tag %s on %s", res.StatusCode, tag, remote.RemoteName()), res)
|
||||
return httputils.NewHTTPRequestError(fmt.Sprintf("Internal server error: %d trying to push tag %s on %s", res.StatusCode, tag, reference.Path(remote)), res)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -645,7 +645,7 @@ func (r *Session) PushImageJSONIndex(remote reference.Named, imgList []*ImgData,
|
|||
if validate {
|
||||
suffix = "images"
|
||||
}
|
||||
u := fmt.Sprintf("%srepositories/%s/%s", r.indexEndpoint.String(), remote.RemoteName(), suffix)
|
||||
u := fmt.Sprintf("%srepositories/%s/%s", r.indexEndpoint.String(), reference.Path(remote), suffix)
|
||||
logrus.Debugf("[registry] PUT %s", u)
|
||||
logrus.Debugf("Image list pushed to index:\n%s", imgListJSON)
|
||||
headers := map[string][]string{
|
||||
|
@ -683,7 +683,7 @@ func (r *Session) PushImageJSONIndex(remote reference.Named, imgList []*ImgData,
|
|||
if err != nil {
|
||||
logrus.Debugf("Error reading response body: %s", err)
|
||||
}
|
||||
return nil, httputils.NewHTTPRequestError(fmt.Sprintf("Error: Status %d trying to push repository %s: %q", res.StatusCode, remote.RemoteName(), errBody), res)
|
||||
return nil, httputils.NewHTTPRequestError(fmt.Sprintf("Error: Status %d trying to push repository %s: %q", res.StatusCode, reference.Path(remote), errBody), res)
|
||||
}
|
||||
tokens = res.Header["X-Docker-Token"]
|
||||
logrus.Debugf("Auth token: %v", tokens)
|
||||
|
@ -701,7 +701,7 @@ func (r *Session) PushImageJSONIndex(remote reference.Named, imgList []*ImgData,
|
|||
if err != nil {
|
||||
logrus.Debugf("Error reading response body: %s", err)
|
||||
}
|
||||
return nil, httputils.NewHTTPRequestError(fmt.Sprintf("Error: Status %d trying to push checksums %s: %q", res.StatusCode, remote.RemoteName(), errBody), res)
|
||||
return nil, httputils.NewHTTPRequestError(fmt.Sprintf("Error: Status %d trying to push checksums %s: %q", res.StatusCode, reference.Path(remote), errBody), res)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package registry
|
||||
|
||||
import (
|
||||
"github.com/docker/distribution/reference"
|
||||
registrytypes "github.com/docker/docker/api/types/registry"
|
||||
"github.com/docker/docker/reference"
|
||||
)
|
||||
|
||||
// RepositoryData tracks the image list, list of endpoints for a repository
|
||||
|
@ -57,7 +57,7 @@ var apiVersions = map[APIVersion]string{
|
|||
|
||||
// RepositoryInfo describes a repository
|
||||
type RepositoryInfo struct {
|
||||
reference.Named
|
||||
Name reference.Named
|
||||
// Index points to registry information
|
||||
Index *registrytypes.IndexInfo
|
||||
// Official indicates whether the repository is considered official.
|
||||
|
|
|
@ -43,7 +43,7 @@ github.com/boltdb/bolt fff57c100f4dea1905678da7e90d92429dff2904
|
|||
github.com/miekg/dns 75e6e86cc601825c5dbcd4e0c209eab180997cd7
|
||||
|
||||
# get graph and distribution packages
|
||||
github.com/docker/distribution 129ad8ea0c3760d878b34cffdb9c3be874a7b2f7
|
||||
github.com/docker/distribution 545102ea07aa9796f189d82f606b7c27d7aa3ed3
|
||||
github.com/vbatts/tar-split v0.10.1
|
||||
github.com/opencontainers/go-digest a6d0ee40d4207ea02364bd3b9e8e77b9159ba1eb
|
||||
|
||||
|
@ -102,7 +102,7 @@ github.com/docker/containerd 78fb8f45890a601e0fd9051cf9f9f74923e950fd
|
|||
github.com/tonistiigi/fifo 1405643975692217d6720f8b54aeee1bf2cd5cf4
|
||||
|
||||
# cluster
|
||||
github.com/docker/swarmkit 78ae345f449ac69aa741c762df7e5f0020f70275
|
||||
github.com/docker/swarmkit 3ca4775ba4a5519e2225c3337c7db8901ec39d26
|
||||
github.com/golang/mock bd3c8e81be01eef76d4b503f5e687d2d1354d2d9
|
||||
github.com/gogo/protobuf 8d70fb3182befc465c4a1eac8ad4d38ff49778e2
|
||||
github.com/cloudflare/cfssl 7fb22c8cba7ecaf98e4082d22d65800cf45e042a
|
||||
|
|
20
vendor/github.com/docker/distribution/manifests.go
generated
vendored
20
vendor/github.com/docker/distribution/manifests.go
generated
vendored
|
@ -22,8 +22,8 @@ type Manifest interface {
|
|||
References() []Descriptor
|
||||
|
||||
// Payload provides the serialized format of the manifest, in addition to
|
||||
// the mediatype.
|
||||
Payload() (mediatype string, payload []byte, err error)
|
||||
// the media type.
|
||||
Payload() (mediaType string, payload []byte, err error)
|
||||
}
|
||||
|
||||
// ManifestBuilder creates a manifest allowing one to include dependencies.
|
||||
|
@ -94,20 +94,20 @@ var mappings = make(map[string]UnmarshalFunc, 0)
|
|||
func UnmarshalManifest(ctHeader string, p []byte) (Manifest, Descriptor, error) {
|
||||
// Need to look up by the actual media type, not the raw contents of
|
||||
// the header. Strip semicolons and anything following them.
|
||||
var mediatype string
|
||||
var mediaType string
|
||||
if ctHeader != "" {
|
||||
var err error
|
||||
mediatype, _, err = mime.ParseMediaType(ctHeader)
|
||||
mediaType, _, err = mime.ParseMediaType(ctHeader)
|
||||
if err != nil {
|
||||
return nil, Descriptor{}, err
|
||||
}
|
||||
}
|
||||
|
||||
unmarshalFunc, ok := mappings[mediatype]
|
||||
unmarshalFunc, ok := mappings[mediaType]
|
||||
if !ok {
|
||||
unmarshalFunc, ok = mappings[""]
|
||||
if !ok {
|
||||
return nil, Descriptor{}, fmt.Errorf("unsupported manifest mediatype and no default available: %s", mediatype)
|
||||
return nil, Descriptor{}, fmt.Errorf("unsupported manifest media type and no default available: %s", mediaType)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -116,10 +116,10 @@ func UnmarshalManifest(ctHeader string, p []byte) (Manifest, Descriptor, error)
|
|||
|
||||
// RegisterManifestSchema registers an UnmarshalFunc for a given schema type. This
|
||||
// should be called from specific
|
||||
func RegisterManifestSchema(mediatype string, u UnmarshalFunc) error {
|
||||
if _, ok := mappings[mediatype]; ok {
|
||||
return fmt.Errorf("manifest mediatype registration would overwrite existing: %s", mediatype)
|
||||
func RegisterManifestSchema(mediaType string, u UnmarshalFunc) error {
|
||||
if _, ok := mappings[mediaType]; ok {
|
||||
return fmt.Errorf("manifest media type registration would overwrite existing: %s", mediaType)
|
||||
}
|
||||
mappings[mediatype] = u
|
||||
mappings[mediaType] = u
|
||||
return nil
|
||||
}
|
||||
|
|
16
vendor/github.com/docker/distribution/reference/helpers.go
generated
vendored
16
vendor/github.com/docker/distribution/reference/helpers.go
generated
vendored
|
@ -1,5 +1,7 @@
|
|||
package reference
|
||||
|
||||
import "path"
|
||||
|
||||
// IsNameOnly returns true if reference only contains a repo name.
|
||||
func IsNameOnly(ref Named) bool {
|
||||
if _, ok := ref.(NamedTagged); ok {
|
||||
|
@ -14,7 +16,7 @@ func IsNameOnly(ref Named) bool {
|
|||
// FamiliarName returns the familiar name string
|
||||
// for the given named, familiarizing if needed.
|
||||
func FamiliarName(ref Named) string {
|
||||
if nn, ok := ref.(NormalizedNamed); ok {
|
||||
if nn, ok := ref.(normalizedNamed); ok {
|
||||
return nn.Familiar().Name()
|
||||
}
|
||||
return ref.Name()
|
||||
|
@ -23,8 +25,18 @@ func FamiliarName(ref Named) string {
|
|||
// FamiliarString returns the familiar string representation
|
||||
// for the given reference, familiarizing if needed.
|
||||
func FamiliarString(ref Reference) string {
|
||||
if nn, ok := ref.(NormalizedNamed); ok {
|
||||
if nn, ok := ref.(normalizedNamed); ok {
|
||||
return nn.Familiar().String()
|
||||
}
|
||||
return ref.String()
|
||||
}
|
||||
|
||||
// FamiliarMatch reports whether ref matches the specified pattern.
|
||||
// See https://godoc.org/path#Match for supported patterns.
|
||||
func FamiliarMatch(pattern string, ref Reference) (bool, error) {
|
||||
matched, err := path.Match(pattern, FamiliarString(ref))
|
||||
if namedRef, isNamed := ref.(Named); isNamed && !matched {
|
||||
matched, _ = path.Match(pattern, FamiliarName(namedRef))
|
||||
}
|
||||
return matched, err
|
||||
}
|
||||
|
|
26
vendor/github.com/docker/distribution/reference/normalize.go
generated
vendored
26
vendor/github.com/docker/distribution/reference/normalize.go
generated
vendored
|
@ -12,16 +12,16 @@ import (
|
|||
var (
|
||||
legacyDefaultDomain = "index.docker.io"
|
||||
defaultDomain = "docker.io"
|
||||
defaultRepoPrefix = "library/"
|
||||
officialRepoName = "library"
|
||||
defaultTag = "latest"
|
||||
)
|
||||
|
||||
// NormalizedNamed represents a name which has been
|
||||
// normalizedNamed represents a name which has been
|
||||
// normalized and has a familiar form. A familiar name
|
||||
// is what is used in Docker UI. An example normalized
|
||||
// name is "docker.io/library/ubuntu" and corresponding
|
||||
// familiar name of "ubuntu".
|
||||
type NormalizedNamed interface {
|
||||
type normalizedNamed interface {
|
||||
Named
|
||||
Familiar() Named
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ type NormalizedNamed interface {
|
|||
// transforming a familiar name from Docker UI to a fully
|
||||
// qualified reference. If the value may be an identifier
|
||||
// use ParseAnyReference.
|
||||
func ParseNormalizedNamed(s string) (NormalizedNamed, error) {
|
||||
func ParseNormalizedNamed(s string) (Named, error) {
|
||||
if ok := anchoredIdentifierRegexp.MatchString(s); ok {
|
||||
return nil, fmt.Errorf("invalid repository name (%s), cannot specify 64-byte hexadecimal strings", s)
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ func ParseNormalizedNamed(s string) (NormalizedNamed, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
named, isNamed := ref.(NormalizedNamed)
|
||||
named, isNamed := ref.(Named)
|
||||
if !isNamed {
|
||||
return nil, fmt.Errorf("reference %s has no name", ref.String())
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ func splitDockerDomain(name string) (domain, remainder string) {
|
|||
domain = defaultDomain
|
||||
}
|
||||
if domain == defaultDomain && !strings.ContainsRune(remainder, '/') {
|
||||
remainder = defaultRepoPrefix + remainder
|
||||
remainder = officialRepoName + "/" + remainder
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -89,7 +89,10 @@ func familiarizeName(named namedRepository) repository {
|
|||
|
||||
if repo.domain == defaultDomain {
|
||||
repo.domain = ""
|
||||
repo.path = strings.TrimPrefix(repo.path, defaultRepoPrefix)
|
||||
// Handle official repositories which have the pattern "library/<official repo name>"
|
||||
if split := strings.Split(repo.path, "/"); len(split) == 2 && split[0] == officialRepoName {
|
||||
repo.path = split[1]
|
||||
}
|
||||
}
|
||||
return repo
|
||||
}
|
||||
|
@ -120,11 +123,10 @@ func (c canonicalReference) Familiar() Named {
|
|||
}
|
||||
}
|
||||
|
||||
// EnsureTagged adds the default tag "latest" to a reference if it only has
|
||||
// TagNameOnly adds the default tag "latest" to a reference if it only has
|
||||
// a repo name.
|
||||
func EnsureTagged(ref Named) NamedTagged {
|
||||
namedTagged, ok := ref.(NamedTagged)
|
||||
if !ok {
|
||||
func TagNameOnly(ref Named) Named {
|
||||
if IsNameOnly(ref) {
|
||||
namedTagged, err := WithTag(ref, defaultTag)
|
||||
if err != nil {
|
||||
// Default tag must be valid, to create a NamedTagged
|
||||
|
@ -134,7 +136,7 @@ func EnsureTagged(ref Named) NamedTagged {
|
|||
}
|
||||
return namedTagged
|
||||
}
|
||||
return namedTagged
|
||||
return ref
|
||||
}
|
||||
|
||||
// ParseAnyReference parses a reference string as a possible identifier,
|
||||
|
|
31
vendor/github.com/docker/distribution/reference/reference.go
generated
vendored
31
vendor/github.com/docker/distribution/reference/reference.go
generated
vendored
|
@ -20,14 +20,13 @@
|
|||
// digest-algorithm-component := /[A-Za-z][A-Za-z0-9]*/
|
||||
// digest-hex := /[0-9a-fA-F]{32,}/ ; At least 128 bit digest value
|
||||
//
|
||||
// identifier := /[a-f0-9]{64}/
|
||||
// short-identifier := /[a-f0-9]{6,64}/
|
||||
// identifier := /[a-f0-9]{64}/
|
||||
// short-identifier := /[a-f0-9]{6,64}/
|
||||
package reference
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/opencontainers/go-digest"
|
||||
|
@ -56,6 +55,9 @@ var (
|
|||
|
||||
// ErrNameTooLong is returned when a repository name is longer than NameTotalLengthMax.
|
||||
ErrNameTooLong = fmt.Errorf("repository name must not be more than %v characters", NameTotalLengthMax)
|
||||
|
||||
// ErrNameNotCanonical is returned when a name is not canonical.
|
||||
ErrNameNotCanonical = errors.New("repository name must be canonical")
|
||||
)
|
||||
|
||||
// Reference is an opaque object reference identifier that may include
|
||||
|
@ -232,18 +234,17 @@ func Parse(s string) (Reference, error) {
|
|||
}
|
||||
|
||||
// ParseNamed parses s and returns a syntactically valid reference implementing
|
||||
// the Named interface. The reference must have a name, otherwise an error is
|
||||
// returned.
|
||||
// the Named interface. The reference must have a name and be in the canonical
|
||||
// form, otherwise an error is returned.
|
||||
// If an error was encountered it is returned, along with a nil Reference.
|
||||
// NOTE: ParseNamed will not handle short digests.
|
||||
func ParseNamed(s string) (Named, error) {
|
||||
ref, err := Parse(s)
|
||||
named, err := ParseNormalizedNamed(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
named, isNamed := ref.(Named)
|
||||
if !isNamed {
|
||||
return nil, fmt.Errorf("reference %s has no name", ref.String())
|
||||
if named.String() != s {
|
||||
return nil, ErrNameNotCanonical
|
||||
}
|
||||
return named, nil
|
||||
}
|
||||
|
@ -317,16 +318,6 @@ func WithDigest(name Named, digest digest.Digest) (Canonical, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
// Match reports whether ref matches the specified pattern.
|
||||
// See https://godoc.org/path#Match for supported patterns.
|
||||
func Match(pattern string, ref Reference) (bool, error) {
|
||||
matched, err := path.Match(pattern, ref.String())
|
||||
if namedRef, isNamed := ref.(Named); isNamed && !matched {
|
||||
matched, _ = path.Match(pattern, namedRef.Name())
|
||||
}
|
||||
return matched, err
|
||||
}
|
||||
|
||||
// TrimNamed removes any tag or digest from the named reference.
|
||||
func TrimNamed(ref Named) Named {
|
||||
domain, path := SplitHostname(ref)
|
||||
|
@ -408,7 +399,7 @@ func (r repository) Path() string {
|
|||
type digestReference digest.Digest
|
||||
|
||||
func (d digestReference) String() string {
|
||||
return d.String()
|
||||
return digest.Digest(d).String()
|
||||
}
|
||||
|
||||
func (d digestReference) Digest() digest.Digest {
|
||||
|
|
2
vendor/github.com/docker/distribution/registry.go
generated
vendored
2
vendor/github.com/docker/distribution/registry.go
generated
vendored
|
@ -35,7 +35,7 @@ type Namespace interface {
|
|||
// reference.
|
||||
Repository(ctx context.Context, name reference.Named) (Repository, error)
|
||||
|
||||
// Repositories fills 'repos' with a lexigraphically sorted catalog of repositories
|
||||
// Repositories fills 'repos' with a lexicographically sorted catalog of repositories
|
||||
// up to the size of 'repos' and returns the value 'n' for the number of entries
|
||||
// which were filled. 'last' contains an offset in the catalog, and 'err' will be
|
||||
// set to io.EOF if there are no more entries to obtain.
|
||||
|
|
2
vendor/github.com/docker/distribution/registry/storage/cache/memory/memory.go
generated
vendored
2
vendor/github.com/docker/distribution/registry/storage/cache/memory/memory.go
generated
vendored
|
@ -26,7 +26,7 @@ func NewInMemoryBlobDescriptorCacheProvider() cache.BlobDescriptorCacheProvider
|
|||
}
|
||||
|
||||
func (imbdcp *inMemoryBlobDescriptorCacheProvider) RepositoryScoped(repo string) (distribution.BlobDescriptorService, error) {
|
||||
if _, err := reference.ParseNamed(repo); err != nil {
|
||||
if _, err := reference.ParseNormalizedNamed(repo); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
|
14
vendor/github.com/docker/swarmkit/agent/agent.go
generated
vendored
14
vendor/github.com/docker/swarmkit/agent/agent.go
generated
vendored
|
@ -39,6 +39,7 @@ type Agent struct {
|
|||
ready chan struct{}
|
||||
leaving chan struct{}
|
||||
leaveOnce sync.Once
|
||||
left chan struct{} // closed after "run" processes "leaving" and will no longer accept new assignments
|
||||
stopped chan struct{} // requests shutdown
|
||||
stopOnce sync.Once // only allow stop to be called once
|
||||
closed chan struct{} // only closed in run
|
||||
|
@ -56,6 +57,7 @@ func New(config *Config) (*Agent, error) {
|
|||
sessionq: make(chan sessionOperation),
|
||||
started: make(chan struct{}),
|
||||
leaving: make(chan struct{}),
|
||||
left: make(chan struct{}),
|
||||
stopped: make(chan struct{}),
|
||||
closed: make(chan struct{}),
|
||||
ready: make(chan struct{}),
|
||||
|
@ -96,6 +98,16 @@ func (a *Agent) Leave(ctx context.Context) error {
|
|||
close(a.leaving)
|
||||
})
|
||||
|
||||
// Do not call Wait until we have confirmed that the agent is no longer
|
||||
// accepting assignments. Starting a worker might race with Wait.
|
||||
select {
|
||||
case <-a.left:
|
||||
case <-a.closed:
|
||||
return ErrClosed
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
}
|
||||
|
||||
// agent could be closed while Leave is in progress
|
||||
var err error
|
||||
ch := make(chan struct{})
|
||||
|
@ -215,6 +227,8 @@ func (a *Agent) run(ctx context.Context) {
|
|||
if err := a.worker.Assign(ctx, nil); err != nil {
|
||||
log.G(ctx).WithError(err).Error("failed removing all assignments")
|
||||
}
|
||||
|
||||
close(a.left)
|
||||
case msg := <-session.assignments:
|
||||
// if we have left, accept no more assignments
|
||||
if leaving == nil {
|
||||
|
|
22
vendor/github.com/docker/swarmkit/agent/exec/controller.go
generated
vendored
22
vendor/github.com/docker/swarmkit/agent/exec/controller.go
generated
vendored
|
@ -104,17 +104,21 @@ func Resolve(ctx context.Context, task *api.Task, executor Executor) (Controller
|
|||
|
||||
// depending on the tasks state, a failed controller resolution has varying
|
||||
// impact. The following expresses that impact.
|
||||
if task.Status.State < api.TaskStateStarting {
|
||||
if err != nil {
|
||||
// before the task has been started, we consider it a rejection.
|
||||
status.Message = "resolving controller failed"
|
||||
status.Err = err.Error()
|
||||
if err != nil {
|
||||
status.Message = "resolving controller failed"
|
||||
status.Err = err.Error()
|
||||
// before the task has been started, we consider it a rejection.
|
||||
// if task is running, consider the task has failed
|
||||
// otherwise keep the existing state
|
||||
if task.Status.State < api.TaskStateStarting {
|
||||
status.State = api.TaskStateRejected
|
||||
} else if task.Status.State < api.TaskStateAccepted {
|
||||
// we always want to proceed to accepted when we resolve the contoller
|
||||
status.Message = "accepted"
|
||||
status.State = api.TaskStateAccepted
|
||||
} else if task.Status.State <= api.TaskStateRunning {
|
||||
status.State = api.TaskStateFailed
|
||||
}
|
||||
} else if task.Status.State < api.TaskStateAccepted {
|
||||
// we always want to proceed to accepted when we resolve the controller
|
||||
status.Message = "accepted"
|
||||
status.State = api.TaskStateAccepted
|
||||
}
|
||||
|
||||
return ctlr, status, err
|
||||
|
|
4
vendor/github.com/docker/swarmkit/api/ca.proto
generated
vendored
4
vendor/github.com/docker/swarmkit/api/ca.proto
generated
vendored
|
@ -30,7 +30,7 @@ service NodeCA {
|
|||
}
|
||||
|
||||
message NodeCertificateStatusRequest {
|
||||
string node_id = 1 [(gogoproto.customname) = "NodeID"];
|
||||
string node_id = 1;
|
||||
}
|
||||
|
||||
message NodeCertificateStatusResponse {
|
||||
|
@ -54,7 +54,7 @@ message IssueNodeCertificateRequest {
|
|||
}
|
||||
|
||||
message IssueNodeCertificateResponse {
|
||||
string node_id = 1 [(gogoproto.customname) = "NodeID"];
|
||||
string node_id = 1;
|
||||
NodeSpec.Membership node_membership = 2;
|
||||
}
|
||||
|
||||
|
|
46
vendor/github.com/docker/swarmkit/api/control.proto
generated
vendored
46
vendor/github.com/docker/swarmkit/api/control.proto
generated
vendored
|
@ -119,7 +119,7 @@ service Control {
|
|||
}
|
||||
|
||||
message GetNodeRequest {
|
||||
string node_id = 1 [(gogoproto.customname) = "NodeID"];
|
||||
string node_id = 1;
|
||||
}
|
||||
|
||||
message GetNodeResponse {
|
||||
|
@ -129,7 +129,7 @@ message GetNodeResponse {
|
|||
message ListNodesRequest {
|
||||
message Filters {
|
||||
repeated string names = 1;
|
||||
repeated string id_prefixes = 2 [(gogoproto.customname) = "IDPrefixes"];
|
||||
repeated string id_prefixes = 2;
|
||||
map<string, string> labels = 3;
|
||||
repeated NodeSpec.Membership memberships = 4;
|
||||
repeated NodeRole roles = 5;
|
||||
|
@ -148,7 +148,7 @@ message ListNodesResponse {
|
|||
// to request a new availability for a node, such as PAUSE. Invalid updates
|
||||
// will be denied and cause an error.
|
||||
message UpdateNodeRequest {
|
||||
string node_id = 1 [(gogoproto.customname) = "NodeID"];
|
||||
string node_id = 1;
|
||||
Version node_version = 2;
|
||||
NodeSpec spec = 3;
|
||||
}
|
||||
|
@ -159,7 +159,7 @@ message UpdateNodeResponse {
|
|||
|
||||
// RemoveNodeRequest requests to delete the specified node from store.
|
||||
message RemoveNodeRequest {
|
||||
string node_id = 1 [(gogoproto.customname) = "NodeID"];
|
||||
string node_id = 1;
|
||||
bool force = 2;
|
||||
}
|
||||
|
||||
|
@ -167,7 +167,7 @@ message RemoveNodeResponse {
|
|||
}
|
||||
|
||||
message GetTaskRequest {
|
||||
string task_id = 1 [(gogoproto.customname) = "TaskID"];
|
||||
string task_id = 1;
|
||||
}
|
||||
|
||||
message GetTaskResponse {
|
||||
|
@ -175,7 +175,7 @@ message GetTaskResponse {
|
|||
}
|
||||
|
||||
message RemoveTaskRequest {
|
||||
string task_id = 1 [(gogoproto.customname) = "TaskID"];
|
||||
string task_id = 1;
|
||||
}
|
||||
|
||||
message RemoveTaskResponse {
|
||||
|
@ -184,10 +184,10 @@ message RemoveTaskResponse {
|
|||
message ListTasksRequest {
|
||||
message Filters {
|
||||
repeated string names = 1;
|
||||
repeated string id_prefixes = 2 [(gogoproto.customname) = "IDPrefixes"];
|
||||
repeated string id_prefixes = 2;
|
||||
map<string, string> labels = 3;
|
||||
repeated string service_ids = 4 [(gogoproto.customname) = "ServiceIDs"];
|
||||
repeated string node_ids = 5 [(gogoproto.customname) = "NodeIDs"];
|
||||
repeated string service_ids = 4;
|
||||
repeated string node_ids = 5;
|
||||
repeated docker.swarmkit.v1.TaskState desired_states = 6;
|
||||
// NamePrefixes matches all objects with the given prefixes
|
||||
repeated string name_prefixes = 7;
|
||||
|
@ -209,7 +209,7 @@ message CreateServiceResponse {
|
|||
}
|
||||
|
||||
message GetServiceRequest {
|
||||
string service_id = 1 [(gogoproto.customname) = "ServiceID"];
|
||||
string service_id = 1;
|
||||
}
|
||||
|
||||
message GetServiceResponse {
|
||||
|
@ -217,7 +217,7 @@ message GetServiceResponse {
|
|||
}
|
||||
|
||||
message UpdateServiceRequest {
|
||||
string service_id = 1 [(gogoproto.customname) = "ServiceID"];
|
||||
string service_id = 1;
|
||||
Version service_version = 2;
|
||||
ServiceSpec spec = 3;
|
||||
}
|
||||
|
@ -227,7 +227,7 @@ message UpdateServiceResponse {
|
|||
}
|
||||
|
||||
message RemoveServiceRequest {
|
||||
string service_id = 1 [(gogoproto.customname) = "ServiceID"];
|
||||
string service_id = 1;
|
||||
}
|
||||
|
||||
message RemoveServiceResponse {
|
||||
|
@ -236,7 +236,7 @@ message RemoveServiceResponse {
|
|||
message ListServicesRequest {
|
||||
message Filters {
|
||||
repeated string names = 1;
|
||||
repeated string id_prefixes = 2 [(gogoproto.customname) = "IDPrefixes"];
|
||||
repeated string id_prefixes = 2;
|
||||
map<string, string> labels = 3;
|
||||
// NamePrefixes matches all objects with the given prefixes
|
||||
repeated string name_prefixes = 4;
|
||||
|
@ -259,7 +259,7 @@ message CreateNetworkResponse {
|
|||
|
||||
message GetNetworkRequest {
|
||||
string name = 1;
|
||||
string network_id = 2 [(gogoproto.customname) = "NetworkID"];
|
||||
string network_id = 2;
|
||||
}
|
||||
|
||||
message GetNetworkResponse {
|
||||
|
@ -268,7 +268,7 @@ message GetNetworkResponse {
|
|||
|
||||
message RemoveNetworkRequest {
|
||||
string name = 1;
|
||||
string network_id = 2 [(gogoproto.customname) = "NetworkID"];
|
||||
string network_id = 2;
|
||||
}
|
||||
|
||||
message RemoveNetworkResponse {}
|
||||
|
@ -276,7 +276,7 @@ message RemoveNetworkResponse {}
|
|||
message ListNetworksRequest {
|
||||
message Filters {
|
||||
repeated string names = 1;
|
||||
repeated string id_prefixes = 2 [(gogoproto.customname) = "IDPrefixes"];
|
||||
repeated string id_prefixes = 2;
|
||||
map<string, string> labels = 3;
|
||||
// NamePrefixes matches all objects with the given prefixes
|
||||
repeated string name_prefixes = 4;
|
||||
|
@ -290,7 +290,7 @@ message ListNetworksResponse {
|
|||
}
|
||||
|
||||
message GetClusterRequest {
|
||||
string cluster_id = 1 [(gogoproto.customname) = "ClusterID"];
|
||||
string cluster_id = 1;
|
||||
}
|
||||
|
||||
message GetClusterResponse {
|
||||
|
@ -300,7 +300,7 @@ message GetClusterResponse {
|
|||
message ListClustersRequest {
|
||||
message Filters {
|
||||
repeated string names = 1;
|
||||
repeated string id_prefixes = 2 [(gogoproto.customname) = "IDPrefixes"];
|
||||
repeated string id_prefixes = 2;
|
||||
map<string, string> labels = 3;
|
||||
// NamePrefixes matches all objects with the given prefixes
|
||||
repeated string name_prefixes = 4;
|
||||
|
@ -328,7 +328,7 @@ message KeyRotation {
|
|||
|
||||
message UpdateClusterRequest {
|
||||
// ClusterID is the cluster ID to update.
|
||||
string cluster_id = 1 [(gogoproto.customname) = "ClusterID"];
|
||||
string cluster_id = 1;
|
||||
|
||||
// ClusterVersion is the version of the cluster being updated.
|
||||
Version cluster_version = 2;
|
||||
|
@ -346,7 +346,7 @@ message UpdateClusterResponse {
|
|||
|
||||
// GetSecretRequest is the request to get a `Secret` object given a secret id.
|
||||
message GetSecretRequest {
|
||||
string secret_id = 1 [(gogoproto.customname) = "SecretID"];
|
||||
string secret_id = 1;
|
||||
}
|
||||
|
||||
// GetSecretResponse contains the Secret corresponding to the id in
|
||||
|
@ -358,7 +358,7 @@ message GetSecretResponse {
|
|||
|
||||
message UpdateSecretRequest {
|
||||
// SecretID is the secret ID to update.
|
||||
string secret_id = 1 [(gogoproto.customname) = "SecretID"];
|
||||
string secret_id = 1;
|
||||
|
||||
// SecretVersion is the version of the secret being updated.
|
||||
Version secret_version = 2;
|
||||
|
@ -378,7 +378,7 @@ message UpdateSecretResponse {
|
|||
message ListSecretsRequest {
|
||||
message Filters {
|
||||
repeated string names = 1;
|
||||
repeated string id_prefixes = 2 [(gogoproto.customname) = "IDPrefixes"];
|
||||
repeated string id_prefixes = 2;
|
||||
map<string, string> labels = 3;
|
||||
repeated string name_prefixes = 4;
|
||||
}
|
||||
|
@ -410,7 +410,7 @@ message CreateSecretResponse {
|
|||
// RemoveSecretRequest contains the ID of the secret that should be removed. This
|
||||
// removes all versions of the secret.
|
||||
message RemoveSecretRequest {
|
||||
string secret_id = 1 [(gogoproto.customname) = "SecretID"];
|
||||
string secret_id = 1;
|
||||
}
|
||||
|
||||
// RemoveSecretResponse is an empty object indicating the successful removal of
|
||||
|
|
14
vendor/github.com/docker/swarmkit/api/dispatcher.proto
generated
vendored
14
vendor/github.com/docker/swarmkit/api/dispatcher.proto
generated
vendored
|
@ -66,7 +66,7 @@ message SessionRequest {
|
|||
// SessionID is empty or invalid, a new SessionID will be assigned.
|
||||
//
|
||||
// See SessionMessage.SessionID for details.
|
||||
string session_id = 2 [(gogoproto.customname) = "SessionID"];
|
||||
string session_id = 2;
|
||||
}
|
||||
|
||||
// SessionMessage instructs an agent on various actions as part of the current
|
||||
|
@ -115,7 +115,7 @@ message SessionMessage {
|
|||
// We considered placing this field in a GRPC header. Because this is a
|
||||
// critical feature of the protocol, we thought it should be represented
|
||||
// directly in the RPC message set.
|
||||
string session_id = 1 [(gogoproto.customname) = "SessionID"];
|
||||
string session_id = 1;
|
||||
|
||||
// Node identifies the registering node.
|
||||
Node node = 2;
|
||||
|
@ -130,7 +130,7 @@ message SessionMessage {
|
|||
|
||||
// HeartbeatRequest provides identifying properties for a single heartbeat.
|
||||
message HeartbeatRequest {
|
||||
string session_id = 1 [(gogoproto.customname) = "SessionID"];
|
||||
string session_id = 1;
|
||||
}
|
||||
|
||||
message HeartbeatResponse {
|
||||
|
@ -142,10 +142,10 @@ message HeartbeatResponse {
|
|||
message UpdateTaskStatusRequest {
|
||||
// Tasks should contain all statuses for running tasks. Only the status
|
||||
// field must be set. The spec is not required.
|
||||
string session_id = 1 [(gogoproto.customname) = "SessionID"];
|
||||
string session_id = 1;
|
||||
|
||||
message TaskStatusUpdate {
|
||||
string task_id = 1 [(gogoproto.customname) = "TaskID"];
|
||||
string task_id = 1;
|
||||
TaskStatus status = 2;
|
||||
}
|
||||
|
||||
|
@ -157,7 +157,7 @@ message UpdateTaskStatusResponse{
|
|||
}
|
||||
|
||||
message TasksRequest {
|
||||
string session_id = 1 [(gogoproto.customname) = "SessionID"];
|
||||
string session_id = 1;
|
||||
}
|
||||
|
||||
message TasksMessage {
|
||||
|
@ -167,7 +167,7 @@ message TasksMessage {
|
|||
}
|
||||
|
||||
message AssignmentsRequest {
|
||||
string session_id = 1 [(gogoproto.customname) = "SessionID"];
|
||||
string session_id = 1;
|
||||
}
|
||||
|
||||
message Assignment {
|
||||
|
|
16
vendor/github.com/docker/swarmkit/api/logbroker.proto
generated
vendored
16
vendor/github.com/docker/swarmkit/api/logbroker.proto
generated
vendored
|
@ -54,16 +54,16 @@ message LogSubscriptionOptions {
|
|||
// possible. For example, if they want to listen to all the tasks of a service,
|
||||
// they should use the service id, rather than specifying the individual tasks.
|
||||
message LogSelector {
|
||||
repeated string service_ids = 1 [(gogoproto.customname) = "ServiceIDs"];
|
||||
repeated string node_ids = 2 [(gogoproto.customname) = "NodeIDs"];
|
||||
repeated string task_ids = 3 [(gogoproto.customname) = "TaskIDs"];
|
||||
repeated string service_ids = 1;
|
||||
repeated string node_ids = 2;
|
||||
repeated string task_ids = 3;
|
||||
}
|
||||
|
||||
// LogContext marks the context from which a log message was generated.
|
||||
message LogContext {
|
||||
string service_id = 1 [(gogoproto.customname) = "ServiceID"];
|
||||
string node_id = 2 [(gogoproto.customname) = "NodeID"];
|
||||
string task_id = 3 [(gogoproto.customname) = "TaskID"];
|
||||
string service_id = 1;
|
||||
string node_id = 2;
|
||||
string task_id = 3;
|
||||
}
|
||||
|
||||
// LogMessage
|
||||
|
@ -147,7 +147,7 @@ message ListenSubscriptionsRequest { }
|
|||
// If Options.Follow == false, the worker should end the subscription on its own.
|
||||
message SubscriptionMessage {
|
||||
// ID identifies the subscription.
|
||||
string id = 1 [(gogoproto.customname) = "ID"];
|
||||
string id = 1;
|
||||
|
||||
// Selector defines which sources should be sent for the subscription.
|
||||
LogSelector selector = 2;
|
||||
|
@ -163,7 +163,7 @@ message SubscriptionMessage {
|
|||
message PublishLogsMessage {
|
||||
// SubscriptionID identifies which subscription the set of messages should
|
||||
// be sent to. We can think of this as a "mail box" for the subscription.
|
||||
string subscription_id = 1 [(gogoproto.customname) = "SubscriptionID"];
|
||||
string subscription_id = 1;
|
||||
|
||||
// Messages is the log message for publishing.
|
||||
repeated LogMessage messages = 2 [(gogoproto.nullable) = false];
|
||||
|
|
18
vendor/github.com/docker/swarmkit/api/objects.proto
generated
vendored
18
vendor/github.com/docker/swarmkit/api/objects.proto
generated
vendored
|
@ -25,7 +25,7 @@ message Meta {
|
|||
// Node provides the internal node state as seen by the cluster.
|
||||
message Node {
|
||||
// ID specifies the identity of the node.
|
||||
string id = 1 [(gogoproto.customname) = "ID"];
|
||||
string id = 1;
|
||||
|
||||
Meta meta = 2 [(gogoproto.nullable) = false];
|
||||
|
||||
|
@ -63,7 +63,7 @@ message Node {
|
|||
}
|
||||
|
||||
message Service {
|
||||
string id = 1 [(gogoproto.customname) = "ID"];
|
||||
string id = 1;
|
||||
|
||||
Meta meta = 2 [(gogoproto.nullable) = false];
|
||||
|
||||
|
@ -101,7 +101,7 @@ message Endpoint {
|
|||
// and the IP addresses the target service will be made available under.
|
||||
message VirtualIP {
|
||||
// NetworkID for which this endpoint attachment was created.
|
||||
string network_id = 1 [(gogoproto.customname) = "NetworkID"];
|
||||
string network_id = 1;
|
||||
|
||||
// A virtual IP is used to address this service in IP
|
||||
// layer that the client can use to send requests to
|
||||
|
@ -123,7 +123,7 @@ message Endpoint {
|
|||
// immutable and idempotent. Once it is dispatched to a node, it will not be
|
||||
// dispatched to another node.
|
||||
message Task {
|
||||
string id = 1 [(gogoproto.customname) = "ID"];
|
||||
string id = 1;
|
||||
|
||||
Meta meta = 2 [(gogoproto.nullable) = false];
|
||||
|
||||
|
@ -133,7 +133,7 @@ message Task {
|
|||
|
||||
// ServiceID indicates the service under which this task is orchestrated. This
|
||||
// should almost always be set.
|
||||
string service_id = 4 [(gogoproto.customname) = "ServiceID"];
|
||||
string service_id = 4;
|
||||
|
||||
// Slot is the service slot number for a task.
|
||||
// For example, if a replicated service has replicas = 2, there will be a
|
||||
|
@ -142,7 +142,7 @@ message Task {
|
|||
|
||||
// NodeID indicates the node to which the task is assigned. If this field
|
||||
// is empty or not set, the task is unassigned.
|
||||
string node_id = 6 [(gogoproto.customname) = "NodeID"];
|
||||
string node_id = 6;
|
||||
|
||||
// Annotations defines the names and labels for the runtime, as set by
|
||||
// the cluster manager.
|
||||
|
@ -204,7 +204,7 @@ message NetworkAttachment {
|
|||
}
|
||||
|
||||
message Network {
|
||||
string id = 1 [(gogoproto.customname) = "ID"];
|
||||
string id = 1;
|
||||
|
||||
Meta meta = 2 [(gogoproto.nullable) = false];
|
||||
|
||||
|
@ -220,7 +220,7 @@ message Network {
|
|||
|
||||
// Cluster provides global cluster settings.
|
||||
message Cluster {
|
||||
string id = 1 [(gogoproto.customname) = "ID"];
|
||||
string id = 1;
|
||||
|
||||
Meta meta = 2 [(gogoproto.nullable) = false];
|
||||
|
||||
|
@ -256,7 +256,7 @@ message Cluster {
|
|||
// information that is generated from the secret data in the `spec`, such as
|
||||
// the digest and size of the secret data.
|
||||
message Secret {
|
||||
string id = 1 [(gogoproto.customname) = "ID"];
|
||||
string id = 1;
|
||||
|
||||
Meta meta = 2 [(gogoproto.nullable) = false];
|
||||
|
||||
|
|
10
vendor/github.com/docker/swarmkit/api/raft.proto
generated
vendored
10
vendor/github.com/docker/swarmkit/api/raft.proto
generated
vendored
|
@ -40,10 +40,10 @@ service RaftMembership {
|
|||
message RaftMember {
|
||||
// RaftID specifies the internal ID used by the manager in a raft context, it can never be modified
|
||||
// and is used only for information purposes
|
||||
uint64 raft_id = 1 [(gogoproto.customname) = "RaftID"];
|
||||
uint64 raft_id = 1;
|
||||
|
||||
// NodeID is the node's ID.
|
||||
string node_id = 2 [(gogoproto.customname) = "NodeID"];
|
||||
string node_id = 2;
|
||||
|
||||
// Addr specifies the address of the member
|
||||
string addr = 3;
|
||||
|
@ -59,7 +59,7 @@ message JoinRequest {
|
|||
|
||||
message JoinResponse {
|
||||
// RaftID is the ID assigned to the new member.
|
||||
uint64 raft_id = 1 [(gogoproto.customname) = "RaftID"];
|
||||
uint64 raft_id = 1;
|
||||
|
||||
// Members is the membership set of the cluster.
|
||||
repeated RaftMember members = 2;
|
||||
|
@ -84,7 +84,7 @@ message ProcessRaftMessageResponse {}
|
|||
|
||||
message ResolveAddressRequest {
|
||||
// raft_id is the ID to resolve to an address.
|
||||
uint64 raft_id = 1 [(gogoproto.customname) = "RaftID"];
|
||||
uint64 raft_id = 1;
|
||||
}
|
||||
|
||||
message ResolveAddressResponse {
|
||||
|
@ -96,7 +96,7 @@ message ResolveAddressResponse {
|
|||
// over the raft backend with a request ID to track when the
|
||||
// action is effectively applied
|
||||
message InternalRaftRequest {
|
||||
uint64 id = 1 [(gogoproto.customname) = "ID"];
|
||||
uint64 id = 1;
|
||||
|
||||
repeated StoreAction action = 2;
|
||||
}
|
||||
|
|
6
vendor/github.com/docker/swarmkit/api/resource.proto
generated
vendored
6
vendor/github.com/docker/swarmkit/api/resource.proto
generated
vendored
|
@ -20,15 +20,15 @@ service ResourceAllocator {
|
|||
|
||||
message AttachNetworkRequest {
|
||||
NetworkAttachmentConfig config = 1;
|
||||
string container_id = 2 [(gogoproto.customname) = "ContainerID"];
|
||||
string container_id = 2;
|
||||
}
|
||||
|
||||
message AttachNetworkResponse {
|
||||
string attachment_id = 1 [(gogoproto.customname) = "AttachmentID"];
|
||||
string attachment_id = 1;
|
||||
}
|
||||
|
||||
message DetachNetworkRequest {
|
||||
string attachment_id = 1 [(gogoproto.customname) = "AttachmentID"];
|
||||
string attachment_id = 1;
|
||||
}
|
||||
|
||||
message DetachNetworkResponse {}
|
||||
|
|
2
vendor/github.com/docker/swarmkit/api/specs.proto
generated
vendored
2
vendor/github.com/docker/swarmkit/api/specs.proto
generated
vendored
|
@ -130,7 +130,7 @@ message TaskSpec {
|
|||
message NetworkAttachmentSpec {
|
||||
// ContainerID spcifies a unique ID of the container for which
|
||||
// this attachment is for.
|
||||
string container_id = 1 [(gogoproto.customname) = "ContainerID"];
|
||||
string container_id = 1;
|
||||
}
|
||||
|
||||
|
||||
|
|
8
vendor/github.com/docker/swarmkit/api/types.proto
generated
vendored
8
vendor/github.com/docker/swarmkit/api/types.proto
generated
vendored
|
@ -410,7 +410,7 @@ enum TaskState {
|
|||
|
||||
// Container specific status.
|
||||
message ContainerStatus {
|
||||
string container_id = 1 [(gogoproto.customname) = "ContainerID"];
|
||||
string container_id = 1;
|
||||
|
||||
int32 pid = 2 [(gogoproto.customname) = "PID"];
|
||||
int32 exit_code = 3;
|
||||
|
@ -574,7 +574,7 @@ message IPAMOptions {
|
|||
|
||||
// Peer should be used anywhere where we are describing a remote peer.
|
||||
message Peer {
|
||||
string node_id = 1 [(gogoproto.customname) = "NodeID"];
|
||||
string node_id = 1;
|
||||
string addr = 2;
|
||||
}
|
||||
|
||||
|
@ -787,7 +787,7 @@ message EncryptionKey {
|
|||
message ManagerStatus {
|
||||
// RaftID specifies the internal ID used by the manager in a raft context, it can never be modified
|
||||
// and is used only for information purposes
|
||||
uint64 raft_id = 1 [(gogoproto.customname) = "RaftID"];
|
||||
uint64 raft_id = 1;
|
||||
|
||||
// Addr is the address advertised to raft.
|
||||
string addr = 2;
|
||||
|
@ -805,7 +805,7 @@ message SecretReference {
|
|||
// SecretID represents the ID of the specific Secret that we're
|
||||
// referencing. This identifier exists so that SecretReferences don't leak
|
||||
// any information about the secret contents.
|
||||
string secret_id = 1 [(gogoproto.customname) = "SecretID"];
|
||||
string secret_id = 1;
|
||||
|
||||
// SecretName is the name of the secret that this references, but this is just provided for
|
||||
// lookup/display purposes. The secret in the reference will be identified by its ID.
|
||||
|
|
21
vendor/github.com/docker/swarmkit/ca/certificates.go
generated
vendored
21
vendor/github.com/docker/swarmkit/ca/certificates.go
generated
vendored
|
@ -151,6 +151,25 @@ func (rca *RootCA) IssueAndSaveNewCertificates(kw KeyWriter, cn, ou, org string)
|
|||
return &tlsKeyPair, nil
|
||||
}
|
||||
|
||||
// Normally we can just call cert.Verify(opts), but since we actually want more information about
|
||||
// whether a certificate is not yet valid or expired, we also need to perform the expiry checks ourselves.
|
||||
func verifyCertificate(cert *x509.Certificate, opts x509.VerifyOptions, allowExpired bool) error {
|
||||
_, err := cert.Verify(opts)
|
||||
if invalidErr, ok := err.(x509.CertificateInvalidError); ok && invalidErr.Reason == x509.Expired {
|
||||
now := time.Now().UTC()
|
||||
if now.Before(cert.NotBefore) {
|
||||
return errors.Wrapf(err, "certificate not valid before %s, and it is currently %s",
|
||||
cert.NotBefore.UTC().Format(time.RFC1123), now.Format(time.RFC1123))
|
||||
}
|
||||
if allowExpired {
|
||||
return nil
|
||||
}
|
||||
return errors.Wrapf(err, "certificate expires at %s, and it is currently %s",
|
||||
cert.NotAfter.UTC().Format(time.RFC1123), now.Format(time.RFC1123))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// RequestAndSaveNewCertificates gets new certificates issued, either by signing them locally if a signer is
|
||||
// available, or by requesting them from the remote server at remoteAddr.
|
||||
func (rca *RootCA) RequestAndSaveNewCertificates(ctx context.Context, kw KeyWriter, config CertificateRequestConfig) (*tls.Certificate, error) {
|
||||
|
@ -199,7 +218,7 @@ func (rca *RootCA) RequestAndSaveNewCertificates(ctx context.Context, kw KeyWrit
|
|||
Roots: rca.Pool,
|
||||
}
|
||||
// Check to see if this certificate was signed by our CA, and isn't expired
|
||||
if _, err := X509Cert.Verify(opts); err != nil {
|
||||
if err := verifyCertificate(X509Cert, opts, false); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
|
35
vendor/github.com/docker/swarmkit/ca/config.go
generated
vendored
35
vendor/github.com/docker/swarmkit/ca/config.go
generated
vendored
|
@ -15,6 +15,7 @@ import (
|
|||
|
||||
"github.com/Sirupsen/logrus"
|
||||
cfconfig "github.com/cloudflare/cfssl/config"
|
||||
events "github.com/docker/go-events"
|
||||
"github.com/docker/swarmkit/api"
|
||||
"github.com/docker/swarmkit/connectionbroker"
|
||||
"github.com/docker/swarmkit/identity"
|
||||
|
@ -50,6 +51,13 @@ const (
|
|||
base36DigestLen = 50
|
||||
)
|
||||
|
||||
// RenewTLSExponentialBackoff sets the exponential backoff when trying to renew TLS certificates that have expired
|
||||
var RenewTLSExponentialBackoff = events.ExponentialBackoffConfig{
|
||||
Base: time.Second * 5,
|
||||
Factor: time.Minute,
|
||||
Max: 1 * time.Hour,
|
||||
}
|
||||
|
||||
// SecurityConfig is used to represent a node's security configuration. It includes information about
|
||||
// the RootCA and ServerTLSCreds/ClientTLSCreds transport authenticators to be used for MTLS
|
||||
type SecurityConfig struct {
|
||||
|
@ -189,7 +197,7 @@ func GenerateJoinToken(rootCA *RootCA) string {
|
|||
|
||||
func getCAHashFromToken(token string) (digest.Digest, error) {
|
||||
split := strings.Split(token, "-")
|
||||
if len(split) != 4 || split[0] != "SWMTKN" || split[1] != "1" {
|
||||
if len(split) != 4 || split[0] != "SWMTKN" || split[1] != "1" || len(split[2]) != base36DigestLen || len(split[3]) != maxGeneratedSecretLength {
|
||||
return "", errors.New("invalid join token")
|
||||
}
|
||||
|
||||
|
@ -242,7 +250,7 @@ func DownloadRootCA(ctx context.Context, paths CertPaths, token string, connBrok
|
|||
|
||||
// LoadSecurityConfig loads TLS credentials from disk, or returns an error if
|
||||
// these credentials do not exist or are unusable.
|
||||
func LoadSecurityConfig(ctx context.Context, rootCA RootCA, krw *KeyReadWriter) (*SecurityConfig, error) {
|
||||
func LoadSecurityConfig(ctx context.Context, rootCA RootCA, krw *KeyReadWriter, allowExpired bool) (*SecurityConfig, error) {
|
||||
ctx = log.WithModule(ctx, "tls")
|
||||
|
||||
// At this point we've successfully loaded the CA details from disk, or
|
||||
|
@ -273,7 +281,7 @@ func LoadSecurityConfig(ctx context.Context, rootCA RootCA, krw *KeyReadWriter)
|
|||
}
|
||||
|
||||
// Check to see if this certificate was signed by our CA, and isn't expired
|
||||
if _, err := X509Cert.Verify(opts); err != nil {
|
||||
if err := verifyCertificate(X509Cert, opts, allowExpired); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -447,6 +455,7 @@ func RenewTLSConfig(ctx context.Context, s *SecurityConfig, connBroker *connecti
|
|||
|
||||
go func() {
|
||||
var retry time.Duration
|
||||
expBackoff := events.NewExponentialBackoff(RenewTLSExponentialBackoff)
|
||||
defer close(updates)
|
||||
for {
|
||||
ctx = log.WithModule(ctx, "tls")
|
||||
|
@ -472,18 +481,12 @@ func RenewTLSConfig(ctx context.Context, s *SecurityConfig, connBroker *connecti
|
|||
return
|
||||
}
|
||||
} else {
|
||||
// If we have an expired certificate, we let's stick with the starting default in
|
||||
// the hope that this is a temporary clock skew.
|
||||
// If we have an expired certificate, try to renew immediately: the hope that this is a temporary clock skew, or
|
||||
// we can issue our own TLS certs.
|
||||
if validUntil.Before(time.Now()) {
|
||||
log.WithError(err).Errorf("failed to create a new client TLS config")
|
||||
|
||||
select {
|
||||
case updates <- CertificateUpdate{Err: errors.New("TLS certificate is expired")}:
|
||||
case <-ctx.Done():
|
||||
log.Info("shutting down certificate renewal routine")
|
||||
return
|
||||
}
|
||||
|
||||
log.Warn("the current TLS certificate is expired, so an attempt to renew it will be made immediately")
|
||||
// retry immediately(ish) with exponential backoff
|
||||
retry = expBackoff.Proceed(nil)
|
||||
} else {
|
||||
// Random retry time between 50% and 80% of the total time to expiration
|
||||
retry = calculateRandomExpiry(validFrom, validUntil)
|
||||
|
@ -492,7 +495,7 @@ func RenewTLSConfig(ctx context.Context, s *SecurityConfig, connBroker *connecti
|
|||
|
||||
log.WithFields(logrus.Fields{
|
||||
"time": time.Now().Add(retry),
|
||||
}).Debugf("next certificate renewal scheduled")
|
||||
}).Debugf("next certificate renewal scheduled for %v from now", retry)
|
||||
|
||||
select {
|
||||
case <-time.After(retry):
|
||||
|
@ -508,8 +511,10 @@ func RenewTLSConfig(ctx context.Context, s *SecurityConfig, connBroker *connecti
|
|||
var certUpdate CertificateUpdate
|
||||
if err := RenewTLSConfigNow(ctx, s, connBroker); err != nil {
|
||||
certUpdate.Err = err
|
||||
expBackoff.Failure(nil, nil)
|
||||
} else {
|
||||
certUpdate.Role = s.ClientTLSCreds.Role()
|
||||
expBackoff = events.NewExponentialBackoff(RenewTLSExponentialBackoff)
|
||||
}
|
||||
|
||||
select {
|
||||
|
|
20
vendor/github.com/docker/swarmkit/manager/controlapi/service.go
generated
vendored
20
vendor/github.com/docker/swarmkit/manager/controlapi/service.go
generated
vendored
|
@ -110,7 +110,7 @@ func validateContainerSpec(container *api.ContainerSpec) error {
|
|||
return grpc.Errorf(codes.InvalidArgument, "ContainerSpec: image reference must be provided")
|
||||
}
|
||||
|
||||
if _, err := reference.ParseNamed(container.Image); err != nil {
|
||||
if _, err := reference.ParseNormalizedNamed(container.Image); err != nil {
|
||||
return grpc.Errorf(codes.InvalidArgument, "ContainerSpec: %q is not a valid repository/tag", container.Image)
|
||||
}
|
||||
|
||||
|
@ -275,6 +275,21 @@ func (s *Server) validateNetworks(networks []*api.NetworkAttachmentConfig) error
|
|||
return nil
|
||||
}
|
||||
|
||||
func validateMode(s *api.ServiceSpec) error {
|
||||
m := s.GetMode()
|
||||
switch m.(type) {
|
||||
case *api.ServiceSpec_Replicated:
|
||||
if int64(m.(*api.ServiceSpec_Replicated).Replicated.Replicas) < 0 {
|
||||
return grpc.Errorf(codes.InvalidArgument, "Number of replicas must be non-negative")
|
||||
}
|
||||
case *api.ServiceSpec_Global:
|
||||
default:
|
||||
return grpc.Errorf(codes.InvalidArgument, "Unrecognized service mode")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateServiceSpec(spec *api.ServiceSpec) error {
|
||||
if spec == nil {
|
||||
return grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
|
||||
|
@ -291,6 +306,9 @@ func validateServiceSpec(spec *api.ServiceSpec) error {
|
|||
if err := validateEndpointSpec(spec.Endpoint); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := validateMode(spec); err != nil {
|
||||
return err
|
||||
}
|
||||
// Check to see if the Secret Reference portion of the spec is valid
|
||||
if err := validateSecretRefsSpec(spec); err != nil {
|
||||
return err
|
||||
|
|
2
vendor/github.com/docker/swarmkit/manager/logbroker/subscription.go
generated
vendored
2
vendor/github.com/docker/swarmkit/manager/logbroker/subscription.go
generated
vendored
|
@ -1,7 +1,6 @@
|
|||
package logbroker
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
|
@ -12,6 +11,7 @@ import (
|
|||
"github.com/docker/swarmkit/manager/state"
|
||||
"github.com/docker/swarmkit/manager/state/store"
|
||||
"github.com/docker/swarmkit/watch"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type subscription struct {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue