Alerting: Remove dependency on alerting package in definitions (#65390)

* move export rules to definitions package
* move provisioning contact point methods to provisioning package
* move AlertRuleGroupWithFolderTitle to ngalert models and adapter functions to api's compat
* move rule_types files back to where they were before.
This commit is contained in:
Yuri Tseretyan
2023-03-29 13:34:59 -04:00
committed by GitHub
parent d23ebf63d2
commit 9eaffdf5a8
11 changed files with 233 additions and 238 deletions
+5 -6
View File
@@ -14,7 +14,6 @@ import (
alerting_models "github.com/grafana/grafana/pkg/services/ngalert/models"
"github.com/grafana/grafana/pkg/services/ngalert/provisioning"
"github.com/grafana/grafana/pkg/services/ngalert/store"
"github.com/grafana/grafana/pkg/services/provisioning/alerting/file"
"github.com/grafana/grafana/pkg/util"
)
@@ -64,8 +63,8 @@ type AlertRuleService interface {
GetRuleGroup(ctx context.Context, orgID int64, folder, group string) (alerting_models.AlertRuleGroup, error)
ReplaceRuleGroup(ctx context.Context, orgID int64, group alerting_models.AlertRuleGroup, userID int64, provenance alerting_models.Provenance) error
GetAlertRuleWithFolderTitle(ctx context.Context, orgID int64, ruleUID string) (provisioning.AlertRuleWithFolderTitle, error)
GetAlertRuleGroupWithFolderTitle(ctx context.Context, orgID int64, folder, group string) (file.AlertRuleGroupWithFolderTitle, error)
GetAlertGroupsWithFolderTitle(ctx context.Context, orgID int64) ([]file.AlertRuleGroupWithFolderTitle, error)
GetAlertRuleGroupWithFolderTitle(ctx context.Context, orgID int64, folder, group string) (alerting_models.AlertRuleGroupWithFolderTitle, error)
GetAlertGroupsWithFolderTitle(ctx context.Context, orgID int64) ([]alerting_models.AlertRuleGroupWithFolderTitle, error)
}
func (srv *ProvisioningSrv) RouteGetPolicyTree(c *contextmodel.ReqContext) response.Response {
@@ -347,7 +346,7 @@ func (srv *ProvisioningSrv) RouteGetAlertRulesExport(c *contextmodel.ReqContext)
return ErrResp(http.StatusInternalServerError, err, "failed to get alert rules")
}
e, err := file.NewAlertingFileExport(groupsWithTitle)
e, err := AlertingFileExportFromAlertRuleGroupWithFolderTitle(groupsWithTitle)
if err != nil {
return ErrResp(http.StatusInternalServerError, err, "failed to create alerting file export")
}
@@ -365,7 +364,7 @@ func (srv *ProvisioningSrv) RouteGetAlertRuleGroupExport(c *contextmodel.ReqCont
return ErrResp(http.StatusInternalServerError, err, "failed to get alert rule group")
}
e, err := file.NewAlertingFileExport([]file.AlertRuleGroupWithFolderTitle{g})
e, err := AlertingFileExportFromAlertRuleGroupWithFolderTitle([]alerting_models.AlertRuleGroupWithFolderTitle{g})
if err != nil {
return ErrResp(http.StatusInternalServerError, err, "failed to create alerting file export")
}
@@ -383,7 +382,7 @@ func (srv *ProvisioningSrv) RouteGetAlertRuleExport(c *contextmodel.ReqContext,
return ErrResp(http.StatusInternalServerError, err, "")
}
e, err := file.NewAlertingFileExport([]file.AlertRuleGroupWithFolderTitle{{
e, err := AlertingFileExportFromAlertRuleGroupWithFolderTitle([]alerting_models.AlertRuleGroupWithFolderTitle{{
AlertRuleGroup: &alerting_models.AlertRuleGroup{
Title: rule.AlertRule.RuleGroup,
FolderUID: rule.AlertRule.NamespaceUID,
+90
View File
@@ -1,6 +1,7 @@
package api
import (
"encoding/json"
"time"
"github.com/prometheus/common/model"
@@ -125,3 +126,92 @@ func ApiAlertRuleGroupFromAlertRuleGroup(d models.AlertRuleGroup) definitions.Al
Rules: rules,
}
}
// AlertingFileExportFromAlertRuleGroupWithFolderTitle creates an definitions.AlertingFileExport DTO from []models.AlertRuleGroupWithFolderTitle.
func AlertingFileExportFromAlertRuleGroupWithFolderTitle(groups []models.AlertRuleGroupWithFolderTitle) (definitions.AlertingFileExport, error) {
f := definitions.AlertingFileExport{APIVersion: 1}
for _, group := range groups {
export, err := AlertRuleGroupExportFromAlertRuleGroupWithFolderTitle(group)
if err != nil {
return definitions.AlertingFileExport{}, err
}
f.Groups = append(f.Groups, export)
}
return f, nil
}
// AlertRuleGroupExportFromAlertRuleGroupWithFolderTitle creates a definitions.AlertRuleGroupExport DTO from models.AlertRuleGroup.
func AlertRuleGroupExportFromAlertRuleGroupWithFolderTitle(d models.AlertRuleGroupWithFolderTitle) (definitions.AlertRuleGroupExport, error) {
rules := make([]definitions.AlertRuleExport, 0, len(d.Rules))
for i := range d.Rules {
alert, err := AlertRuleExportFromAlertRule(d.Rules[i])
if err != nil {
return definitions.AlertRuleGroupExport{}, err
}
rules = append(rules, alert)
}
return definitions.AlertRuleGroupExport{
OrgID: d.OrgID,
Name: d.Title,
Folder: d.FolderTitle,
Interval: model.Duration(time.Duration(d.Interval) * time.Second),
Rules: rules,
}, nil
}
// AlertRuleExportFromAlertRule creates a definitions.AlertRuleExport DTO from models.AlertRule.
func AlertRuleExportFromAlertRule(rule models.AlertRule) (definitions.AlertRuleExport, error) {
data := make([]definitions.AlertQueryExport, 0, len(rule.Data))
for i := range rule.Data {
query, err := AlertQueryExportFromAlertQuery(rule.Data[i])
if err != nil {
return definitions.AlertRuleExport{}, err
}
data = append(data, query)
}
var dashboardUID string
if rule.DashboardUID != nil {
dashboardUID = *rule.DashboardUID
}
var panelID int64
if rule.PanelID != nil {
panelID = *rule.PanelID
}
return definitions.AlertRuleExport{
UID: rule.UID,
Title: rule.Title,
For: model.Duration(rule.For),
Condition: rule.Condition,
Data: data,
DashboardUID: dashboardUID,
PanelID: panelID,
NoDataState: definitions.NoDataState(rule.NoDataState),
ExecErrState: definitions.ExecutionErrorState(rule.ExecErrState),
Annotations: rule.Annotations,
Labels: rule.Labels,
IsPaused: rule.IsPaused,
}, nil
}
// AlertQueryExportFromAlertQuery creates a definitions.AlertQueryExport DTO from models.AlertQuery.
func AlertQueryExportFromAlertQuery(query models.AlertQuery) (definitions.AlertQueryExport, error) {
// We unmarshal the json.RawMessage model into a map in order to facilitate yaml marshalling.
var mdl map[string]interface{}
err := json.Unmarshal(query.Model, &mdl)
if err != nil {
return definitions.AlertQueryExport{}, err
}
return definitions.AlertQueryExport{
RefID: query.RefID,
QueryType: query.QueryType,
RelativeTimeRange: definitions.RelativeTimeRange{
From: definitions.Duration(query.RelativeTimeRange.From),
To: definitions.Duration(query.RelativeTimeRange.To),
},
DatasourceUID: query.DatasourceUID,
Model: mdl,
}, nil
}
@@ -4,8 +4,6 @@ import (
"time"
"github.com/prometheus/common/model"
"github.com/grafana/grafana/pkg/services/provisioning/alerting/file"
)
// swagger:route GET /api/v1/provisioning/alert-rules provisioning stable RouteGetAlertRules
@@ -217,4 +215,41 @@ type AlertRuleGroup struct {
// AlertingFileExport is the full provisioned file export.
// swagger:model
type AlertingFileExport = file.AlertingFileExport
type AlertingFileExport struct {
APIVersion int64 `json:"apiVersion" yaml:"apiVersion"`
Groups []AlertRuleGroupExport `json:"groups" yaml:"groups"`
}
// AlertRuleGroupExport is the provisioned file export of AlertRuleGroupV1.
type AlertRuleGroupExport struct {
OrgID int64 `json:"orgId" yaml:"orgId"`
Name string `json:"name" yaml:"name"`
Folder string `json:"folder" yaml:"folder"`
Interval model.Duration `json:"interval" yaml:"interval"`
Rules []AlertRuleExport `json:"rules" yaml:"rules"`
}
// AlertRuleExport is the provisioned file export of models.AlertRule.
type AlertRuleExport struct {
UID string `json:"uid" yaml:"uid"`
Title string `json:"title" yaml:"title"`
Condition string `json:"condition" yaml:"condition"`
Data []AlertQueryExport `json:"data" yaml:"data"`
DashboardUID string `json:"dasboardUid,omitempty" yaml:"dashboardUid,omitempty"`
PanelID int64 `json:"panelId,omitempty" yaml:"panelId,omitempty"`
NoDataState NoDataState `json:"noDataState" yaml:"noDataState"`
ExecErrState ExecutionErrorState `json:"execErrState" yaml:"execErrState"`
For model.Duration `json:"for" yaml:"for"`
Annotations map[string]string `json:"annotations,omitempty" yaml:"annotations,omitempty"`
Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"`
IsPaused bool `json:"isPaused" yaml:"isPaused"`
}
// AlertQueryExport is the provisioned export of models.AlertQuery.
type AlertQueryExport struct {
RefID string `json:"refId" yaml:"refId"`
QueryType string `json:"queryType,omitempty" yaml:"queryType,omitempty"`
RelativeTimeRange RelativeTimeRange `json:"relativeTimeRange,omitempty" yaml:"relativeTimeRange,omitempty"`
DatasourceUID string `json:"datasourceUid" yaml:"datasourceUid"`
Model map[string]interface{} `json:"model" yaml:"model"`
}
@@ -1,15 +1,7 @@
package definitions
import (
"fmt"
"github.com/grafana/alerting/logging"
alertingNotify "github.com/grafana/alerting/notify"
"github.com/grafana/alerting/receivers"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/services/ngalert/notifier/channels_config"
"github.com/grafana/grafana/pkg/setting"
)
// swagger:route GET /api/v1/provisioning/contact-points provisioning stable RouteGetContactpoints
@@ -101,63 +93,6 @@ type EmbeddedContactPoint struct {
const RedactedValue = "[REDACTED]"
func (e *EmbeddedContactPoint) Valid(decryptFunc receivers.GetDecryptedValueFn) error {
if e.Type == "" {
return fmt.Errorf("type should not be an empty string")
}
if e.Settings == nil {
return fmt.Errorf("settings should not be empty")
}
factory, exists := alertingNotify.Factory(e.Type)
if !exists {
return fmt.Errorf("unknown type '%s'", e.Type)
}
jsonBytes, err := e.Settings.MarshalJSON()
if err != nil {
return err
}
cfg, _ := receivers.NewFactoryConfig(&receivers.NotificationChannelConfig{
Settings: jsonBytes,
Type: e.Type,
}, nil, decryptFunc, nil, nil, func(ctx ...interface{}) logging.Logger {
return &logging.FakeLogger{}
}, setting.BuildVersion)
if _, err := factory(cfg); err != nil {
return err
}
return nil
}
func (e *EmbeddedContactPoint) SecretKeys() ([]string, error) {
notifiers := channels_config.GetAvailableNotifiers()
for _, n := range notifiers {
if n.Type == e.Type {
secureFields := []string{}
for _, field := range n.Options {
if field.Secure {
secureFields = append(secureFields, field.PropertyName)
}
}
return secureFields, nil
}
}
return nil, fmt.Errorf("no secrets configured for type '%s'", e.Type)
}
func (e *EmbeddedContactPoint) ExtractSecrets() (map[string]string, error) {
secrets := map[string]string{}
secretKeys, err := e.SecretKeys()
if err != nil {
return nil, err
}
for _, secretKey := range secretKeys {
secretValue := e.Settings.Get(secretKey).MustString()
e.Settings.Del(secretKey)
secrets[secretKey] = secretValue
}
return secrets, nil
}
func (e *EmbeddedContactPoint) ResourceID() string {
return e.UID
}