distribution/registry/images.go
Stephen J Day d2bfb5825c Integrate contextual logging with regsitry app
This changeset integrates contextual logging into the registry web application.
Idiomatic context use is attempted within the current webapp layout. The
functionality is centered around making lifecycle objects (application and
request context) into contexts themselves. Relevant data has been moved into
the context where appropriate.  We still have some work to do to factor out the
registry.Context object and the dispatching functionality to remove some
awkward portions.

The api tests were slightly refactored to use a test environment to eliminate
common code.

Signed-off-by: Stephen J Day <stephen.day@docker.com>
2015-02-06 16:51:53 -08:00

118 lines
3.6 KiB
Go

package registry
import (
"encoding/json"
"fmt"
"net/http"
"github.com/docker/distribution/api/v2"
ctxu "github.com/docker/distribution/context"
"github.com/docker/distribution/digest"
"github.com/docker/distribution/manifest"
"github.com/docker/distribution/storage"
"github.com/gorilla/handlers"
)
// imageManifestDispatcher takes the request context and builds the
// appropriate handler for handling image manifest requests.
func imageManifestDispatcher(ctx *Context, r *http.Request) http.Handler {
imageManifestHandler := &imageManifestHandler{
Context: ctx,
Tag: getTag(ctx),
}
return handlers.MethodHandler{
"GET": http.HandlerFunc(imageManifestHandler.GetImageManifest),
"PUT": http.HandlerFunc(imageManifestHandler.PutImageManifest),
"DELETE": http.HandlerFunc(imageManifestHandler.DeleteImageManifest),
}
}
// imageManifestHandler handles http operations on image manifests.
type imageManifestHandler struct {
*Context
Tag string
}
// GetImageManifest fetches the image manifest from the storage backend, if it exists.
func (imh *imageManifestHandler) GetImageManifest(w http.ResponseWriter, r *http.Request) {
ctxu.GetLogger(imh).Debug("GetImageManifest")
manifests := imh.Repository.Manifests()
manifest, err := manifests.Get(imh.Tag)
if err != nil {
imh.Errors.Push(v2.ErrorCodeManifestUnknown, err)
w.WriteHeader(http.StatusNotFound)
return
}
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.Header().Set("Content-Length", fmt.Sprint(len(manifest.Raw)))
w.Write(manifest.Raw)
}
// PutImageManifest validates and stores and image in the registry.
func (imh *imageManifestHandler) PutImageManifest(w http.ResponseWriter, r *http.Request) {
ctxu.GetLogger(imh).Debug("PutImageManifest")
manifests := imh.Repository.Manifests()
dec := json.NewDecoder(r.Body)
var manifest manifest.SignedManifest
if err := dec.Decode(&manifest); err != nil {
imh.Errors.Push(v2.ErrorCodeManifestInvalid, err)
w.WriteHeader(http.StatusBadRequest)
return
}
if err := manifests.Put(imh.Tag, &manifest); err != nil {
// TODO(stevvooe): These error handling switches really need to be
// handled by an app global mapper.
switch err := err.(type) {
case storage.ErrManifestVerification:
for _, verificationError := range err {
switch verificationError := verificationError.(type) {
case storage.ErrUnknownLayer:
imh.Errors.Push(v2.ErrorCodeBlobUnknown, verificationError.FSLayer)
case storage.ErrManifestUnverified:
imh.Errors.Push(v2.ErrorCodeManifestUnverified)
default:
if verificationError == digest.ErrDigestInvalidFormat {
// TODO(stevvooe): We need to really need to move all
// errors to types. Its much more straightforward.
imh.Errors.Push(v2.ErrorCodeDigestInvalid)
} else {
imh.Errors.PushErr(verificationError)
}
}
}
default:
imh.Errors.PushErr(err)
}
w.WriteHeader(http.StatusBadRequest)
return
}
w.WriteHeader(http.StatusAccepted)
}
// DeleteImageManifest removes the image with the given tag from the registry.
func (imh *imageManifestHandler) DeleteImageManifest(w http.ResponseWriter, r *http.Request) {
ctxu.GetLogger(imh).Debug("DeleteImageManifest")
manifests := imh.Repository.Manifests()
if err := manifests.Delete(imh.Tag); err != nil {
switch err := err.(type) {
case storage.ErrUnknownManifest:
imh.Errors.Push(v2.ErrorCodeManifestUnknown, err)
w.WriteHeader(http.StatusNotFound)
default:
imh.Errors.Push(v2.ErrorCodeUnknown, err)
w.WriteHeader(http.StatusBadRequest)
}
return
}
w.Header().Set("Content-Length", "0")
w.WriteHeader(http.StatusAccepted)
}