mirror of
https://github.com/docker/docs.git
synced 2026-04-12 06:19:22 +07:00
Use the github.com/docker/distribution/context package to get a logger
that adds a unique ID and useful information about each HTTP request.
Use this logger in HTTP handlers instead of using logrus or the log
package directly.
Remove [Notary Server] and [Notary Signer] prefixes from log messages.
The distribution/context package was already vendored, so there are no
Godeps changes necessary.
Sample output:
notaryserver_1 | time="2015-07-31T23:02:01Z" level=debug msg="retrieving timestamp key for docker.com/docker"
notarysigner_1 | time="2015-07-31T23:02:01Z" level=debug msg="generated ECDSA key with keyID: ea89e7dc49a13feab1e5ed349760b148c3c6ebd86968b2bc6cb0d003a8b79f78"
notarysigner_1 | time="2015-07-31T23:02:01Z" level=debug msg="generated new ecdsa key for role: and keyID: ea89e7dc49a13feab1e5ed349760b148c3c6ebd86968b2bc6cb0d003a8b79f78"
notarysigner_1 | time="2015-07-31T23:02:01Z" level=info msg="CreateKey: Created KeyID ea89e7dc49a13feab1e5ed349760b148c3c6ebd86968b2bc6cb0d003a8b79f78"
notaryserver_1 | time="2015-07-31T23:02:01Z" level=debug msg="Creating new timestamp key for docker.com/docker. With algo: ecdsa"
notaryserver_1 | time="2015-07-31T23:02:01Z" level=debug msg="Inserting timestamp key for docker.com/docker"
notaryserver_1 | time="2015-07-31T23:02:01Z" level=debug msg="200 GET timestamp key" docker.com/docker=gun http.request.host="192.168.99.100:4443" http.request.id=a720da02-4312-48ae-b122-6d4bce9d3b20 http.request.method=GET http.request.remoteaddr="192.168.99.1:58178" http.request.uri="/v2/docker.com/docker/_trust/tuf/timestamp.key" http.request.useragent="Go 1.1 package http"
notaryserver_1 | time="2015-07-31T23:02:01Z" level=info msg="response completed" http.request.host="192.168.99.100:4443" http.request.id=a720da02-4312-48ae-b122-6d4bce9d3b20 http.request.method=GET http.request.remoteaddr="192.168.99.1:58178" http.request.uri="/v2/docker.com/docker/_trust/tuf/timestamp.key" http.request.useragent="Go 1.1 package http" http.response.duration=29.703624ms http.response.status=200 http.response.written=181
Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
102 lines
3.1 KiB
Go
102 lines
3.1 KiB
Go
package utils
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"github.com/Sirupsen/logrus"
|
|
ctxu "github.com/docker/distribution/context"
|
|
"github.com/docker/distribution/registry/api/errcode"
|
|
"github.com/docker/distribution/registry/api/v2"
|
|
"github.com/docker/distribution/registry/auth"
|
|
"github.com/docker/notary/errors"
|
|
"github.com/endophage/gotuf/signed"
|
|
"github.com/gorilla/mux"
|
|
"golang.org/x/net/context"
|
|
)
|
|
|
|
// contextHandler defines an alterate HTTP handler interface which takes in
|
|
// a context for authorization and returns an HTTP application error.
|
|
type contextHandler func(ctx context.Context, w http.ResponseWriter, r *http.Request) error
|
|
|
|
// rootHandler is an implementation of an HTTP request handler which handles
|
|
// authorization and calling out to the defined alternate http handler.
|
|
type rootHandler struct {
|
|
handler contextHandler
|
|
auth auth.AccessController
|
|
actions []string
|
|
context context.Context
|
|
trust signed.CryptoService
|
|
//cachePool redis.Pool
|
|
}
|
|
|
|
// RootHandlerFactory creates a new rootHandler factory using the given
|
|
// Context creator and authorizer. The returned factory allows creating
|
|
// new rootHandlers from the alternate http handler contextHandler and
|
|
// a scope.
|
|
func RootHandlerFactory(auth auth.AccessController, ctx context.Context, trust signed.CryptoService) func(contextHandler, ...string) *rootHandler {
|
|
return func(handler contextHandler, actions ...string) *rootHandler {
|
|
return &rootHandler{
|
|
handler: handler,
|
|
auth: auth,
|
|
actions: actions,
|
|
context: ctx,
|
|
trust: trust,
|
|
}
|
|
}
|
|
}
|
|
|
|
// ServeHTTP serves an HTTP request and implements the http.Handler interface.
|
|
func (root *rootHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
vars := mux.Vars(r)
|
|
ctx := ctxu.WithRequest(root.context, r)
|
|
ctx, w = ctxu.WithResponseWriter(ctx, w)
|
|
ctx = ctxu.WithLogger(ctx, ctxu.GetRequestLogger(ctx))
|
|
ctx = context.WithValue(ctx, "repo", vars["imageName"])
|
|
ctx = context.WithValue(ctx, "cryptoService", root.trust)
|
|
|
|
defer func() {
|
|
ctxu.GetResponseLogger(ctx).Info("response completed")
|
|
}()
|
|
|
|
if root.auth != nil {
|
|
var err error
|
|
access := buildAccessRecords(vars["imageName"], root.actions...)
|
|
if ctx, err = root.auth.Authorized(ctx, access...); err != nil {
|
|
if err, ok := err.(auth.Challenge); ok {
|
|
err.ServeHTTP(w, r)
|
|
w.WriteHeader(http.StatusUnauthorized)
|
|
return
|
|
}
|
|
errcode.ServeJSON(w, v2.ErrorCodeUnauthorized)
|
|
return
|
|
}
|
|
}
|
|
if err := root.handler(ctx, w, r); err != nil {
|
|
e := errcode.ServeJSON(w, err)
|
|
if e != nil {
|
|
logrus.Error(e)
|
|
}
|
|
return
|
|
}
|
|
}
|
|
|
|
func buildAccessRecords(repo string, actions ...string) []auth.Access {
|
|
requiredAccess := make([]auth.Access, 0, len(actions))
|
|
for _, action := range actions {
|
|
requiredAccess = append(requiredAccess, auth.Access{
|
|
Resource: auth.Resource{
|
|
Type: "repository",
|
|
Name: repo,
|
|
},
|
|
Action: action,
|
|
})
|
|
}
|
|
return requiredAccess
|
|
}
|
|
|
|
// NotFoundHandler is used as a generic catch all handler to return the ErrMetadataNotFound
|
|
// 404 response
|
|
func NotFoundHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
|
|
return errors.ErrMetadataNotFound.WithDetail(nil)
|
|
}
|