mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
CloudWatch: Migrate alias to dynamic labels (#48555)
This commit is contained in:
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/google/uuid"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
)
|
||||
|
||||
var validMetricDataID = regexp.MustCompile(`^[a-z][a-zA-Z0-9_]*$`)
|
||||
@@ -20,7 +21,8 @@ var validMetricDataID = regexp.MustCompile(`^[a-z][a-zA-Z0-9_]*$`)
|
||||
// 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)
|
||||
|
||||
migratedQueries, err := migrateLegacyQuery(queries, e.features.IsEnabled(featuremgmt.FlagCloudWatchDynamicLabels), startTime, endTime)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -51,32 +53,28 @@ func (e *cloudWatchExecutor) parseQueries(queries []backend.DataQuery, startTime
|
||||
return requestQueries, nil
|
||||
}
|
||||
|
||||
// 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) {
|
||||
// migrateLegacyQuery is also done in the frontend, so this should only ever be needed for alerting queries
|
||||
func migrateLegacyQuery(queries []backend.DataQuery, dynamicLabelsEnabled bool, startTime time.Time, endTime time.Time) ([]*backend.DataQuery, error) {
|
||||
migratedQueries := []*backend.DataQuery{}
|
||||
for _, q := range queries {
|
||||
query := q
|
||||
model, err := simplejson.NewJson(query.JSON)
|
||||
queryJson, 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 := migrateStatisticsToStatistic(queryJson); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, labelExists := queryJson.CheckGet("label")
|
||||
if !labelExists && dynamicLabelsEnabled {
|
||||
migrateAliasToDynamicLabel(queryJson)
|
||||
}
|
||||
|
||||
query.JSON, err = queryJson.MarshalJSON()
|
||||
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
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
migratedQueries = append(migratedQueries, &query)
|
||||
@@ -85,6 +83,53 @@ func migrateLegacyQuery(queries []backend.DataQuery, startTime time.Time, endTim
|
||||
return migratedQueries, nil
|
||||
}
|
||||
|
||||
// migrateStatisticsToStatistic migrates queries that has a `statistics` field to use the `statistic` field instead.
|
||||
// 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 migrateStatisticsToStatistic(queryJson *simplejson.Json) error {
|
||||
_, err := queryJson.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 := queryJson.Get("statistics").StringArray()
|
||||
if err != nil {
|
||||
return fmt.Errorf("query must have either statistic or statistics field")
|
||||
}
|
||||
queryJson.Del("statistics")
|
||||
queryJson.Set("statistic", stats[0])
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var aliasPatterns = map[string]string{
|
||||
"metric": `${PROP('MetricName')}`,
|
||||
"namespace": `${PROP('Namespace')}`,
|
||||
"period": `${PROP('Period')}`,
|
||||
"region": `${PROP('Region')}`,
|
||||
"stat": `${PROP('Stat')}`,
|
||||
"label": `${LABEL}`,
|
||||
}
|
||||
|
||||
var legacyAliasRegexp = regexp.MustCompile(`{{\s*(.+?)\s*}}`)
|
||||
|
||||
func migrateAliasToDynamicLabel(queryJson *simplejson.Json) {
|
||||
fullAliasField := queryJson.Get("alias").MustString()
|
||||
if fullAliasField != "" {
|
||||
matches := legacyAliasRegexp.FindAllStringSubmatch(fullAliasField, -1)
|
||||
for _, groups := range matches {
|
||||
fullMatch := groups[0]
|
||||
subgroup := groups[1]
|
||||
if dynamicLabel, ok := aliasPatterns[subgroup]; ok {
|
||||
fullAliasField = strings.ReplaceAll(fullAliasField, fullMatch, dynamicLabel)
|
||||
} else {
|
||||
fullAliasField = strings.ReplaceAll(fullAliasField, fullMatch, fmt.Sprintf(`${PROP('Dim.%s')}`, subgroup))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
queryJson.Set("label", fullAliasField)
|
||||
}
|
||||
|
||||
func parseRequestQuery(model *simplejson.Json, refId string, startTime time.Time, endTime time.Time) (*cloudWatchQuery, error) {
|
||||
plog.Debug("Parsing request query", "query", model)
|
||||
reNumber := regexp.MustCompile(`^\d+$`)
|
||||
|
||||
Reference in New Issue
Block a user