Przeglądaj źródła

Merge pull request #28459 from dmcgowan/plugin-repository-pinning

Plugin repository pinning
Victor Vieux 8 lat temu
rodzic
commit
c1a1b381f9

+ 8 - 4
distribution/errors.go

@@ -60,21 +60,25 @@ func shouldV2Fallback(err errcode.Error) bool {
 	return false
 }
 
-func translatePullError(err error, ref reference.Named) error {
+// TranslatePullError is used to convert an error from a registry pull
+// operation to an error representing the entire pull operation. Any error
+// information which is not used by the returned error gets output to
+// log at info level.
+func TranslatePullError(err error, ref reference.Named) error {
 	switch v := err.(type) {
 	case errcode.Errors:
 		if len(v) != 0 {
 			for _, extra := range v[1:] {
 				logrus.Infof("Ignoring extra error returned from registry: %v", extra)
 			}
-			return translatePullError(v[0], ref)
+			return TranslatePullError(v[0], ref)
 		}
 	case errcode.Error:
 		var newErr 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 read access", ref.Name())
+			newErr = errors.Errorf("repository %s not found: does not exist or no pull access", ref.Name())
 		case v2.ErrorCodeManifestUnknown:
 			newErr = errors.Errorf("manifest for %s not found", ref.String())
 		case v2.ErrorCodeNameUnknown:
@@ -85,7 +89,7 @@ func translatePullError(err error, ref reference.Named) error {
 			return newErr
 		}
 	case xfer.DoNotRetry:
-		return translatePullError(v.Err, ref)
+		return TranslatePullError(v.Err, ref)
 	}
 
 	return err

+ 2 - 2
distribution/pull.go

@@ -168,7 +168,7 @@ func Pull(ctx context.Context, ref reference.Named, imagePullConfig *ImagePullCo
 				continue
 			}
 			logrus.Errorf("Not continuing with pull after error: %v", err)
-			return translatePullError(err, ref)
+			return TranslatePullError(err, ref)
 		}
 
 		imagePullConfig.ImageEventLogger(ref.String(), repoInfo.Name(), "pull")
@@ -179,7 +179,7 @@ func Pull(ctx context.Context, ref reference.Named, imagePullConfig *ImagePullCo
 		lastErr = fmt.Errorf("no endpoints found for %s", ref.String())
 	}
 
-	return translatePullError(lastErr, ref)
+	return TranslatePullError(lastErr, ref)
 }
 
 // writeStatus writes a status message to out. If layersDownloaded is true, the

+ 12 - 7
distribution/registry.go

