Add middleware to proxy HEAD request for proxy cache project

Fixes: #13153, containerd need to head manifest before pull image
Signed-off-by: stonezdj <stonezdj@gmail.com>
This commit is contained in:
stonezdj 2020-10-13 17:17:23 +08:00
parent cdd0eee2d4
commit 0641b300f3
3 changed files with 33 additions and 9 deletions

View File

@ -60,7 +60,9 @@ type Controller interface {
ProxyBlob(ctx context.Context, p *models.Project, art lib.ArtifactInfo) (int64, io.ReadCloser, error)
// ProxyManifest proxy the manifest request to the remote server, p is the proxy project,
// art is the ArtifactInfo which includes the tag or digest of the manifest
ProxyManifest(ctx context.Context, p *models.Project, art lib.ArtifactInfo, remote RemoteInterface) (distribution.Manifest, error)
ProxyManifest(ctx context.Context, art lib.ArtifactInfo, remote RemoteInterface) (distribution.Manifest, error)
// HeadManifest send manifest head request to the remote server
HeadManifest(ctx context.Context, art lib.ArtifactInfo, remote RemoteInterface) (bool, string, error)
}
type controller struct {
blobCtl blob.Controller
@ -121,7 +123,7 @@ func (c *controller) UseLocalManifest(ctx context.Context, art lib.ArtifactInfo,
return dig == a.Digest, nil // digest matches
}
func (c *controller) ProxyManifest(ctx context.Context, p *models.Project, art lib.ArtifactInfo, remote RemoteInterface) (distribution.Manifest, error) {
func (c *controller) ProxyManifest(ctx context.Context, art lib.ArtifactInfo, remote RemoteInterface) (distribution.Manifest, error) {
var man distribution.Manifest
remoteRepo := getRemoteRepo(art)
ref := getReference(art)
@ -166,7 +168,11 @@ func (c *controller) ProxyManifest(ctx context.Context, p *models.Project, art l
return man, nil
}
func (c *controller) HeadManifest(ctx context.Context, art lib.ArtifactInfo, remote RemoteInterface) (bool, string, error) {
remoteRepo := getRemoteRepo(art)
ref := getReference(art)
return remote.ManifestExist(remoteRepo, ref)
}
func (c *controller) ProxyBlob(ctx context.Context, p *models.Project, art lib.ArtifactInfo) (int64, io.ReadCloser, error) {
remoteRepo := getRemoteRepo(art)
log.Debugf("The blob doesn't exist, proxy the request to the target server, url:%v", remoteRepo)

View File

@ -83,8 +83,8 @@ func preCheck(ctx context.Context) (art lib.ArtifactInfo, p *models.Project, ctl
return
}
// ManifestGetMiddleware middleware handle request for get manifest
func ManifestGetMiddleware() func(http.Handler) http.Handler {
// ManifestMiddleware middleware handle request for get or head manifest
func ManifestMiddleware() func(http.Handler) http.Handler {
return middleware.New(func(w http.ResponseWriter, r *http.Request, next http.Handler) {
if err := handleManifest(w, r, next); err != nil {
httpLib.SendError(w, err)
@ -115,7 +115,11 @@ func handleManifest(w http.ResponseWriter, r *http.Request, next http.Handler) e
return nil
}
log.Debugf("the tag is %v, digest is %v", art.Tag, art.Digest)
err = proxyManifest(ctx, w, proxyCtl, p, art, remote)
if r.Method == http.MethodHead {
err = proxyManifestHead(ctx, w, proxyCtl, p, art, remote)
} else if r.Method == http.MethodGet {
err = proxyManifestGet(ctx, w, proxyCtl, p, art, remote)
}
if err != nil {
if errors.IsNotFoundErr(err) {
return err
@ -126,8 +130,8 @@ func handleManifest(w http.ResponseWriter, r *http.Request, next http.Handler) e
return nil
}
func proxyManifest(ctx context.Context, w http.ResponseWriter, ctl proxy.Controller, p *models.Project, art lib.ArtifactInfo, remote proxy.RemoteInterface) error {
man, err := ctl.ProxyManifest(ctx, p, art, remote)
func proxyManifestGet(ctx context.Context, w http.ResponseWriter, ctl proxy.Controller, p *models.Project, art lib.ArtifactInfo, remote proxy.RemoteInterface) error {
man, err := ctl.ProxyManifest(ctx, art, remote)
if err != nil {
return err
}
@ -200,3 +204,16 @@ func DisableBlobAndManifestUploadMiddleware() func(http.Handler) http.Handler {
return
})
}
func proxyManifestHead(ctx context.Context, w http.ResponseWriter, ctl proxy.Controller, p *models.Project, art lib.ArtifactInfo, remote proxy.RemoteInterface) error {
exist, dig, err := ctl.HeadManifest(ctx, art, remote)
if err != nil {
return err
}
if !exist {
return errors.NotFoundError(fmt.Errorf("The tag %v:%v is not found", art.Repository, art.Tag))
}
w.Header().Set("Docker-Content-Digest", dig)
w.Header().Set("Etag", dig)
return nil
}

View File

@ -46,13 +46,14 @@ func RegisterRoutes() {
root.NewRoute().
Method(http.MethodGet).
Path("/*/manifests/:reference").
Middleware(repoproxy.ManifestGetMiddleware()).
Middleware(repoproxy.ManifestMiddleware()).
Middleware(contenttrust.Middleware()).
Middleware(vulnerable.Middleware()).
HandlerFunc(getManifest)
root.NewRoute().
Method(http.MethodHead).
Path("/*/manifests/:reference").
Middleware(repoproxy.ManifestMiddleware()).
HandlerFunc(getManifest)
root.NewRoute().
Method(http.MethodDelete).