@@ -71,6 +71,14 @@ const (
7171 recordingRuleFilter string = "record"
7272)
7373
74+ type DisabledRuleGroupErr struct {
75+ Message string
76+ }
77+
78+ func (e * DisabledRuleGroupErr ) Error () string {
79+ return e .Message
80+ }
81+
7482// Config is the configuration for the recording rules server.
7583type Config struct {
7684 // This is used for template expansion in alerts; must be a valid URL.
@@ -400,6 +408,17 @@ func SendAlerts(n sender, externalURL string) promRules.NotifyFunc {
400408 }
401409}
402410
411+ func ruleGroupDisabled (ruleGroup * rulespb.RuleGroupDesc , disabledRuleGroupsForUser validation.DisabledRuleGroups ) bool {
412+ for _ , disabledRuleGroupForUser := range disabledRuleGroupsForUser {
413+ if ruleGroup .Namespace == disabledRuleGroupForUser .Namespace &&
414+ ruleGroup .Name == disabledRuleGroupForUser .Name &&
415+ ruleGroup .User == disabledRuleGroupForUser .User {
416+ return true
417+ }
418+ }
419+ return false
420+ }
421+
403422var sep = []byte ("/" )
404423
405424func tokenForGroup (g * rulespb.RuleGroupDesc ) uint32 {
@@ -415,7 +434,10 @@ func tokenForGroup(g *rulespb.RuleGroupDesc) uint32 {
415434 return ringHasher .Sum32 ()
416435}
417436
418- func instanceOwnsRuleGroup (r ring.ReadRing , g * rulespb.RuleGroupDesc , instanceAddr string ) (bool , error ) {
437+ func instanceOwnsRuleGroup (r ring.ReadRing , g * rulespb.RuleGroupDesc , disabledRuleGroups validation.DisabledRuleGroups , instanceAddr string ) (bool , error ) {
438+ if ruleGroupDisabled (g , disabledRuleGroups ) {
439+ return false , & DisabledRuleGroupErr {Message : fmt .Sprintf ("rule group %s, namespace %s, user %s is disabled" , g .Name , g .Namespace , g .User )}
440+ }
419441 hash := tokenForGroup (g )
420442
421443 rlrs , err := r .Get (hash , RingOp , nil , nil , nil )
@@ -533,7 +555,26 @@ func (r *Ruler) listRules(ctx context.Context) (result map[string]rulespb.RuleGr
533555}
534556
535557func (r * Ruler ) listRulesNoSharding (ctx context.Context ) (map [string ]rulespb.RuleGroupList , error ) {
536- return r .store .ListAllRuleGroups (ctx )
558+ allRuleGroups , err := r .store .ListAllRuleGroups (ctx )
559+ if err != nil {
560+ return nil , err
561+ }
562+ for userID , groups := range allRuleGroups {
563+ disabledRuleGroupsForUser := r .limits .DisabledRuleGroups (userID )
564+ if len (disabledRuleGroupsForUser ) == 0 {
565+ continue
566+ }
567+ filteredGroupsForUser := rulespb.RuleGroupList {}
568+ for _ , group := range groups {
569+ if ! ruleGroupDisabled (group , disabledRuleGroupsForUser ) {
570+ filteredGroupsForUser = append (filteredGroupsForUser , group )
571+ } else {
572+ level .Info (r .logger ).Log ("msg" , "rule group disabled" , "rule group name" , group .Name , "namespace" , group .Namespace , "user" , group .User )
573+ }
574+ }
575+ allRuleGroups [userID ] = filteredGroupsForUser
576+ }
577+ return allRuleGroups , nil
537578}
538579
539580func (r * Ruler ) listRulesShardingDefault (ctx context.Context ) (map [string ]rulespb.RuleGroupList , error ) {
@@ -544,7 +585,7 @@ func (r *Ruler) listRulesShardingDefault(ctx context.Context) (map[string]rulesp
544585
545586 filteredConfigs := make (map [string ]rulespb.RuleGroupList )
546587 for userID , groups := range configs {
547- filtered := filterRuleGroups (userID , groups , r .ring , r .lifecycler .GetInstanceAddr (), r .logger , r .ringCheckErrors )
588+ filtered := filterRuleGroups (userID , groups , r .limits . DisabledRuleGroups ( userID ), r . ring , r .lifecycler .GetInstanceAddr (), r .logger , r .ringCheckErrors )
548589 if len (filtered ) > 0 {
549590 filteredConfigs [userID ] = filtered
550591 }
@@ -602,7 +643,7 @@ func (r *Ruler) listRulesShuffleSharding(ctx context.Context) (map[string]rulesp
602643 return errors .Wrapf (err , "failed to fetch rule groups for user %s" , userID )
603644 }
604645
605- filtered := filterRuleGroups (userID , groups , userRings [userID ], r .lifecycler .GetInstanceAddr (), r .logger , r .ringCheckErrors )
646+ filtered := filterRuleGroups (userID , groups , r . limits . DisabledRuleGroups ( userID ), userRings [userID ], r .lifecycler .GetInstanceAddr (), r .logger , r .ringCheckErrors )
606647 if len (filtered ) == 0 {
607648 continue
608649 }
@@ -624,15 +665,21 @@ func (r *Ruler) listRulesShuffleSharding(ctx context.Context) (map[string]rulesp
624665//
625666// Reason why this function is not a method on Ruler is to make sure we don't accidentally use r.ring,
626667// but only ring passed as parameter.
627- func filterRuleGroups (userID string , ruleGroups []* rulespb.RuleGroupDesc , ring ring.ReadRing , instanceAddr string , log log.Logger , ringCheckErrors prometheus.Counter ) []* rulespb.RuleGroupDesc {
668+ func filterRuleGroups (userID string , ruleGroups []* rulespb.RuleGroupDesc , disabledRuleGroups validation. DisabledRuleGroups , ring ring.ReadRing , instanceAddr string , log log.Logger , ringCheckErrors prometheus.Counter ) []* rulespb.RuleGroupDesc {
628669 // Prune the rule group to only contain rules that this ruler is responsible for, based on ring.
629670 var result []* rulespb.RuleGroupDesc
630671 for _ , g := range ruleGroups {
631- owned , err := instanceOwnsRuleGroup (ring , g , instanceAddr )
672+ owned , err := instanceOwnsRuleGroup (ring , g , disabledRuleGroups , instanceAddr )
632673 if err != nil {
633- ringCheckErrors .Inc ()
634- level .Error (log ).Log ("msg" , "failed to check if the ruler replica owns the rule group" , "user" , userID , "namespace" , g .Namespace , "group" , g .Name , "err" , err )
635- continue
674+ switch e := err .(type ) {
675+ case * DisabledRuleGroupErr :
676+ level .Info (log ).Log ("msg" , e .Message )
677+ continue
678+ default :
679+ ringCheckErrors .Inc ()
680+ level .Error (log ).Log ("msg" , "failed to check if the ruler replica owns the rule group" , "user" , userID , "namespace" , g .Namespace , "group" , g .Name , "err" , err )
681+ continue
682+ }
636683 }
637684
638685 if owned {
0 commit comments