@@ -70,17 +70,22 @@ func NewV2Repository(ctx context.Context, repoInfo *registry.RepositoryInfo, end
 		passThruTokenHandler := &existingTokenHandler{token: authConfig.RegistryToken}
 		modifiers = append(modifiers, auth.NewAuthorizer(challengeManager, passThruTokenHandler))
 	} else {
+		scope := auth.RepositoryScope{
+			Repository: repoName,
+			Actions:    actions,
+		}
+
+		// Keep image repositories blank for scope compatibility
+		if repoInfo.Class != "image" {
+			scope.Class = repoInfo.Class
+		}
+
 		creds := registry.NewStaticCredentialStore(authConfig)
 		tokenHandlerOptions := auth.TokenHandlerOptions{
 			Transport:   authTransport,
 			Credentials: creds,
-			Scopes: []auth.Scope{
-				auth.RepositoryScope{
-					Repository: repoName,
-					Actions:    actions,
-				},
-			},
-			ClientID: registry.AuthClientID,
+			Scopes:      []auth.Scope{scope},
+			ClientID:    registry.AuthClientID,
 		}
 		tokenHandler := auth.NewTokenHandlerWithOptions(tokenHandlerOptions)
 		basicHandler := auth.NewBasicHandler(creds)

+ 1 - 1
integration-cli/docker_cli_pull_test.go

@@ -98,7 +98,7 @@ func (s *DockerHubPullSuite) TestPullNonExistingImage(c *check.C) {
 	for record := range recordChan {
 		if len(record.option) == 0 {
 			c.Assert(record.err, checker.NotNil, check.Commentf("expected non-zero exit status when pulling non-existing image: %s", record.out))
-			c.Assert(record.out, checker.Contains, fmt.Sprintf("repository %s not found: does not exist or no read access", record.e.repo), check.Commentf("expected image not found error messages"))
+			c.Assert(record.out, checker.Contains, fmt.Sprintf("repository %s not found: does not exist or no pull access", record.e.repo), check.Commentf("expected image not found error messages"))
 		} else {
 			// pull -a on a nonexistent registry should fall back as well
 			c.Assert(record.err, checker.NotNil, check.Commentf("expected non-zero exit status when pulling non-existing image: %s", record.out))

+ 2 - 2
plugin/distribution/pull.go

@@ -85,6 +85,7 @@ func Pull(ref reference.Named, rs registry.Service, metaheader http.Header, auth
 		logrus.Debugf("pull.go: error in ResolveRepository: %v", err)
 		return nil, err
 	}
+	repoInfo.Class = "plugin"
 
 	if err := dockerdist.ValidateRepoName(repoInfo.Name()); err != nil {
 		logrus.Debugf("pull.go: error in ValidateRepoName: %v", err)
@@ -138,9 +139,8 @@ func Pull(ref reference.Named, rs registry.Service, metaheader http.Header, auth
 	}
 	manifest, err := msv.Get(context.Background(), "", distribution.WithTag(tag))
 	if err != nil {
-		// TODO: change 401 to 404
 		logrus.Debugf("pull.go: error in msv.Get(): %v", err)
-		return nil, err
+		return nil, dockerdist.TranslatePullError(err, repoInfo)
 	}
 
 	_, pl, err := manifest.Payload()

+ 1 - 0
plugin/distribution/push.go

@@ -27,6 +27,7 @@ func Push(name string, rs registry.Service, metaHeader http.Header, authConfig *
 	if err != nil {
 		return "", err
 	}
+	repoInfo.Class = "plugin"
 
 	if err := dockerdist.ValidateRepoName(repoInfo.Name()); err != nil {
 		return "", err

+ 5 - 1
registry/config.go

@@ -280,7 +280,11 @@ func newRepositoryInfo(config *serviceConfig, name reference.Named) (*Repository
 		return nil, err
 	}
 	official := !strings.ContainsRune(name.Name(), '/')
-	return &RepositoryInfo{name, index, official}, nil
+	return &RepositoryInfo{
+		Named:    name,
+		Index:    index,
+		Official: official,
+	}, nil
 }
 
 // ParseRepositoryInfo performs the breakdown of a repository name into a RepositoryInfo, but

+ 3 - 0
registry/types.go

@@ -67,4 +67,7 @@ type RepositoryInfo struct {
 	// If the registry is official, and the normalized name does not
 	// contain a '/' (e.g. "foo"), then it is considered an official repo.
 	Official bool
+	// Class represents the class of the repository, such as "plugin"
+	// or "image".
+	Class string
 }

+ 1 - 1
vendor.conf

@@ -44,7 +44,7 @@ github.com/boltdb/bolt fff57c100f4dea1905678da7e90d92429dff2904
 github.com/miekg/dns 75e6e86cc601825c5dbcd4e0c209eab180997cd7
 
 # get graph and distribution packages
-github.com/docker/distribution d22e09a6686c32be8c17b684b639da4b90efe320
+github.com/docker/distribution a6bf3dd064f15598166bca2d66a9962a9555139e
 github.com/vbatts/tar-split v0.10.1
 
 # get go-zfs packages

+ 6 - 1
vendor/github.com/docker/distribution/registry/client/auth/session.go

@@ -147,13 +147,18 @@ type Scope interface {
 // to a repository.
 type RepositoryScope struct {
 	Repository string
+	Class      string
 	Actions    []string
 }
 
 // String returns the string representation of the repository
 // using the scope grammar
 func (rs RepositoryScope) String() string {
-	return fmt.Sprintf("repository:%s:%s", rs.Repository, strings.Join(rs.Actions, ","))
+	repoType := "repository"
+	if rs.Class != "" {
+		repoType = fmt.Sprintf("%s(%s)", repoType, rs.Class)
+	}
+	return fmt.Sprintf("%s:%s:%s", repoType, rs.Repository, strings.Join(rs.Actions, ","))
 }
 
 // RegistryScope represents a token scope for access