Alerting: Allow hooking into request handler functions. (#67000)

* Alerting: Allow hooking into request handler functions.

Adds a facility to AlertNG for hooking into API handlers, allowing the
replacement of request handlers for specific paths. One of goals of this
approach was to allow hooking as late as possible in the request, e.g.
after all middleware has been applied, to simplfiy usage.

* Update pkg/services/ngalert/api/hooks.go

Co-authored-by: gotjosh <josue.abreu@gmail.com>

* Update pkg/services/ngalert/api/hooks.go

Co-authored-by: gotjosh <josue.abreu@gmail.com>

* Update pkg/services/ngalert/ngalert.go

Co-authored-by: gotjosh <josue.abreu@gmail.com>

* Fixes to review comments

* Fix passing logger in

---------

Co-authored-by: gotjosh <josue.abreu@gmail.com>
This commit is contained in:
Steve Simpson 2023-04-24 18:18:44 +02:00 committed by GitHub
parent 68a277b53b
commit 9effb9a708
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 135 additions and 81 deletions

View File

@ -85,6 +85,9 @@ type API struct {
Historian Historian
AppUrl *url.URL
// Hooks can be used to replace API handlers for specific paths.
Hooks *Hooks
}
// RegisterAPIEndpoints registers API handlers

View File

@ -190,7 +190,7 @@ func (api *API) RegisterAlertmanagerApiEndpoints(srv AlertmanagerApi, m *metrics
metrics.Instrument(
http.MethodPost,
"/api/alertmanager/grafana/api/v2/silences",
srv.RouteCreateGrafanaSilence,
api.Hooks.Wrap(srv.RouteCreateGrafanaSilence),
m,
),
)
@ -200,7 +200,7 @@ func (api *API) RegisterAlertmanagerApiEndpoints(srv AlertmanagerApi, m *metrics
metrics.Instrument(
http.MethodPost,
"/api/alertmanager/{DatasourceUID}/api/v2/silences",
srv.RouteCreateSilence,
api.Hooks.Wrap(srv.RouteCreateSilence),
m,
),
)
@ -210,7 +210,7 @@ func (api *API) RegisterAlertmanagerApiEndpoints(srv AlertmanagerApi, m *metrics
metrics.Instrument(
http.MethodDelete,
"/api/alertmanager/{DatasourceUID}/config/api/v1/alerts",
srv.RouteDeleteAlertingConfig,
api.Hooks.Wrap(srv.RouteDeleteAlertingConfig),
m,
),
)
@ -220,7 +220,7 @@ func (api *API) RegisterAlertmanagerApiEndpoints(srv AlertmanagerApi, m *metrics
metrics.Instrument(
http.MethodDelete,
"/api/alertmanager/grafana/config/api/v1/alerts",
srv.RouteDeleteGrafanaAlertingConfig,
api.Hooks.Wrap(srv.RouteDeleteGrafanaAlertingConfig),
m,
),
)
@ -230,7 +230,7 @@ func (api *API) RegisterAlertmanagerApiEndpoints(srv AlertmanagerApi, m *metrics
metrics.Instrument(
http.MethodDelete,
"/api/alertmanager/grafana/api/v2/silence/{SilenceId}",
srv.RouteDeleteGrafanaSilence,
api.Hooks.Wrap(srv.RouteDeleteGrafanaSilence),
m,
),
)
@ -240,7 +240,7 @@ func (api *API) RegisterAlertmanagerApiEndpoints(srv AlertmanagerApi, m *metrics
metrics.Instrument(
http.MethodDelete,
"/api/alertmanager/{DatasourceUID}/api/v2/silence/{SilenceId}",
srv.RouteDeleteSilence,
api.Hooks.Wrap(srv.RouteDeleteSilence),
m,
),
)
@ -250,7 +250,7 @@ func (api *API) RegisterAlertmanagerApiEndpoints(srv AlertmanagerApi, m *metrics
metrics.Instrument(
http.MethodGet,
"/api/alertmanager/{DatasourceUID}/api/v2/alerts/groups",
srv.RouteGetAMAlertGroups,
api.Hooks.Wrap(srv.RouteGetAMAlertGroups),
m,
),
)
@ -260,7 +260,7 @@ func (api *API) RegisterAlertmanagerApiEndpoints(srv AlertmanagerApi, m *metrics
metrics.Instrument(
http.MethodGet,
"/api/alertmanager/{DatasourceUID}/api/v2/alerts",
srv.RouteGetAMAlerts,
api.Hooks.Wrap(srv.RouteGetAMAlerts),
m,
),
)
@ -270,7 +270,7 @@ func (api *API) RegisterAlertmanagerApiEndpoints(srv AlertmanagerApi, m *metrics
metrics.Instrument(
http.MethodGet,
"/api/alertmanager/{DatasourceUID}/api/v2/status",
srv.RouteGetAMStatus,
api.Hooks.Wrap(srv.RouteGetAMStatus),
m,
),
)
@ -280,7 +280,7 @@ func (api *API) RegisterAlertmanagerApiEndpoints(srv AlertmanagerApi, m *metrics
metrics.Instrument(
http.MethodGet,
"/api/alertmanager/{DatasourceUID}/config/api/v1/alerts",
srv.RouteGetAlertingConfig,
api.Hooks.Wrap(srv.RouteGetAlertingConfig),
m,
),
)
@ -290,7 +290,7 @@ func (api *API) RegisterAlertmanagerApiEndpoints(srv AlertmanagerApi, m *metrics
metrics.Instrument(
http.MethodGet,
"/api/alertmanager/grafana/api/v2/alerts/groups",
srv.RouteGetGrafanaAMAlertGroups,
api.Hooks.Wrap(srv.RouteGetGrafanaAMAlertGroups),
m,
),
)
@ -300,7 +300,7 @@ func (api *API) RegisterAlertmanagerApiEndpoints(srv AlertmanagerApi, m *metrics
metrics.Instrument(
http.MethodGet,
"/api/alertmanager/grafana/api/v2/alerts",
srv.RouteGetGrafanaAMAlerts,
api.Hooks.Wrap(srv.RouteGetGrafanaAMAlerts),
m,
),
)
@ -310,7 +310,7 @@ func (api *API) RegisterAlertmanagerApiEndpoints(srv AlertmanagerApi, m *metrics
metrics.Instrument(
http.MethodGet,
"/api/alertmanager/grafana/api/v2/status",
srv.RouteGetGrafanaAMStatus,
api.Hooks.Wrap(srv.RouteGetGrafanaAMStatus),
m,
),
)
@ -320,7 +320,7 @@ func (api *API) RegisterAlertmanagerApiEndpoints(srv AlertmanagerApi, m *metrics
metrics.Instrument(
http.MethodGet,
"/api/alertmanager/grafana/config/api/v1/alerts",
srv.RouteGetGrafanaAlertingConfig,
api.Hooks.Wrap(srv.RouteGetGrafanaAlertingConfig),
m,
),
)
@ -330,7 +330,7 @@ func (api *API) RegisterAlertmanagerApiEndpoints(srv AlertmanagerApi, m *metrics
metrics.Instrument(
http.MethodGet,
"/api/alertmanager/grafana/config/history",
srv.RouteGetGrafanaAlertingConfigHistory,
api.Hooks.Wrap(srv.RouteGetGrafanaAlertingConfigHistory),
m,
),
)
@ -340,7 +340,7 @@ func (api *API) RegisterAlertmanagerApiEndpoints(srv AlertmanagerApi, m *metrics
metrics.Instrument(
http.MethodGet,
"/api/alertmanager/grafana/config/api/v1/receivers",
srv.RouteGetGrafanaReceivers,
api.Hooks.Wrap(srv.RouteGetGrafanaReceivers),
m,
),
)
@ -350,7 +350,7 @@ func (api *API) RegisterAlertmanagerApiEndpoints(srv AlertmanagerApi, m *metrics
metrics.Instrument(
http.MethodGet,
"/api/alertmanager/grafana/api/v2/silence/{SilenceId}",
srv.RouteGetGrafanaSilence,
api.Hooks.Wrap(srv.RouteGetGrafanaSilence),
m,
),
)
@ -360,7 +360,7 @@ func (api *API) RegisterAlertmanagerApiEndpoints(srv AlertmanagerApi, m *metrics
metrics.Instrument(
http.MethodGet,
"/api/alertmanager/grafana/api/v2/silences",
srv.RouteGetGrafanaSilences,
api.Hooks.Wrap(srv.RouteGetGrafanaSilences),
m,
),
)
@ -370,7 +370,7 @@ func (api *API) RegisterAlertmanagerApiEndpoints(srv AlertmanagerApi, m *metrics
metrics.Instrument(
http.MethodGet,
"/api/alertmanager/{DatasourceUID}/api/v2/silence/{SilenceId}",
srv.RouteGetSilence,
api.Hooks.Wrap(srv.RouteGetSilence),
m,
),
)
@ -380,7 +380,7 @@ func (api *API) RegisterAlertmanagerApiEndpoints(srv AlertmanagerApi, m *metrics
metrics.Instrument(
http.MethodGet,
"/api/alertmanager/{DatasourceUID}/api/v2/silences",
srv.RouteGetSilences,
api.Hooks.Wrap(srv.RouteGetSilences),
m,
),
)
@ -390,7 +390,7 @@ func (api *API) RegisterAlertmanagerApiEndpoints(srv AlertmanagerApi, m *metrics
metrics.Instrument(
http.MethodPost,
"/api/alertmanager/{DatasourceUID}/api/v2/alerts",
srv.RoutePostAMAlerts,
api.Hooks.Wrap(srv.RoutePostAMAlerts),
m,
),
)
@ -400,7 +400,7 @@ func (api *API) RegisterAlertmanagerApiEndpoints(srv AlertmanagerApi, m *metrics
metrics.Instrument(
http.MethodPost,
"/api/alertmanager/{DatasourceUID}/config/api/v1/alerts",
srv.RoutePostAlertingConfig,
api.Hooks.Wrap(srv.RoutePostAlertingConfig),
m,
),
)
@ -410,7 +410,7 @@ func (api *API) RegisterAlertmanagerApiEndpoints(srv AlertmanagerApi, m *metrics
metrics.Instrument(
http.MethodPost,
"/api/alertmanager/grafana/config/api/v1/alerts",
srv.RoutePostGrafanaAlertingConfig,
api.Hooks.Wrap(srv.RoutePostGrafanaAlertingConfig),
m,
),
)
@ -420,7 +420,7 @@ func (api *API) RegisterAlertmanagerApiEndpoints(srv AlertmanagerApi, m *metrics
metrics.Instrument(
http.MethodPost,
"/api/alertmanager/grafana/config/history/{id}/_activate",
srv.RoutePostGrafanaAlertingConfigHistoryActivate,
api.Hooks.Wrap(srv.RoutePostGrafanaAlertingConfigHistoryActivate),
m,
),
)
@ -430,7 +430,7 @@ func (api *API) RegisterAlertmanagerApiEndpoints(srv AlertmanagerApi, m *metrics
metrics.Instrument(
http.MethodPost,
"/api/alertmanager/grafana/config/api/v1/receivers/test",
srv.RoutePostTestGrafanaReceivers,
api.Hooks.Wrap(srv.RoutePostTestGrafanaReceivers),
m,
),
)

View File

@ -55,7 +55,7 @@ func (api *API) RegisterConfigurationApiEndpoints(srv ConfigurationApi, m *metri
metrics.Instrument(
http.MethodDelete,
"/api/v1/ngalert/admin_config",
srv.RouteDeleteNGalertConfig,
api.Hooks.Wrap(srv.RouteDeleteNGalertConfig),
m,
),
)
@ -65,7 +65,7 @@ func (api *API) RegisterConfigurationApiEndpoints(srv ConfigurationApi, m *metri
metrics.Instrument(
http.MethodGet,
"/api/v1/ngalert/alertmanagers",
srv.RouteGetAlertmanagers,
api.Hooks.Wrap(srv.RouteGetAlertmanagers),
m,
),
)
@ -75,7 +75,7 @@ func (api *API) RegisterConfigurationApiEndpoints(srv ConfigurationApi, m *metri
metrics.Instrument(
http.MethodGet,
"/api/v1/ngalert/admin_config",
srv.RouteGetNGalertConfig,
api.Hooks.Wrap(srv.RouteGetNGalertConfig),
m,
),
)
@ -85,7 +85,7 @@ func (api *API) RegisterConfigurationApiEndpoints(srv ConfigurationApi, m *metri
metrics.Instrument(
http.MethodGet,
"/api/v1/ngalert",
srv.RouteGetStatus,
api.Hooks.Wrap(srv.RouteGetStatus),
m,
),
)
@ -95,7 +95,7 @@ func (api *API) RegisterConfigurationApiEndpoints(srv ConfigurationApi, m *metri
metrics.Instrument(
http.MethodPost,
"/api/v1/ngalert/admin_config",
srv.RoutePostNGalertConfig,
api.Hooks.Wrap(srv.RoutePostNGalertConfig),
m,
),
)

View File

@ -32,7 +32,7 @@ func (api *API) RegisterHistoryApiEndpoints(srv HistoryApi, m *metrics.API) {
metrics.Instrument(
http.MethodGet,
"/api/v1/rules/history",
srv.RouteGetStateHistory,
api.Hooks.Wrap(srv.RouteGetStateHistory),
m,
),
)

View File

@ -49,7 +49,7 @@ func (api *API) RegisterPrometheusApiEndpoints(srv PrometheusApi, m *metrics.API
metrics.Instrument(
http.MethodGet,
"/api/prometheus/{DatasourceUID}/api/v1/alerts",
srv.RouteGetAlertStatuses,
api.Hooks.Wrap(srv.RouteGetAlertStatuses),
m,
),
)
@ -59,7 +59,7 @@ func (api *API) RegisterPrometheusApiEndpoints(srv PrometheusApi, m *metrics.API
metrics.Instrument(
http.MethodGet,
"/api/prometheus/grafana/api/v1/alerts",
srv.RouteGetGrafanaAlertStatuses,
api.Hooks.Wrap(srv.RouteGetGrafanaAlertStatuses),
m,
),
)
@ -69,7 +69,7 @@ func (api *API) RegisterPrometheusApiEndpoints(srv PrometheusApi, m *metrics.API
metrics.Instrument(
http.MethodGet,
"/api/prometheus/grafana/api/v1/rules",
srv.RouteGetGrafanaRuleStatuses,
api.Hooks.Wrap(srv.RouteGetGrafanaRuleStatuses),
m,
),
)
@ -79,7 +79,7 @@ func (api *API) RegisterPrometheusApiEndpoints(srv PrometheusApi, m *metrics.API
metrics.Instrument(
http.MethodGet,
"/api/prometheus/{DatasourceUID}/api/v1/rules",
srv.RouteGetRuleStatuses,
api.Hooks.Wrap(srv.RouteGetRuleStatuses),
m,
),
)

View File

@ -212,7 +212,7 @@ func (api *API) RegisterProvisioningApiEndpoints(srv ProvisioningApi, m *metrics
metrics.Instrument(
http.MethodDelete,
"/api/v1/provisioning/alert-rules/{UID}",
srv.RouteDeleteAlertRule,
api.Hooks.Wrap(srv.RouteDeleteAlertRule),
m,
),
)
@ -222,7 +222,7 @@ func (api *API) RegisterProvisioningApiEndpoints(srv ProvisioningApi, m *metrics
metrics.Instrument(
http.MethodDelete,
"/api/v1/provisioning/contact-points/{UID}",
srv.RouteDeleteContactpoints,
api.Hooks.Wrap(srv.RouteDeleteContactpoints),
m,
),
)
@ -232,7 +232,7 @@ func (api *API) RegisterProvisioningApiEndpoints(srv ProvisioningApi, m *metrics
metrics.Instrument(
http.MethodDelete,
"/api/v1/provisioning/mute-timings/{name}",
srv.RouteDeleteMuteTiming,
api.Hooks.Wrap(srv.RouteDeleteMuteTiming),
m,
),
)
@ -242,7 +242,7 @@ func (api *API) RegisterProvisioningApiEndpoints(srv ProvisioningApi, m *metrics
metrics.Instrument(
http.MethodDelete,
"/api/v1/provisioning/templates/{name}",
srv.RouteDeleteTemplate,
api.Hooks.Wrap(srv.RouteDeleteTemplate),
m,
),
)
@ -252,7 +252,7 @@ func (api *API) RegisterProvisioningApiEndpoints(srv ProvisioningApi, m *metrics
metrics.Instrument(
http.MethodGet,
"/api/v1/provisioning/alert-rules/{UID}",
srv.RouteGetAlertRule,
api.Hooks.Wrap(srv.RouteGetAlertRule),
m,
),
)
@ -262,7 +262,7 @@ func (api *API) RegisterProvisioningApiEndpoints(srv ProvisioningApi, m *metrics
metrics.Instrument(
http.MethodGet,
"/api/v1/provisioning/alert-rules/{UID}/export",
srv.RouteGetAlertRuleExport,
api.Hooks.Wrap(srv.RouteGetAlertRuleExport),
m,
),
)
@ -272,7 +272,7 @@ func (api *API) RegisterProvisioningApiEndpoints(srv ProvisioningApi, m *metrics
metrics.Instrument(
http.MethodGet,
"/api/v1/provisioning/folder/{FolderUID}/rule-groups/{Group}",
srv.RouteGetAlertRuleGroup,
api.Hooks.Wrap(srv.RouteGetAlertRuleGroup),
m,
),
)
@ -282,7 +282,7 @@ func (api *API) RegisterProvisioningApiEndpoints(srv ProvisioningApi, m *metrics
metrics.Instrument(
http.MethodGet,
"/api/v1/provisioning/folder/{FolderUID}/rule-groups/{Group}/export",
srv.RouteGetAlertRuleGroupExport,
api.Hooks.Wrap(srv.RouteGetAlertRuleGroupExport),
m,
),
)
@ -292,7 +292,7 @@ func (api *API) RegisterProvisioningApiEndpoints(srv ProvisioningApi, m *metrics
metrics.Instrument(
http.MethodGet,
"/api/v1/provisioning/alert-rules",
srv.RouteGetAlertRules,
api.Hooks.Wrap(srv.RouteGetAlertRules),
m,
),
)
@ -302,7 +302,7 @@ func (api *API) RegisterProvisioningApiEndpoints(srv ProvisioningApi, m *metrics
metrics.Instrument(
http.MethodGet,
"/api/v1/provisioning/alert-rules/export",
srv.RouteGetAlertRulesExport,
api.Hooks.Wrap(srv.RouteGetAlertRulesExport),
m,
),
)
@ -312,7 +312,7 @@ func (api *API) RegisterProvisioningApiEndpoints(srv ProvisioningApi, m *metrics
metrics.Instrument(
http.MethodGet,
"/api/v1/provisioning/contact-points",
srv.RouteGetContactpoints,
api.Hooks.Wrap(srv.RouteGetContactpoints),
m,
),
)
@ -322,7 +322,7 @@ func (api *API) RegisterProvisioningApiEndpoints(srv ProvisioningApi, m *metrics
metrics.Instrument(
http.MethodGet,
"/api/v1/provisioning/mute-timings/{name}",
srv.RouteGetMuteTiming,
api.Hooks.Wrap(srv.RouteGetMuteTiming),
m,
),
)
@ -332,7 +332,7 @@ func (api *API) RegisterProvisioningApiEndpoints(srv ProvisioningApi, m *metrics
metrics.Instrument(
http.MethodGet,
"/api/v1/provisioning/mute-timings",
srv.RouteGetMuteTimings,
api.Hooks.Wrap(srv.RouteGetMuteTimings),
m,
),
)
@ -342,7 +342,7 @@ func (api *API) RegisterProvisioningApiEndpoints(srv ProvisioningApi, m *metrics
metrics.Instrument(
http.MethodGet,
"/api/v1/provisioning/policies",
srv.RouteGetPolicyTree,
api.Hooks.Wrap(srv.RouteGetPolicyTree),
m,
),
)
@ -352,7 +352,7 @@ func (api *API) RegisterProvisioningApiEndpoints(srv ProvisioningApi, m *metrics
metrics.Instrument(
http.MethodGet,
"/api/v1/provisioning/templates/{name}",
srv.RouteGetTemplate,
api.Hooks.Wrap(srv.RouteGetTemplate),
m,
),
)
@ -362,7 +362,7 @@ func (api *API) RegisterProvisioningApiEndpoints(srv ProvisioningApi, m *metrics
metrics.Instrument(
http.MethodGet,
"/api/v1/provisioning/templates",
srv.RouteGetTemplates,
api.Hooks.Wrap(srv.RouteGetTemplates),
m,
),
)
@ -372,7 +372,7 @@ func (api *API) RegisterProvisioningApiEndpoints(srv ProvisioningApi, m *metrics
metrics.Instrument(
http.MethodPost,
"/api/v1/provisioning/alert-rules",
srv.RoutePostAlertRule,
api.Hooks.Wrap(srv.RoutePostAlertRule),
m,
),
)
@ -382,7 +382,7 @@ func (api *API) RegisterProvisioningApiEndpoints(srv ProvisioningApi, m *metrics
metrics.Instrument(
http.MethodPost,
"/api/v1/provisioning/contact-points",
srv.RoutePostContactpoints,
api.Hooks.Wrap(srv.RoutePostContactpoints),
m,
),
)
@ -392,7 +392,7 @@ func (api *API) RegisterProvisioningApiEndpoints(srv ProvisioningApi, m *metrics
metrics.Instrument(
http.MethodPost,
"/api/v1/provisioning/mute-timings",
srv.RoutePostMuteTiming,
api.Hooks.Wrap(srv.RoutePostMuteTiming),
m,
),
)
@ -402,7 +402,7 @@ func (api *API) RegisterProvisioningApiEndpoints(srv ProvisioningApi, m *metrics
metrics.Instrument(
http.MethodPut,
"/api/v1/provisioning/alert-rules/{UID}",
srv.RoutePutAlertRule,
api.Hooks.Wrap(srv.RoutePutAlertRule),
m,
),
)
@ -412,7 +412,7 @@ func (api *API) RegisterProvisioningApiEndpoints(srv ProvisioningApi, m *metrics
metrics.Instrument(
http.MethodPut,
"/api/v1/provisioning/folder/{FolderUID}/rule-groups/{Group}",
srv.RoutePutAlertRuleGroup,
api.Hooks.Wrap(srv.RoutePutAlertRuleGroup),
m,
),
)
@ -422,7 +422,7 @@ func (api *API) RegisterProvisioningApiEndpoints(srv ProvisioningApi, m *metrics
metrics.Instrument(
http.MethodPut,
"/api/v1/provisioning/contact-points/{UID}",
srv.RoutePutContactpoint,
api.Hooks.Wrap(srv.RoutePutContactpoint),
m,
),
)
@ -432,7 +432,7 @@ func (api *API) RegisterProvisioningApiEndpoints(srv ProvisioningApi, m *metrics
metrics.Instrument(
http.MethodPut,
"/api/v1/provisioning/mute-timings/{name}",
srv.RoutePutMuteTiming,
api.Hooks.Wrap(srv.RoutePutMuteTiming),
m,
),
)
@ -442,7 +442,7 @@ func (api *API) RegisterProvisioningApiEndpoints(srv ProvisioningApi, m *metrics
metrics.Instrument(
http.MethodPut,
"/api/v1/provisioning/policies",
srv.RoutePutPolicyTree,
api.Hooks.Wrap(srv.RoutePutPolicyTree),
m,
),
)
@ -452,7 +452,7 @@ func (api *API) RegisterProvisioningApiEndpoints(srv ProvisioningApi, m *metrics
metrics.Instrument(
http.MethodPut,
"/api/v1/provisioning/templates/{name}",
srv.RoutePutTemplate,
api.Hooks.Wrap(srv.RoutePutTemplate),
m,
),
)
@ -462,7 +462,7 @@ func (api *API) RegisterProvisioningApiEndpoints(srv ProvisioningApi, m *metrics
metrics.Instrument(
http.MethodDelete,
"/api/v1/provisioning/policies",
srv.RouteResetPolicyTree,
api.Hooks.Wrap(srv.RouteResetPolicyTree),
m,
),
)

View File

@ -119,7 +119,7 @@ func (api *API) RegisterRulerApiEndpoints(srv RulerApi, m *metrics.API) {
metrics.Instrument(
http.MethodDelete,
"/api/ruler/grafana/api/v1/rules/{Namespace}/{Groupname}",
srv.RouteDeleteGrafanaRuleGroupConfig,
api.Hooks.Wrap(srv.RouteDeleteGrafanaRuleGroupConfig),
m,
),
)
@ -129,7 +129,7 @@ func (api *API) RegisterRulerApiEndpoints(srv RulerApi, m *metrics.API) {
metrics.Instrument(
http.MethodDelete,
"/api/ruler/grafana/api/v1/rules/{Namespace}",
srv.RouteDeleteNamespaceGrafanaRulesConfig,
api.Hooks.Wrap(srv.RouteDeleteNamespaceGrafanaRulesConfig),
m,
),
)
@ -139,7 +139,7 @@ func (api *API) RegisterRulerApiEndpoints(srv RulerApi, m *metrics.API) {
metrics.Instrument(
http.MethodDelete,
"/api/ruler/{DatasourceUID}/api/v1/rules/{Namespace}",
srv.RouteDeleteNamespaceRulesConfig,
api.Hooks.Wrap(srv.RouteDeleteNamespaceRulesConfig),
m,
),
)
@ -149,7 +149,7 @@ func (api *API) RegisterRulerApiEndpoints(srv RulerApi, m *metrics.API) {
metrics.Instrument(
http.MethodDelete,
"/api/ruler/{DatasourceUID}/api/v1/rules/{Namespace}/{Groupname}",
srv.RouteDeleteRuleGroupConfig,
api.Hooks.Wrap(srv.RouteDeleteRuleGroupConfig),
m,
),
)
@ -159,7 +159,7 @@ func (api *API) RegisterRulerApiEndpoints(srv RulerApi, m *metrics.API) {
metrics.Instrument(
http.MethodGet,
"/api/ruler/grafana/api/v1/rules/{Namespace}/{Groupname}",
srv.RouteGetGrafanaRuleGroupConfig,
api.Hooks.Wrap(srv.RouteGetGrafanaRuleGroupConfig),
m,
),
)
@ -169,7 +169,7 @@ func (api *API) RegisterRulerApiEndpoints(srv RulerApi, m *metrics.API) {
metrics.Instrument(
http.MethodGet,
"/api/ruler/grafana/api/v1/rules",
srv.RouteGetGrafanaRulesConfig,
api.Hooks.Wrap(srv.RouteGetGrafanaRulesConfig),
m,
),
)
@ -179,7 +179,7 @@ func (api *API) RegisterRulerApiEndpoints(srv RulerApi, m *metrics.API) {
metrics.Instrument(
http.MethodGet,
"/api/ruler/grafana/api/v1/rules/{Namespace}",
srv.RouteGetNamespaceGrafanaRulesConfig,
api.Hooks.Wrap(srv.RouteGetNamespaceGrafanaRulesConfig),
m,
),
)
@ -189,7 +189,7 @@ func (api *API) RegisterRulerApiEndpoints(srv RulerApi, m *metrics.API) {
metrics.Instrument(
http.MethodGet,
"/api/ruler/{DatasourceUID}/api/v1/rules/{Namespace}",
srv.RouteGetNamespaceRulesConfig,
api.Hooks.Wrap(srv.RouteGetNamespaceRulesConfig),
m,
),
)
@ -199,7 +199,7 @@ func (api *API) RegisterRulerApiEndpoints(srv RulerApi, m *metrics.API) {
metrics.Instrument(
http.MethodGet,
"/api/ruler/{DatasourceUID}/api/v1/rules/{Namespace}/{Groupname}",
srv.RouteGetRulegGroupConfig,
api.Hooks.Wrap(srv.RouteGetRulegGroupConfig),
m,
),
)
@ -209,7 +209,7 @@ func (api *API) RegisterRulerApiEndpoints(srv RulerApi, m *metrics.API) {
metrics.Instrument(
http.MethodGet,
"/api/ruler/{DatasourceUID}/api/v1/rules",
srv.RouteGetRulesConfig,
api.Hooks.Wrap(srv.RouteGetRulesConfig),
m,
),
)
@ -219,7 +219,7 @@ func (api *API) RegisterRulerApiEndpoints(srv RulerApi, m *metrics.API) {
metrics.Instrument(
http.MethodPost,
"/api/ruler/grafana/api/v1/rules/{Namespace}",
srv.RoutePostNameGrafanaRulesConfig,
api.Hooks.Wrap(srv.RoutePostNameGrafanaRulesConfig),
m,
),
)
@ -229,7 +229,7 @@ func (api *API) RegisterRulerApiEndpoints(srv RulerApi, m *metrics.API) {
metrics.Instrument(
http.MethodPost,
"/api/ruler/{DatasourceUID}/api/v1/rules/{Namespace}",
srv.RoutePostNameRulesConfig,
api.Hooks.Wrap(srv.RoutePostNameRulesConfig),
m,
),
)

View File

@ -68,7 +68,7 @@ func (api *API) RegisterTestingApiEndpoints(srv TestingApi, m *metrics.API) {
metrics.Instrument(
http.MethodPost,
"/api/v1/rule/backtest",
srv.BacktestConfig,
api.Hooks.Wrap(srv.BacktestConfig),
m,
),
)
@ -78,7 +78,7 @@ func (api *API) RegisterTestingApiEndpoints(srv TestingApi, m *metrics.API) {
metrics.Instrument(
http.MethodPost,
"/api/v1/eval",
srv.RouteEvalQueries,
api.Hooks.Wrap(srv.RouteEvalQueries),
m,
),
)
@ -88,7 +88,7 @@ func (api *API) RegisterTestingApiEndpoints(srv TestingApi, m *metrics.API) {
metrics.Instrument(
http.MethodPost,
"/api/v1/rule/test/{DatasourceUID}",
srv.RouteTestRuleConfig,
api.Hooks.Wrap(srv.RouteTestRuleConfig),
m,
),
)
@ -98,7 +98,7 @@ func (api *API) RegisterTestingApiEndpoints(srv TestingApi, m *metrics.API) {
metrics.Instrument(
http.MethodPost,
"/api/v1/rule/test/grafana",
srv.RouteTestRuleGrafanaConfig,
api.Hooks.Wrap(srv.RouteTestRuleGrafanaConfig),
m,
),
)

View File

@ -0,0 +1,43 @@
package api
import (
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/infra/log"
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
)
type RequestHandlerFunc func(*contextmodel.ReqContext) response.Response
type Hooks struct {
logger log.Logger
hooks map[string]RequestHandlerFunc
}
// NewHooks creates an empty set of request handler hooks. Hooks can be used
// to replace handlers for specific paths.
func NewHooks(logger log.Logger) *Hooks {
return &Hooks{
logger: logger,
hooks: make(map[string]RequestHandlerFunc),
}
}
// Add creates a new request hook for a path, causing requests to the path to
// be handled by the hook function, and not the original handler.
func (h *Hooks) Set(path string, hook RequestHandlerFunc) {
h.logger.Info("setting hook override for the specified route", "path", path)
h.hooks[path] = hook
}
// Wrap returns a new handler which will intercept paths with hooks configured,
// and invoke the hooked in handler instead. If no hook is configured for a path,
// then the given handler is invoked.
func (h *Hooks) Wrap(next RequestHandlerFunc) RequestHandlerFunc {
return func(req *contextmodel.ReqContext) response.Response {
if hook, ok := h.hooks[req.Context.Req.URL.Path]; ok {
h.logger.Debug("hook defined - invoking new handler", "path", req.Context.Req.URL.Path)
return hook(req)
}
return next(req)
}
}

View File

@ -40,7 +40,7 @@ func (api *API) Register{{classname}}Endpoints(srv {{classname}}, m *metrics.API
metrics.Instrument(
http.Method{{httpMethod}},
"{{{path}}}",
srv.{{nickname}},
api.Hooks.Wrap(srv.{{nickname}}),
m,
),
){{/operation}}{{/operations}}

View File

@ -127,6 +127,7 @@ type AlertNG struct {
stateManager *state.Manager
folderService folder.Service
dashboardService dashboards.DashboardService
api *api.API
// Alerting notification services
MultiOrgAlertmanager *notifier.MultiOrgAlertmanager
@ -246,7 +247,7 @@ func (ng *AlertNG) init() error {
int64(ng.Cfg.UnifiedAlerting.DefaultRuleEvaluationInterval.Seconds()),
int64(ng.Cfg.UnifiedAlerting.BaseInterval.Seconds()), ng.Log)
api := api.API{
ng.api = &api.API{
Cfg: ng.Cfg,
DatasourceCache: ng.DataSourceCache,
DatasourceService: ng.DataSourceService,
@ -271,8 +272,9 @@ func (ng *AlertNG) init() error {
FeatureManager: ng.FeatureToggles,
AppUrl: appUrl,
Historian: history,
Hooks: api.NewHooks(ng.Log),
}
api.RegisterAPIEndpoints(ng.Metrics.GetAPIMetrics())
ng.api.RegisterAPIEndpoints(ng.Metrics.GetAPIMetrics())
defaultLimits, err := readQuotaConfig(ng.Cfg)
if err != nil {
@ -282,7 +284,7 @@ func (ng *AlertNG) init() error {
if err := ng.QuotaService.RegisterQuotaReporter(&quota.NewUsageReporter{
TargetSrv: models.QuotaTargetSrv,
DefaultLimits: defaultLimits,
Reporter: api.Usage,
Reporter: ng.api.Usage,
}); err != nil {
return err
}
@ -349,6 +351,12 @@ func (ng *AlertNG) IsDisabled() bool {
return !ng.Cfg.UnifiedAlerting.IsEnabled()
}
// GetHooks returns a facility for replacing handlers for paths. The handler hook for a path
// is invoked after all other middleware is invoked (authentication, instrumentation).
func (ng *AlertNG) GetHooks() *api.Hooks {
return ng.api.Hooks
}
func readQuotaConfig(cfg *setting.Cfg) (*quota.Map, error) {
limits := &quota.Map{}