diff --git a/cli/serve.go b/cli/serve.go index da90a855bb..6fef981c0d 100644 --- a/cli/serve.go +++ b/cli/serve.go @@ -22,6 +22,7 @@ import ( "github.com/kolide/kolide-ose/server/service" "github.com/kolide/kolide-ose/server/version" "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/spf13/cobra" "golang.org/x/net/context" ) @@ -143,16 +144,18 @@ the way that the kolide server works. } } + // a list of dependencies which could affect the status of the app if unavailable healthCheckers := map[string]interface{}{ "datastore": ds, "query_result_store": resultStore, } + + http.Handle("/healthz", prometheus.InstrumentHandler("healthz", healthz(healthCheckers))) + http.Handle("/version", prometheus.InstrumentHandler("version", version.Handler())) + http.Handle("/assets/", prometheus.InstrumentHandler("static_assets", service.ServeStaticAssets("/assets/"))) + http.Handle("/metrics", prometheus.InstrumentHandler("metrics", promhttp.Handler())) http.Handle("/api/", apiHandler) - http.Handle("/healthz", healthz(healthCheckers)) - http.Handle("/version", version.Handler()) - http.Handle("/metrics", prometheus.Handler()) - http.Handle("/assets/", service.ServeStaticAssets("/assets/")) - http.Handle("/", service.ServeFrontend()) + http.Handle("/", prometheus.InstrumentHandler("get_frontend", service.ServeFrontend())) errs := make(chan error, 2) go func() { diff --git a/server/service/handler.go b/server/service/handler.go index b14f9b40a8..f783c2781a 100644 --- a/server/service/handler.go +++ b/server/service/handler.go @@ -9,6 +9,7 @@ import ( kithttp "github.com/go-kit/kit/transport/http" "github.com/gorilla/mux" "github.com/kolide/kolide-ose/server/kolide" + "github.com/prometheus/client_golang/prometheus" "golang.org/x/net/context" ) @@ -137,65 +138,65 @@ func MakeKolideServerEndpoints(svc kolide.Service, jwtKey string) KolideEndpoint } type kolideHandlers struct { - Login *kithttp.Server - Logout *kithttp.Server - ForgotPassword *kithttp.Server - ResetPassword *kithttp.Server - Me *kithttp.Server - ChangePassword *kithttp.Server - CreateUser *kithttp.Server - GetUser *kithttp.Server - ListUsers *kithttp.Server - ModifyUser *kithttp.Server - GetSessionsForUserInfo *kithttp.Server - DeleteSessionsForUser *kithttp.Server - GetSessionInfo *kithttp.Server - DeleteSession *kithttp.Server - GetAppConfig *kithttp.Server - ModifyAppConfig *kithttp.Server - CreateInvite *kithttp.Server - ListInvites *kithttp.Server - DeleteInvite *kithttp.Server - GetQuery *kithttp.Server - ListQueries *kithttp.Server - CreateQuery *kithttp.Server - ModifyQuery *kithttp.Server - DeleteQuery *kithttp.Server - DeleteQueries *kithttp.Server - CreateDistributedQueryCampaign *kithttp.Server - GetPack *kithttp.Server - ListPacks *kithttp.Server - CreatePack *kithttp.Server - ModifyPack *kithttp.Server - DeletePack *kithttp.Server - ScheduleQuery *kithttp.Server - GetScheduledQueriesInPack *kithttp.Server - GetScheduledQuery *kithttp.Server - ModifyScheduledQuery *kithttp.Server - DeleteScheduledQuery *kithttp.Server - EnrollAgent *kithttp.Server - GetClientConfig *kithttp.Server - GetDistributedQueries *kithttp.Server - SubmitDistributedQueryResults *kithttp.Server - SubmitLogs *kithttp.Server - GetLabel *kithttp.Server - ListLabels *kithttp.Server - CreateLabel *kithttp.Server - DeleteLabel *kithttp.Server - AddLabelToPack *kithttp.Server - GetLabelsForPack *kithttp.Server - DeleteLabelFromPack *kithttp.Server - GetHost *kithttp.Server - DeleteHost *kithttp.Server - ListHosts *kithttp.Server - SearchTargets *kithttp.Server + Login http.Handler + Logout http.Handler + ForgotPassword http.Handler + ResetPassword http.Handler + Me http.Handler + ChangePassword http.Handler + CreateUser http.Handler + GetUser http.Handler + ListUsers http.Handler + ModifyUser http.Handler + GetSessionsForUserInfo http.Handler + DeleteSessionsForUser http.Handler + GetSessionInfo http.Handler + DeleteSession http.Handler + GetAppConfig http.Handler + ModifyAppConfig http.Handler + CreateInvite http.Handler + ListInvites http.Handler + DeleteInvite http.Handler + GetQuery http.Handler + ListQueries http.Handler + CreateQuery http.Handler + ModifyQuery http.Handler + DeleteQuery http.Handler + DeleteQueries http.Handler + CreateDistributedQueryCampaign http.Handler + GetPack http.Handler + ListPacks http.Handler + CreatePack http.Handler + ModifyPack http.Handler + DeletePack http.Handler + ScheduleQuery http.Handler + GetScheduledQueriesInPack http.Handler + GetScheduledQuery http.Handler + ModifyScheduledQuery http.Handler + DeleteScheduledQuery http.Handler + EnrollAgent http.Handler + GetClientConfig http.Handler + GetDistributedQueries http.Handler + SubmitDistributedQueryResults http.Handler + SubmitLogs http.Handler + GetLabel http.Handler + ListLabels http.Handler + CreateLabel http.Handler + DeleteLabel http.Handler + AddLabelToPack http.Handler + GetLabelsForPack http.Handler + DeleteLabelFromPack http.Handler + GetHost http.Handler + DeleteHost http.Handler + ListHosts http.Handler + SearchTargets http.Handler } -func makeKolideKitHandlers(ctx context.Context, e KolideEndpoints, opts []kithttp.ServerOption) kolideHandlers { - newServer := func(e endpoint.Endpoint, decodeFn kithttp.DecodeRequestFunc) *kithttp.Server { +func makeKolideKitHandlers(ctx context.Context, e KolideEndpoints, opts []kithttp.ServerOption) *kolideHandlers { + newServer := func(e endpoint.Endpoint, decodeFn kithttp.DecodeRequestFunc) http.Handler { return kithttp.NewServer(ctx, e, decodeFn, encodeResponse, opts...) } - return kolideHandlers{ + return &kolideHandlers{ Login: newServer(e.Login, decodeLoginRequest), Logout: newServer(e.Logout, decodeNoParamsRequest), ForgotPassword: newServer(e.ForgotPassword, decodeForgotPasswordRequest), @@ -271,72 +272,84 @@ func MakeHandler(ctx context.Context, svc kolide.Service, jwtKey string, logger attachKolideAPIRoutes(r, kolideHandlers) r.HandleFunc("/api/v1/kolide/results/{id}", makeStreamDistributedQueryCampaignResultsHandler(svc, jwtKey)). - Methods("GET") + Methods("GET").Name("distributed_query_results") + + addMetrics(r) return r } -func attachKolideAPIRoutes(r *mux.Router, h kolideHandlers) { - r.Handle("/api/v1/kolide/login", h.Login).Methods("POST") - r.Handle("/api/v1/kolide/logout", h.Logout).Methods("POST") - r.Handle("/api/v1/kolide/forgot_password", h.ForgotPassword).Methods("POST") - r.Handle("/api/v1/kolide/reset_password", h.ResetPassword).Methods("POST") - r.Handle("/api/v1/kolide/me", h.Me).Methods("GET") - r.Handle("/api/v1/kolide/change_password", h.ChangePassword).Methods("POST") +// addMetrics decorates each hander with prometheus instrumentation +func addMetrics(r *mux.Router) { + walkFn := func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error { + route.Handler(prometheus.InstrumentHandler(route.GetName(), route.GetHandler())) + return nil + } + r.Walk(walkFn) - r.Handle("/api/v1/kolide/users", h.ListUsers).Methods("GET") - r.Handle("/api/v1/kolide/users", h.CreateUser).Methods("POST") - r.Handle("/api/v1/kolide/users/{id}", h.GetUser).Methods("GET") - r.Handle("/api/v1/kolide/users/{id}", h.ModifyUser).Methods("PATCH") - r.Handle("/api/v1/kolide/users/{id}/sessions", h.GetSessionsForUserInfo).Methods("GET") - r.Handle("/api/v1/kolide/users/{id}/sessions", h.DeleteSessionsForUser).Methods("DELETE") +} - r.Handle("/api/v1/kolide/sessions/{id}", h.GetSessionInfo).Methods("GET") - r.Handle("/api/v1/kolide/sessions/{id}", h.DeleteSession).Methods("DELETE") +func attachKolideAPIRoutes(r *mux.Router, h *kolideHandlers) { + r.Handle("/api/v1/kolide/login", h.Login).Methods("POST").Name("login") + r.Handle("/api/v1/kolide/logout", h.Logout).Methods("POST").Name("logout") + r.Handle("/api/v1/kolide/forgot_password", h.ForgotPassword).Methods("POST").Name("forgot_password") + r.Handle("/api/v1/kolide/reset_password", h.ResetPassword).Methods("POST").Name("reset_password") + r.Handle("/api/v1/kolide/me", h.Me).Methods("GET").Name("me") + r.Handle("/api/v1/kolide/change_password", h.ChangePassword).Methods("POST").Name("change_password") - r.Handle("/api/v1/kolide/config", h.GetAppConfig).Methods("GET") - r.Handle("/api/v1/kolide/config", h.ModifyAppConfig).Methods("PATCH") - r.Handle("/api/v1/kolide/invites", h.CreateInvite).Methods("POST") - r.Handle("/api/v1/kolide/invites", h.ListInvites).Methods("GET") - r.Handle("/api/v1/kolide/invites/{id}", h.DeleteInvite).Methods("DELETE") + r.Handle("/api/v1/kolide/users", h.ListUsers).Methods("GET").Name("list_users") + r.Handle("/api/v1/kolide/users", h.CreateUser).Methods("POST").Name("create_user") + r.Handle("/api/v1/kolide/users/{id}", h.GetUser).Methods("GET").Name("get_user") + r.Handle("/api/v1/kolide/users/{id}", h.ModifyUser).Methods("PATCH").Name("modify_user") + r.Handle("/api/v1/kolide/users/{id}/sessions", h.GetSessionsForUserInfo).Methods("GET").Name("get_session_for_user") + r.Handle("/api/v1/kolide/users/{id}/sessions", h.DeleteSessionsForUser).Methods("DELETE").Name("delete_session_for_user") - r.Handle("/api/v1/kolide/queries/{id}", h.GetQuery).Methods("GET") - r.Handle("/api/v1/kolide/queries", h.ListQueries).Methods("GET") - r.Handle("/api/v1/kolide/queries", h.CreateQuery).Methods("POST") - r.Handle("/api/v1/kolide/queries/{id}", h.ModifyQuery).Methods("PATCH") - r.Handle("/api/v1/kolide/queries/{id}", h.DeleteQuery).Methods("DELETE") - r.Handle("/api/v1/kolide/queries/delete", h.DeleteQueries).Methods("POST") - r.Handle("/api/v1/kolide/queries/run", h.CreateDistributedQueryCampaign).Methods("POST") + r.Handle("/api/v1/kolide/sessions/{id}", h.GetSessionInfo).Methods("GET").Name("get_session_info") + r.Handle("/api/v1/kolide/sessions/{id}", h.DeleteSession).Methods("DELETE").Name("delete_session") - r.Handle("/api/v1/kolide/packs/{id}", h.GetPack).Methods("GET") - r.Handle("/api/v1/kolide/packs", h.ListPacks).Methods("GET") - r.Handle("/api/v1/kolide/packs", h.CreatePack).Methods("POST") - r.Handle("/api/v1/kolide/packs/{id}", h.ModifyPack).Methods("PATCH") - r.Handle("/api/v1/kolide/packs/{id}", h.DeletePack).Methods("DELETE") - r.Handle("/api/v1/kolide/packs/{id}/scheduled", h.GetScheduledQueriesInPack).Methods("GET") - r.Handle("/api/v1/kolide/schedule", h.ScheduleQuery).Methods("POST") - r.Handle("/api/v1/kolide/schedule/{id}", h.GetScheduledQuery).Methods("GET") - r.Handle("/api/v1/kolide/schedule/{id}", h.ModifyScheduledQuery).Methods("PATCH") - r.Handle("/api/v1/kolide/schedule/{id}", h.DeleteScheduledQuery).Methods("DELETE") - r.Handle("/api/v1/kolide/labels/{id}", h.GetLabel).Methods("GET") - r.Handle("/api/v1/kolide/labels", h.ListLabels).Methods("GET") - r.Handle("/api/v1/kolide/labels", h.CreateLabel).Methods("POST") - r.Handle("/api/v1/kolide/labels/{id}", h.DeleteLabel).Methods("DELETE") - r.Handle("/api/v1/kolide/packs/{pid}/labels/{lid}", h.AddLabelToPack).Methods("POST") - r.Handle("/api/v1/kolide/packs/{pid}/labels", h.GetLabelsForPack).Methods("GET") - r.Handle("/api/v1/kolide/packs/{pid}/labels/{lid}", h.DeleteLabelFromPack).Methods("DELETE") + r.Handle("/api/v1/kolide/config", h.GetAppConfig).Methods("GET").Name("get_app_config") + r.Handle("/api/v1/kolide/config", h.ModifyAppConfig).Methods("PATCH").Name("modify_app_config") + r.Handle("/api/v1/kolide/invites", h.CreateInvite).Methods("POST").Name("create_invite") + r.Handle("/api/v1/kolide/invites", h.ListInvites).Methods("GET").Name("list_invites") + r.Handle("/api/v1/kolide/invites/{id}", h.DeleteInvite).Methods("DELETE").Name("delete_invite") - r.Handle("/api/v1/kolide/hosts", h.ListHosts).Methods("GET") - r.Handle("/api/v1/kolide/hosts/{id}", h.GetHost).Methods("GET") - r.Handle("/api/v1/kolide/hosts/{id}", h.DeleteHost).Methods("DELETE") + r.Handle("/api/v1/kolide/queries/{id}", h.GetQuery).Methods("GET").Name("get_query") + r.Handle("/api/v1/kolide/queries", h.ListQueries).Methods("GET").Name("list_queries") + r.Handle("/api/v1/kolide/queries", h.CreateQuery).Methods("POST").Name("create_query") + r.Handle("/api/v1/kolide/queries/{id}", h.ModifyQuery).Methods("PATCH").Name("modify_query") + r.Handle("/api/v1/kolide/queries/{id}", h.DeleteQuery).Methods("DELETE").Name("delete_query") + r.Handle("/api/v1/kolide/queries/delete", h.DeleteQueries).Methods("POST").Name("delete_queries") + r.Handle("/api/v1/kolide/queries/run", h.CreateDistributedQueryCampaign).Methods("POST").Name("create_distributed_query_campaign") - r.Handle("/api/v1/kolide/targets", h.SearchTargets).Methods("POST") + r.Handle("/api/v1/kolide/packs/{id}", h.GetPack).Methods("GET").Name("get_pack") + r.Handle("/api/v1/kolide/packs", h.ListPacks).Methods("GET").Name("list_packs") + r.Handle("/api/v1/kolide/packs", h.CreatePack).Methods("POST").Name("create_pack") + r.Handle("/api/v1/kolide/packs/{id}", h.ModifyPack).Methods("PATCH").Name("modify_pack") + r.Handle("/api/v1/kolide/packs/{id}", h.DeletePack).Methods("DELETE").Name("delete_pack") + r.Handle("/api/v1/kolide/packs/{id}/scheduled", h.GetScheduledQueriesInPack).Methods("GET").Name("get_scheduled_queries_in_pack") + r.Handle("/api/v1/kolide/schedule", h.ScheduleQuery).Methods("POST").Name("schedule_query") + r.Handle("/api/v1/kolide/schedule/{id}", h.GetScheduledQuery).Methods("GET").Name("get_scheduled_query") + r.Handle("/api/v1/kolide/schedule/{id}", h.ModifyScheduledQuery).Methods("PATCH").Name("modify_scheduled_query") + r.Handle("/api/v1/kolide/schedule/{id}", h.DeleteScheduledQuery).Methods("DELETE").Name("delete_scheduled_query") + r.Handle("/api/v1/kolide/labels/{id}", h.GetLabel).Methods("GET").Name("get_label") + r.Handle("/api/v1/kolide/labels", h.ListLabels).Methods("GET").Name("list_labels") + r.Handle("/api/v1/kolide/labels", h.CreateLabel).Methods("POST").Name("create_label") + r.Handle("/api/v1/kolide/labels/{id}", h.DeleteLabel).Methods("DELETE").Name("delete_label") + r.Handle("/api/v1/kolide/packs/{pid}/labels/{lid}", h.AddLabelToPack).Methods("POST").Name("add_label_to_pack") + r.Handle("/api/v1/kolide/packs/{pid}/labels", h.GetLabelsForPack).Methods("GET").Name("get_labels_for_pack") + r.Handle("/api/v1/kolide/packs/{pid}/labels/{lid}", h.DeleteLabelFromPack).Methods("DELETE").Name("delete_label_from_pack") - r.Handle("/api/v1/osquery/enroll", h.EnrollAgent).Methods("POST") - r.Handle("/api/v1/osquery/config", h.GetClientConfig).Methods("POST") - r.Handle("/api/v1/osquery/distributed/read", h.GetDistributedQueries).Methods("POST") - r.Handle("/api/v1/osquery/distributed/write", h.SubmitDistributedQueryResults).Methods("POST") - r.Handle("/api/v1/osquery/log", h.SubmitLogs).Methods("POST") + r.Handle("/api/v1/kolide/hosts", h.ListHosts).Methods("GET").Name("list_hosts") + r.Handle("/api/v1/kolide/hosts/{id}", h.GetHost).Methods("GET").Name("get_host") + r.Handle("/api/v1/kolide/hosts/{id}", h.DeleteHost).Methods("DELETE").Name("delete_host") + + r.Handle("/api/v1/kolide/targets", h.SearchTargets).Methods("POST").Name("search_targets") + + r.Handle("/api/v1/osquery/enroll", h.EnrollAgent).Methods("POST").Name("enroll_agent") + r.Handle("/api/v1/osquery/config", h.GetClientConfig).Methods("POST").Name("get_client_config") + r.Handle("/api/v1/osquery/distributed/read", h.GetDistributedQueries).Methods("POST").Name("get_distributed_queries") + r.Handle("/api/v1/osquery/distributed/write", h.SubmitDistributedQueryResults).Methods("POST").Name("submit_distributed_query_results") + r.Handle("/api/v1/osquery/log", h.SubmitLogs).Methods("POST").Name("submit_logs") } // WithSetup is an http middleware that checks if a database user exists.