mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Merge pull request #28459 from dmcgowan/plugin-repository-pinning
Plugin repository pinning
This commit is contained in:
commit
c1a1b381f9
10 changed files with 41 additions and 19 deletions
|
@ -60,21 +60,25 @@ func shouldV2Fallback(err errcode.Error) bool {
|
||||||
return false
|
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) {
|
switch v := err.(type) {
|
||||||
case errcode.Errors:
|
case errcode.Errors:
|
||||||
if len(v) != 0 {
|
if len(v) != 0 {
|
||||||
for _, extra := range v[1:] {
|
for _, extra := range v[1:] {
|
||||||
logrus.Infof("Ignoring extra error returned from registry: %v", extra)
|
logrus.Infof("Ignoring extra error returned from registry: %v", extra)
|
||||||
}
|
}
|
||||||
return translatePullError(v[0], ref)
|
return TranslatePullError(v[0], ref)
|
||||||
}
|
}
|
||||||
case errcode.Error:
|
case errcode.Error:
|
||||||
var newErr error
|
var newErr error
|
||||||
switch v.Code {
|
switch v.Code {
|
||||||
case errcode.ErrorCodeDenied:
|
case errcode.ErrorCodeDenied:
|
||||||
// ErrorCodeDenied is used when access to the repository was denied
|
// 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:
|
case v2.ErrorCodeManifestUnknown:
|
||||||
newErr = errors.Errorf("manifest for %s not found", ref.String())
|
newErr = errors.Errorf("manifest for %s not found", ref.String())
|
||||||
case v2.ErrorCodeNameUnknown:
|
case v2.ErrorCodeNameUnknown:
|
||||||
|
@ -85,7 +89,7 @@ func translatePullError(err error, ref reference.Named) error {
|
||||||
return newErr
|
return newErr
|
||||||
}
|
}
|
||||||
case xfer.DoNotRetry:
|
case xfer.DoNotRetry:
|
||||||
return translatePullError(v.Err, ref)
|
return TranslatePullError(v.Err, ref)
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -168,7 +168,7 @@ func Pull(ctx context.Context, ref reference.Named, imagePullConfig *ImagePullCo
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
logrus.Errorf("Not continuing with pull after error: %v", err)
|
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")
|
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())
|
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
|
// writeStatus writes a status message to out. If layersDownloaded is true, the
|
||||||
|
|
|
@ -70,17 +70,22 @@ func NewV2Repository(ctx context.Context, repoInfo *registry.RepositoryInfo, end
|
||||||
passThruTokenHandler := &existingTokenHandler{token: authConfig.RegistryToken}
|
passThruTokenHandler := &existingTokenHandler{token: authConfig.RegistryToken}
|
||||||
modifiers = append(modifiers, auth.NewAuthorizer(challengeManager, passThruTokenHandler))
|
modifiers = append(modifiers, auth.NewAuthorizer(challengeManager, passThruTokenHandler))
|
||||||
} else {
|
} 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)
|
creds := registry.NewStaticCredentialStore(authConfig)
|
||||||
tokenHandlerOptions := auth.TokenHandlerOptions{
|
tokenHandlerOptions := auth.TokenHandlerOptions{
|
||||||
Transport: authTransport,
|
Transport: authTransport,
|
||||||
Credentials: creds,
|
Credentials: creds,
|
||||||
Scopes: []auth.Scope{
|
Scopes: []auth.Scope{scope},
|
||||||
auth.RepositoryScope{
|
ClientID: registry.AuthClientID,
|
||||||
Repository: repoName,
|
|
||||||
Actions: actions,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
ClientID: registry.AuthClientID,
|
|
||||||
}
|
}
|
||||||
tokenHandler := auth.NewTokenHandlerWithOptions(tokenHandlerOptions)
|
tokenHandler := auth.NewTokenHandlerWithOptions(tokenHandlerOptions)
|
||||||
basicHandler := auth.NewBasicHandler(creds)
|
basicHandler := auth.NewBasicHandler(creds)
|
||||||
|
|
|
@ -98,7 +98,7 @@ func (s *DockerHubPullSuite) TestPullNonExistingImage(c *check.C) {
|
||||||
for record := range recordChan {
|
for record := range recordChan {
|
||||||
if len(record.option) == 0 {
|
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.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 {
|
} else {
|
||||||
// pull -a on a nonexistent registry should fall back as well
|
// 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))
|
c.Assert(record.err, checker.NotNil, check.Commentf("expected non-zero exit status when pulling non-existing image: %s", record.out))
|
||||||
|
|
|
@ -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)
|
logrus.Debugf("pull.go: error in ResolveRepository: %v", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
repoInfo.Class = "plugin"
|
||||||
|
|
||||||
if err := dockerdist.ValidateRepoName(repoInfo.Name()); err != nil {
|
if err := dockerdist.ValidateRepoName(repoInfo.Name()); err != nil {
|
||||||
logrus.Debugf("pull.go: error in ValidateRepoName: %v", err)
|
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))
|
manifest, err := msv.Get(context.Background(), "", distribution.WithTag(tag))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// TODO: change 401 to 404
|
|
||||||
logrus.Debugf("pull.go: error in msv.Get(): %v", err)
|
logrus.Debugf("pull.go: error in msv.Get(): %v", err)
|
||||||
return nil, err
|
return nil, dockerdist.TranslatePullError(err, repoInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, pl, err := manifest.Payload()
|
_, pl, err := manifest.Payload()
|
||||||
|
|
|
@ -27,6 +27,7 @@ func Push(name string, rs registry.Service, metaHeader http.Header, authConfig *
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
repoInfo.Class = "plugin"
|
||||||
|
|
||||||
if err := dockerdist.ValidateRepoName(repoInfo.Name()); err != nil {
|
if err := dockerdist.ValidateRepoName(repoInfo.Name()); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
|
|
@ -280,7 +280,11 @@ func newRepositoryInfo(config *serviceConfig, name reference.Named) (*Repository
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
official := !strings.ContainsRune(name.Name(), '/')
|
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
|
// ParseRepositoryInfo performs the breakdown of a repository name into a RepositoryInfo, but
|
||||||
|
|
|
@ -67,4 +67,7 @@ type RepositoryInfo struct {
|
||||||
// If the registry is official, and the normalized name does not
|
// If the registry is official, and the normalized name does not
|
||||||
// contain a '/' (e.g. "foo"), then it is considered an official repo.
|
// contain a '/' (e.g. "foo"), then it is considered an official repo.
|
||||||
Official bool
|
Official bool
|
||||||
|
// Class represents the class of the repository, such as "plugin"
|
||||||
|
// or "image".
|
||||||
|
Class string
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,7 @@ github.com/boltdb/bolt fff57c100f4dea1905678da7e90d92429dff2904
|
||||||
github.com/miekg/dns 75e6e86cc601825c5dbcd4e0c209eab180997cd7
|
github.com/miekg/dns 75e6e86cc601825c5dbcd4e0c209eab180997cd7
|
||||||
|
|
||||||
# get graph and distribution packages
|
# get graph and distribution packages
|
||||||
github.com/docker/distribution d22e09a6686c32be8c17b684b639da4b90efe320
|
github.com/docker/distribution a6bf3dd064f15598166bca2d66a9962a9555139e
|
||||||
github.com/vbatts/tar-split v0.10.1
|
github.com/vbatts/tar-split v0.10.1
|
||||||
|
|
||||||
# get go-zfs packages
|
# get go-zfs packages
|
||||||
|
|
7
vendor/github.com/docker/distribution/registry/client/auth/session.go
generated
vendored
7
vendor/github.com/docker/distribution/registry/client/auth/session.go
generated
vendored
|
@ -147,13 +147,18 @@ type Scope interface {
|
||||||
// to a repository.
|
// to a repository.
|
||||||
type RepositoryScope struct {
|
type RepositoryScope struct {
|
||||||
Repository string
|
Repository string
|
||||||
|
Class string
|
||||||
Actions []string
|
Actions []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns the string representation of the repository
|
// String returns the string representation of the repository
|
||||||
// using the scope grammar
|
// using the scope grammar
|
||||||
func (rs RepositoryScope) String() string {
|
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
|
// RegistryScope represents a token scope for access
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue