mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Alerting: Remove internal labels from prometheus compatible API responses (#46548)
* Alerting: Remove internal labels from prometheus compatible API responses * Appease the linter * Fix integration tests * Fix API documentation & linter * move removal of internal labels to the models
This commit is contained in:
parent
d5883c1b27
commit
a338c78ca8
@ -9,17 +9,16 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
apiv1 "github.com/prometheus/client_golang/api/prometheus/v1"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/eval"
|
||||
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/store"
|
||||
|
||||
"github.com/grafana/grafana/pkg/api/response"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/eval"
|
||||
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/state"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/store"
|
||||
|
||||
apiv1 "github.com/prometheus/client_golang/api/prometheus/v1"
|
||||
)
|
||||
|
||||
type PrometheusSrv struct {
|
||||
@ -28,6 +27,8 @@ type PrometheusSrv struct {
|
||||
store store.RuleStore
|
||||
}
|
||||
|
||||
const queryIncludeInternalLabels = "includeInternalLabels"
|
||||
|
||||
func (srv PrometheusSrv) RouteGetAlertStatuses(c *models.ReqContext) response.Response {
|
||||
alertResponse := apimodels.AlertResponse{
|
||||
DiscoveryBase: apimodels.DiscoveryBase{
|
||||
@ -37,6 +38,12 @@ func (srv PrometheusSrv) RouteGetAlertStatuses(c *models.ReqContext) response.Re
|
||||
Alerts: []*apimodels.Alert{},
|
||||
},
|
||||
}
|
||||
|
||||
var labelOptions []ngmodels.LabelOption
|
||||
if !c.QueryBoolWithDefault(queryIncludeInternalLabels, false) {
|
||||
labelOptions = append(labelOptions, ngmodels.WithoutInternalLabels())
|
||||
}
|
||||
|
||||
for _, alertState := range srv.manager.GetAll(c.OrgId) {
|
||||
startsAt := alertState.StartsAt
|
||||
valString := ""
|
||||
@ -45,7 +52,7 @@ func (srv PrometheusSrv) RouteGetAlertStatuses(c *models.ReqContext) response.Re
|
||||
}
|
||||
|
||||
alertResponse.Data.Alerts = append(alertResponse.Data.Alerts, &apimodels.Alert{
|
||||
Labels: map[string]string(alertState.Labels),
|
||||
Labels: alertState.GetLabels(labelOptions...),
|
||||
Annotations: alertState.Annotations,
|
||||
State: alertState.State.String(),
|
||||
ActiveAt: &startsAt,
|
||||
@ -73,6 +80,11 @@ func (srv PrometheusSrv) RouteGetRuleStatuses(c *models.ReqContext) response.Res
|
||||
},
|
||||
}
|
||||
|
||||
var labelOptions []ngmodels.LabelOption
|
||||
if !c.QueryBoolWithDefault(queryIncludeInternalLabels, false) {
|
||||
labelOptions = append(labelOptions, ngmodels.WithoutInternalLabels())
|
||||
}
|
||||
|
||||
namespaceMap, err := srv.store.GetNamespaces(c.Req.Context(), c.OrgId, c.SignedInUser)
|
||||
if err != nil {
|
||||
return ErrResp(http.StatusInternalServerError, err, "failed to get namespaces visible to the user")
|
||||
@ -157,7 +169,7 @@ func (srv PrometheusSrv) RouteGetRuleStatuses(c *models.ReqContext) response.Res
|
||||
|
||||
newRule := apimodels.Rule{
|
||||
Name: rule.Title,
|
||||
Labels: rule.Labels,
|
||||
Labels: rule.GetLabels(labelOptions...),
|
||||
Health: "ok",
|
||||
Type: apiv1.RuleTypeAlerting,
|
||||
LastEvaluation: time.Time{},
|
||||
@ -169,8 +181,9 @@ func (srv PrometheusSrv) RouteGetRuleStatuses(c *models.ReqContext) response.Res
|
||||
if alertState.State == eval.Alerting {
|
||||
valString = alertState.LastEvaluationString
|
||||
}
|
||||
|
||||
alert := &apimodels.Alert{
|
||||
Labels: map[string]string(alertState.Labels),
|
||||
Labels: alertState.GetLabels(labelOptions...),
|
||||
Annotations: alertState.Annotations,
|
||||
State: alertState.State.String(),
|
||||
ActiveAt: &activeAt,
|
||||
|
@ -21,19 +21,14 @@ import (
|
||||
)
|
||||
|
||||
func TestRouteGetAlertStatuses(t *testing.T) {
|
||||
fakeStore := store.NewFakeRuleStore(t)
|
||||
fakeAlertInstanceManager := NewFakeAlertInstanceManager(t)
|
||||
orgID := int64(1)
|
||||
|
||||
api := PrometheusSrv{
|
||||
log: log.NewNopLogger(),
|
||||
manager: fakeAlertInstanceManager,
|
||||
store: fakeStore,
|
||||
}
|
||||
|
||||
c := &models.ReqContext{SignedInUser: &models.SignedInUser{OrgId: orgID}}
|
||||
|
||||
t.Run("with no alerts", func(t *testing.T) {
|
||||
_, _, api := setupAPI(t)
|
||||
req, err := http.NewRequest("GET", "/api/v1/alerts", nil)
|
||||
require.NoError(t, err)
|
||||
c := &models.ReqContext{Context: &web.Context{Req: req}, SignedInUser: &models.SignedInUser{OrgId: orgID}}
|
||||
|
||||
r := api.RouteGetAlertStatuses(c)
|
||||
require.Equal(t, http.StatusOK, r.Status())
|
||||
require.JSONEq(t, `
|
||||
@ -47,7 +42,54 @@ func TestRouteGetAlertStatuses(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("with two alerts", func(t *testing.T) {
|
||||
fakeAlertInstanceManager.GenerateAlertInstances(1, util.GenerateShortUID(), 2)
|
||||
_, fakeAIM, api := setupAPI(t)
|
||||
fakeAIM.GenerateAlertInstances(1, util.GenerateShortUID(), 2)
|
||||
req, err := http.NewRequest("GET", "/api/v1/alerts", nil)
|
||||
require.NoError(t, err)
|
||||
c := &models.ReqContext{Context: &web.Context{Req: req}, SignedInUser: &models.SignedInUser{OrgId: orgID}}
|
||||
|
||||
r := api.RouteGetAlertStatuses(c)
|
||||
require.Equal(t, http.StatusOK, r.Status())
|
||||
require.JSONEq(t, `
|
||||
{
|
||||
"status": "success",
|
||||
"data": {
|
||||
"alerts": [{
|
||||
"labels": {
|
||||
"alertname": "test_title_0",
|
||||
"instance_label": "test",
|
||||
"label": "test"
|
||||
},
|
||||
"annotations": {
|
||||
"annotation": "test"
|
||||
},
|
||||
"state": "Normal",
|
||||
"activeAt": "0001-01-01T00:00:00Z",
|
||||
"value": ""
|
||||
}, {
|
||||
"labels": {
|
||||
"alertname": "test_title_1",
|
||||
"instance_label": "test",
|
||||
"label": "test"
|
||||
},
|
||||
"annotations": {
|
||||
"annotation": "test"
|
||||
},
|
||||
"state": "Normal",
|
||||
"activeAt": "0001-01-01T00:00:00Z",
|
||||
"value": ""
|
||||
}]
|
||||
}
|
||||
}`, string(r.Body()))
|
||||
})
|
||||
|
||||
t.Run("with the inclusion of internal labels", func(t *testing.T) {
|
||||
_, fakeAIM, api := setupAPI(t)
|
||||
fakeAIM.GenerateAlertInstances(orgID, util.GenerateShortUID(), 2)
|
||||
req, err := http.NewRequest("GET", "/api/v1/alerts?includeInternalLabels=true", nil)
|
||||
require.NoError(t, err)
|
||||
c := &models.ReqContext{Context: &web.Context{Req: req}, SignedInUser: &models.SignedInUser{OrgId: orgID}}
|
||||
|
||||
r := api.RouteGetAlertStatuses(c)
|
||||
require.Equal(t, http.StatusOK, r.Status())
|
||||
require.JSONEq(t, `
|
||||
@ -138,9 +180,63 @@ func TestRouteGetRuleStatuses(t *testing.T) {
|
||||
"activeAt": "0001-01-01T00:00:00Z",
|
||||
"value": ""
|
||||
}],
|
||||
"labels": null,
|
||||
"labels": {
|
||||
"__a_private_label_on_the_rule__": "a_value"
|
||||
},
|
||||
"health": "ok",
|
||||
"type": "alerting",
|
||||
"lastEvaluation": "2022-03-10T14:01:00Z",
|
||||
"duration": 180,
|
||||
"evaluationTime": 60
|
||||
}],
|
||||
"interval": 60,
|
||||
"lastEvaluation": "2022-03-10T14:01:00Z",
|
||||
"evaluationTime": 0
|
||||
}]
|
||||
}
|
||||
}
|
||||
`, string(r.Body()))
|
||||
})
|
||||
|
||||
t.Run("with the inclusion of internal Labels", func(t *testing.T) {
|
||||
fakeStore, fakeAIM, api := setupAPI(t)
|
||||
generateRuleAndInstanceWithQuery(t, orgID, fakeAIM, fakeStore, withClassicConditionSingleQuery())
|
||||
|
||||
req, err := http.NewRequest("GET", "/api/v1/rules?includeInternalLabels=true", nil)
|
||||
require.NoError(t, err)
|
||||
c := &models.ReqContext{Context: &web.Context{Req: req}, SignedInUser: &models.SignedInUser{OrgId: orgID}}
|
||||
|
||||
r := api.RouteGetRuleStatuses(c)
|
||||
require.Equal(t, http.StatusOK, r.Status())
|
||||
require.JSONEq(t, `
|
||||
{
|
||||
"status": "success",
|
||||
"data": {
|
||||
"groups": [{
|
||||
"name": "rule-group",
|
||||
"file": "namespaceUID",
|
||||
"rules": [{
|
||||
"state": "inactive",
|
||||
"name": "AlwaysFiring",
|
||||
"query": "vector(1)",
|
||||
"alerts": [{
|
||||
"labels": {
|
||||
"job": "prometheus",
|
||||
"__alert_rule_namespace_uid__": "test_namespace_uid",
|
||||
"__alert_rule_uid__": "test_alert_rule_uid_0"
|
||||
},
|
||||
"annotations": {
|
||||
"severity": "critical"
|
||||
},
|
||||
"state": "Normal",
|
||||
"activeAt": "0001-01-01T00:00:00Z",
|
||||
"value": ""
|
||||
}],
|
||||
"labels": {
|
||||
"__a_private_label_on_the_rule__": "a_value",
|
||||
"__alert_rule_uid__": "RuleUID"
|
||||
},
|
||||
"health": "ok",
|
||||
"lastError": "",
|
||||
"type": "alerting",
|
||||
"lastEvaluation": "2022-03-10T14:01:00Z",
|
||||
"duration": 180,
|
||||
@ -183,9 +279,10 @@ func TestRouteGetRuleStatuses(t *testing.T) {
|
||||
"activeAt": "0001-01-01T00:00:00Z",
|
||||
"value": ""
|
||||
}],
|
||||
"labels": null,
|
||||
"labels": {
|
||||
"__a_private_label_on_the_rule__": "a_value"
|
||||
},
|
||||
"health": "ok",
|
||||
"lastError": "",
|
||||
"type": "alerting",
|
||||
"lastEvaluation": "2022-03-10T14:01:00Z",
|
||||
"duration": 180,
|
||||
@ -219,7 +316,11 @@ func generateRuleAndInstanceWithQuery(t *testing.T, orgID int64, fakeAIM *fakeAl
|
||||
rules := ngmodels.GenerateAlertRules(1, ngmodels.AlertRuleGen(withOrgID(orgID), asFixture(), query))
|
||||
|
||||
fakeAIM.GenerateAlertInstances(orgID, rules[0].UID, 1, func(s *state.State) *state.State {
|
||||
s.Labels = data.Labels{"job": "prometheus"}
|
||||
s.Labels = data.Labels{
|
||||
"job": "prometheus",
|
||||
ngmodels.NamespaceUIDLabel: "test_namespace_uid",
|
||||
ngmodels.RuleUIDLabel: "test_alert_rule_uid_0",
|
||||
}
|
||||
s.Annotations = data.Labels{"severity": "critical"}
|
||||
return s
|
||||
})
|
||||
@ -237,7 +338,10 @@ func asFixture() func(r *ngmodels.AlertRule) {
|
||||
r.NamespaceUID = "namespaceUID"
|
||||
r.RuleGroup = "rule-group"
|
||||
r.UID = "RuleUID"
|
||||
r.Labels = nil
|
||||
r.Labels = map[string]string{
|
||||
"__a_private_label_on_the_rule__": "a_value",
|
||||
ngmodels.RuleUIDLabel: "RuleUID",
|
||||
}
|
||||
r.Annotations = nil
|
||||
r.IntervalSeconds = 60
|
||||
r.For = 180 * time.Second
|
||||
|
@ -297,14 +297,6 @@ type GetSilencesParams struct {
|
||||
Filter []string `json:"filter"`
|
||||
}
|
||||
|
||||
// swagger:parameters RouteGetRuleStatuses RouteGetGrafanaRuleStatuses
|
||||
type GetRuleStatusesParams struct {
|
||||
// in: query
|
||||
DashboardUID string
|
||||
// in: query
|
||||
PanelID int64
|
||||
}
|
||||
|
||||
// swagger:model
|
||||
type GettableStatus struct {
|
||||
// cluster
|
||||
|
@ -115,10 +115,10 @@ type Rule struct {
|
||||
Name string `json:"name"`
|
||||
// required: true
|
||||
Query string `json:"query"`
|
||||
Labels overrideLabels `json:"labels"`
|
||||
Labels overrideLabels `json:"labels,omitempty"`
|
||||
// required: true
|
||||
Health string `json:"health"`
|
||||
LastError string `json:"lastError"`
|
||||
LastError string `json:"lastError,omitempty"`
|
||||
// required: true
|
||||
Type v1.RuleType `json:"type"`
|
||||
LastEvaluation time.Time `json:"lastEvaluation"`
|
||||
@ -142,3 +142,31 @@ type Alert struct {
|
||||
// override the labels type with a map for generation.
|
||||
// The custom marshaling for labels.Labels ends up doing this anyways.
|
||||
type overrideLabels map[string]string
|
||||
|
||||
// swagger:parameters RouteGetGrafanaAlertStatuses
|
||||
type GetGrafanaAlertStatusesParams struct {
|
||||
// Include Grafana specific labels as part of the response.
|
||||
// in: query
|
||||
// required: false
|
||||
// default: false
|
||||
IncludeInternalLabels bool `json:"includeInternalLabels"`
|
||||
}
|
||||
|
||||
// swagger:parameters RouteGetGrafanaRuleStatuses
|
||||
type GetGrafanaRuleStatusesParams struct {
|
||||
// Include Grafana specific labels as part of the response.
|
||||
// in: query
|
||||
// required: false
|
||||
// default: false
|
||||
IncludeInternalLabels bool `json:"includeInternalLabels"`
|
||||
|
||||
// Filter the list of rules to those that belong to the specified dashboard UID.
|
||||
// in: query
|
||||
// required: false
|
||||
DashboardUID string
|
||||
|
||||
// Filter the list of rules to those that belong to the specified panel ID. Dashboard UID must be specified.
|
||||
// in: query
|
||||
// required: false
|
||||
PanelID int64
|
||||
}
|
||||
|
@ -2803,6 +2803,7 @@
|
||||
"x-go-package": "github.com/prometheus/alertmanager/timeinterval"
|
||||
},
|
||||
"URL": {
|
||||
"description": "The general form represented is:\n\n[scheme:][//[userinfo@]host][/]path[?query][#fragment]\n\nURLs that do not start with a slash after the scheme are interpreted as:\n\nscheme:opaque[?query][#fragment]\n\nNote that the Path field is stored in decoded form: /%47%6f%2f becomes /Go/.\nA consequence is that it is impossible to tell which slashes in the Path were\nslashes in the raw URL and which were %2f. This distinction is rarely important,\nbut when it is, the code should use RawPath, an optional field which only gets\nset if the default encoding is different from Path.\n\nURL's String method uses the EscapedPath method to obtain the path. See the\nEscapedPath method for more details.",
|
||||
"properties": {
|
||||
"ForceQuery": {
|
||||
"type": "boolean"
|
||||
@ -2835,9 +2836,9 @@
|
||||
"$ref": "#/definitions/Userinfo"
|
||||
}
|
||||
},
|
||||
"title": "URL is a custom URL type that allows validation at configuration load time.",
|
||||
"title": "A URL represents a parsed URL (technically, a URI reference).",
|
||||
"type": "object",
|
||||
"x-go-package": "github.com/prometheus/common/config"
|
||||
"x-go-package": "net/url"
|
||||
},
|
||||
"Userinfo": {
|
||||
"description": "The Userinfo type is an immutable encapsulation of username and\npassword details for a URL. An existing Userinfo value is guaranteed\nto have a username set (potentially empty, as allowed by RFC 2396),\nand optionally a password.",
|
||||
@ -3034,6 +3035,7 @@
|
||||
"x-go-package": "github.com/prometheus/alertmanager/api/v2/models"
|
||||
},
|
||||
"alertGroup": {
|
||||
"description": "AlertGroup alert group",
|
||||
"properties": {
|
||||
"alerts": {
|
||||
"description": "alerts",
|
||||
@ -3055,9 +3057,7 @@
|
||||
"labels",
|
||||
"receiver"
|
||||
],
|
||||
"type": "object",
|
||||
"x-go-name": "AlertGroup",
|
||||
"x-go-package": "github.com/prometheus/alertmanager/api/v2/models"
|
||||
"type": "object"
|
||||
},
|
||||
"alertGroups": {
|
||||
"items": {
|
||||
@ -4615,6 +4615,16 @@
|
||||
"get": {
|
||||
"description": "gets the current alerts",
|
||||
"operationId": "RouteGetGrafanaAlertStatuses",
|
||||
"parameters": [
|
||||
{
|
||||
"default": false,
|
||||
"description": "Include Grafana specific labels as part of the response.",
|
||||
"in": "query",
|
||||
"name": "includeInternalLabels",
|
||||
"type": "boolean",
|
||||
"x-go-name": "IncludeInternalLabels"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "AlertResponse",
|
||||
@ -4634,11 +4644,21 @@
|
||||
"operationId": "RouteGetGrafanaRuleStatuses",
|
||||
"parameters": [
|
||||
{
|
||||
"default": false,
|
||||
"description": "Include Grafana specific labels as part of the response.",
|
||||
"in": "query",
|
||||
"name": "includeInternalLabels",
|
||||
"type": "boolean",
|
||||
"x-go-name": "IncludeInternalLabels"
|
||||
},
|
||||
{
|
||||
"description": "Filter the list of rules to those that belong to the specified dashboard UID.",
|
||||
"in": "query",
|
||||
"name": "DashboardUID",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"description": "Filter the list of rules to those that belong to the specified panel ID. Dashboard UID must be specified.",
|
||||
"format": "int64",
|
||||
"in": "query",
|
||||
"name": "PanelID",
|
||||
@ -4690,17 +4710,6 @@
|
||||
"description": "gets the evaluation statuses of all rules",
|
||||
"operationId": "RouteGetRuleStatuses",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "query",
|
||||
"name": "DashboardUID",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"format": "int64",
|
||||
"in": "query",
|
||||
"name": "PanelID",
|
||||
"type": "integer"
|
||||
},
|
||||
{
|
||||
"description": "Recipient should be the numeric datasource id",
|
||||
"format": "int64",
|
||||
|
@ -1022,6 +1022,16 @@
|
||||
"prometheus"
|
||||
],
|
||||
"operationId": "RouteGetGrafanaAlertStatuses",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"x-go-name": "IncludeInternalLabels",
|
||||
"description": "Include Grafana specific labels as part of the response.",
|
||||
"name": "includeInternalLabels",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "AlertResponse",
|
||||
@ -1040,14 +1050,24 @@
|
||||
],
|
||||
"operationId": "RouteGetGrafanaRuleStatuses",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"x-go-name": "IncludeInternalLabels",
|
||||
"description": "Include Grafana specific labels as part of the response.",
|
||||
"name": "includeInternalLabels",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Filter the list of rules to those that belong to the specified dashboard UID.",
|
||||
"name": "DashboardUID",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"description": "Filter the list of rules to those that belong to the specified panel ID. Dashboard UID must be specified.",
|
||||
"name": "PanelID",
|
||||
"in": "query"
|
||||
}
|
||||
@ -1097,17 +1117,6 @@
|
||||
],
|
||||
"operationId": "RouteGetRuleStatuses",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"name": "DashboardUID",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"name": "PanelID",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
@ -4555,8 +4564,9 @@
|
||||
"x-go-package": "github.com/prometheus/alertmanager/timeinterval"
|
||||
},
|
||||
"URL": {
|
||||
"description": "The general form represented is:\n\n[scheme:][//[userinfo@]host][/]path[?query][#fragment]\n\nURLs that do not start with a slash after the scheme are interpreted as:\n\nscheme:opaque[?query][#fragment]\n\nNote that the Path field is stored in decoded form: /%47%6f%2f becomes /Go/.\nA consequence is that it is impossible to tell which slashes in the Path were\nslashes in the raw URL and which were %2f. This distinction is rarely important,\nbut when it is, the code should use RawPath, an optional field which only gets\nset if the default encoding is different from Path.\n\nURL's String method uses the EscapedPath method to obtain the path. See the\nEscapedPath method for more details.",
|
||||
"type": "object",
|
||||
"title": "URL is a custom URL type that allows validation at configuration load time.",
|
||||
"title": "A URL represents a parsed URL (technically, a URI reference).",
|
||||
"properties": {
|
||||
"ForceQuery": {
|
||||
"type": "boolean"
|
||||
@ -4589,7 +4599,7 @@
|
||||
"$ref": "#/definitions/Userinfo"
|
||||
}
|
||||
},
|
||||
"x-go-package": "github.com/prometheus/common/config"
|
||||
"x-go-package": "net/url"
|
||||
},
|
||||
"Userinfo": {
|
||||
"description": "The Userinfo type is an immutable encapsulation of username and\npassword details for a URL. An existing Userinfo value is guaranteed\nto have a username set (potentially empty, as allowed by RFC 2396),\nand optionally a password.",
|
||||
@ -4786,6 +4796,7 @@
|
||||
"x-go-package": "github.com/prometheus/alertmanager/api/v2/models"
|
||||
},
|
||||
"alertGroup": {
|
||||
"description": "AlertGroup alert group",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"alerts",
|
||||
@ -4808,8 +4819,6 @@
|
||||
"$ref": "#/definitions/receiver"
|
||||
}
|
||||
},
|
||||
"x-go-name": "AlertGroup",
|
||||
"x-go-package": "github.com/prometheus/alertmanager/api/v2/models",
|
||||
"$ref": "#/definitions/alertGroup"
|
||||
},
|
||||
"alertGroups": {
|
||||
|
@ -18,12 +18,9 @@ var (
|
||||
// ErrAlertRuleFailedGenerateUniqueUID is an error for failure to generate alert rule UID
|
||||
ErrAlertRuleFailedGenerateUniqueUID = errors.New("failed to generate alert rule UID")
|
||||
// ErrCannotEditNamespace is an error returned if the user does not have permissions to edit the namespace
|
||||
ErrCannotEditNamespace = errors.New("user does not have permissions to edit the namespace")
|
||||
// ErrRuleGroupNamespaceNotFound
|
||||
ErrRuleGroupNamespaceNotFound = errors.New("rule group not found under this namespace")
|
||||
// ErrAlertRuleFailedValidation
|
||||
ErrAlertRuleFailedValidation = errors.New("invalid alert rule")
|
||||
// ErrAlertRuleUniqueConstraintViolation
|
||||
ErrCannotEditNamespace = errors.New("user does not have permissions to edit the namespace")
|
||||
ErrRuleGroupNamespaceNotFound = errors.New("rule group not found under this namespace")
|
||||
ErrAlertRuleFailedValidation = errors.New("invalid alert rule")
|
||||
ErrAlertRuleUniqueConstraintViolation = errors.New("a conflicting alert rule is found: rule title under the same organisation and folder should be unique")
|
||||
)
|
||||
|
||||
@ -77,6 +74,12 @@ const (
|
||||
OkErrState ExecutionErrorState = "OK"
|
||||
)
|
||||
|
||||
// InternalLabelNameSet are labels that grafana automatically include as part of the labelset.
|
||||
var InternalLabelNameSet = map[string]struct{}{
|
||||
RuleUIDLabel: {},
|
||||
NamespaceUIDLabel: {},
|
||||
}
|
||||
|
||||
const (
|
||||
RuleUIDLabel = "__alert_rule_uid__"
|
||||
NamespaceUIDLabel = "__alert_rule_namespace_uid__"
|
||||
@ -110,6 +113,29 @@ type AlertRule struct {
|
||||
Labels map[string]string
|
||||
}
|
||||
|
||||
type LabelOption func(map[string]string)
|
||||
|
||||
func WithoutInternalLabels() LabelOption {
|
||||
return func(labels map[string]string) {
|
||||
for k := range labels {
|
||||
if _, ok := InternalLabelNameSet[k]; ok {
|
||||
delete(labels, k)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetLabels returns the labels specified as part of the alert rule.
|
||||
func (alertRule *AlertRule) GetLabels(opts ...LabelOption) map[string]string {
|
||||
labels := alertRule.Labels
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(labels)
|
||||
}
|
||||
|
||||
return labels
|
||||
}
|
||||
|
||||
// Diff calculates diff between two alert rules. Returns nil if two rules are equal. Otherwise, returns cmputil.DiffReport
|
||||
func (alertRule *AlertRule) Diff(rule *AlertRule, ignore ...string) cmputil.DiffReport {
|
||||
var reporter cmputil.DiffReporter
|
||||
|
@ -47,7 +47,7 @@ func NewEvaluationValues(m map[string]eval.NumberValueCapture) map[string]*float
|
||||
return result
|
||||
}
|
||||
|
||||
func (a *State) resultNormal(alertRule *ngModels.AlertRule, result eval.Result) {
|
||||
func (a *State) resultNormal(_ *ngModels.AlertRule, result eval.Result) {
|
||||
a.Error = result.Error // should be nil since state is not error
|
||||
|
||||
if a.State != eval.Normal {
|
||||
@ -177,3 +177,13 @@ func (a *State) setEndsAt(alertRule *ngModels.AlertRule, result eval.Result) {
|
||||
|
||||
a.EndsAt = result.EvaluatedAt.Add(ends * 3)
|
||||
}
|
||||
|
||||
func (a *State) GetLabels(opts ...ngModels.LabelOption) map[string]string {
|
||||
labels := a.Labels.Copy()
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(labels)
|
||||
}
|
||||
|
||||
return labels
|
||||
}
|
||||
|
@ -245,7 +245,6 @@ func TestPrometheusRules(t *testing.T) {
|
||||
"label1": "val1"
|
||||
},
|
||||
"health": "ok",
|
||||
"lastError": "",
|
||||
"type": "alerting",
|
||||
"lastEvaluation": "0001-01-01T00:00:00Z",
|
||||
"evaluationTime": 0
|
||||
@ -253,9 +252,7 @@ func TestPrometheusRules(t *testing.T) {
|
||||
"state": "inactive",
|
||||
"name": "AlwaysFiringButSilenced",
|
||||
"query": "[{\"refId\":\"A\",\"queryType\":\"\",\"relativeTimeRange\":{\"from\":18000,\"to\":10800},\"datasourceUid\":\"-100\",\"model\":{\"expression\":\"2 + 3 \\u003e 1\",\"intervalMs\":1000,\"maxDataPoints\":43200,\"type\":\"math\"}}]",
|
||||
"labels": null,
|
||||
"health": "ok",
|
||||
"lastError": "",
|
||||
"type": "alerting",
|
||||
"lastEvaluation": "0001-01-01T00:00:00Z",
|
||||
"evaluationTime": 0
|
||||
@ -300,7 +297,6 @@ func TestPrometheusRules(t *testing.T) {
|
||||
"label1": "val1"
|
||||
},
|
||||
"health": "ok",
|
||||
"lastError": "",
|
||||
"type": "alerting",
|
||||
"lastEvaluation": "0001-01-01T00:00:00Z",
|
||||
"evaluationTime": 0
|
||||
@ -308,9 +304,7 @@ func TestPrometheusRules(t *testing.T) {
|
||||
"state": "inactive",
|
||||
"name": "AlwaysFiringButSilenced",
|
||||
"query": "[{\"refId\":\"A\",\"queryType\":\"\",\"relativeTimeRange\":{\"from\":18000,\"to\":10800},\"datasourceUid\":\"-100\",\"model\":{\"expression\":\"2 + 3 \\u003e 1\",\"intervalMs\":1000,\"maxDataPoints\":43200,\"type\":\"math\"}}]",
|
||||
"labels": null,
|
||||
"health": "ok",
|
||||
"lastError": "",
|
||||
"type": "alerting",
|
||||
"lastEvaluation": "0001-01-01T00:00:00Z",
|
||||
"evaluationTime": 0
|
||||
@ -446,9 +440,7 @@ func TestPrometheusRulesFilterByDashboard(t *testing.T) {
|
||||
"__dashboardUid__": "%s",
|
||||
"__panelId__": "1"
|
||||
},
|
||||
"labels": null,
|
||||
"health": "ok",
|
||||
"lastError": "",
|
||||
"type": "alerting",
|
||||
"lastEvaluation": "0001-01-01T00:00:00Z",
|
||||
"evaluationTime": 0
|
||||
@ -456,9 +448,7 @@ func TestPrometheusRulesFilterByDashboard(t *testing.T) {
|
||||
"state": "inactive",
|
||||
"name": "AlwaysFiringButSilenced",
|
||||
"query": "[{\"refId\":\"A\",\"queryType\":\"\",\"relativeTimeRange\":{\"from\":18000,\"to\":10800},\"datasourceUid\":\"-100\",\"model\":{\"expression\":\"2 + 3 \\u003e 1\",\"intervalMs\":1000,\"maxDataPoints\":43200,\"type\":\"math\"}}]",
|
||||
"labels": null,
|
||||
"health": "ok",
|
||||
"lastError": "",
|
||||
"type": "alerting",
|
||||
"lastEvaluation": "0001-01-01T00:00:00Z",
|
||||
"evaluationTime": 0
|
||||
@ -485,9 +475,7 @@ func TestPrometheusRulesFilterByDashboard(t *testing.T) {
|
||||
"__dashboardUid__": "%s",
|
||||
"__panelId__": "1"
|
||||
},
|
||||
"labels": null,
|
||||
"health": "ok",
|
||||
"lastError": "",
|
||||
"type": "alerting",
|
||||
"lastEvaluation": "0001-01-01T00:00:00Z",
|
||||
"evaluationTime": 0
|
||||
@ -694,7 +682,6 @@ func TestPrometheusRulesPermissions(t *testing.T) {
|
||||
"label1": "val1"
|
||||
},
|
||||
"health": "ok",
|
||||
"lastError": "",
|
||||
"type": "alerting",
|
||||
"lastEvaluation": "0001-01-01T00:00:00Z",
|
||||
"evaluationTime": 0
|
||||
@ -718,7 +705,6 @@ func TestPrometheusRulesPermissions(t *testing.T) {
|
||||
"label1": "val1"
|
||||
},
|
||||
"health": "ok",
|
||||
"lastError": "",
|
||||
"type": "alerting",
|
||||
"lastEvaluation": "0001-01-01T00:00:00Z",
|
||||
"evaluationTime": 0
|
||||
@ -767,7 +753,6 @@ func TestPrometheusRulesPermissions(t *testing.T) {
|
||||
"label1": "val1"
|
||||
},
|
||||
"health": "ok",
|
||||
"lastError": "",
|
||||
"type": "alerting",
|
||||
"lastEvaluation": "0001-01-01T00:00:00Z",
|
||||
"evaluationTime": 0
|
||||
|
File diff suppressed because it is too large
Load Diff
2815
public/api-spec.json
2815
public/api-spec.json
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user