2019-11-14 17:59:41 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								package  cloudwatch  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								import  (  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"errors" 
							 
						 
					
						
							
								
									
										
										
										
											2021-07-09 19:43:22 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"fmt" 
							 
						 
					
						
							
								
									
										
										
										
											2020-01-17 20:22:43 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"math" 
							 
						 
					
						
							
								
									
										
										
										
											2019-11-14 17:59:41 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									"regexp" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"sort" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"strconv" 
							 
						 
					
						
							
								
									
										
										
										
											2020-01-17 20:22:43 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"strings" 
							 
						 
					
						
							
								
									
										
										
										
											2019-11-14 17:59:41 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									"time" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-03-15 00:44:04 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"github.com/google/uuid" 
							 
						 
					
						
							
								
									
										
										
										
											2021-03-23 23:32:12 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"github.com/grafana/grafana-plugin-sdk-go/backend" 
							 
						 
					
						
							
								
									
										
										
										
											2019-11-14 17:59:41 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									"github.com/grafana/grafana/pkg/components/simplejson" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								)  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-03-15 00:44:04 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								var  validMetricDataID  =  regexp . MustCompile ( ` ^[a-z][a-zA-Z0-9_]*$ ` )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-09-08 22:06:43 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// parseQueries parses the json queries and returns a map of cloudWatchQueries by region. The cloudWatchQuery has a 1 to 1 mapping to a query editor row
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( e  * cloudWatchExecutor )  parseQueries ( queries  [ ] backend . DataQuery ,  startTime  time . Time ,  endTime  time . Time )  ( map [ string ] [ ] * cloudWatchQuery ,  error )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									requestQueries  :=  make ( map [ string ] [ ] * cloudWatchQuery ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									migratedQueries ,  err  :=  migrateLegacyQuery ( queries ,  startTime ,  endTime ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  _ ,  query  :=  range  migratedQueries  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-03-23 23:32:12 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										model ,  err  :=  simplejson . NewJson ( query . JSON ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  nil ,  & queryError { err :  err ,  RefID :  query . RefID } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										queryType  :=  model . Get ( "type" ) . MustString ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-11-14 17:59:41 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										if  queryType  !=  "timeSeriesQuery"  &&  queryType  !=  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-03-08 14:02:49 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										refID  :=  query . RefID 
							 
						 
					
						
							
								
									
										
										
										
											2021-03-23 23:32:12 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										query ,  err  :=  parseRequestQuery ( model ,  refID ,  startTime ,  endTime ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-11-14 17:59:41 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-18 18:25:58 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											return  nil ,  & queryError { err :  err ,  RefID :  refID } 
							 
						 
					
						
							
								
									
										
										
										
											2019-11-14 17:59:41 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-18 18:25:58 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-11-14 17:59:41 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										if  _ ,  exist  :=  requestQueries [ query . Region ] ;  ! exist  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-08 22:06:43 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											requestQueries [ query . Region ]  =  [ ] * cloudWatchQuery { } 
							 
						 
					
						
							
								
									
										
										
										
											2019-11-14 17:59:41 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										requestQueries [ query . Region ]  =  append ( requestQueries [ query . Region ] ,  query ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  requestQueries ,  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-09-08 22:06:43 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// migrateLegacyQuery migrates queries that has a `statistics` field to use the `statistic` field instead.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// This migration is also done in the frontend, so this should only ever be needed for alerting queries
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// In case the query used more than one stat, the first stat in the slice will be used in the statistic field
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// Read more here https://github.com/grafana/grafana/issues/30629
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  migrateLegacyQuery ( queries  [ ] backend . DataQuery ,  startTime  time . Time ,  endTime  time . Time )  ( [ ] * backend . DataQuery ,  error )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									migratedQueries  :=  [ ] * backend . DataQuery { } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  _ ,  q  :=  range  queries  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										query  :=  q 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										model ,  err  :=  simplejson . NewJson ( query . JSON ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										_ ,  err  =  model . Get ( "statistic" ) . String ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// If there's not a statistic property in the json, we know it's the legacy format and then it has to be migrated
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											stats ,  err  :=  model . Get ( "statistics" ) . StringArray ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return  nil ,  fmt . Errorf ( "query must have either statistic or statistics field" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											model . Del ( "statistics" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											model . Set ( "statistic" ,  stats [ 0 ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											query . JSON ,  err  =  model . MarshalJSON ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										migratedQueries  =  append ( migratedQueries ,  & query ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  migratedQueries ,  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  parseRequestQuery ( model  * simplejson . Json ,  refId  string ,  startTime  time . Time ,  endTime  time . Time )  ( * cloudWatchQuery ,  error )  {  
						 
					
						
							
								
									
										
										
										
											2020-10-06 19:45:58 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									plog . Debug ( "Parsing request query" ,  "query" ,  model ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-18 18:25:58 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									reNumber  :=  regexp . MustCompile ( ` ^\d+$ ` ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-11-14 17:59:41 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									region ,  err  :=  model . Get ( "region" ) . String ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									namespace ,  err  :=  model . Get ( "namespace" ) . String ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-07-09 19:43:22 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  nil ,  fmt . Errorf ( "failed to get namespace: %v" ,  err ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-11-14 17:59:41 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									metricName ,  err  :=  model . Get ( "metricName" ) . String ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-07-09 19:43:22 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  nil ,  fmt . Errorf ( "failed to get metricName: %v" ,  err ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-11-14 17:59:41 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									dimensions ,  err  :=  parseDimensions ( model ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-07-09 19:43:22 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  nil ,  fmt . Errorf ( "failed to parse dimensions: %v" ,  err ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-11-14 17:59:41 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-08 22:06:43 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									statistic ,  err  :=  model . Get ( "statistic" ) . String ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  fmt . Errorf ( "failed to parse statistic: %v" ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2019-11-14 17:59:41 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									p  :=  model . Get ( "period" ) . MustString ( "" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									var  period  int 
							 
						 
					
						
							
								
									
										
										
										
											2020-01-17 20:22:43 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  strings . ToLower ( p )  ==  "auto"  ||  p  ==  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										deltaInSeconds  :=  endTime . Sub ( startTime ) . Seconds ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-01 15:44:47 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										periods  :=  getRetainedPeriods ( time . Since ( startTime ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-01-22 20:43:36 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										datapoints  :=  int ( math . Ceil ( deltaInSeconds  /  2000 ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										period  =  periods [ len ( periods ) - 1 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										for  _ ,  value  :=  range  periods  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  datapoints  <=  value  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												period  =  value 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												break 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2019-11-14 17:59:41 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									}  else  { 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-18 18:25:58 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  reNumber . Match ( [ ] byte ( p ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2020-01-17 20:22:43 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											period ,  err  =  strconv . Atoi ( p ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-07-09 19:43:22 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												return  nil ,  fmt . Errorf ( "failed to parse period as integer: %v" ,  err ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-01-17 20:22:43 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											d ,  err  :=  time . ParseDuration ( p ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-07-09 19:43:22 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												return  nil ,  fmt . Errorf ( "failed to parse period as duration: %v" ,  err ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-01-17 20:22:43 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											period  =  int ( d . Seconds ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-11-14 17:59:41 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									id  :=  model . Get ( "id" ) . MustString ( "" ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-08 22:06:43 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  id  ==  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// Why not just use refId if id is not specified in the frontend? When specifying an id in the editor,
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// and alphabetical must be used. The id must be unique, so if an id like for example a, b or c would be used,
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// it would likely collide with some ref id. That's why the `query` prefix is used.
 
							 
						 
					
						
							
								
									
										
										
										
											2022-03-15 00:44:04 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										suffix  :=  refId 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ! validMetricDataID . MatchString ( suffix )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											uuid  :=  uuid . NewString ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											suffix  =  strings . Replace ( uuid ,  "-" ,  "" ,  - 1 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										id  =  fmt . Sprintf ( "query%s" ,  suffix ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-08 22:06:43 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2019-11-14 17:59:41 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									expression  :=  model . Get ( "expression" ) . MustString ( "" ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-11-30 17:53:31 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									sqlExpression  :=  model . Get ( "sqlExpression" ) . MustString ( "" ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-11-14 17:59:41 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									alias  :=  model . Get ( "alias" ) . MustString ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									returnData  :=  ! model . Get ( "hide" ) . MustBool ( false ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									queryType  :=  model . Get ( "type" ) . MustString ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  queryType  ==  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// If no type is provided we assume we are called by alerting service, which requires to return data!
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// Note, this is sort of a hack, but the official Grafana interfaces do not carry the information
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// who (which service) called the TsdbQueryEndpoint.Query(...) function.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										returnData  =  true 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									matchExact  :=  model . Get ( "matchExact" ) . MustBool ( true ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-11-30 17:53:31 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									metricQueryType  :=  metricQueryType ( model . Get ( "metricQueryType" ) . MustInt ( 0 ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									var  metricEditorModeValue  metricEditorMode 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									memv ,  err  :=  model . Get ( "metricEditorMode" ) . Int ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  &&  len ( expression )  >  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// this should only ever happen if this is an alerting query that has not yet been migrated in the frontend
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										metricEditorModeValue  =  MetricEditorModeRaw 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										metricEditorModeValue  =  metricEditorMode ( memv ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2019-11-14 17:59:41 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-09-08 22:06:43 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  & cloudWatchQuery { 
							 
						 
					
						
							
								
									
										
										
										
											2021-11-30 17:53:31 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										RefId :             refId , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										Region :            region , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										Id :                id , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										Namespace :         namespace , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										MetricName :        metricName , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										Statistic :         statistic , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										Expression :        expression , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ReturnData :        returnData , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										Dimensions :        dimensions , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										Period :            period , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										Alias :             alias , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										MatchExact :        matchExact , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										UsedExpression :    "" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										MetricQueryType :   metricQueryType , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										MetricEditorMode :  metricEditorModeValue , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										SqlExpression :     sqlExpression , 
							 
						 
					
						
							
								
									
										
										
										
											2019-11-14 17:59:41 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} ,  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-09-01 15:44:47 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  getRetainedPeriods ( timeSince  time . Duration )  [ ] int  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// See https://aws.amazon.com/about-aws/whats-new/2016/11/cloudwatch-extends-metrics-retention-and-new-user-interface/
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  timeSince  >  time . Duration ( 455 ) * 24 * time . Hour  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  [ ] int { 21600 ,  86400 } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}  else  if  timeSince  >  time . Duration ( 63 ) * 24 * time . Hour  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  [ ] int { 3600 ,  21600 ,  86400 } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}  else  if  timeSince  >  time . Duration ( 15 ) * 24 * time . Hour  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  [ ] int { 300 ,  900 ,  3600 ,  21600 ,  86400 } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  [ ] int { 60 ,  300 ,  900 ,  3600 ,  21600 ,  86400 } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-11-14 17:59:41 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								func  parseDimensions ( model  * simplejson . Json )  ( map [ string ] [ ] string ,  error )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									parsedDimensions  :=  make ( map [ string ] [ ] string ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  k ,  v  :=  range  model . Get ( "dimensions" ) . MustMap ( )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// This is for backwards compatibility. Before 6.5 dimensions values were stored as strings and not arrays
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  value ,  ok  :=  v . ( string ) ;  ok  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											parsedDimensions [ k ]  =  [ ] string { value } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}  else  if  values ,  ok  :=  v . ( [ ] interface { } ) ;  ok  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											for  _ ,  value  :=  range  values  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												parsedDimensions [ k ]  =  append ( parsedDimensions [ k ] ,  value . ( string ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}  else  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-07-09 19:43:22 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											return  nil ,  errors . New ( "unknown type as dimension value" ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-11-14 17:59:41 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									sortedDimensions  :=  sortDimensions ( parsedDimensions ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  sortedDimensions ,  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  sortDimensions ( dimensions  map [ string ] [ ] string )  map [ string ] [ ] string  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									sortedDimensions  :=  make ( map [ string ] [ ] string ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									var  keys  [ ] string 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  k  :=  range  dimensions  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										keys  =  append ( keys ,  k ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									sort . Strings ( keys ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  _ ,  k  :=  range  keys  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										sortedDimensions [ k ]  =  dimensions [ k ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  sortedDimensions 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}