2023-10-12 13:43:10 +01:00
package migration
2021-05-31 17:30:58 +05:30
import (
2024-02-16 10:47:34 -05:00
"context"
2021-05-31 17:30:58 +05:30
"fmt"
"time"
pb "github.com/prometheus/alertmanager/silence/silencepb"
2021-11-04 16:42:34 -04:00
"github.com/prometheus/common/model"
2021-05-31 17:30:58 +05:30
2024-01-24 15:56:19 -05:00
"github.com/grafana/grafana/pkg/infra/log"
2023-10-12 13:43:10 +01:00
"github.com/grafana/grafana/pkg/services/ngalert/models"
2024-01-24 15:56:19 -05:00
ngstate "github.com/grafana/grafana/pkg/services/ngalert/state"
"github.com/grafana/grafana/pkg/util"
2021-05-31 17:30:58 +05:30
)
2024-01-24 15:56:19 -05:00
// TimeNow makes it possible to test usage of time
var TimeNow = time . Now
2021-11-25 10:46:47 +00:00
2024-01-24 15:56:19 -05:00
// silenceHandler is a helper for managing and writing migration silences.
type silenceHandler struct {
rulesWithErrorSilenceLabels int
rulesWithNoDataSilenceLabels int
2024-02-16 10:47:34 -05:00
persistSilences func ( context . Context , int64 , [ ] * pb . MeshSilence ) error
2024-01-24 15:56:19 -05:00
}
// handleSilenceLabels adds labels to the alert rule if the rule requires silence labels for error/nodata keep_state.
func ( sh * silenceHandler ) handleSilenceLabels ( ar * models . AlertRule , parsedSettings dashAlertSettings ) {
if parsedSettings . ExecutionErrorState == "keep_state" {
sh . rulesWithErrorSilenceLabels ++
ar . Labels [ models . MigratedSilenceLabelErrorKeepState ] = "true"
}
if parsedSettings . NoDataState == "keep_state" {
sh . rulesWithNoDataSilenceLabels ++
ar . Labels [ models . MigratedSilenceLabelNodataKeepState ] = "true"
}
}
// createSilences creates silences and writes them to a file.
2024-02-16 10:47:34 -05:00
func ( sh * silenceHandler ) createSilences ( ctx context . Context , orgID int64 , log log . Logger ) error {
2024-01-24 15:56:19 -05:00
var silences [ ] * pb . MeshSilence
if sh . rulesWithErrorSilenceLabels > 0 {
log . Info ( "Creating silence for rules with ExecutionErrorState = keep_state" , "rules" , sh . rulesWithErrorSilenceLabels )
silences = append ( silences , errorSilence ( ) )
}
if sh . rulesWithNoDataSilenceLabels > 0 {
log . Info ( "Creating silence for rules with NoDataState = keep_state" , "rules" , sh . rulesWithNoDataSilenceLabels )
silences = append ( silences , noDataSilence ( ) )
}
if len ( silences ) > 0 {
2024-02-16 10:47:34 -05:00
log . Debug ( "Writing silences to kvstore" , "silences" , len ( silences ) )
if err := sh . persistSilences ( ctx , orgID , silences ) ; err != nil {
return fmt . Errorf ( "write silences to kvstore: %w" , err )
2024-01-24 15:56:19 -05:00
}
2021-11-25 10:46:47 +00:00
}
2024-01-24 15:56:19 -05:00
return nil
}
2021-11-25 10:46:47 +00:00
2024-01-24 15:56:19 -05:00
// errorSilence creates a silence that matches DatasourceError alerts for rules which have a label attached when ExecutionErrorState was set to keep_state.
func errorSilence ( ) * pb . MeshSilence {
return & pb . MeshSilence {
2021-11-25 10:46:47 +00:00
Silence : & pb . Silence {
2024-01-24 15:56:19 -05:00
Id : util . GenerateShortUID ( ) ,
2021-11-25 10:46:47 +00:00
Matchers : [ ] * pb . Matcher {
{
Type : pb . Matcher_EQUAL ,
Name : model . AlertNameLabel ,
2024-01-24 15:56:19 -05:00
Pattern : ngstate . ErrorAlertName ,
2021-11-25 10:46:47 +00:00
} ,
{
Type : pb . Matcher_EQUAL ,
2024-01-24 15:56:19 -05:00
Name : models . MigratedSilenceLabelErrorKeepState ,
Pattern : "true" ,
2021-11-25 10:46:47 +00:00
} ,
} ,
2024-01-24 15:56:19 -05:00
StartsAt : TimeNow ( ) ,
EndsAt : TimeNow ( ) . AddDate ( 1 , 0 , 0 ) , // 1 year
2021-11-25 10:46:47 +00:00
CreatedBy : "Grafana Migration" ,
2024-01-24 15:56:19 -05:00
Comment : "Created during migration to unified alerting to silence Error state when the option 'Keep Last State' was selected for Error state" ,
2021-11-25 10:46:47 +00:00
} ,
2024-01-24 15:56:19 -05:00
ExpiresAt : TimeNow ( ) . AddDate ( 1 , 0 , 0 ) , // 1 year
2021-11-25 10:46:47 +00:00
}
}
2024-01-24 15:56:19 -05:00
// noDataSilence creates a silence that matches DatasourceNoData alerts for rules which have a label attached when NoDataState was set to keep_state.
func noDataSilence ( ) * pb . MeshSilence {
return & pb . MeshSilence {
2021-11-04 16:42:34 -04:00
Silence : & pb . Silence {
2024-01-24 15:56:19 -05:00
Id : util . GenerateShortUID ( ) ,
2021-11-04 16:42:34 -04:00
Matchers : [ ] * pb . Matcher {
{
Type : pb . Matcher_EQUAL ,
Name : model . AlertNameLabel ,
2024-01-24 15:56:19 -05:00
Pattern : ngstate . NoDataAlertName ,
2021-11-04 16:42:34 -04:00
} ,
{
Type : pb . Matcher_EQUAL ,
2024-01-24 15:56:19 -05:00
Name : models . MigratedSilenceLabelNodataKeepState ,
Pattern : "true" ,
2021-11-04 16:42:34 -04:00
} ,
} ,
2024-01-24 15:56:19 -05:00
StartsAt : TimeNow ( ) ,
EndsAt : TimeNow ( ) . AddDate ( 1 , 0 , 0 ) , // 1 year.
2021-11-04 16:42:34 -04:00
CreatedBy : "Grafana Migration" ,
2024-01-24 15:56:19 -05:00
Comment : "Created during migration to unified alerting to silence NoData state when the option 'Keep Last State' was selected for NoData state" ,
2021-11-04 16:42:34 -04:00
} ,
2024-01-24 15:56:19 -05:00
ExpiresAt : TimeNow ( ) . AddDate ( 1 , 0 , 0 ) , // 1 year.
2021-11-04 16:42:34 -04:00
}
}