2022-06-04 20:55:46 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								package  api  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								import  (  
						 
					
						
							
								
									
										
										
										
											2022-12-17 02:01:06 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"encoding/json" 
							 
						 
					
						
							
								
									
										
										
										
											2022-06-04 20:55:46 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									"fmt" 
							 
						 
					
						
							
								
									
										
										
										
											2024-02-08 20:36:09 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"time" 
							 
						 
					
						
							
								
									
										
										
										
											2022-06-04 20:55:46 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"github.com/google/go-cmp/cmp" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"github.com/google/go-cmp/cmp/cmpopts" 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-17 02:01:06 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									amConfig  "github.com/prometheus/alertmanager/config" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"github.com/prometheus/alertmanager/pkg/labels" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-05-25 23:41:11 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"github.com/grafana/grafana/pkg/infra/log" 
							 
						 
					
						
							
								
									
										
										
										
											2022-06-04 20:55:46 +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/util/cmputil" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								)  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( srv  AlertmanagerSrv )  provenanceGuard ( currentConfig  apimodels . GettableUserConfig ,  newConfig  apimodels . PostableUserConfig )  error  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  :=  checkRoutes ( currentConfig ,  newConfig ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  :=  checkTemplates ( currentConfig ,  newConfig ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2023-05-25 23:41:11 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  err  :=  checkContactPoints ( srv . log ,  currentConfig . AlertmanagerConfig . Receivers ,  newConfig . AlertmanagerConfig . Receivers ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-06-04 20:55:46 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										return  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  :=  checkMuteTimes ( currentConfig ,  newConfig ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  checkRoutes ( currentConfig  apimodels . GettableUserConfig ,  newConfig  apimodels . PostableUserConfig )  error  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									reporter  :=  cmputil . DiffReporter { } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									options  :=  [ ] cmp . Option { cmp . Reporter ( & reporter ) ,  cmpopts . EquateEmpty ( ) ,  cmpopts . IgnoreUnexported ( labels . Matcher { } ) } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									routesEqual  :=  cmp . Equal ( currentConfig . AlertmanagerConfig . Route ,  newConfig . AlertmanagerConfig . Route ,  options ... ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-02-28 06:57:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ! routesEqual  &&  currentConfig . AlertmanagerConfig . Route . Provenance  !=  apimodels . Provenance ( ngmodels . ProvenanceNone )  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-06-04 20:55:46 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										return  fmt . Errorf ( "policies were provisioned and cannot be changed through the UI" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  checkTemplates ( currentConfig  apimodels . GettableUserConfig ,  newConfig  apimodels . PostableUserConfig )  error  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  name ,  template  :=  range  currentConfig . TemplateFiles  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										provenance  :=  ngmodels . ProvenanceNone 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  prov ,  present  :=  currentConfig . TemplateFileProvenances [ name ] ;  present  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-02-28 06:57:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											provenance  =  ngmodels . Provenance ( prov ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-06-04 20:55:46 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  provenance  ==  ngmodels . ProvenanceNone  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											continue  // we are only interested in non none
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										found  :=  false 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										for  newName ,  newTemplate  :=  range  newConfig . TemplateFiles  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  name  !=  newName  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											found  =  true 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  template  !=  newTemplate  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return  fmt . Errorf ( "cannot save provisioned template '%s'" ,  name ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											break  // we found the template and we can proceed
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ! found  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  fmt . Errorf ( "cannot delete provisioned template '%s'" ,  name ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-05-25 23:41:11 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  checkContactPoints ( l  log . Logger ,  currReceivers  [ ] * apimodels . GettableApiReceiver ,  newReceivers  [ ] * apimodels . PostableApiReceiver )  error  {  
						 
					
						
							
								
									
										
										
										
											2022-06-04 20:55:46 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									newCPs  :=  make ( map [ string ] * apimodels . PostableGrafanaReceiver ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  _ ,  postedReceiver  :=  range  newReceivers  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										for  _ ,  postedContactPoint  :=  range  postedReceiver . GrafanaManagedReceivers  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											newCPs [ postedContactPoint . UID ]  =  postedContactPoint 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  _ ,  existingReceiver  :=  range  currReceivers  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										for  _ ,  contactPoint  :=  range  existingReceiver . GrafanaManagedReceivers  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-02-28 06:57:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											if  contactPoint . Provenance  ==  apimodels . Provenance ( ngmodels . ProvenanceNone )  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-06-04 20:55:46 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
												continue  // we are only interested in non none
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											postedContactPoint ,  present  :=  newCPs [ contactPoint . UID ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  ! present  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return  fmt . Errorf ( "cannot delete provisioned contact point '%s'" ,  contactPoint . Name ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											editErr  :=  fmt . Errorf ( "cannot save provisioned contact point '%s'" ,  contactPoint . Name ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  contactPoint . DisableResolveMessage  !=  postedContactPoint . DisableResolveMessage  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return  editErr 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  contactPoint . Name  !=  postedContactPoint . Name  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return  editErr 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  contactPoint . Type  !=  postedContactPoint . Type  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return  editErr 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											for  key  :=  range  contactPoint . SecureFields  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												if  value ,  present  :=  postedContactPoint . SecureSettings [ key ] ;  present  &&  value  !=  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													return  editErr 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-30 23:46:47 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											existingSettings  :=  map [ string ] any { } 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-17 02:01:06 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											err  :=  json . Unmarshal ( contactPoint . Settings ,  & existingSettings ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-30 23:46:47 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											newSettings  :=  map [ string ] any { } 
							 
						 
					
						
							
								
									
										
										
										
											2023-05-25 23:41:11 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											err  =  json . Unmarshal ( postedContactPoint . Settings ,  & newSettings ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-06-04 20:55:46 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2023-05-25 23:41:11 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											d  :=  cmp . Diff ( existingSettings ,  newSettings ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  len ( d )  >  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												l . Warn ( "Settings of contact point with provenance status cannot be changed via regular API." ,  "contactPoint" ,  postedContactPoint . Name ,  "settingsDiff" ,  d ,  "error" ,  editErr ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return  editErr 
							 
						 
					
						
							
								
									
										
										
										
											2022-06-04 20:55:46 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  checkMuteTimes ( currentConfig  apimodels . GettableUserConfig ,  newConfig  apimodels . PostableUserConfig )  error  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									newMTs  :=  make ( map [ string ] amConfig . MuteTimeInterval ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  _ ,  newMuteTime  :=  range  newConfig . AlertmanagerConfig . MuteTimeIntervals  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										newMTs [ newMuteTime . Name ]  =  newMuteTime 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  _ ,  muteTime  :=  range  currentConfig . AlertmanagerConfig . MuteTimeIntervals  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										provenance  :=  ngmodels . ProvenanceNone 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  prov ,  present  :=  currentConfig . AlertmanagerConfig . MuteTimeProvenances [ muteTime . Name ] ;  present  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-02-28 06:57:15 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											provenance  =  ngmodels . Provenance ( prov ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-06-04 20:55:46 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  provenance  ==  ngmodels . ProvenanceNone  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											continue  // we are only interested in non none
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										postedMT ,  present  :=  newMTs [ muteTime . Name ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ! present  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  fmt . Errorf ( "cannot delete provisioned mute time '%s'" ,  muteTime . Name ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										reporter  :=  cmputil . DiffReporter { } 
							 
						 
					
						
							
								
									
										
										
										
											2024-02-08 20:36:09 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										options  :=  [ ] cmp . Option { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											cmp . Reporter ( & reporter ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											cmp . Comparer ( func ( a ,  b  * time . Location )  bool  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												// Check if both are nil or both have the same string representation
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return  ( a  ==  nil  &&  b  ==  nil )  ||  ( a  !=  nil  &&  b  !=  nil  &&  a . String ( )  ==  b . String ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											cmpopts . EquateEmpty ( ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2022-06-04 20:55:46 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										timesEqual  :=  cmp . Equal ( muteTime . TimeIntervals ,  postedMT . TimeIntervals ,  options ... ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ! timesEqual  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  fmt . Errorf ( "cannot save provisioned mute time '%s'" ,  muteTime . Name ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}