@@ -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