2020-11-12 07:11:30 -06:00
|
|
|
package ngalert
|
|
|
|
|
|
|
|
import (
|
2020-12-17 08:00:09 -06:00
|
|
|
"context"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/benbjohnson/clock"
|
2020-11-12 07:11:30 -06:00
|
|
|
"github.com/grafana/grafana/pkg/services/ngalert/eval"
|
2021-03-03 09:52:19 -06:00
|
|
|
"github.com/grafana/grafana/pkg/services/sqlstore"
|
2020-11-12 07:11:30 -06:00
|
|
|
|
|
|
|
"github.com/grafana/grafana/pkg/api/routing"
|
|
|
|
"github.com/grafana/grafana/pkg/infra/log"
|
|
|
|
"github.com/grafana/grafana/pkg/registry"
|
|
|
|
"github.com/grafana/grafana/pkg/services/datasources"
|
|
|
|
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
|
|
|
|
"github.com/grafana/grafana/pkg/setting"
|
|
|
|
)
|
|
|
|
|
2020-12-17 08:00:09 -06:00
|
|
|
const (
|
|
|
|
maxAttempts int64 = 3
|
|
|
|
// scheduler interval
|
|
|
|
// changing this value is discouraged
|
|
|
|
// because this could cause existing alert definition
|
|
|
|
// with intervals that are not exactly divided by this number
|
|
|
|
// not to be evaluated
|
|
|
|
baseIntervalSeconds = 10
|
|
|
|
// default alert definiiton interval
|
|
|
|
defaultIntervalSeconds int64 = 6 * baseIntervalSeconds
|
|
|
|
)
|
|
|
|
|
2020-11-12 07:11:30 -06:00
|
|
|
// AlertNG is the service for evaluating the condition of an alert definition.
|
|
|
|
type AlertNG struct {
|
|
|
|
Cfg *setting.Cfg `inject:""`
|
|
|
|
DatasourceCache datasources.CacheService `inject:""`
|
|
|
|
RouteRegister routing.RouteRegister `inject:""`
|
|
|
|
SQLStore *sqlstore.SQLStore `inject:""`
|
|
|
|
log log.Logger
|
2021-03-03 09:52:19 -06:00
|
|
|
schedule scheduleService
|
2020-11-12 07:11:30 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
registry.RegisterService(&AlertNG{})
|
|
|
|
}
|
|
|
|
|
|
|
|
// Init initializes the AlertingService.
|
|
|
|
func (ng *AlertNG) Init() error {
|
|
|
|
ng.log = log.New("ngalert")
|
|
|
|
|
2021-03-03 09:52:19 -06:00
|
|
|
baseInterval := baseIntervalSeconds * time.Second
|
|
|
|
|
|
|
|
store := storeImpl{baseInterval: baseInterval, SQLStore: ng.SQLStore}
|
|
|
|
|
2021-01-22 11:27:33 -06:00
|
|
|
schedCfg := schedulerCfg{
|
|
|
|
c: clock.New(),
|
2021-03-03 09:52:19 -06:00
|
|
|
baseInterval: baseInterval,
|
2021-01-22 11:27:33 -06:00
|
|
|
logger: ng.log,
|
|
|
|
evaluator: eval.Evaluator{Cfg: ng.Cfg},
|
2021-03-03 09:52:19 -06:00
|
|
|
store: store,
|
2021-01-22 11:27:33 -06:00
|
|
|
}
|
|
|
|
ng.schedule = newScheduler(schedCfg)
|
2021-03-03 09:52:19 -06:00
|
|
|
|
|
|
|
api := apiImpl{
|
|
|
|
Cfg: ng.Cfg,
|
|
|
|
DatasourceCache: ng.DatasourceCache,
|
|
|
|
RouteRegister: ng.RouteRegister,
|
|
|
|
schedule: ng.schedule,
|
|
|
|
store: store}
|
|
|
|
api.registerAPIEndpoints()
|
|
|
|
|
2020-11-12 07:11:30 -06:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-12-17 08:00:09 -06:00
|
|
|
// Run starts the scheduler
|
|
|
|
func (ng *AlertNG) Run(ctx context.Context) error {
|
|
|
|
ng.log.Debug("ngalert starting")
|
2021-03-03 09:52:19 -06:00
|
|
|
return ng.schedule.Ticker(ctx)
|
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
|
|
|
}
|
|
|
|
// Check also about expressions?
|
|
|
|
return !ng.Cfg.IsNgAlertEnabled()
|
|
|
|
}
|
|
|
|
|
|
|
|
// AddMigration defines database migrations.
|
|
|
|
// If Alerting NG is not enabled does nothing.
|
|
|
|
func (ng *AlertNG) AddMigration(mg *migrator.Migrator) {
|
|
|
|
if ng.IsDisabled() {
|
|
|
|
return
|
|
|
|
}
|
2020-12-17 08:00:09 -06:00
|
|
|
addAlertDefinitionMigrations(mg)
|
|
|
|
addAlertDefinitionVersionMigrations(mg)
|
2021-01-18 12:57:17 -06:00
|
|
|
// Create alert_instance table
|
|
|
|
alertInstanceMigration(mg)
|
2020-11-12 07:11:30 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// LoadAlertCondition returns a Condition object for the given alertDefinitionID.
|
2021-03-03 09:52:19 -06:00
|
|
|
func (api *apiImpl) LoadAlertCondition(alertDefinitionUID string, orgID int64) (*eval.Condition, error) {
|
2021-01-07 09:45:42 -06:00
|
|
|
q := getAlertDefinitionByUIDQuery{UID: alertDefinitionUID, OrgID: orgID}
|
2021-03-03 09:52:19 -06:00
|
|
|
if err := api.store.getAlertDefinitionByUID(&q); err != nil {
|
2020-11-12 07:11:30 -06:00
|
|
|
return nil, err
|
|
|
|
}
|
2021-01-07 09:45:42 -06:00
|
|
|
alertDefinition := q.Result
|
2020-11-12 07:11:30 -06:00
|
|
|
|
2021-03-03 09:52:19 -06:00
|
|
|
err := api.store.validateAlertDefinition(alertDefinition, true)
|
2020-11-12 07:11:30 -06:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return &eval.Condition{
|
|
|
|
RefID: alertDefinition.Condition,
|
2020-12-17 08:00:09 -06:00
|
|
|
OrgID: alertDefinition.OrgID,
|
2020-11-12 07:11:30 -06:00
|
|
|
QueriesAndExpressions: alertDefinition.Data,
|
|
|
|
}, nil
|
|
|
|
}
|