2020-11-12 07:11:30 -06:00
|
|
|
package ngalert
|
|
|
|
|
|
|
|
import (
|
2020-12-17 08:00:09 -06:00
|
|
|
"context"
|
2022-07-12 14:13:04 -05:00
|
|
|
"fmt"
|
2021-09-30 11:51:20 -05:00
|
|
|
"net/url"
|
2023-01-26 03:31:20 -06:00
|
|
|
"time"
|
2020-12-17 08:00:09 -06:00
|
|
|
|
2021-10-07 09:33:50 -05:00
|
|
|
"github.com/benbjohnson/clock"
|
2022-03-08 08:22:16 -06:00
|
|
|
"golang.org/x/sync/errgroup"
|
|
|
|
|
2020-11-12 07:11:30 -06:00
|
|
|
"github.com/grafana/grafana/pkg/api/routing"
|
2022-06-17 12:10:49 -05:00
|
|
|
"github.com/grafana/grafana/pkg/bus"
|
2022-08-01 18:28:38 -05:00
|
|
|
"github.com/grafana/grafana/pkg/events"
|
2021-11-10 04:52:16 -06:00
|
|
|
"github.com/grafana/grafana/pkg/expr"
|
2022-10-19 08:02:15 -05:00
|
|
|
"github.com/grafana/grafana/pkg/infra/db"
|
2021-09-09 11:25:22 -05:00
|
|
|
"github.com/grafana/grafana/pkg/infra/kvstore"
|
2020-11-12 07:11:30 -06:00
|
|
|
"github.com/grafana/grafana/pkg/infra/log"
|
2023-01-06 20:21:43 -06:00
|
|
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
2022-12-08 03:44:02 -06:00
|
|
|
"github.com/grafana/grafana/pkg/plugins"
|
2022-03-08 08:22:16 -06:00
|
|
|
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
2022-09-19 02:54:37 -05:00
|
|
|
"github.com/grafana/grafana/pkg/services/annotations"
|
2022-02-16 07:15:44 -06:00
|
|
|
"github.com/grafana/grafana/pkg/services/dashboards"
|
2021-03-24 09:20:44 -05:00
|
|
|
"github.com/grafana/grafana/pkg/services/datasourceproxy"
|
2020-11-12 07:11:30 -06:00
|
|
|
"github.com/grafana/grafana/pkg/services/datasources"
|
2022-10-06 01:22:58 -05:00
|
|
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
2022-10-10 14:47:53 -05:00
|
|
|
"github.com/grafana/grafana/pkg/services/folder"
|
2021-09-09 11:25:22 -05:00
|
|
|
"github.com/grafana/grafana/pkg/services/ngalert/api"
|
|
|
|
"github.com/grafana/grafana/pkg/services/ngalert/eval"
|
2022-05-22 09:33:49 -05:00
|
|
|
"github.com/grafana/grafana/pkg/services/ngalert/image"
|
2021-09-09 11:25:22 -05:00
|
|
|
"github.com/grafana/grafana/pkg/services/ngalert/metrics"
|
2022-08-01 18:28:38 -05:00
|
|
|
"github.com/grafana/grafana/pkg/services/ngalert/models"
|
2021-03-24 09:20:44 -05:00
|
|
|
"github.com/grafana/grafana/pkg/services/ngalert/notifier"
|
2022-04-05 16:48:51 -05:00
|
|
|
"github.com/grafana/grafana/pkg/services/ngalert/provisioning"
|
2021-03-24 09:20:44 -05:00
|
|
|
"github.com/grafana/grafana/pkg/services/ngalert/schedule"
|
2022-07-12 14:13:04 -05:00
|
|
|
"github.com/grafana/grafana/pkg/services/ngalert/sender"
|
2021-09-09 11:25:22 -05:00
|
|
|
"github.com/grafana/grafana/pkg/services/ngalert/state"
|
2022-10-05 15:32:20 -05:00
|
|
|
"github.com/grafana/grafana/pkg/services/ngalert/state/historian"
|
2021-09-09 11:25:22 -05:00
|
|
|
"github.com/grafana/grafana/pkg/services/ngalert/store"
|
2022-01-26 09:42:40 -06:00
|
|
|
"github.com/grafana/grafana/pkg/services/notifications"
|
2021-09-09 11:25:22 -05:00
|
|
|
"github.com/grafana/grafana/pkg/services/quota"
|
2022-05-22 09:33:49 -05:00
|
|
|
"github.com/grafana/grafana/pkg/services/rendering"
|
2021-11-04 11:47:21 -05:00
|
|
|
"github.com/grafana/grafana/pkg/services/secrets"
|
2020-11-12 07:11:30 -06:00
|
|
|
"github.com/grafana/grafana/pkg/setting"
|
|
|
|
)
|
|
|
|
|
2022-10-06 01:22:58 -05:00
|
|
|
func ProvideService(
|
|
|
|
cfg *setting.Cfg,
|
|
|
|
featureToggles featuremgmt.FeatureToggles,
|
|
|
|
dataSourceCache datasources.CacheService,
|
|
|
|
dataSourceService datasources.DataSourceService,
|
|
|
|
routeRegister routing.RouteRegister,
|
2022-10-19 08:02:15 -05:00
|
|
|
sqlStore db.DB,
|
2022-10-06 01:22:58 -05:00
|
|
|
kvStore kvstore.KVStore,
|
|
|
|
expressionService *expr.Service,
|
|
|
|
dataProxy *datasourceproxy.DataSourceProxyService,
|
|
|
|
quotaService quota.Service,
|
|
|
|
secretsService secrets.Service,
|
|
|
|
notificationService notifications.Service,
|
|
|
|
m *metrics.NGAlert,
|
2022-10-10 14:47:53 -05:00
|
|
|
folderService folder.Service,
|
2022-10-06 01:22:58 -05:00
|
|
|
ac accesscontrol.AccessControl,
|
|
|
|
dashboardService dashboards.DashboardService,
|
|
|
|
renderService rendering.Service,
|
|
|
|
bus bus.Bus,
|
|
|
|
accesscontrolService accesscontrol.Service,
|
|
|
|
annotationsRepo annotations.Repository,
|
2022-12-08 03:44:02 -06:00
|
|
|
pluginsStore plugins.Store,
|
2023-01-06 20:21:43 -06:00
|
|
|
tracer tracing.Tracer,
|
2022-10-06 01:22:58 -05:00
|
|
|
) (*AlertNG, error) {
|
2021-08-25 08:11:22 -05:00
|
|
|
ng := &AlertNG{
|
2022-08-26 02:59:34 -05:00
|
|
|
Cfg: cfg,
|
2022-10-06 01:22:58 -05:00
|
|
|
FeatureToggles: featureToggles,
|
2022-08-26 02:59:34 -05:00
|
|
|
DataSourceCache: dataSourceCache,
|
|
|
|
DataSourceService: dataSourceService,
|
|
|
|
RouteRegister: routeRegister,
|
|
|
|
SQLStore: sqlStore,
|
|
|
|
KVStore: kvStore,
|
|
|
|
ExpressionService: expressionService,
|
|
|
|
DataProxy: dataProxy,
|
|
|
|
QuotaService: quotaService,
|
|
|
|
SecretsService: secretsService,
|
|
|
|
Metrics: m,
|
|
|
|
Log: log.New("ngalert"),
|
|
|
|
NotificationService: notificationService,
|
|
|
|
folderService: folderService,
|
|
|
|
accesscontrol: ac,
|
|
|
|
dashboardService: dashboardService,
|
|
|
|
renderService: renderService,
|
|
|
|
bus: bus,
|
|
|
|
accesscontrolService: accesscontrolService,
|
2022-09-19 02:54:37 -05:00
|
|
|
annotationsRepo: annotationsRepo,
|
2022-12-08 03:44:02 -06:00
|
|
|
pluginsStore: pluginsStore,
|
2023-01-06 20:21:43 -06:00
|
|
|
tracer: tracer,
|
2021-08-25 08:11:22 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if ng.IsDisabled() {
|
|
|
|
return ng, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := ng.init(); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return ng, nil
|
|
|
|
}
|
|
|
|
|
2020-11-12 07:11:30 -06:00
|
|
|
// AlertNG is the service for evaluating the condition of an alert definition.
|
|
|
|
type AlertNG struct {
|
2022-01-26 09:42:40 -06:00
|
|
|
Cfg *setting.Cfg
|
2022-10-06 01:22:58 -05:00
|
|
|
FeatureToggles featuremgmt.FeatureToggles
|
2022-01-26 09:42:40 -06:00
|
|
|
DataSourceCache datasources.CacheService
|
2022-07-20 09:50:49 -05:00
|
|
|
DataSourceService datasources.DataSourceService
|
2022-01-26 09:42:40 -06:00
|
|
|
RouteRegister routing.RouteRegister
|
2022-10-14 14:33:06 -05:00
|
|
|
SQLStore db.DB
|
2022-01-26 09:42:40 -06:00
|
|
|
KVStore kvstore.KVStore
|
|
|
|
ExpressionService *expr.Service
|
|
|
|
DataProxy *datasourceproxy.DataSourceProxyService
|
2022-07-15 11:06:44 -05:00
|
|
|
QuotaService quota.Service
|
2022-01-26 09:42:40 -06:00
|
|
|
SecretsService secrets.Service
|
|
|
|
Metrics *metrics.NGAlert
|
|
|
|
NotificationService notifications.Service
|
|
|
|
Log log.Logger
|
2022-05-22 09:33:49 -05:00
|
|
|
renderService rendering.Service
|
|
|
|
imageService image.ImageService
|
2022-01-26 09:42:40 -06:00
|
|
|
schedule schedule.ScheduleService
|
|
|
|
stateManager *state.Manager
|
2022-10-10 14:47:53 -05:00
|
|
|
folderService folder.Service
|
2022-05-17 13:52:22 -05:00
|
|
|
dashboardService dashboards.DashboardService
|
2021-08-06 07:06:56 -05:00
|
|
|
|
|
|
|
// Alerting notification services
|
2021-08-24 05:28:09 -05:00
|
|
|
MultiOrgAlertmanager *notifier.MultiOrgAlertmanager
|
2022-07-12 14:13:04 -05:00
|
|
|
AlertsRouter *sender.AlertsRouter
|
2022-03-08 08:22:16 -06:00
|
|
|
accesscontrol accesscontrol.AccessControl
|
2022-08-26 02:59:34 -05:00
|
|
|
accesscontrolService accesscontrol.Service
|
2022-09-19 02:54:37 -05:00
|
|
|
annotationsRepo annotations.Repository
|
2022-11-04 13:23:08 -05:00
|
|
|
store *store.DBstore
|
2022-06-17 12:10:49 -05:00
|
|
|
|
2022-12-08 03:44:02 -06:00
|
|
|
bus bus.Bus
|
|
|
|
pluginsStore plugins.Store
|
2023-01-06 20:21:43 -06:00
|
|
|
tracer tracing.Tracer
|
2020-11-12 07:11:30 -06:00
|
|
|
}
|
|
|
|
|
2021-08-25 08:11:22 -05:00
|
|
|
func (ng *AlertNG) init() error {
|
2021-09-16 09:33:51 -05:00
|
|
|
var err error
|
|
|
|
|
2023-01-26 03:31:20 -06:00
|
|
|
// AlertNG should be initialized before the cancellation deadline of initCtx
|
|
|
|
initCtx, cancelFunc := context.WithTimeout(context.Background(), 30*time.Second)
|
|
|
|
defer cancelFunc()
|
|
|
|
|
2021-05-14 15:13:44 -05:00
|
|
|
store := &store.DBstore{
|
2022-07-15 13:13:30 -05:00
|
|
|
Cfg: ng.Cfg.UnifiedAlerting,
|
2022-10-06 01:22:58 -05:00
|
|
|
FeatureToggles: ng.FeatureToggles,
|
2022-05-24 08:24:55 -05:00
|
|
|
SQLStore: ng.SQLStore,
|
|
|
|
Logger: ng.Log,
|
|
|
|
FolderService: ng.folderService,
|
|
|
|
AccessControl: ng.accesscontrol,
|
|
|
|
DashboardService: ng.dashboardService,
|
2021-05-14 15:13:44 -05:00
|
|
|
}
|
2022-11-04 13:23:08 -05:00
|
|
|
ng.store = store
|
2021-05-13 13:01:38 -05:00
|
|
|
|
2021-11-04 11:47:21 -05:00
|
|
|
decryptFn := ng.SecretsService.GetDecryptedValue
|
2021-09-16 09:33:51 -05:00
|
|
|
multiOrgMetrics := ng.Metrics.GetMultiOrgAlertmanagerMetrics()
|
2022-04-22 11:57:56 -05:00
|
|
|
ng.MultiOrgAlertmanager, err = notifier.NewMultiOrgAlertmanager(ng.Cfg, store, store, ng.KVStore, store, decryptFn, multiOrgMetrics, ng.NotificationService, log.New("ngalert.multiorg.alertmanager"), ng.SecretsService)
|
2021-09-16 09:33:51 -05:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-08-24 05:28:09 -05:00
|
|
|
|
2022-09-21 04:25:07 -05:00
|
|
|
imageService, err := image.NewScreenshotImageServiceFromCfg(ng.Cfg, store, ng.dashboardService, ng.renderService, ng.Metrics.Registerer)
|
2022-05-22 09:33:49 -05:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
ng.imageService = imageService
|
|
|
|
|
2021-08-24 05:28:09 -05:00
|
|
|
// Let's make sure we're able to complete an initial sync of Alertmanagers before we start the alerting components.
|
2023-01-26 03:31:20 -06:00
|
|
|
if err := ng.MultiOrgAlertmanager.LoadAndSyncAlertmanagersForOrgs(initCtx); err != nil {
|
2022-07-12 14:13:04 -05:00
|
|
|
return fmt.Errorf("failed to initialize alerting because multiorg alertmanager manager failed to warm up: %w", err)
|
2021-01-22 11:27:33 -06:00
|
|
|
}
|
2021-09-30 11:51:20 -05:00
|
|
|
|
|
|
|
appUrl, err := url.Parse(ng.Cfg.AppURL)
|
|
|
|
if err != nil {
|
2022-10-19 16:36:54 -05:00
|
|
|
ng.Log.Error("Failed to parse application URL. Continue without it.", "error", err)
|
2021-09-30 11:51:20 -05:00
|
|
|
appUrl = nil
|
|
|
|
}
|
2022-05-22 09:33:49 -05:00
|
|
|
|
2022-07-12 14:13:04 -05:00
|
|
|
clk := clock.New()
|
|
|
|
|
2022-07-20 09:50:49 -05:00
|
|
|
alertsRouter := sender.NewAlertsRouter(ng.MultiOrgAlertmanager, store, clk, appUrl, ng.Cfg.UnifiedAlerting.DisabledOrgs,
|
|
|
|
ng.Cfg.UnifiedAlerting.AdminConfigPollInterval, ng.DataSourceService, ng.SecretsService)
|
2022-07-12 14:13:04 -05:00
|
|
|
|
|
|
|
// Make sure we sync at least once as Grafana starts to get the router up and running before we start sending any alerts.
|
|
|
|
if err := alertsRouter.SyncAndApplyConfigFromDatabase(); err != nil {
|
|
|
|
return fmt.Errorf("failed to initialize alerting because alert notifications router failed to warm up: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
ng.AlertsRouter = alertsRouter
|
|
|
|
|
2022-12-08 03:44:02 -06:00
|
|
|
evalFactory := eval.NewEvaluatorFactory(ng.Cfg.UnifiedAlerting, ng.DataSourceCache, ng.ExpressionService, ng.pluginsStore)
|
2022-07-12 14:13:04 -05:00
|
|
|
schedCfg := schedule.SchedulerCfg{
|
2022-12-02 16:02:07 -06:00
|
|
|
MaxAttempts: ng.Cfg.UnifiedAlerting.MaxAttempts,
|
|
|
|
C: clk,
|
|
|
|
BaseInterval: ng.Cfg.UnifiedAlerting.BaseInterval,
|
|
|
|
MinRuleInterval: ng.Cfg.UnifiedAlerting.MinInterval,
|
|
|
|
DisableGrafanaFolder: ng.Cfg.UnifiedAlerting.ReservedLabels.IsReservedLabelDisabled(models.FolderTitleLabel),
|
|
|
|
AppURL: appUrl,
|
|
|
|
EvaluatorFactory: evalFactory,
|
|
|
|
RuleStore: store,
|
|
|
|
Metrics: ng.Metrics.GetSchedulerMetrics(),
|
|
|
|
AlertSender: alertsRouter,
|
2023-01-06 20:21:43 -06:00
|
|
|
Tracer: ng.tracer,
|
2022-07-12 14:13:04 -05:00
|
|
|
}
|
|
|
|
|
2023-03-13 15:54:46 -05:00
|
|
|
history, err := configureHistorianBackend(initCtx, ng.Cfg.UnifiedAlerting.StateHistory, ng.annotationsRepo, ng.dashboardService, ng.store, ng.Metrics.GetHistorianMetrics(), ng.Log)
|
2023-01-06 12:06:01 -06:00
|
|
|
if err != nil {
|
|
|
|
return err
|
2023-01-05 12:21:07 -06:00
|
|
|
}
|
2023-01-10 15:26:15 -06:00
|
|
|
cfg := state.ManagerCfg{
|
2023-01-13 17:29:29 -06:00
|
|
|
Metrics: ng.Metrics.GetStateMetrics(),
|
|
|
|
ExternalURL: appUrl,
|
|
|
|
InstanceStore: store,
|
|
|
|
Images: ng.imageService,
|
|
|
|
Clock: clk,
|
|
|
|
Historian: history,
|
|
|
|
DoNotSaveNormalState: ng.FeatureToggles.IsEnabled(featuremgmt.FlagAlertingNoNormalState),
|
2023-01-10 15:26:15 -06:00
|
|
|
}
|
|
|
|
stateManager := state.NewManager(cfg)
|
2022-12-02 16:02:07 -06:00
|
|
|
scheduler := schedule.NewScheduler(schedCfg, stateManager)
|
2022-08-01 18:28:38 -05:00
|
|
|
|
|
|
|
// if it is required to include folder title to the alerts, we need to subscribe to changes of alert title
|
|
|
|
if !ng.Cfg.UnifiedAlerting.ReservedLabels.IsReservedLabelDisabled(models.FolderTitleLabel) {
|
2023-01-26 03:31:20 -06:00
|
|
|
subscribeToFolderChanges(context.Background(), ng.Log, ng.bus, store, scheduler)
|
2022-08-01 18:28:38 -05:00
|
|
|
}
|
2021-08-13 07:14:36 -05:00
|
|
|
|
2021-08-25 08:11:22 -05:00
|
|
|
ng.stateManager = stateManager
|
2021-09-30 11:51:20 -05:00
|
|
|
ng.schedule = scheduler
|
2021-03-03 09:52:19 -06:00
|
|
|
|
2022-04-05 16:48:51 -05:00
|
|
|
// Provisioning
|
2022-07-08 16:23:18 -05:00
|
|
|
policyService := provisioning.NewNotificationPolicyService(store, store, store, ng.Cfg.UnifiedAlerting, ng.Log)
|
2022-04-13 15:15:55 -05:00
|
|
|
contactPointService := provisioning.NewContactPointService(store, ng.SecretsService, store, store, ng.Log)
|
2022-04-28 13:51:57 -05:00
|
|
|
templateService := provisioning.NewTemplateService(store, store, store, ng.Log)
|
2022-05-17 13:42:48 -05:00
|
|
|
muteTimingService := provisioning.NewMuteTimingService(store, store, store, ng.Log)
|
2023-01-27 10:39:16 -06:00
|
|
|
alertRuleService := provisioning.NewAlertRuleService(store, store, ng.dashboardService, ng.QuotaService, store,
|
2022-06-09 02:28:32 -05:00
|
|
|
int64(ng.Cfg.UnifiedAlerting.DefaultRuleEvaluationInterval.Seconds()),
|
|
|
|
int64(ng.Cfg.UnifiedAlerting.BaseInterval.Seconds()), ng.Log)
|
2022-04-05 16:48:51 -05:00
|
|
|
|
2021-03-08 14:19:21 -06:00
|
|
|
api := api.API{
|
2021-08-24 05:28:09 -05:00
|
|
|
Cfg: ng.Cfg,
|
2021-08-25 08:11:22 -05:00
|
|
|
DatasourceCache: ng.DataSourceCache,
|
2022-07-20 09:50:49 -05:00
|
|
|
DatasourceService: ng.DataSourceService,
|
2021-08-24 05:28:09 -05:00
|
|
|
RouteRegister: ng.RouteRegister,
|
|
|
|
Schedule: ng.schedule,
|
|
|
|
DataProxy: ng.DataProxy,
|
|
|
|
QuotaService: ng.QuotaService,
|
2022-03-15 11:48:42 -05:00
|
|
|
TransactionManager: store,
|
2021-08-24 05:28:09 -05:00
|
|
|
RuleStore: store,
|
|
|
|
AlertingStore: store,
|
|
|
|
AdminConfigStore: store,
|
2022-04-28 14:27:34 -05:00
|
|
|
ProvenanceStore: store,
|
2021-08-24 05:28:09 -05:00
|
|
|
MultiOrgAlertmanager: ng.MultiOrgAlertmanager,
|
|
|
|
StateManager: ng.stateManager,
|
2022-03-08 08:22:16 -06:00
|
|
|
AccessControl: ng.accesscontrol,
|
2022-04-05 16:48:51 -05:00
|
|
|
Policies: policyService,
|
2022-04-13 15:15:55 -05:00
|
|
|
ContactPointService: contactPointService,
|
2022-04-28 13:51:57 -05:00
|
|
|
Templates: templateService,
|
2022-05-17 13:42:48 -05:00
|
|
|
MuteTimings: muteTimingService,
|
2022-06-02 07:48:53 -05:00
|
|
|
AlertRules: alertRuleService,
|
2022-07-12 14:13:04 -05:00
|
|
|
AlertsRouter: alertsRouter,
|
2022-11-02 09:13:39 -05:00
|
|
|
EvaluatorFactory: evalFactory,
|
2022-12-14 08:44:14 -06:00
|
|
|
FeatureManager: ng.FeatureToggles,
|
|
|
|
AppUrl: appUrl,
|
2023-02-02 11:34:00 -06:00
|
|
|
Historian: history,
|
2021-03-24 09:20:44 -05:00
|
|
|
}
|
2021-09-14 06:55:01 -05:00
|
|
|
api.RegisterAPIEndpoints(ng.Metrics.GetAPIMetrics())
|
2021-03-03 09:52:19 -06:00
|
|
|
|
2022-11-14 13:08:10 -06:00
|
|
|
defaultLimits, err := readQuotaConfig(ng.Cfg)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := ng.QuotaService.RegisterQuotaReporter("a.NewUsageReporter{
|
|
|
|
TargetSrv: models.QuotaTargetSrv,
|
|
|
|
DefaultLimits: defaultLimits,
|
|
|
|
Reporter: api.Usage,
|
|
|
|
}); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2022-10-26 18:16:02 -05:00
|
|
|
log.RegisterContextualLogProvider(func(ctx context.Context) ([]interface{}, bool) {
|
|
|
|
key, ok := models.RuleKeyFromContext(ctx)
|
|
|
|
if !ok {
|
|
|
|
return nil, false
|
|
|
|
}
|
|
|
|
return key.LogContext(), true
|
|
|
|
})
|
|
|
|
|
2022-08-26 02:59:34 -05:00
|
|
|
return DeclareFixedRoles(ng.accesscontrolService)
|
2020-11-12 07:11:30 -06:00
|
|
|
}
|
|
|
|
|
2023-01-26 03:31:20 -06:00
|
|
|
func subscribeToFolderChanges(ctx context.Context, logger log.Logger, bus bus.Bus, dbStore api.RuleStore, scheduler schedule.ScheduleService) {
|
2022-08-01 18:28:38 -05:00
|
|
|
// if folder title is changed, we update all alert rules in that folder to make sure that all peers (in HA mode) will update folder title and
|
|
|
|
// clean up the current state
|
|
|
|
bus.AddEventListener(func(ctx context.Context, e *events.FolderTitleUpdated) error {
|
|
|
|
// do not block the upstream execution
|
|
|
|
go func(evt *events.FolderTitleUpdated) {
|
2022-10-20 12:43:48 -05:00
|
|
|
logger.Info("Got folder title updated event. updating rules in the folder", "folderUID", evt.UID)
|
2023-01-26 03:31:20 -06:00
|
|
|
updated, err := dbStore.IncreaseVersionForAllRulesInNamespace(ctx, evt.OrgID, evt.UID)
|
2022-08-01 18:28:38 -05:00
|
|
|
if err != nil {
|
2022-10-20 12:43:48 -05:00
|
|
|
logger.Error("Failed to update alert rules in the folder after its title was changed", "error", err, "folderUID", evt.UID, "folder", evt.Title)
|
2022-08-01 18:28:38 -05:00
|
|
|
return
|
|
|
|
}
|
|
|
|
if len(updated) > 0 {
|
2022-10-20 12:43:48 -05:00
|
|
|
logger.Info("Rules that belong to the folder have been updated successfully. Clearing their status", "folderUID", evt.UID, "updatedRules", len(updated))
|
2022-08-01 18:28:38 -05:00
|
|
|
for _, key := range updated {
|
2023-01-26 11:29:10 -06:00
|
|
|
scheduler.UpdateAlertRule(key.AlertRuleKey, key.Version, key.IsPaused)
|
2022-08-01 18:28:38 -05:00
|
|
|
}
|
|
|
|
} else {
|
2022-10-20 12:43:48 -05:00
|
|
|
logger.Debug("No alert rules found in the folder. nothing to update", "folderUID", evt.UID, "folder", evt.Title)
|
2022-08-01 18:28:38 -05:00
|
|
|
}
|
|
|
|
}(e)
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-07-27 05:52:59 -05:00
|
|
|
// Run starts the scheduler and Alertmanager.
|
2020-12-17 08:00:09 -06:00
|
|
|
func (ng *AlertNG) Run(ctx context.Context) error {
|
2022-10-20 12:43:48 -05:00
|
|
|
ng.Log.Debug("Starting")
|
2022-11-04 13:23:08 -05:00
|
|
|
ng.stateManager.Warm(ctx, ng.store)
|
2021-05-13 13:01:38 -05:00
|
|
|
|
|
|
|
children, subCtx := errgroup.WithContext(ctx)
|
2021-09-28 05:00:16 -05:00
|
|
|
|
2022-11-04 16:06:47 -05:00
|
|
|
children.Go(func() error {
|
|
|
|
return ng.stateManager.Run(subCtx)
|
|
|
|
})
|
|
|
|
|
2022-07-12 14:13:04 -05:00
|
|
|
children.Go(func() error {
|
|
|
|
return ng.MultiOrgAlertmanager.Run(subCtx)
|
|
|
|
})
|
|
|
|
children.Go(func() error {
|
|
|
|
return ng.AlertsRouter.Run(subCtx)
|
|
|
|
})
|
|
|
|
|
2021-09-28 05:00:16 -05:00
|
|
|
if ng.Cfg.UnifiedAlerting.ExecuteAlerts {
|
|
|
|
children.Go(func() error {
|
|
|
|
return ng.schedule.Run(subCtx)
|
|
|
|
})
|
|
|
|
}
|
2021-05-13 13:01:38 -05:00
|
|
|
return children.Wait()
|
2020-12-17 08:00:09 -06:00
|
|
|
}
|
|
|
|
|
2020-11-12 07:11:30 -06:00
|
|
|
// IsDisabled returns true if the alerting service is disable for this instance.
|
|
|
|
func (ng *AlertNG) IsDisabled() bool {
|
|
|
|
if ng.Cfg == nil {
|
2020-12-17 08:00:09 -06:00
|
|
|
return true
|
2020-11-12 07:11:30 -06:00
|
|
|
}
|
2021-11-24 13:56:07 -06:00
|
|
|
return !ng.Cfg.UnifiedAlerting.IsEnabled()
|
2020-11-12 07:11:30 -06:00
|
|
|
}
|
2022-11-14 13:08:10 -06:00
|
|
|
|
|
|
|
func readQuotaConfig(cfg *setting.Cfg) (*quota.Map, error) {
|
|
|
|
limits := "a.Map{}
|
|
|
|
|
|
|
|
if cfg == nil {
|
|
|
|
return limits, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
var alertOrgQuota int64
|
|
|
|
var alertGlobalQuota int64
|
|
|
|
|
|
|
|
if cfg.UnifiedAlerting.IsEnabled() {
|
|
|
|
alertOrgQuota = cfg.Quota.Org.AlertRule
|
|
|
|
alertGlobalQuota = cfg.Quota.Global.AlertRule
|
|
|
|
}
|
|
|
|
|
|
|
|
globalQuotaTag, err := quota.NewTag(models.QuotaTargetSrv, models.QuotaTarget, quota.GlobalScope)
|
|
|
|
if err != nil {
|
|
|
|
return limits, err
|
|
|
|
}
|
|
|
|
orgQuotaTag, err := quota.NewTag(models.QuotaTargetSrv, models.QuotaTarget, quota.OrgScope)
|
|
|
|
if err != nil {
|
|
|
|
return limits, err
|
|
|
|
}
|
|
|
|
|
|
|
|
limits.Set(globalQuotaTag, alertGlobalQuota)
|
|
|
|
limits.Set(orgQuotaTag, alertOrgQuota)
|
|
|
|
return limits, nil
|
|
|
|
}
|
2023-01-06 12:06:01 -06:00
|
|
|
|
2023-02-02 11:34:00 -06:00
|
|
|
type Historian interface {
|
|
|
|
api.Historian
|
|
|
|
state.Historian
|
|
|
|
}
|
|
|
|
|
2023-03-13 15:54:46 -05:00
|
|
|
func configureHistorianBackend(ctx context.Context, cfg setting.UnifiedAlertingStateHistorySettings, ar annotations.Repository, ds dashboards.DashboardService, rs historian.RuleStore, met *metrics.Historian, l log.Logger) (Historian, error) {
|
2023-01-06 12:06:01 -06:00
|
|
|
if !cfg.Enabled {
|
2023-03-06 10:40:37 -06:00
|
|
|
met.Info.WithLabelValues("noop").Set(0)
|
2023-01-06 12:06:01 -06:00
|
|
|
return historian.NewNopHistorian(), nil
|
|
|
|
}
|
|
|
|
|
2023-03-06 10:40:37 -06:00
|
|
|
met.Info.WithLabelValues(cfg.Backend).Set(1)
|
2023-01-06 12:06:01 -06:00
|
|
|
if cfg.Backend == "annotations" {
|
2023-03-06 10:40:37 -06:00
|
|
|
return historian.NewAnnotationBackend(ar, ds, rs, met), nil
|
2023-01-06 12:06:01 -06:00
|
|
|
}
|
|
|
|
if cfg.Backend == "loki" {
|
2023-01-30 16:30:05 -06:00
|
|
|
lcfg, err := historian.NewLokiConfig(cfg)
|
2023-01-17 13:58:52 -06:00
|
|
|
if err != nil {
|
2023-01-30 16:30:05 -06:00
|
|
|
return nil, fmt.Errorf("invalid remote loki configuration: %w", err)
|
2023-01-17 13:58:52 -06:00
|
|
|
}
|
2023-02-23 17:52:02 -06:00
|
|
|
req := historian.NewRequester()
|
|
|
|
backend := historian.NewRemoteLokiBackend(lcfg, req, met)
|
2023-01-30 16:30:05 -06:00
|
|
|
|
2023-01-26 03:31:20 -06:00
|
|
|
testConnCtx, cancelFunc := context.WithTimeout(ctx, 10*time.Second)
|
|
|
|
defer cancelFunc()
|
|
|
|
if err := backend.TestConnection(testConnCtx); err != nil {
|
2023-03-13 15:54:46 -05:00
|
|
|
l.Error("Failed to communicate with configured remote Loki backend, state history may not be persisted", "error", err)
|
2023-01-17 13:58:52 -06:00
|
|
|
}
|
|
|
|
return backend, nil
|
2023-01-06 12:06:01 -06:00
|
|
|
}
|
|
|
|
if cfg.Backend == "sql" {
|
|
|
|
return historian.NewSqlBackend(), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil, fmt.Errorf("unrecognized state history backend: %s", cfg.Backend)
|
|
|
|
}
|