2023-07-25 04:12:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								package  api  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								import  (  
						 
					
						
							
								
									
										
										
										
											2023-09-26 02:11:24 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"bytes" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"encoding/json" 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-09 23:32:28 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"fmt" 
							 
						 
					
						
							
								
									
										
										
										
											2023-09-26 02:11:24 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"io" 
							 
						 
					
						
							
								
									
										
										
										
											2023-07-25 04:12:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									"net/http" 
							 
						 
					
						
							
								
									
										
										
										
											2023-10-26 17:42:00 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"sort" 
							 
						 
					
						
							
								
									
										
										
										
											2023-09-26 02:11:24 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"strconv" 
							 
						 
					
						
							
								
									
										
										
										
											2023-07-25 04:12:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"github.com/grafana/grafana/pkg/api/response" 
							 
						 
					
						
							
								
									
										
										
										
											2023-09-26 02:11:24 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"github.com/grafana/grafana/pkg/infra/log" 
							 
						 
					
						
							
								
									
										
										
										
											2023-07-25 04:12:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									contextmodel  "github.com/grafana/grafana/pkg/services/contexthandler/model" 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-09 23:32:28 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"github.com/grafana/grafana/pkg/services/featuremgmt" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"github.com/grafana/grafana/pkg/setting" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"github.com/grafana/grafana/pkg/web" 
							 
						 
					
						
							
								
									
										
										
										
											2023-07-25 04:12:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								)  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( hs  * HTTPServer )  GetFeatureToggles ( ctx  * contextmodel . ReqContext )  response . Response  {  
						 
					
						
							
								
									
										
										
										
											2023-08-09 23:32:28 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// object being returned
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									dtos  :=  make ( [ ] featuremgmt . FeatureToggleDTO ,  0 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// loop through features an add features that should be visible to dtos
 
							 
						 
					
						
							
								
									
										
										
										
											2024-01-10 02:38:06 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									for  _ ,  ft  :=  range  hs . featureManager . GetFlags ( )  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-01-18 13:32:44 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										flag  :=  ft . Name 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  hs . featureManager . IsHiddenFromAdminPage ( flag ,  false )  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-07-25 04:12:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-09 23:32:28 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										dto  :=  featuremgmt . FeatureToggleDTO { 
							 
						 
					
						
							
								
									
										
										
										
											2024-01-18 13:32:44 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											Name :         flag , 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-09 23:32:28 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											Description :  ft . Description , 
							 
						 
					
						
							
								
									
										
										
										
											2024-01-18 13:32:44 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											Enabled :      hs . featureManager . IsEnabled ( ctx . Req . Context ( ) ,  flag ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ReadOnly :     ! hs . featureManager . IsEditableFromAdminPage ( flag ) , 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-09 23:32:28 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										dtos  =  append ( dtos ,  dto ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-10-26 17:42:00 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										sort . Slice ( dtos ,  func ( i ,  j  int )  bool  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  dtos [ i ] . Name  <  dtos [ j ] . Name 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-09 23:32:28 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  response . JSON ( http . StatusOK ,  dtos ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( hs  * HTTPServer )  UpdateFeatureToggle ( ctx  * contextmodel . ReqContext )  response . Response  {  
						 
					
						
							
								
									
										
										
										
											2024-01-18 13:32:44 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									featureMgmtCfg  :=  hs . featureManager . Settings 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-09 23:32:28 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ! featureMgmtCfg . AllowEditing  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  response . Error ( http . StatusForbidden ,  "feature toggles are read-only" ,  fmt . Errorf ( "feature toggles are configured to be read-only" ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-09-26 02:11:24 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  featureMgmtCfg . UpdateWebhook  ==  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  response . Error ( http . StatusInternalServerError ,  "feature toggles service is misconfigured" ,  fmt . Errorf ( "[feature_management]update_webhook is not set" ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-09 23:32:28 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									cmd  :=  featuremgmt . UpdateFeatureTogglesCommand { } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  :=  web . Bind ( ctx . Req ,  & cmd ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  response . Error ( http . StatusBadRequest ,  "bad request data" ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-09-26 02:11:24 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									payload  :=  UpdatePayload { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										FeatureToggles :  make ( map [ string ] string ,  len ( cmd . FeatureToggles ) ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										User :            ctx . SignedInUser . Email , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-08-09 23:32:28 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									for  _ ,  t  :=  range  cmd . FeatureToggles  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// make sure flag exists, and only continue if flag is writeable
 
							 
						 
					
						
							
								
									
										
										
										
											2024-01-18 13:32:44 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  hs . featureManager . IsEditableFromAdminPage ( t . Name )  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-09 23:32:28 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											hs . log . Info ( "UpdateFeatureToggle: updating toggle" ,  "toggle_name" ,  t . Name ,  "enabled" ,  t . Enabled ,  "username" ,  ctx . SignedInUser . Login ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-09-26 02:11:24 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											payload . FeatureToggles [ t . Name ]  =  strconv . FormatBool ( t . Enabled ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-09 23:32:28 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											hs . log . Warn ( "UpdateFeatureToggle: invalid toggle passed in" ,  "toggle_name" ,  t . Name ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  response . Error ( http . StatusBadRequest ,  "invalid toggle passed in" ,  fmt . Errorf ( "invalid toggle passed in: %s" ,  t . Name ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-07-25 04:12:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-09-26 02:11:24 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									err  :=  sendWebhookUpdate ( featureMgmtCfg ,  payload ,  hs . log ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										hs . log . Error ( "UpdateFeatureToggle: Failed to perform webhook request" ,  "error" ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  response . Respond ( http . StatusBadRequest ,  "Failed to perform webhook request" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-09 23:32:28 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-01-10 02:38:06 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									hs . featureManager . SetRestartRequired ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-10-13 18:54:34 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-09-26 02:11:24 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  response . Respond ( http . StatusOK ,  "feature toggles updated successfully" ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-09 23:32:28 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-10-13 18:54:34 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  ( hs  * HTTPServer )  GetFeatureMgmtState ( ctx  * contextmodel . ReqContext )  response . Response  {  
						 
					
						
							
								
									
										
										
										
											2024-01-10 02:38:06 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									fmState  :=  hs . featureManager . GetState ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-10-13 18:54:34 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  response . Respond ( http . StatusOK ,  fmState ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-09-26 02:11:24 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								type  UpdatePayload  struct  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									FeatureToggles  map [ string ] string  ` json:"feature_toggles" ` 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									User            string             ` json:"user" ` 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  sendWebhookUpdate ( cfg  setting . FeatureMgmtSettings ,  payload  UpdatePayload ,  logger  log . Logger )  error  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									data ,  err  :=  json . Marshal ( payload ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									req ,  err  :=  http . NewRequest ( http . MethodPost ,  cfg . UpdateWebhook ,  bytes . NewBuffer ( data ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									req . Header . Set ( "Content-Type" ,  "application/json" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									req . Header . Set ( "Authorization" ,  "Bearer " + cfg . UpdateWebhookToken ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									client  :=  & http . Client { } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									resp ,  err  :=  client . Do ( req ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									defer  func ( )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  err  :=  resp . Body . Close ( ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											logger . Warn ( "Failed to close response body" ,  "err" ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  resp . StatusCode  >=  http . StatusBadRequest  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  body ,  err  :=  io . ReadAll ( resp . Body ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  fmt . Errorf ( "SendWebhookUpdate failed with status=%d, error: %s" ,  resp . StatusCode ,  string ( body ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  fmt . Errorf ( "SendWebhookUpdate failed with status=%d, error: %w" ,  resp . StatusCode ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  nil 
							 
						 
					
						
							
								
									
										
										
										
											2023-07-25 04:12:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}