diff --git a/cmd/routing-api/main.go b/cmd/routing-api/main.go index cbb44a2..dd686c0 100644 --- a/cmd/routing-api/main.go +++ b/cmd/routing-api/main.go @@ -323,6 +323,7 @@ func apiHandler(cfg config.Config, uaaClient uaaclient.TokenValidator, database tcpMappingsHandler := handlers.NewTcpRouteMappingsHandler(uaaClient, validator, database, int(cfg.MaxTTL.Seconds()), logger) actions := rata.Handlers{ + routing_api.CheckHealth: route(routesHandler.Health), routing_api.UpsertRoute: route(routesHandler.Upsert), routing_api.DeleteRoute: route(routesHandler.Delete), routing_api.ListRoute: route(routesHandler.List), diff --git a/db/db_sql.go b/db/db_sql.go index 39027b1..10ad06d 100644 --- a/db/db_sql.go +++ b/db/db_sql.go @@ -23,6 +23,7 @@ import ( //go:generate counterfeiter -o fakes/fake_db.go . DB type DB interface { + CheckHealth() error ReadRoutes() ([]models.Route, error) SaveRoute(route models.Route) error DeleteRoute(route models.Route) error @@ -361,6 +362,15 @@ func notImplementedError() error { return fmt.Errorf("function not implemented: %s", fnName) } +func (s *SqlDB) CheckHealth() error { + var routes []models.Route + err := s.Client.First(&routes) + if err != nil { + return fmt.Errorf("checking health error: %v", err) + } + return nil +} + func (s *SqlDB) ReadRoutes() ([]models.Route, error) { var routes []models.Route now := time.Now() diff --git a/handlers/middleware.go b/handlers/middleware.go index 72d95fb..4215a7d 100644 --- a/handlers/middleware.go +++ b/handlers/middleware.go @@ -12,8 +12,9 @@ func LogWrap(handler http.Handler, logger lager.Logger) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { requestLog := logger.Session("request", lager.Data{ - "method": r.Method, - "request": r.URL.String(), + "remoteAddr": r.RemoteAddr, + "method": r.Method, + "request": r.URL.String(), }) requestLog.Info("serving", lager.Data{"request-headers": filter(r.Header)}) diff --git a/handlers/routes_handler.go b/handlers/routes_handler.go index 5a3e8bf..8be2183 100644 --- a/handlers/routes_handler.go +++ b/handlers/routes_handler.go @@ -2,6 +2,7 @@ package handlers import ( "encoding/json" + "fmt" "net/http" "code.cloudfoundry.org/lager/v3" @@ -28,11 +29,29 @@ func NewRoutesHandler(uaaClient uaaclient.TokenValidator, maxTTL int, validator } } +func (h *RoutesHandler) Health(w http.ResponseWriter, req *http.Request) { + log := h.logger.Session("health-check") + + err := h.db.CheckHealth() + if err != nil { + handleDBCommunicationError(w, err, log) + return + } + w.WriteHeader(http.StatusOK) +} + func (h *RoutesHandler) List(w http.ResponseWriter, req *http.Request) { log := h.logger.Session("list-routes") - err := h.uaaClient.ValidateToken(req.Header.Get("Authorization"), RoutingRoutesReadScope) + authHeader := req.Header.Get("Authorization") + if authHeader == "" { + err := fmt.Errorf("authorization header can't be empty (remoteAddr: %s)", req.RemoteAddr) + handleUnauthorizedError(w, err, log) + return + } + err := h.uaaClient.ValidateToken(authHeader, RoutingRoutesReadScope) if err != nil { + err := fmt.Errorf("%v (remoteAddr: %s)", err, req.RemoteAddr) handleUnauthorizedError(w, err, log) return } diff --git a/routes.go b/routes.go index 71fffc3..cc0e51b 100644 --- a/routes.go +++ b/routes.go @@ -3,6 +3,7 @@ package routing_api import "github.com/tedsuo/rata" const ( + CheckHealth = "Health" UpsertRoute = "UpsertRoute" DeleteRoute = "Delete" ListRoute = "List" @@ -17,7 +18,9 @@ const ( EventStreamTcpRoute = "TcpRouteEventStream" ) -var RoutesMap = map[string]rata.Route{UpsertRoute: {Path: "/routing/v1/routes", Method: "POST", Name: UpsertRoute}, +var RoutesMap = map[string]rata.Route{ + CheckHealth: {Path: "/routing/v1/health", Method: "GET", Name: CheckHealth}, + UpsertRoute: {Path: "/routing/v1/routes", Method: "POST", Name: UpsertRoute}, DeleteRoute: {Path: "/routing/v1/routes", Method: "DELETE", Name: DeleteRoute}, ListRoute: {Path: "/routing/v1/routes", Method: "GET", Name: ListRoute}, EventStreamRoute: {Path: "/routing/v1/events", Method: "GET", Name: EventStreamRoute},