2024-05-04 03:32:30 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								package  notifier 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								import  ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									"context" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-05-31 00:04:47 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									"golang.org/x/exp/maps" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-06-04 05:39:06 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									alertingModels  "github.com/grafana/alerting/models" 
							 
						 
					
						
							
								
									
										
										
										
											2024-06-13 12:11:35 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									"github.com/grafana/grafana/pkg/apimachinery/identity" 
							 
						 
					
						
							
								
									
										
										
										
											2024-05-04 03:32:30 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									"github.com/grafana/grafana/pkg/infra/log" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									"github.com/grafana/grafana/pkg/services/ngalert/models" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// SilenceService is the authenticated service for managing alertmanager silences.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								type  SilenceService  struct  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-05-31 00:04:47 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									authz      SilenceAccessControlService 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									xact       transactionManager 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									log        log . Logger 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									store      SilenceStore 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									ruleStore  RuleStore 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									ruleAuthz  RuleAccessControlService 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								type  RuleAccessControlService  interface  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-06-20 04:18:33 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									HasAccessInFolder ( ctx  context . Context ,  user  identity . Requester ,  rule  models . Namespaced )  ( bool ,  error ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-05-04 03:32:30 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// SilenceAccessControlService provides access control for silences.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								type  SilenceAccessControlService  interface  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									FilterByAccess ( ctx  context . Context ,  user  identity . Requester ,  silences  ... * models . Silence )  ( [ ] * models . Silence ,  error ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									AuthorizeReadSilence ( ctx  context . Context ,  user  identity . Requester ,  silence  * models . Silence )  error 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									AuthorizeCreateSilence ( ctx  context . Context ,  user  identity . Requester ,  silence  * models . Silence )  error 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									AuthorizeUpdateSilence ( ctx  context . Context ,  user  identity . Requester ,  silence  * models . Silence )  error 
							 
						 
					
						
							
								
									
										
										
										
											2024-05-31 00:04:47 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									SilenceAccess ( ctx  context . Context ,  user  identity . Requester ,  silences  [ ] * models . Silence )  ( map [ * models . Silence ] models . SilencePermissionSet ,  error ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-05-04 03:32:30 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// SilenceStore is the interface for storing and retrieving silences. Currently, this is implemented by
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// MultiOrgAlertmanager but should eventually be replaced with an actual store.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								type  SilenceStore  interface  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									ListSilences ( ctx  context . Context ,  orgID  int64 ,  filter  [ ] string )  ( [ ] * models . Silence ,  error ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									GetSilence ( ctx  context . Context ,  orgID  int64 ,  id  string )  ( * models . Silence ,  error ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									CreateSilence ( ctx  context . Context ,  orgID  int64 ,  ps  models . Silence )  ( string ,  error ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									UpdateSilence ( ctx  context . Context ,  orgID  int64 ,  ps  models . Silence )  ( string ,  error ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									DeleteSilence ( ctx  context . Context ,  orgID  int64 ,  id  string )  error 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-05-31 00:04:47 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								type  RuleStore  interface  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									ListAlertRules ( ctx  context . Context ,  query  * models . ListAlertRulesQuery )  ( models . RulesGroup ,  error ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-05-04 03:32:30 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								func  NewSilenceService ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									authz  SilenceAccessControlService , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									xact  transactionManager , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									log  log . Logger , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									store  SilenceStore , 
							 
						 
					
						
							
								
									
										
										
										
											2024-05-31 00:04:47 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									ruleStore  RuleStore , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									ruleAuthz  RuleAccessControlService , 
							 
						 
					
						
							
								
									
										
										
										
											2024-05-04 03:32:30 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								)  * SilenceService  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									return  & SilenceService { 
							 
						 
					
						
							
								
									
										
										
										
											2024-05-31 00:04:47 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										authz :      authz , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										xact :       xact , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										log :        log , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										store :      store , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										ruleStore :  ruleStore , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										ruleAuthz :  ruleAuthz , 
							 
						 
					
						
							
								
									
										
										
										
											2024-05-04 03:32:30 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// GetSilence retrieves a silence by its ID.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  ( s  * SilenceService )  GetSilence ( ctx  context . Context ,  user  identity . Requester ,  silenceID  string )  ( * models . Silence ,  error )  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-05-31 00:04:47 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									silence ,  err  :=  s . store . GetSilence ( ctx ,  user . GetOrgID ( ) ,  silenceID ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-05-04 03:32:30 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-05-31 00:04:47 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									if  err  :=  s . authz . AuthorizeReadSilence ( ctx ,  user ,  silence ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-05-04 03:32:30 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-05-31 00:04:47 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									return  silence ,  nil 
							 
						 
					
						
							
								
									
										
										
										
											2024-05-04 03:32:30 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// ListSilences retrieves all silences that match the given filter. This will include all rule-specific silences that
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// the user has access to as well as all general silences.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  ( s  * SilenceService )  ListSilences ( ctx  context . Context ,  user  identity . Requester ,  filter  [ ] string )  ( [ ] * models . Silence ,  error )  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-05-31 00:04:47 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									silences ,  err  :=  s . store . ListSilences ( ctx ,  user . GetOrgID ( ) ,  filter ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-05-04 03:32:30 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-05-31 00:04:47 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									return  s . authz . FilterByAccess ( ctx ,  user ,  silences ... ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-05-04 03:32:30 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// CreateSilence creates a new silence.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// For rule-specific silences, the user needs permission to create silences in the folder that the associated rule is in.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// For general silences, the user needs broader permissions.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  ( s  * SilenceService )  CreateSilence ( ctx  context . Context ,  user  identity . Requester ,  ps  models . Silence )  ( string ,  error )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  :=  s . authz . AuthorizeCreateSilence ( ctx ,  user ,  & ps ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  "" ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									silenceId ,  err  :=  s . store . CreateSilence ( ctx ,  user . GetOrgID ( ) ,  ps ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  "" ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									return  silenceId ,  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// UpdateSilence updates an existing silence.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// For rule-specific silences, the user needs permission to update silences in the folder that the associated rule is in.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// For general silences, the user needs broader permissions.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  ( s  * SilenceService )  UpdateSilence ( ctx  context . Context ,  user  identity . Requester ,  ps  models . Silence )  ( string ,  error )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  :=  s . authz . AuthorizeUpdateSilence ( ctx ,  user ,  & ps ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  "" ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-06-04 05:39:06 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									existing ,  err  :=  s . store . GetSilence ( ctx ,  user . GetOrgID ( ) ,  * ps . ID ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  "" ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  :=  validateSilenceUpdate ( existing ,  ps ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  "" ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-05-04 03:32:30 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									silenceId ,  err  :=  s . store . UpdateSilence ( ctx ,  user . GetOrgID ( ) ,  ps ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  "" ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									return  silenceId ,  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// DeleteSilence deletes a silence by its ID.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// For rule-specific silences, the user needs permission to update silences in the folder that the associated rule is in.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// For general silences, the user needs broader permissions.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  ( s  * SilenceService )  DeleteSilence ( ctx  context . Context ,  user  identity . Requester ,  silenceID  string )  error  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									silence ,  err  :=  s . GetSilence ( ctx ,  user ,  silenceID ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  :=  s . authz . AuthorizeUpdateSilence ( ctx ,  user ,  silence ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									err  =  s . store . DeleteSilence ( ctx ,  user . GetOrgID ( ) ,  silenceID ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									return  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
									
										
										
										
											2024-05-31 00:04:47 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// WithAccessControlMetadata adds access control metadata to the given SilenceWithMetadata.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  ( s  * SilenceService )  WithAccessControlMetadata ( ctx  context . Context ,  user  identity . Requester ,  silencesWithMetadata  ... * models . SilenceWithMetadata )  error  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									silences  :=  make ( [ ] * models . Silence ,  0 ,  len ( silencesWithMetadata ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									for  _ ,  silence  :=  range  silencesWithMetadata  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										silences  =  append ( silences ,  silence . Silence ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									permissions ,  err  :=  s . authz . SilenceAccess ( ctx ,  user ,  silences ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  len ( permissions )  !=  len ( silences )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										s . log . Warn ( "failed to get metadata for all silences" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									for  _ ,  silence  :=  range  silencesWithMetadata  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  perms ,  ok  :=  permissions [ silence . Silence ] ;  ok  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											silence . Metadata . Permissions  =  & perms 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									return  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// WithRuleMetadata adds rule metadata to the given SilenceWithMetadata.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  ( s  * SilenceService )  WithRuleMetadata ( ctx  context . Context ,  user  identity . Requester ,  silences  ... * models . SilenceWithMetadata )  error  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									byRuleUID  :=  make ( map [ string ] [ ] * models . SilenceWithMetadata ,  len ( silences ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									for  _ ,  silence  :=  range  silences  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										ruleUID  :=  silence . GetRuleUID ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  ruleUID  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											byRuleUID [ * ruleUID ]  =  append ( byRuleUID [ * ruleUID ] ,  silence ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											silence . Metadata . RuleMetadata  =  & models . SilenceRuleMetadata {  // Attach metadata with rule UID regardless of access.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												RuleUID :  * ruleUID , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  len ( byRuleUID )  ==  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									q  :=  models . ListAlertRulesQuery { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										RuleUIDs :  maps . Keys ( byRuleUID ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										OrgID :     user . GetOrgID ( ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									rules ,  err  :=  s . ruleStore . ListAlertRules ( ctx ,  & q ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									accessCacheByFolder  :=  make ( map [ string ] bool ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									for  _ ,  rule  :=  range  rules  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										// TODO: Preferably silence service should not need to know about the internal details of rule access control.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										// This can be improved by adding a method to ruleAuthz that does the filtering itself or a method that exposes
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										// an access fingerprint for a rule that callers can use to do their own caching.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										fp  :=  rule . NamespaceUID 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										canAccess ,  ok  :=  accessCacheByFolder [ fp ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  ! ok  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											var  err  error 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											if  canAccess ,  err  =  s . ruleAuthz . HasAccessInFolder ( ctx ,  user ,  rule ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												continue  // Assume no access if there is an error but don't cache.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											accessCacheByFolder [ fp ]  =  canAccess  // Only cache if there is no error.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  ! canAccess  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  ruleSilences ,  ok  :=  byRuleUID [ rule . UID ] ;  ok  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											for  _ ,  sil  :=  range  ruleSilences  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												if  sil . Metadata . RuleMetadata  ==  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
													sil . Metadata . RuleMetadata  =  & models . SilenceRuleMetadata { } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												sil . Metadata . RuleMetadata . RuleTitle  =  rule . Title 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												sil . Metadata . RuleMetadata . FolderUID  =  rule . NamespaceUID 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									return  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
									
										
										
										
											2024-06-04 05:39:06 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// validateSilenceUpdate validates the diff between an existing silence and a new silence. Currently, this is use to
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// prevent changing the rule UID matcher.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Alternatively, we could check WRITE permission on the old silence followed by CREATE permission on the new silence
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// if the rule folder is different.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  validateSilenceUpdate ( existing  * models . Silence ,  new  models . Silence )  error  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									existingRuleUID  :=  existing . GetRuleUID ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									newRuleUID  :=  new . GetRuleUID ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  existingRuleUID  ==  nil  ||  newRuleUID  ==  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  existingRuleUID  !=  newRuleUID  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											return  WithPublicError ( ErrSilencesBadRequest . Errorf ( "Silence rule matcher '%s' cannot be updated, please create a new silence" ,  alertingModels . RuleUIDLabel ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									}  else  if  * existingRuleUID  !=  * newRuleUID  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  WithPublicError ( ErrSilencesBadRequest . Errorf ( "Silence rule matcher '%s' cannot be updated, please create a new silence" ,  alertingModels . RuleUIDLabel ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									return  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								}