2022-02-24 00:30:04 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								package  api  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								import  (  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"errors" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"fmt" 
							 
						 
					
						
							
								
									
										
										
										
											2023-06-16 05:37:30 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"sort" 
							 
						 
					
						
							
								
									
										
										
										
											2023-06-16 01:33:42 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"strings" 
							 
						 
					
						
							
								
									
										
										
										
											2022-02-24 00:30:04 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									"time" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-11-11 21:28:24 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"github.com/grafana/grafana/pkg/services/folder" 
							 
						 
					
						
							
								
									
										
										
										
											2022-02-24 00:30:04 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									apimodels  "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ngmodels  "github.com/grafana/grafana/pkg/services/ngalert/models" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"github.com/grafana/grafana/pkg/services/ngalert/store" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"github.com/grafana/grafana/pkg/setting" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								)  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// validateRuleNode validates API model (definitions.PostableExtendedRuleNode) and converts it to models.AlertRule
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  validateRuleNode (  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ruleNode  * apimodels . PostableExtendedRuleNode , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									groupName  string , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									interval  time . Duration , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									orgId  int64 , 
							 
						 
					
						
							
								
									
										
										
										
											2022-11-11 21:28:24 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									namespace  * folder . Folder , 
							 
						 
					
						
							
								
									
										
										
										
											2022-02-24 00:30:04 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									cfg  * setting . UnifiedAlertingSettings )  ( * ngmodels . AlertRule ,  error )  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-28 22:40:11 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									intervalSeconds ,  err  :=  validateInterval ( cfg ,  interval ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  err 
							 
						 
					
						
							
								
									
										
										
										
											2022-02-24 00:30:04 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ruleNode . GrafanaManagedAlert  ==  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  fmt . Errorf ( "not Grafana managed alert rule" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// if UID is specified then we can accept partial model. Therefore, some validation can be skipped as it will be patched later
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									canPatch  :=  ruleNode . GrafanaManagedAlert . UID  !=  "" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ruleNode . GrafanaManagedAlert . Title  ==  ""  &&  ! canPatch  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  errors . New ( "alert rule title cannot be empty" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  len ( ruleNode . GrafanaManagedAlert . Title )  >  store . AlertRuleMaxTitleLength  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  fmt . Errorf ( "alert rule title is too long. Max length is %d" ,  store . AlertRuleMaxTitleLength ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									noDataState  :=  ngmodels . NoData 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ruleNode . GrafanaManagedAlert . NoDataState  ==  ""  &&  canPatch  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										noDataState  =  "" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ruleNode . GrafanaManagedAlert . NoDataState  !=  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										noDataState ,  err  =  ngmodels . NoDataStateFromString ( string ( ruleNode . GrafanaManagedAlert . NoDataState ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									errorState  :=  ngmodels . AlertingErrState 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ruleNode . GrafanaManagedAlert . ExecErrState  ==  ""  &&  canPatch  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										errorState  =  "" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ruleNode . GrafanaManagedAlert . ExecErrState  !=  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										errorState ,  err  =  ngmodels . ErrStateFromString ( string ( ruleNode . GrafanaManagedAlert . ExecErrState ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  len ( ruleNode . GrafanaManagedAlert . Data )  ==  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  canPatch  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  ruleNode . GrafanaManagedAlert . Condition  !=  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return  nil ,  fmt . Errorf ( "%w: query is not specified by condition is. You must specify both query and condition to update existing alert rule" ,  ngmodels . ErrAlertRuleFailedValidation ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  nil ,  fmt . Errorf ( "%w: no queries or expressions are found" ,  ngmodels . ErrAlertRuleFailedValidation ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2023-06-16 01:33:42 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										err  =  validateCondition ( ruleNode . GrafanaManagedAlert . Condition ,  ruleNode . GrafanaManagedAlert . Data ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  nil ,  fmt . Errorf ( "%w: %s" ,  ngmodels . ErrAlertRuleFailedValidation ,  err . Error ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2022-02-24 00:30:04 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-03-27 23:55:13 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									queries  :=  AlertQueriesFromApiAlertQueries ( ruleNode . GrafanaManagedAlert . Data ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-02-24 00:30:04 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									newAlertRule  :=  ngmodels . AlertRule { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										OrgID :            orgId , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										Title :            ruleNode . GrafanaManagedAlert . Title , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										Condition :        ruleNode . GrafanaManagedAlert . Condition , 
							 
						 
					
						
							
								
									
										
										
										
											2023-03-27 23:55:13 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										Data :             queries , 
							 
						 
					
						
							
								
									
										
										
										
											2022-02-24 00:30:04 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										UID :              ruleNode . GrafanaManagedAlert . UID , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										IntervalSeconds :  intervalSeconds , 
							 
						 
					
						
							
								
									
										
										
										
											2022-11-11 21:28:24 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										NamespaceUID :     namespace . UID , 
							 
						 
					
						
							
								
									
										
										
										
											2022-02-24 00:30:04 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										RuleGroup :        groupName , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										NoDataState :      noDataState , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ExecErrState :     errorState , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-06-30 23:46:26 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									newAlertRule . For ,  err  =  validateForInterval ( ruleNode ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-02-24 00:30:04 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									if  ruleNode . ApiRuleNode  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										newAlertRule . Annotations  =  ruleNode . ApiRuleNode . Annotations 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										newAlertRule . Labels  =  ruleNode . ApiRuleNode . Labels 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-12-16 18:47:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										err  =  newAlertRule . SetDashboardAndPanelFromAnnotations ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-08-03 22:05:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  nil ,  err 
							 
						 
					
						
							
								
									
										
										
										
											2022-02-24 00:30:04 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  & newAlertRule ,  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-06-16 01:33:42 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  validateCondition ( condition  string ,  queries  [ ] apimodels . AlertQuery )  error  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  condition  ==  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  errors . New ( "condition cannot be empty" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  len ( queries )  ==  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  errors . New ( "no query/expressions specified" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									refIDs  :=  make ( map [ string ] int ,  len ( queries ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  idx ,  query  :=  range  queries  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  query . RefID  ==  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  fmt . Errorf ( "refID is not specified for data query/expression at index %d" ,  idx ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  usedIdx ,  ok  :=  refIDs [ query . RefID ] ;  ok  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  fmt . Errorf ( "refID '%s' is already used by query/expression at index %d" ,  query . RefID ,  usedIdx ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										refIDs [ query . RefID ]  =  idx 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  _ ,  ok  :=  refIDs [ condition ] ;  ! ok  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ids  :=  make ( [ ] string ,  0 ,  len ( refIDs ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										for  id  :=  range  refIDs  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ids  =  append ( ids ,  id ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2023-06-16 05:37:30 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										sort . Strings ( ids ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-06-16 01:33:42 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  fmt . Errorf ( "condition %s does not exist, must be one of [%s]" ,  condition ,  strings . Join ( ids ,  "," ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-10-28 22:40:11 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  validateInterval ( cfg  * setting . UnifiedAlertingSettings ,  interval  time . Duration )  ( int64 ,  error )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									intervalSeconds  :=  int64 ( interval . Seconds ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									baseIntervalSeconds  :=  int64 ( cfg . BaseInterval . Seconds ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  interval  <=  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  0 ,  fmt . Errorf ( "rule evaluation interval must be positive duration that is multiple of the base interval %d seconds" ,  baseIntervalSeconds ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  intervalSeconds % baseIntervalSeconds  !=  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  0 ,  fmt . Errorf ( "rule evaluation interval %d should be multiple of the base interval of %d seconds" ,  int64 ( interval . Seconds ( ) ) ,  baseIntervalSeconds ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  intervalSeconds ,  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-06-30 23:46:26 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// validateForInterval validates ApiRuleNode.For and converts it to time.Duration. If the field is not specified returns 0 if GrafanaManagedAlert.UID is empty and -1 if it is not.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  validateForInterval ( ruleNode  * apimodels . PostableExtendedRuleNode )  ( time . Duration ,  error )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ruleNode . ApiRuleNode  ==  nil  ||  ruleNode . ApiRuleNode . For  ==  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ruleNode . GrafanaManagedAlert . UID  !=  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  - 1 ,  nil  // will be patched later with the real value of the current version of the rule
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  0 ,  nil  // if it's a new rule, use the 0 as the default
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									duration  :=  time . Duration ( * ruleNode . ApiRuleNode . For ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  duration  <  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  0 ,  fmt . Errorf ( "field `for` cannot be negative [%v]. 0 or any positive duration are allowed" ,  * ruleNode . ApiRuleNode . For ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  duration ,  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-02-24 00:30:04 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								// validateRuleGroup validates API model (definitions.PostableRuleGroupConfig) and converts it to a collection of models.AlertRule.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// Returns a slice that contains all rules described by API model or error if either group specification or an alert definition is not valid.
  
						 
					
						
							
								
									
										
										
										
											2023-02-01 20:15:03 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// It also returns a map containing current existing alerts that don't contain the is_paused field in the body of the call.
  
						 
					
						
							
								
									
										
										
										
											2022-02-24 00:30:04 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								func  validateRuleGroup (  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ruleGroupConfig  * apimodels . PostableRuleGroupConfig , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									orgId  int64 , 
							 
						 
					
						
							
								
									
										
										
										
											2022-11-11 21:28:24 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									namespace  * folder . Folder , 
							 
						 
					
						
							
								
									
										
										
										
											2023-02-01 20:15:03 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									cfg  * setting . UnifiedAlertingSettings )  ( [ ] * ngmodels . AlertRuleWithOptionals ,  error )  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-02-24 00:30:04 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									if  ruleGroupConfig . Name  ==  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  errors . New ( "rule group name cannot be empty" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  len ( ruleGroupConfig . Name )  >  store . AlertRuleMaxRuleGroupNameLength  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  fmt . Errorf ( "rule group name is too long. Max length is %d" ,  store . AlertRuleMaxRuleGroupNameLength ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									interval  :=  time . Duration ( ruleGroupConfig . Interval ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  interval  ==  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// if group interval is 0 (undefined) then we automatically fall back to the default interval
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										interval  =  cfg . DefaultRuleEvaluationInterval 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  interval  <  0  ||  int64 ( interval . Seconds ( ) ) % int64 ( cfg . BaseInterval . Seconds ( ) )  !=  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  fmt . Errorf ( "rule evaluation interval (%d second) should be positive number that is multiple of the base interval of %d seconds" ,  int64 ( interval . Seconds ( ) ) ,  int64 ( cfg . BaseInterval . Seconds ( ) ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// TODO should we validate that interval is >= cfg.MinInterval? Currently, we allow to save but fix the specified interval if it is < cfg.MinInterval
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-02-01 20:15:03 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									result  :=  make ( [ ] * ngmodels . AlertRuleWithOptionals ,  0 ,  len ( ruleGroupConfig . Rules ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-02-24 00:30:04 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									uids  :=  make ( map [ string ] int ,  cap ( result ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  idx  :=  range  ruleGroupConfig . Rules  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-06-16 01:33:42 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										rule ,  err  :=  validateRuleNode ( & ruleGroupConfig . Rules [ idx ] ,  ruleGroupConfig . Name ,  interval ,  orgId ,  namespace ,  cfg ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-02-24 00:30:04 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										// TODO do not stop on the first failure but return all failures
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  nil ,  fmt . Errorf ( "invalid rule specification at index [%d]: %w" ,  idx ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  rule . UID  !=  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  existingIdx ,  ok  :=  uids [ rule . UID ] ;  ok  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return  nil ,  fmt . Errorf ( "rule [%d] has UID %s that is already assigned to another rule at index %d" ,  idx ,  rule . UID ,  existingIdx ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											uids [ rule . UID ]  =  idx 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2023-02-01 20:15:03 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										var  hasPause ,  isPaused  bool 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										original  :=  ruleGroupConfig . Rules [ idx ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  alert  :=  original . GrafanaManagedAlert ;  alert  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  alert . IsPaused  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												isPaused  =  * alert . IsPaused 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												hasPause  =  true 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ruleWithOptionals  :=  ngmodels . AlertRuleWithOptionals { } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										rule . IsPaused  =  isPaused 
							 
						 
					
						
							
								
									
										
										
										
											2022-06-22 22:52:46 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										rule . RuleGroupIndex  =  idx  +  1 
							 
						 
					
						
							
								
									
										
										
										
											2023-02-01 20:15:03 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										ruleWithOptionals . AlertRule  =  * rule 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ruleWithOptionals . HasPause  =  hasPause 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										result  =  append ( result ,  & ruleWithOptionals ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-02-24 00:30:04 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  result ,  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}