From 90c479b23cd5e90339788cf286f721fda45e223f Mon Sep 17 00:00:00 2001 From: Ankit Chawla Date: Fri, 22 Apr 2022 14:21:58 +0530 Subject: [PATCH] Restructured authmiddleware fn and added tests (#2410) * Created separate file for authmiddleware fn * Optimize auth login and middleware * Added unittests for authmiddleware * Fixed authURL * Removed featureConfig as global variable * Fix integration test according to examples repo changes * Fix integration test path for go module-example Co-authored-by: Sanket Sudake --- pkg/controller/api.go | 2 +- pkg/executor/api.go | 2 +- pkg/featureconfig/config.go | 4 + pkg/router/auth.go | 170 +++++++++++++++++ pkg/router/auth_test.go | 154 +++++++++++++++ pkg/router/httpTriggers.go | 176 ++---------------- pkg/router/mutablemux_test.go | 4 +- pkg/router/router.go | 2 +- pkg/storagesvc/storagesvc.go | 2 +- pkg/utils/metrics/http_metrics.go | 50 +++-- test/tests/test_environments/test_go_env.sh | 4 +- .../test_environments/test_java_builder.sh | 2 +- .../test_tensorflow_serving_env.sh | 2 +- 13 files changed, 373 insertions(+), 201 deletions(-) create mode 100644 pkg/router/auth.go create mode 100644 pkg/router/auth_test.go diff --git a/pkg/controller/api.go b/pkg/controller/api.go index 9792fbfc..280b9b97 100644 --- a/pkg/controller/api.go +++ b/pkg/controller/api.go @@ -200,7 +200,7 @@ func (api *API) GetSvcName(w http.ResponseWriter, r *http.Request) { func (api *API) GetHandler() http.Handler { r := mux.NewRouter() - r.Use(metrics.HTTPMetricMiddleware()) + r.Use(metrics.HTTPMetricMiddleware) r.HandleFunc("/healthz", api.HealthHandler).Methods("GET") // Give a useful error message if an older CLI attempts to make a request r.HandleFunc(`/v1/{rest:[a-zA-Z0-9=\-\/]+}`, api.ApiVersionMismatchHandler) diff --git a/pkg/executor/api.go b/pkg/executor/api.go index 34cfe792..f765378d 100644 --- a/pkg/executor/api.go +++ b/pkg/executor/api.go @@ -253,7 +253,7 @@ func (executor *Executor) unTapService(w http.ResponseWriter, r *http.Request) { // GetHandler returns an http.Handler. func (executor *Executor) GetHandler() http.Handler { r := mux.NewRouter() - r.Use(metrics.HTTPMetricMiddleware()) + r.Use(metrics.HTTPMetricMiddleware) r.HandleFunc("/v2/getServiceForFunction", executor.getServiceForFunctionAPI).Methods("POST") r.HandleFunc("/v2/tapService", executor.tapService).Methods("POST") // for backward compatibility r.HandleFunc("/v2/tapServices", executor.tapServices).Methods("POST") diff --git a/pkg/featureconfig/config.go b/pkg/featureconfig/config.go index 2b8fba05..c0b2d8e6 100644 --- a/pkg/featureconfig/config.go +++ b/pkg/featureconfig/config.go @@ -45,5 +45,9 @@ func GetFeatureConfig() (*FeatureConfig, error) { return nil, fmt.Errorf("error unmarshalling YAML config %v", err) } + if featureConfig.AuthConfig.AuthUriPath == "" { + featureConfig.AuthConfig.AuthUriPath = "/auth/login" + } + return featureConfig, err } diff --git a/pkg/router/auth.go b/pkg/router/auth.go new file mode 100644 index 00000000..d6264653 --- /dev/null +++ b/pkg/router/auth.go @@ -0,0 +1,170 @@ +package router + +import ( + "encoding/json" + "errors" + "fmt" + "io" + "net/http" + "os" + "strings" + "time" + + "github.com/golang-jwt/jwt/v4" + "github.com/gorilla/mux" + + fv1 "github.com/fission/fission/pkg/apis/core/v1" + config "github.com/fission/fission/pkg/featureconfig" +) + +var ( + malformedToken = errors.New("Unauthorized: malformed token") + expiredToken = errors.New("Unauthorized: token is either expired or not active yet") + invalidCreds = errors.New("Unauthorized: invalid username or password") +) + +func checkAuthToken(r *http.Request) error { + authHeader := strings.Split(r.Header.Get("Authorization"), "Bearer ") + if len(authHeader) != 2 || len(authHeader[1]) == 0 { + // malformed token + return malformedToken + } + + jwtToken := authHeader[1] + token, err := jwt.Parse(jwtToken, func(token *jwt.Token) (interface{}, error) { + return []byte(os.Getenv("JWT_SIGNING_KEY")), nil + }) + + if token != nil && token.Valid { + // valid token + return nil + } + + if ve, ok := err.(*jwt.ValidationError); ok { + if ve.Errors&jwt.ValidationErrorMalformed != 0 { + // malformed token + err = malformedToken + } else if ve.Errors&(jwt.ValidationErrorExpired|jwt.ValidationErrorNotValidYet) != 0 { + // token is either expired or not active yet + err = expiredToken + } else { + err = fmt.Errorf("Unauthorized: %w", err) + } + } + + if err == nil { + err = errors.New("Unauthorized: invalid token") + } + + return err +} + +func authMiddleware(featureConfig *config.FeatureConfig) mux.MiddlewareFunc { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != featureConfig.AuthConfig.AuthUriPath && r.URL.Path != "/router-healthz" { + err := checkAuthToken(r) + if err != nil { + http.Error(w, err.Error(), http.StatusUnauthorized) + return + } + } + next.ServeHTTP(w, r) + }) + } +} + +type AuthConf struct { + username string + password string + jwtSigningKey string +} + +func parseAuthConf(auth *AuthConf) error { + username, ok := os.LookupEnv("AUTH_USERNAME") + if !ok || len(username) == 0 { + return fmt.Errorf("Username not configured or invalid") + } + + password, ok := os.LookupEnv("AUTH_PASSWORD") + if !ok || len(password) == 0 { + return fmt.Errorf("Password not configured or invalid") + } + + signingKey, ok := os.LookupEnv("JWT_SIGNING_KEY") + if !ok || len(signingKey) == 0 { + return fmt.Errorf("Signing key not configured or invalid") + } + + auth.username = username + auth.password = password + auth.jwtSigningKey = signingKey + return nil +} + +func authLoginHandler(featureConfig *config.FeatureConfig) func(w http.ResponseWriter, r *http.Request) { + var ( + err error + validConf bool + ) + + validConf = true + + auth := &AuthConf{} + if err = parseAuthConf(auth); err != nil { + validConf = false + } + + return func(w http.ResponseWriter, r *http.Request) { + if !validConf { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + body, err := io.ReadAll(r.Body) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + var t fv1.AuthLogin + + err = json.Unmarshal(body, &t) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + rat := &fv1.RouterAuthToken{} + + if t.Username != auth.username || t.Password != auth.password { + http.Error(w, invalidCreds.Error(), http.StatusUnauthorized) + return + } + + claims := &jwt.RegisteredClaims{ + ExpiresAt: jwt.NewNumericDate(jwt.TimeFunc().Add(featureConfig.AuthConfig.JWTExpiryTime * time.Second)), + Issuer: featureConfig.AuthConfig.JWTIssuer, + NotBefore: jwt.NewNumericDate(jwt.TimeFunc()), + } + + token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + ss, err := token.SignedString([]byte(auth.jwtSigningKey)) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + rat.AccessToken = ss + rat.TokenType = "Bearer" + + resp, err := json.Marshal(rat) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + w.WriteHeader(http.StatusCreated) + _, _ = w.Write(resp) + } + +} diff --git a/pkg/router/auth_test.go b/pkg/router/auth_test.go new file mode 100644 index 00000000..36731a31 --- /dev/null +++ b/pkg/router/auth_test.go @@ -0,0 +1,154 @@ +package router + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "net/http" + "os" + "testing" + + "github.com/gorilla/mux" + + fv1 "github.com/fission/fission/pkg/apis/core/v1" + config "github.com/fission/fission/pkg/featureconfig" + "github.com/fission/fission/pkg/utils/httpserver" + "github.com/fission/fission/pkg/utils/loggerfactory" + "github.com/fission/fission/pkg/utils/metrics" +) + +func setup(tb testing.TB) func(tb testing.TB) { + + os.Setenv("AUTH_USERNAME", "Foo") + os.Setenv("AUTH_PASSWORD", "Bar") + os.Setenv("JWT_SIGNING_KEY", "test") + return func(tb testing.TB) { + os.Unsetenv("AUTH_USERNAME") + os.Unsetenv("AUTH_PASSWORD") + os.Unsetenv("JWT_SIGNING_KEY") + } +} + +func GetRouterWithAuth() *mux.Router { + testHandler := func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + _, err := io.WriteString(w, "OK") + if err != nil { + fmt.Println(fmt.Errorf("Error in writing string: %s", err)) + } + } + + featureConfig := config.FeatureConfig{} + featureConfig.AuthConfig.AuthUriPath = "/auth/login" + featureConfig.AuthConfig.JWTIssuer = "fission" + featureConfig.AuthConfig.JWTExpiryTime = 120 + + muxRouter := mux.NewRouter() + muxRouter.Use(authMiddleware(&featureConfig)) + muxRouter.Use(metrics.HTTPMetricMiddleware) + + muxRouter.HandleFunc("/auth/login", authLoginHandler(&featureConfig)).Methods("POST") + // We should be able to access health without login + muxRouter.HandleFunc("/router-healthz", routerHealthHandler).Methods("GET") + muxRouter.HandleFunc("/test", testHandler).Methods("GET") + return muxRouter +} + +func TestRouterAuth(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + teardown := setup(t) + defer teardown(t) + logger := loggerfactory.GetLogger() + testmux := GetRouterWithAuth() + + go httpserver.StartServer(ctx, logger, "test", "8990", testmux) + + postBody, _ := json.Marshal(map[string]string{ + "username": "Foo", + "password": "Bar", + }) + responseBody := bytes.NewBuffer(postBody) + + tests := []struct { + URL string + StatusCode int + Body string + AuthReq bool + }{ + { + URL: "http://localhost:8990/router-healthz", + StatusCode: http.StatusOK, + Body: "", + AuthReq: false, + }, + { + URL: "http://localhost:8990/router-healthz", + StatusCode: http.StatusOK, + Body: "", + AuthReq: true, + }, + { + URL: "http://localhost:8990/test", + StatusCode: http.StatusOK, + Body: "OK", + AuthReq: true, + }, + { + URL: "http://localhost:8990/test", + StatusCode: http.StatusUnauthorized, + Body: "Unauthorized: malformed token\n", + AuthReq: false, + }, + } + + loginResp, err := http.Post("http://localhost:8990/auth/login", "application/json", responseBody) + if err != nil { + t.Error(err) + } + defer loginResp.Body.Close() + + body, err := io.ReadAll(loginResp.Body) + if err != nil { + t.Error(err, "error creating token") + } + + var rat fv1.RouterAuthToken + if loginResp.StatusCode == http.StatusCreated { + err = json.Unmarshal(body, &rat) + if err != nil { + t.Error(err) + } + } + + client := &http.Client{} + + for _, test := range tests { + req, err := http.NewRequest("GET", test.URL, nil) + if err != nil { + t.Errorf("failed to make get request %v: %v", test.URL, err) + } + if test.AuthReq == true { + req.Header.Add("Authorization", fmt.Sprintf("Bearer %v", rat.AccessToken)) + } + + resp, err := client.Do(req) + if err != nil { + t.Error(err) + } + defer resp.Body.Close() + if resp.StatusCode != test.StatusCode { + t.Errorf("expected status code %v, got %v", test.StatusCode, resp.StatusCode) + } + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + t.Errorf("failed to read response body: %v", err) + } + if string(body) != test.Body { + t.Errorf("expected body \"%v\", got \"%v\"", test.Body, string(body)) + } + } +} diff --git a/pkg/router/httpTriggers.go b/pkg/router/httpTriggers.go index 914d1f2b..9242b388 100644 --- a/pkg/router/httpTriggers.go +++ b/pkg/router/httpTriggers.go @@ -18,16 +18,10 @@ package router import ( "context" - "encoding/json" - "errors" - "fmt" - "io" "net/http" - "os" "strings" "time" - "github.com/golang-jwt/jwt/v4" "github.com/gorilla/mux" "go.uber.org/zap" "k8s.io/apimachinery/pkg/types" @@ -46,8 +40,6 @@ import ( "github.com/fission/fission/pkg/utils/tracing" ) -var featureConfig *config.FeatureConfig - // HTTPTriggerSet represents an HTTP trigger set type HTTPTriggerSet struct { *functionServiceMap @@ -69,20 +61,6 @@ type HTTPTriggerSet struct { unTapServiceTimeout time.Duration } -func init() { - _ = loadFeatureConfigmap() -} - -func loadFeatureConfigmap() error { - var err error - featureConfig, err = config.GetFeatureConfig() - if err != nil { - fmt.Println(err) - return errors.New("error while loading feature configmap") - } - return nil -} - func makeHTTPTriggerSet(logger *zap.Logger, fmap *functionServiceMap, fissionClient versioned.Interface, kubeClient kubernetes.Interface, executor *executorClient.Client, params *tsRoundTripperParams, isDebugEnv bool, unTapServiceTimeout time.Duration, actionThrottler *throttler.Throttler) *HTTPTriggerSet { @@ -130,95 +108,19 @@ func defaultHomeHandler(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) } -func createErrorResponse(errMsg string, statusCode int) []byte { - resp, _ := json.Marshal(map[string]interface{}{"statusCode": statusCode, "message": errMsg}) - return resp -} - func routerHealthHandler(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) } -func authLoginHandler(w http.ResponseWriter, r *http.Request) { - - body, err := io.ReadAll(r.Body) - if err != nil { - w.WriteHeader(http.StatusBadRequest) - _, _ = w.Write(createErrorResponse("Error while reading request body", http.StatusBadRequest)) - return - } - - var t fv1.AuthLogin - - err = json.Unmarshal(body, &t) - if err != nil { - w.WriteHeader(http.StatusBadRequest) - _, _ = w.Write(createErrorResponse("Error while reading request body", http.StatusBadRequest)) - return - } - - username, ok := os.LookupEnv("AUTH_USERNAME") - if !ok || len(username) == 0 { - w.WriteHeader(http.StatusBadRequest) - _, _ = w.Write(createErrorResponse("Username not found or invalid", http.StatusBadRequest)) - return - } - - password, ok := os.LookupEnv("AUTH_PASSWORD") - if !ok || len(password) == 0 { - w.WriteHeader(http.StatusBadRequest) - _, _ = w.Write(createErrorResponse("Password not found or invalid", http.StatusBadRequest)) - return - } - - signingKey, ok := os.LookupEnv("JWT_SIGNING_KEY") - if !ok || len(signingKey) == 0 { - w.WriteHeader(http.StatusInternalServerError) - _, _ = w.Write(createErrorResponse("Internal server error occurred", http.StatusInternalServerError)) - return - } - - rat := &fv1.RouterAuthToken{} - - if t.Username == username && t.Password == password { - - claims := &jwt.RegisteredClaims{ - ExpiresAt: jwt.NewNumericDate(jwt.TimeFunc().Add(featureConfig.AuthConfig.JWTExpiryTime * time.Second)), - Issuer: featureConfig.AuthConfig.JWTIssuer, - NotBefore: jwt.NewNumericDate(jwt.TimeFunc()), - } - - token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) - ss, err := token.SignedString([]byte(signingKey)) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - _, _ = w.Write(createErrorResponse("Internal server error occurred", http.StatusInternalServerError)) - return - } - rat.AccessToken = ss - rat.TokenType = "Bearer" - - } else { - w.WriteHeader(http.StatusUnauthorized) - _, _ = w.Write(createErrorResponse("Unauthorized: invalid username and/or password", http.StatusUnauthorized)) - return - } - - resp, err := json.Marshal(rat) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - _, _ = w.Write(createErrorResponse("Internal server error occurred", http.StatusInternalServerError)) - return - } - - w.WriteHeader(http.StatusCreated) - _, _ = w.Write(resp) - -} - func (ts *HTTPTriggerSet) getRouter(fnTimeoutMap map[types.UID]int) *mux.Router { + + featureConfig, _ := config.GetFeatureConfig() + muxRouter := mux.NewRouter() - muxRouter.Use(metrics.HTTPMetricMiddleware()) + muxRouter.Use(metrics.HTTPMetricMiddleware) + if featureConfig.AuthConfig.IsEnabled { + muxRouter.Use(authMiddleware(featureConfig)) + } openTracingEnabled := tracing.TracingEnabled(ts.logger) @@ -306,12 +208,7 @@ func (ts *HTTPTriggerSet) getRouter(fnTimeoutMap map[types.UID]int) *mux.Router } ts.logger.Debug("add prefix route for function", zap.String("route", prefix), zap.Any("function", fh.function), zap.Strings("methods", methods)) } else { - var ht1 *mux.Route - if featureConfig.AuthConfig.IsEnabled { - ht1 = muxRouter.Handle(prefix, authMiddleware(handler)) - } else { - ht1 = muxRouter.Handle(prefix, handler) - } + ht1 := muxRouter.Handle(prefix, handler) ht1.Methods(methods...) if trigger.Spec.Host != "" { ht1.Host(trigger.Spec.Host) @@ -324,12 +221,7 @@ func (ts *HTTPTriggerSet) getRouter(fnTimeoutMap map[types.UID]int) *mux.Router ts.logger.Debug("add prefix and handler route for function", zap.String("route", prefix), zap.Any("function", fh.function), zap.Strings("methods", methods)) } } else { - var ht *mux.Route - if featureConfig.AuthConfig.IsEnabled { - ht = muxRouter.Handle(trigger.Spec.RelativeURL, authMiddleware(handler)) - } else { - ht = muxRouter.Handle(trigger.Spec.RelativeURL, handler) - } + ht := muxRouter.Handle(trigger.Spec.RelativeURL, handler) ht.Methods(methods...) if trigger.Spec.Host != "" { ht.Host(trigger.Spec.Host) @@ -377,11 +269,7 @@ func (ts *HTTPTriggerSet) getRouter(fnTimeoutMap map[types.UID]int) *mux.Router handler = otel.GetHandlerWithOTEL(http.HandlerFunc(fh.handler), internalRoute) } - if featureConfig.AuthConfig.IsEnabled { - muxRouter.Handle(internalRoute, authMiddleware(handler)) - } else { - muxRouter.Handle(internalRoute, handler) - } + muxRouter.Handle(internalRoute, handler) muxRouter.PathPrefix(internalPrefixRoute).Handler(handler) ts.logger.Debug("add internal handler and prefix route for function", zap.String("router", internalRoute), zap.Any("function", fn)) } @@ -389,12 +277,8 @@ func (ts *HTTPTriggerSet) getRouter(fnTimeoutMap map[types.UID]int) *mux.Router if featureConfig.AuthConfig.IsEnabled { path := featureConfig.AuthConfig.AuthUriPath - if len(path) == 0 { - path = "/auth/login" - } - // Auth endpoint for the router. - muxRouter.HandleFunc(path, authLoginHandler).Methods("POST") + muxRouter.HandleFunc(path, authLoginHandler(featureConfig)).Methods("POST") } // Healthz endpoint for the router. @@ -403,44 +287,6 @@ func (ts *HTTPTriggerSet) getRouter(fnTimeoutMap map[types.UID]int) *mux.Router return muxRouter } -func authMiddleware(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - - authHeader := strings.Split(r.Header.Get("Authorization"), "Bearer ") - if len(authHeader) != 2 || len(authHeader[1]) == 0 { - // malformed token - w.WriteHeader(http.StatusUnauthorized) - _, _ = w.Write(createErrorResponse("Unauthorized: malformed Token", http.StatusUnauthorized)) - } else { - jwtToken := authHeader[1] - token, err := jwt.Parse(jwtToken, func(token *jwt.Token) (interface{}, error) { - return []byte(os.Getenv("JWT_SIGNING_KEY")), nil - }) - - if token != nil && token.Valid { - // valid token - next.ServeHTTP(w, r) - } else if ve, ok := err.(*jwt.ValidationError); ok { - w.WriteHeader(http.StatusUnauthorized) - if ve.Errors&jwt.ValidationErrorMalformed != 0 { - // malformed token - _, _ = w.Write(createErrorResponse("Unauthorized: malformed Token", http.StatusUnauthorized)) - } else if ve.Errors&(jwt.ValidationErrorExpired|jwt.ValidationErrorNotValidYet) != 0 { - // token is either expired or not active yet - _, _ = w.Write(createErrorResponse("Unauthorized: token is either expired or not active yet", http.StatusUnauthorized)) - } else { - _, _ = w.Write(createErrorResponse(fmt.Sprintf("Unauthorized: %v", err.Error()), http.StatusUnauthorized)) - } - } else { - w.WriteHeader(http.StatusUnauthorized) - _, _ = w.Write(createErrorResponse("Unauthorized", http.StatusUnauthorized)) - } - - } - - }) -} - func (ts *HTTPTriggerSet) updateTriggerStatusFailed(ht *fv1.HTTPTrigger, err error) { // TODO } diff --git a/pkg/router/mutablemux_test.go b/pkg/router/mutablemux_test.go index 9dd99d22..51d20793 100644 --- a/pkg/router/mutablemux_test.go +++ b/pkg/router/mutablemux_test.go @@ -70,7 +70,7 @@ func TestMutableMux(t *testing.T) { // make a simple mutable router log.Print("Create mutable router") muxRouter := mux.NewRouter() - muxRouter.Use(metrics.HTTPMetricMiddleware()) + muxRouter.Use(metrics.HTTPMetricMiddleware) muxRouter.HandleFunc("/", OldHandler) config := zap.NewDevelopmentConfig() config.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder @@ -97,7 +97,7 @@ func TestMutableMux(t *testing.T) { // change the muxer log.Print("Change mux router") newMuxRouter := mux.NewRouter() - newMuxRouter.Use(metrics.HTTPMetricMiddleware()) + newMuxRouter.Use(metrics.HTTPMetricMiddleware) newMuxRouter.HandleFunc("/", NewHandler) mr.updateRouter(newMuxRouter) diff --git a/pkg/router/router.go b/pkg/router/router.go index 8a7f34de..85b9c640 100644 --- a/pkg/router/router.go +++ b/pkg/router/router.go @@ -70,7 +70,7 @@ import ( func router(ctx context.Context, logger *zap.Logger, httpTriggerSet *HTTPTriggerSet) *mutableRouter { var mr *mutableRouter mux := mux.NewRouter() - mux.Use(metrics.HTTPMetricMiddleware()) + mux.Use(metrics.HTTPMetricMiddleware) // see issue https://github.com/fission/fission/issues/1317 useEncodedPath, _ := strconv.ParseBool(os.Getenv("USE_ENCODED_PATH")) diff --git a/pkg/storagesvc/storagesvc.go b/pkg/storagesvc/storagesvc.go index a5105da5..8c2f6d65 100644 --- a/pkg/storagesvc/storagesvc.go +++ b/pkg/storagesvc/storagesvc.go @@ -217,7 +217,7 @@ func MakeStorageService(logger *zap.Logger, storageClient *StowClient, port int) func (ss *StorageService) Start(ctx context.Context, port int, openTracingEnabled bool) { r := mux.NewRouter() - r.Use(metrics.HTTPMetricMiddleware()) + r.Use(metrics.HTTPMetricMiddleware) r.HandleFunc("/v1/archive", ss.uploadHandler).Methods("POST") r.HandleFunc("/v1/archive", ss.downloadHandler).Methods("GET") r.HandleFunc("/v1/archive", ss.deleteHandler).Methods("DELETE") diff --git a/pkg/utils/metrics/http_metrics.go b/pkg/utils/metrics/http_metrics.go index 4775ef5e..1a85a3d3 100644 --- a/pkg/utils/metrics/http_metrics.go +++ b/pkg/utils/metrics/http_metrics.go @@ -62,31 +62,29 @@ func (rw *ResponseWriterWrapper) WriteHeader(statuscode int) { rw.ResponseWriter.WriteHeader(statuscode) } -func HTTPMetricMiddleware() mux.MiddlewareFunc { - return func(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if util.IsWebsocketRequest(r) { - next.ServeHTTP(w, r) - return +func HTTPMetricMiddleware(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if util.IsWebsocketRequest(r) { + next.ServeHTTP(w, r) + return + } + labels := make(prometheus.Labels, 0) + labels["path"] = r.URL.Path + if route := mux.CurrentRoute(r); route != nil { + if routePath, err := route.GetPathTemplate(); err == nil { + labels["path"] = routePath } - labels := make(prometheus.Labels, 0) - labels["path"] = r.URL.Path - if route := mux.CurrentRoute(r); route != nil { - if routePath, err := route.GetPathTemplate(); err == nil { - labels["path"] = routePath - } - } - labels["method"] = r.Method - rw := ResponseWriterWrapper{w, http.StatusOK} - httpRequestInFlight.With(labels).Inc() - httpRequestDuration := prometheus.NewTimer(httpRequestDuration.With(labels)) - defer func() { - httpRequestDuration.ObserveDuration() - httpRequestInFlight.With(labels).Dec() - labels["code"] = fmt.Sprintf("%d", rw.statusCode) - httpRequestsTotal.With(labels).Inc() - }() - next.ServeHTTP(&rw, r) - }) - } + } + labels["method"] = r.Method + rw := ResponseWriterWrapper{w, http.StatusOK} + httpRequestInFlight.With(labels).Inc() + httpRequestDuration := prometheus.NewTimer(httpRequestDuration.With(labels)) + defer func() { + httpRequestDuration.ObserveDuration() + httpRequestInFlight.With(labels).Dec() + labels["code"] = fmt.Sprintf("%d", rw.statusCode) + httpRequestsTotal.With(labels).Inc() + }() + next.ServeHTTP(&rw, r) + }) } diff --git a/test/tests/test_environments/test_go_env.sh b/test/tests/test_environments/test_go_env.sh index 8fff7bde..edbab6ae 100755 --- a/test/tests/test_environments/test_go_env.sh +++ b/test/tests/test_environments/test_go_env.sh @@ -27,7 +27,7 @@ env=go-$TEST_ID fn_poolmgr=hello-go-poolmgr-$TEST_ID fn_nd=hello-go-nd-$TEST_ID -cd $ROOT/examples/go +cd $ROOT/examples/go/hello-world log "Creating environment for Golang" fission env create --name $env --image $GO_RUNTIME_IMAGE --builder $GO_BUILDER_IMAGE --period 5 @@ -58,7 +58,7 @@ log "Testing new deployment function" timeout 60 bash -c "test_fn $fn_nd 'Hello'" # Create zip file without top level directory (module-example) -cd module-example && zip -r $tmp_dir/module.zip * +cd ../module-example && zip -r $tmp_dir/module.zip * pkgName=$(generate_test_id) fission package create --name $pkgName --src $tmp_dir/module.zip --env $env diff --git a/test/tests/test_environments/test_java_builder.sh b/test/tests/test_environments/test_java_builder.sh index aa1cc841..af40e3a0 100755 --- a/test/tests/test_environments/test_java_builder.sh +++ b/test/tests/test_environments/test_java_builder.sh @@ -27,7 +27,7 @@ else log "TEST_NOCLEANUP is set; not cleaning up test artifacts afterwards." fi -cd $ROOT/examples/jvm/java +cd $ROOT/examples/java/hello-world log "Creating zip from source code" zip -r $tmp_dir/java-src-pkg.zip * diff --git a/test/tests/test_environments/test_tensorflow_serving_env.sh b/test/tests/test_environments/test_tensorflow_serving_env.sh index cc392663..57d0051f 100755 --- a/test/tests/test_environments/test_tensorflow_serving_env.sh +++ b/test/tests/test_environments/test_tensorflow_serving_env.sh @@ -27,7 +27,7 @@ env=ts-$TEST_ID fn_poolmgr=hello-ts-poolmgr-$TEST_ID fn_nd=hello-ts-nd-$TEST_ID -cd $ROOT/examples/tensorflow-serving +cd $ROOT/examples/miscellaneous/tensorflow-serving log "Creating environment for Tensorflow Serving" fission env create --name $env --image $TS_RUNTIME_IMAGE --version 2 --period 5