Merge pull request #13422 from heww/disable-db-acess-for-ping

feat: skip middlewares require db for ping
This commit is contained in:
He Weiwei 2020-11-05 08:19:49 +08:00 committed by GitHub
commit 955431257c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 41 additions and 23 deletions

View File

@ -214,7 +214,7 @@ func init() {
mockServer := test.NewJobServiceServer() mockServer := test.NewJobServiceServer()
defer mockServer.Close() defer mockServer.Close()
chain := middleware.Chain(orm.Middleware(), security.Middleware()) chain := middleware.Chain(orm.Middleware(), security.Middleware(), security.UnauthorizedMiddleware())
handler = chain(beego.BeeApp.Handlers) handler = chain(beego.BeeApp.Handlers)
} }

View File

@ -38,6 +38,10 @@ var (
match = regexp.MustCompile match = regexp.MustCompile
numericRegexp = match(`[0-9]+`) numericRegexp = match(`[0-9]+`)
// The ping endpoint will be blocked when DB conns reach the max open conns of the sql.DB
// which will make ping request timeout, so skip the middlewares which will require DB conn.
pingSkipper = middleware.MethodAndPathSkipper(http.MethodGet, match("^/api/v2.0/ping"))
// dbTxSkippers skip the transaction middleware for GET Blob, PATCH Blob Upload and PUT Blob Upload APIs // dbTxSkippers skip the transaction middleware for GET Blob, PATCH Blob Upload and PUT Blob Upload APIs
// because the APIs may take a long time to run, enable the transaction middleware in them will hold the database connections // because the APIs may take a long time to run, enable the transaction middleware in them will hold the database connections
// until the API finished, this behavior may eat all the database connections. // until the API finished, this behavior may eat all the database connections.
@ -47,6 +51,7 @@ var (
middleware.MethodAndPathSkipper(http.MethodGet, distribution.BlobURLRegexp), middleware.MethodAndPathSkipper(http.MethodGet, distribution.BlobURLRegexp),
middleware.MethodAndPathSkipper(http.MethodPatch, distribution.BlobUploadURLRegexp), middleware.MethodAndPathSkipper(http.MethodPatch, distribution.BlobUploadURLRegexp),
middleware.MethodAndPathSkipper(http.MethodPut, distribution.BlobUploadURLRegexp), middleware.MethodAndPathSkipper(http.MethodPut, distribution.BlobUploadURLRegexp),
pingSkipper,
} }
// readonlySkippers skip the post request when harbor sets to readonly. // readonlySkippers skip the post request when harbor sets to readonly.
@ -63,6 +68,7 @@ var (
middleware.MethodAndPathSkipper(http.MethodPost, match("^/service/notifications/jobs/retention/task/"+numericRegexp.String())), middleware.MethodAndPathSkipper(http.MethodPost, match("^/service/notifications/jobs/retention/task/"+numericRegexp.String())),
middleware.MethodAndPathSkipper(http.MethodPost, match("^/service/notifications/jobs/schedules/"+numericRegexp.String())), middleware.MethodAndPathSkipper(http.MethodPost, match("^/service/notifications/jobs/schedules/"+numericRegexp.String())),
middleware.MethodAndPathSkipper(http.MethodPost, match("^/service/notifications/jobs/webhook/"+numericRegexp.String())), middleware.MethodAndPathSkipper(http.MethodPost, match("^/service/notifications/jobs/webhook/"+numericRegexp.String())),
pingSkipper,
} }
) )
@ -74,11 +80,12 @@ func MiddleWares() []beego.MiddleWare {
log.Middleware(), log.Middleware(),
session.Middleware(), session.Middleware(),
csrf.Middleware(), csrf.Middleware(),
orm.Middleware(), orm.Middleware(pingSkipper),
notification.Middleware(), // notification must ahead of transaction ensure the DB transaction execution complete notification.Middleware(pingSkipper), // notification must ahead of transaction ensure the DB transaction execution complete
transaction.Middleware(dbTxSkippers...), transaction.Middleware(dbTxSkippers...),
artifactinfo.Middleware(), artifactinfo.Middleware(),
security.Middleware(), security.Middleware(pingSkipper),
security.UnauthorizedMiddleware(),
readonly.Middleware(readonlySkippers...), readonly.Middleware(readonlySkippers...),
} }
} }

View File

@ -21,6 +21,7 @@ import (
"github.com/goharbor/harbor/src/core/config" "github.com/goharbor/harbor/src/core/config"
"github.com/goharbor/harbor/src/lib" "github.com/goharbor/harbor/src/lib"
"github.com/goharbor/harbor/src/lib/log" "github.com/goharbor/harbor/src/lib/log"
"github.com/goharbor/harbor/src/server/middleware"
) )
var ( var (
@ -34,7 +35,6 @@ var (
&basicAuth{}, &basicAuth{},
&session{}, &session{},
&proxyCacheSecret{}, &proxyCacheSecret{},
&unauthorized{},
} }
) )
@ -44,23 +44,34 @@ type generator interface {
} }
// Middleware returns a security context middleware that populates the security context into the request context // Middleware returns a security context middleware that populates the security context into the request context
func Middleware() func(http.Handler) http.Handler { func Middleware(skippers ...middleware.Skipper) func(http.Handler) http.Handler {
return func(handler http.Handler) http.Handler { return middleware.New(func(w http.ResponseWriter, r *http.Request, next http.Handler) {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { log := log.G(r.Context())
log := log.G(r.Context()) mode, err := config.AuthMode()
mode, err := config.AuthMode() if err == nil {
if err == nil { r = r.WithContext(lib.WithAuthMode(r.Context(), mode))
r = r.WithContext(lib.WithAuthMode(r.Context(), mode)) } else {
} else { log.Warningf("failed to get auth mode: %v", err)
log.Warningf("failed to get auth mode: %v", err) }
for _, generator := range generators {
if ctx := generator.Generate(r); ctx != nil {
r = r.WithContext(security.NewContext(r.Context(), ctx))
break
} }
for _, generator := range generators { }
if ctx := generator.Generate(r); ctx != nil { next.ServeHTTP(w, r)
r = r.WithContext(security.NewContext(r.Context(), ctx)) }, skippers...)
break }
}
} // UnauthorizedMiddleware returns a security context middleware
handler.ServeHTTP(w, r) // that populates the unauthorized security context when not security context found in the request context
}) func UnauthorizedMiddleware(skippers ...middleware.Skipper) func(http.Handler) http.Handler {
} return middleware.New(func(w http.ResponseWriter, r *http.Request, next http.Handler) {
if _, ok := security.FromContext(r.Context()); !ok {
u := &unauthorized{}
r = r.WithContext(security.NewContext(r.Context(), u.Generate(r)))
}
next.ServeHTTP(w, r)
}, skippers...)
} }