diff --git a/pkg/tsdb/azuremonitor/metrics/azuremonitor-datasource.go b/pkg/tsdb/azuremonitor/metrics/azuremonitor-datasource.go index f7c73a8ef18..c3cb16f8eac 100644 --- a/pkg/tsdb/azuremonitor/metrics/azuremonitor-datasource.go +++ b/pkg/tsdb/azuremonitor/metrics/azuremonitor-datasource.go @@ -74,33 +74,28 @@ func (e *AzureMonitorDatasource) buildQueries(queries []backend.DataQuery, dsInf } azJSONModel := queryJSONModel.AzureMonitor + // Legacy: If only MetricDefinition is set, use it as namespace + if azJSONModel.MetricDefinition != "" && azJSONModel.MetricNamespace == "" { + azJSONModel.MetricNamespace = azJSONModel.MetricDefinition + } ub := urlBuilder{ ResourceURI: azJSONModel.ResourceURI, - // Legacy, used to reconstruct resource URI if it's not present + // Alternative, used to reconstruct resource URI if it's not present DefaultSubscription: dsInfo.Settings.SubscriptionId, Subscription: queryJSONModel.Subscription, ResourceGroup: azJSONModel.ResourceGroup, - MetricDefinition: azJSONModel.MetricDefinition, + MetricNamespace: azJSONModel.MetricNamespace, ResourceName: azJSONModel.ResourceName, } azJSONModel.DimensionFilters = MigrateDimensionFilters(azJSONModel.DimensionFilters) azureURL := ub.BuildMetricsURL() - resourceName := azJSONModel.ResourceName - if resourceName == "" { - resourceName = extractResourceNameFromMetricsURL(azureURL) + if azJSONModel.ResourceName == "" { + azJSONModel.ResourceName = extractResourceNameFromMetricsURL(azureURL) } - urlComponents := map[string]string{} - urlComponents["resourceURI"] = azJSONModel.ResourceURI - // Legacy fields used for constructing a deep link to display the query in Azure Portal. - urlComponents["subscription"] = queryJSONModel.Subscription - urlComponents["resourceGroup"] = azJSONModel.ResourceGroup - urlComponents["metricDefinition"] = azJSONModel.MetricDefinition - urlComponents["resourceName"] = resourceName - alias := azJSONModel.Alias timeGrain := azJSONModel.TimeGrain @@ -156,13 +151,14 @@ func (e *AzureMonitorDatasource) buildQueries(queries []backend.DataQuery, dsInf } azureMonitorQueries = append(azureMonitorQueries, &types.AzureMonitorQuery{ - URL: azureURL, - UrlComponents: urlComponents, - Target: target, - Params: params, - RefID: query.RefID, - Alias: alias, - TimeRange: query.TimeRange, + ResourceName: azJSONModel.ResourceName, + ResourceURI: ub.buildResourceURI(), + URL: azureURL, + Target: target, + Params: params, + RefID: query.RefID, + Alias: alias, + TimeRange: query.TimeRange, }) } @@ -288,7 +284,7 @@ func (e *AzureMonitorDatasource) parseResponse(amr types.AzureMonitorResponse, q }) } if query.Alias != "" { - displayName := formatAzureMonitorLegendKey(query.Alias, query.UrlComponents["resourceName"], + displayName := formatAzureMonitorLegendKey(query.Alias, query.ResourceName, amr.Value[0].Name.LocalizedValue, "", "", amr.Namespace, amr.Value[0].ID, labels) if dataField.Config != nil { @@ -353,32 +349,20 @@ func getQueryUrl(query *types.AzureMonitorQuery, azurePortalUrl string) (string, } escapedTime := url.QueryEscape(string(timespan)) - id := query.UrlComponents["resourceURI"] - - if id == "" { - ub := urlBuilder{ - Subscription: query.UrlComponents["subscription"], - ResourceGroup: query.UrlComponents["resourceGroup"], - MetricDefinition: query.UrlComponents["metricDefinition"], - ResourceName: query.UrlComponents["resourceName"], - } - id = ub.buildResourceURIFromLegacyQuery() - } - chartDef, err := json.Marshal(map[string]interface{}{ "v2charts": []interface{}{ map[string]interface{}{ "metrics": []types.MetricChartDefinition{ { ResourceMetadata: map[string]string{ - "id": id, + "id": query.ResourceURI, }, Name: query.Params.Get("metricnames"), AggregationType: aggregationType, Namespace: query.Params.Get("metricnamespace"), MetricVisualization: types.MetricVisualization{ DisplayName: query.Params.Get("metricnames"), - ResourceDisplayName: query.UrlComponents["resourceName"], + ResourceDisplayName: query.ResourceName, }, }, }, @@ -414,7 +398,7 @@ func formatAzureMonitorLegendKey(alias string, resourceName string, metricName s for k := range lowerLabels { keys = append(keys, k) } - keys = sort.StringSlice(keys) + sort.Strings(keys) result := types.LegendKeyFormat.ReplaceAllFunc([]byte(alias), func(in []byte) []byte { metaPartName := strings.Replace(string(in), "{{", "", 1) diff --git a/pkg/tsdb/azuremonitor/metrics/azuremonitor-datasource_test.go b/pkg/tsdb/azuremonitor/metrics/azuremonitor-datasource_test.go index 33be35745c4..27ba75c83ee 100644 --- a/pkg/tsdb/azuremonitor/metrics/azuremonitor-datasource_test.go +++ b/pkg/tsdb/azuremonitor/metrics/azuremonitor-datasource_test.go @@ -51,7 +51,7 @@ func TestAzureMonitorBuildQueries(t *testing.T) { }, resourceURI: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana", expectedInterval: "PT1M", - azureMonitorQueryTarget: "aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute-virtualMachines×pan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z", + azureMonitorQueryTarget: "aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute%2FvirtualMachines×pan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z", }, { name: "legacy query without resourceURI and time grain set to auto", @@ -61,7 +61,7 @@ func TestAzureMonitorBuildQueries(t *testing.T) { }, queryInterval: duration, expectedInterval: "PT15M", - azureMonitorQueryTarget: "aggregation=Average&api-version=2018-01-01&interval=PT15M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute-virtualMachines×pan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z", + azureMonitorQueryTarget: "aggregation=Average&api-version=2018-01-01&interval=PT15M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute%2FvirtualMachines×pan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z", }, { name: "legacy query without resourceURI and time grain set to auto", @@ -72,7 +72,7 @@ func TestAzureMonitorBuildQueries(t *testing.T) { }, queryInterval: duration, expectedInterval: "PT5M", - azureMonitorQueryTarget: "aggregation=Average&api-version=2018-01-01&interval=PT5M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute-virtualMachines×pan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z", + azureMonitorQueryTarget: "aggregation=Average&api-version=2018-01-01&interval=PT5M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute%2FvirtualMachines×pan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z", }, { name: "legacy query without resourceURI and has a dimension filter", @@ -84,7 +84,7 @@ func TestAzureMonitorBuildQueries(t *testing.T) { }, queryInterval: duration, expectedInterval: "PT1M", - azureMonitorQueryTarget: "%24filter=blob+eq+%27%2A%27&aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute-virtualMachines×pan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z&top=30", + azureMonitorQueryTarget: "%24filter=blob+eq+%27%2A%27&aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute%2FvirtualMachines×pan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z&top=30", }, { name: "legacy query without resourceURI and has a dimension filter and none Dimension", @@ -96,7 +96,7 @@ func TestAzureMonitorBuildQueries(t *testing.T) { }, queryInterval: duration, expectedInterval: "PT1M", - azureMonitorQueryTarget: "aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute-virtualMachines×pan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z", + azureMonitorQueryTarget: "aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute%2FvirtualMachines×pan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z", }, { name: "legacy query without resourceURI and has dimensionFilter*s* property with one dimension", @@ -107,7 +107,7 @@ func TestAzureMonitorBuildQueries(t *testing.T) { }, queryInterval: duration, expectedInterval: "PT1M", - azureMonitorQueryTarget: "%24filter=blob+eq+%27%2A%27&aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute-virtualMachines×pan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z&top=30", + azureMonitorQueryTarget: "%24filter=blob+eq+%27%2A%27&aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute%2FvirtualMachines×pan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z&top=30", }, { name: "legacy query without resourceURI and has dimensionFilter*s* property with two dimensions", @@ -118,7 +118,7 @@ func TestAzureMonitorBuildQueries(t *testing.T) { }, queryInterval: duration, expectedInterval: "PT1M", - azureMonitorQueryTarget: "%24filter=blob+eq+%27%2A%27+and+tier+eq+%27%2A%27&aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute-virtualMachines×pan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z&top=30", + azureMonitorQueryTarget: "%24filter=blob+eq+%27%2A%27+and+tier+eq+%27%2A%27&aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute%2FvirtualMachines×pan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z&top=30", }, { name: "legacy query without resourceURI and has a dimension filter without specifying a top", @@ -129,7 +129,7 @@ func TestAzureMonitorBuildQueries(t *testing.T) { }, queryInterval: duration, expectedInterval: "PT1M", - azureMonitorQueryTarget: "%24filter=blob+eq+%27%2A%27&aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute-virtualMachines×pan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z", + azureMonitorQueryTarget: "%24filter=blob+eq+%27%2A%27&aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute%2FvirtualMachines×pan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z", }, { name: "has dimensionFilter*s* property with not equals operator", @@ -140,7 +140,7 @@ func TestAzureMonitorBuildQueries(t *testing.T) { }, queryInterval: duration, expectedInterval: "PT1M", - azureMonitorQueryTarget: "%24filter=blob+ne+%27test%27&aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute-virtualMachines×pan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z&top=30", + azureMonitorQueryTarget: "%24filter=blob+ne+%27test%27&aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute%2FvirtualMachines×pan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z&top=30", }, { name: "has dimensionFilter*s* property with startsWith operator", @@ -151,7 +151,7 @@ func TestAzureMonitorBuildQueries(t *testing.T) { }, queryInterval: duration, expectedInterval: "PT1M", - azureMonitorQueryTarget: "%24filter=blob+sw+%27test%27&aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute-virtualMachines×pan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z&top=30", + azureMonitorQueryTarget: "%24filter=blob+sw+%27test%27&aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute%2FvirtualMachines×pan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z&top=30", }, { name: "correctly sets dimension operator to eq (irrespective of operator) when filter value is '*'", @@ -162,7 +162,7 @@ func TestAzureMonitorBuildQueries(t *testing.T) { }, queryInterval: duration, expectedInterval: "PT1M", - azureMonitorQueryTarget: "%24filter=blob+eq+%27%2A%27+and+tier+eq+%27%2A%27&aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute-virtualMachines×pan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z&top=30", + azureMonitorQueryTarget: "%24filter=blob+eq+%27%2A%27+and+tier+eq+%27%2A%27&aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute%2FvirtualMachines×pan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z&top=30", }, { name: "correctly constructs target when multiple filter values are provided for the 'eq' operator", @@ -173,7 +173,7 @@ func TestAzureMonitorBuildQueries(t *testing.T) { }, queryInterval: duration, expectedInterval: "PT1M", - azureMonitorQueryTarget: "%24filter=blob+eq+%27test%27+or+blob+eq+%27test2%27&aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute-virtualMachines×pan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z&top=30", + azureMonitorQueryTarget: "%24filter=blob+eq+%27test%27+or+blob+eq+%27test2%27&aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute%2FvirtualMachines×pan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z&top=30", }, { name: "correctly constructs target when multiple filter values are provided for ne 'eq' operator", @@ -184,17 +184,16 @@ func TestAzureMonitorBuildQueries(t *testing.T) { }, queryInterval: duration, expectedInterval: "PT1M", - azureMonitorQueryTarget: "%24filter=blob+ne+%27test%27+and+blob+ne+%27test2%27&aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute-virtualMachines×pan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z&top=30", + azureMonitorQueryTarget: "%24filter=blob+ne+%27test%27+and+blob+ne+%27test2%27&aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute%2FvirtualMachines×pan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z&top=30", }, } commonAzureModelProps := map[string]interface{}{ - "aggregation": "Average", - "resourceGroup": "grafanastaging", - "resourceName": "grafana", - "metricDefinition": "Microsoft.Compute/virtualMachines", - "metricNamespace": "Microsoft.Compute-virtualMachines", - "metricName": "Percentage CPU", + "aggregation": "Average", + "resourceGroup": "grafanastaging", + "resourceName": "grafana", + "metricNamespace": "Microsoft.Compute/virtualMachines", + "metricName": "Percentage CPU", "alias": "testalias", "queryType": "Azure Monitor", @@ -222,17 +221,12 @@ func TestAzureMonitorBuildQueries(t *testing.T) { } azureMonitorQuery := &types.AzureMonitorQuery{ - URL: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana/providers/microsoft.insights/metrics", - UrlComponents: map[string]string{ - "resourceURI": tt.resourceURI, - "metricDefinition": "Microsoft.Compute/virtualMachines", - "resourceGroup": "grafanastaging", - "resourceName": "grafana", - "subscription": "12345678-aaaa-bbbb-cccc-123456789abc", - }, - Target: tt.azureMonitorQueryTarget, - RefID: "A", - Alias: "testalias", + ResourceName: "grafana", + ResourceURI: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana", + URL: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana/providers/microsoft.insights/metrics", + Target: tt.azureMonitorQueryTarget, + RefID: "A", + Alias: "testalias", TimeRange: backend.TimeRange{ From: fromStart, To: fromStart.Add(34 * time.Minute), @@ -248,7 +242,7 @@ func TestAzureMonitorBuildQueries(t *testing.T) { expected := `http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/` + `TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%222018-03-15T13%3A00%3A00Z%22%2C%22endTime%22%3A%222018-03-15T13%3A34%3A00Z%22%7D%7D/` + `ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C` + - `%22name%22%3A%22Percentage%20CPU%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22Microsoft.Compute-virtualMachines%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22Percentage%20CPU%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D` + `%22name%22%3A%22Percentage%20CPU%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22Microsoft.Compute%2FvirtualMachines%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22Percentage%20CPU%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D` actual, err := getQueryUrl(queries[0], "http://ds") require.NoError(t, err) require.Equal(t, expected, actual) @@ -300,10 +294,8 @@ func TestAzureMonitorParseResponse(t *testing.T) { name: "average aggregate time series response", responseFile: "1-azure-monitor-response-avg.json", mockQuery: &types.AzureMonitorQuery{ - UrlComponents: map[string]string{ - "resourceName": "grafana", - "resourceURI": "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana", - }, + ResourceName: "grafana", + ResourceURI: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana", Params: url.Values{ "aggregation": {"Average"}, }, @@ -322,10 +314,8 @@ func TestAzureMonitorParseResponse(t *testing.T) { name: "total aggregate time series response", responseFile: "2-azure-monitor-response-total.json", mockQuery: &types.AzureMonitorQuery{ - UrlComponents: map[string]string{ - "resourceName": "grafana", - "resourceURI": "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana", - }, + ResourceName: "grafana", + ResourceURI: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana", Params: url.Values{ "aggregation": {"Total"}, }, @@ -344,10 +334,8 @@ func TestAzureMonitorParseResponse(t *testing.T) { name: "maximum aggregate time series response", responseFile: "3-azure-monitor-response-maximum.json", mockQuery: &types.AzureMonitorQuery{ - UrlComponents: map[string]string{ - "resourceName": "grafana", - "resourceURI": "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana", - }, + ResourceName: "grafana", + ResourceURI: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana", Params: url.Values{ "aggregation": {"Maximum"}, }, @@ -366,10 +354,8 @@ func TestAzureMonitorParseResponse(t *testing.T) { name: "minimum aggregate time series response", responseFile: "4-azure-monitor-response-minimum.json", mockQuery: &types.AzureMonitorQuery{ - UrlComponents: map[string]string{ - "resourceName": "grafana", - "resourceURI": "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana", - }, + ResourceName: "grafana", + ResourceURI: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana", Params: url.Values{ "aggregation": {"Minimum"}, }, @@ -388,10 +374,8 @@ func TestAzureMonitorParseResponse(t *testing.T) { name: "count aggregate time series response", responseFile: "5-azure-monitor-response-count.json", mockQuery: &types.AzureMonitorQuery{ - UrlComponents: map[string]string{ - "resourceName": "grafana", - "resourceURI": "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana", - }, + ResourceName: "grafana", + ResourceURI: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana", Params: url.Values{ "aggregation": {"Count"}, }, @@ -410,10 +394,8 @@ func TestAzureMonitorParseResponse(t *testing.T) { name: "single dimension time series response", responseFile: "6-azure-monitor-response-single-dimension.json", mockQuery: &types.AzureMonitorQuery{ - UrlComponents: map[string]string{ - "resourceName": "grafana", - "resourceURI": "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana", - }, + ResourceName: "grafana", + ResourceURI: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana", Params: url.Values{ "aggregation": {"Average"}, }, @@ -445,11 +427,9 @@ func TestAzureMonitorParseResponse(t *testing.T) { name: "with alias patterns in the query", responseFile: "2-azure-monitor-response-total.json", mockQuery: &types.AzureMonitorQuery{ - Alias: "custom {{resourcegroup}} {{namespace}} {{resourceName}} {{metric}}", - UrlComponents: map[string]string{ - "resourceName": "grafana", - "resourceURI": "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana", - }, + ResourceName: "grafana", + ResourceURI: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana", + Alias: "custom {{resourcegroup}} {{namespace}} {{resourceName}} {{metric}}", Params: url.Values{ "aggregation": {"Total"}, }, @@ -468,11 +448,9 @@ func TestAzureMonitorParseResponse(t *testing.T) { name: "single dimension with alias", responseFile: "6-azure-monitor-response-single-dimension.json", mockQuery: &types.AzureMonitorQuery{ - Alias: "{{dimensionname}}={{DimensionValue}}", - UrlComponents: map[string]string{ - "resourceName": "grafana", - "resourceURI": "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana", - }, + ResourceName: "grafana", + ResourceURI: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana", + Alias: "{{dimensionname}}={{DimensionValue}}", Params: url.Values{ "aggregation": {"Average"}, }, @@ -506,11 +484,9 @@ func TestAzureMonitorParseResponse(t *testing.T) { name: "multiple dimension time series response with label alias", responseFile: "7-azure-monitor-response-multi-dimension.json", mockQuery: &types.AzureMonitorQuery{ - Alias: "{{resourcegroup}} {Blob Type={{blobtype}}, Tier={{Tier}}}", - UrlComponents: map[string]string{ - "resourceName": "grafana", - "resourceURI": "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana", - }, + ResourceName: "grafana", + ResourceURI: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana", + Alias: "{{resourcegroup}} {Blob Type={{blobtype}}, Tier={{Tier}}}", Params: url.Values{ "aggregation": {"Average"}, }, @@ -545,11 +521,9 @@ func TestAzureMonitorParseResponse(t *testing.T) { name: "unspecified unit with alias should not panic", responseFile: "8-azure-monitor-response-unspecified-unit.json", mockQuery: &types.AzureMonitorQuery{ - Alias: "custom", - UrlComponents: map[string]string{ - "resourceName": "grafana", - "resourceURI": "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana", - }, + ResourceName: "grafana", + ResourceURI: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana", + Alias: "custom", Params: url.Values{ "aggregation": {"Average"}, }, @@ -568,13 +542,9 @@ func TestAzureMonitorParseResponse(t *testing.T) { name: "with legacy azure monitor query properties and without a resource uri", responseFile: "2-azure-monitor-response-total.json", mockQuery: &types.AzureMonitorQuery{ - Alias: "custom {{resourcegroup}} {{namespace}} {{resourceName}} {{metric}}", - UrlComponents: map[string]string{ - "subscription": "12345678-aaaa-bbbb-cccc-123456789abc", - "resourceGroup": "grafanastaging", - "metricDefinition": "Microsoft.Compute/virtualMachines", - "resourceName": "grafana", - }, + ResourceName: "grafana", + ResourceURI: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana", + Alias: "custom {{resourcegroup}} {{namespace}} {{resourceName}} {{metric}}", Params: url.Values{ "aggregation": {"Total"}, }, @@ -593,14 +563,9 @@ func TestAzureMonitorParseResponse(t *testing.T) { name: "with legacy azure monitor query properties and with a resource uri it should use the resource uri", responseFile: "2-azure-monitor-response-total.json", mockQuery: &types.AzureMonitorQuery{ - Alias: "custom {{resourcegroup}} {{namespace}} {{resourceName}} {{metric}}", - UrlComponents: map[string]string{ - "resourceURI": "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana", - "subscription": "12345678-aaaa-bbbb-cccc-123456789abc-nope", - "resourceGroup": "grafanastaging-nope", - "metricDefinition": "Microsoft.Compute/virtualMachines-nope", - "resourceName": "grafana", - }, + ResourceName: "grafana", + ResourceURI: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana", + Alias: "custom {{resourcegroup}} {{namespace}} {{resourceName}} {{metric}}", Params: url.Values{ "aggregation": {"Total"}, }, diff --git a/pkg/tsdb/azuremonitor/metrics/url-builder.go b/pkg/tsdb/azuremonitor/metrics/url-builder.go index 432e80a98aa..2378a96220f 100644 --- a/pkg/tsdb/azuremonitor/metrics/url-builder.go +++ b/pkg/tsdb/azuremonitor/metrics/url-builder.go @@ -9,26 +9,29 @@ import ( type urlBuilder struct { ResourceURI string - // Following fields will be deprecated in grafana 9 and will not included in new queries. - // For backwards compat, we recreate the ResourceURI using these fields + // Following fields will be used to generate a ResourceURI DefaultSubscription string Subscription string ResourceGroup string - MetricDefinition string + MetricNamespace string ResourceName string } -func (params *urlBuilder) buildResourceURIFromLegacyQuery() string { +func (params *urlBuilder) buildResourceURI() string { + if params.ResourceURI != "" { + return params.ResourceURI + } + subscription := params.Subscription if params.Subscription == "" { subscription = params.DefaultSubscription } - metricDefinitionArray := strings.Split(params.MetricDefinition, "/") + metricNamespaceArray := strings.Split(params.MetricNamespace, "/") resourceNameArray := strings.Split(params.ResourceName, "/") - provider := metricDefinitionArray[0] - metricDefinitionArray = metricDefinitionArray[1:] + provider := metricNamespaceArray[0] + metricNamespaceArray = metricNamespaceArray[1:] urlArray := []string{ "/subscriptions", @@ -39,22 +42,22 @@ func (params *urlBuilder) buildResourceURIFromLegacyQuery() string { provider, } - for i, metricDefinition := range metricDefinitionArray { - urlArray = append(urlArray, metricDefinition, resourceNameArray[i]) + for i, namespace := range metricNamespaceArray { + urlArray = append(urlArray, namespace, resourceNameArray[i]) } resourceURI := strings.Join(urlArray, "/") return resourceURI } -// BuildMetricsURL checks the metric definition property to see which form of the url +// BuildMetricsURL checks the metric properties to see which form of the url // should be returned func (params *urlBuilder) BuildMetricsURL() string { resourceURI := params.ResourceURI // Prior to Grafana 9, we had a legacy query object rather than a resourceURI, so we manually create the resource URI if resourceURI == "" { - resourceURI = params.buildResourceURIFromLegacyQuery() + resourceURI = params.buildResourceURI() } return fmt.Sprintf("%s/providers/microsoft.insights/metrics", resourceURI) diff --git a/pkg/tsdb/azuremonitor/metrics/url-builder_test.go b/pkg/tsdb/azuremonitor/metrics/url-builder_test.go index 1abde71f094..5a184db02df 100644 --- a/pkg/tsdb/azuremonitor/metrics/url-builder_test.go +++ b/pkg/tsdb/azuremonitor/metrics/url-builder_test.go @@ -22,7 +22,7 @@ func TestURLBuilder(t *testing.T) { ResourceURI: "/subscriptions/sub/resource/uri", DefaultSubscription: "default-sub", ResourceGroup: "rg", - MetricDefinition: "Microsoft.NetApp/netAppAccounts/capacityPools/volumes", + MetricNamespace: "Microsoft.NetApp/netAppAccounts/capacityPools/volumes", ResourceName: "rn1/rn2/rn3", } @@ -35,7 +35,7 @@ func TestURLBuilder(t *testing.T) { ub := &urlBuilder{ DefaultSubscription: "default-sub", ResourceGroup: "rg", - MetricDefinition: "Microsoft.Compute/virtualMachines", + MetricNamespace: "Microsoft.Compute/virtualMachines", ResourceName: "rn", } @@ -48,7 +48,7 @@ func TestURLBuilder(t *testing.T) { DefaultSubscription: "default-sub", Subscription: "specified-sub", ResourceGroup: "rg", - MetricDefinition: "Microsoft.Compute/virtualMachines", + MetricNamespace: "Microsoft.Compute/virtualMachines", ResourceName: "rn", } @@ -60,7 +60,7 @@ func TestURLBuilder(t *testing.T) { ub := &urlBuilder{ DefaultSubscription: "default-sub", ResourceGroup: "rg", - MetricDefinition: "Microsoft.Storage/storageAccounts/blobServices", + MetricNamespace: "Microsoft.Storage/storageAccounts/blobServices", ResourceName: "rn1/default", } @@ -72,7 +72,7 @@ func TestURLBuilder(t *testing.T) { ub := &urlBuilder{ DefaultSubscription: "default-sub", ResourceGroup: "rg", - MetricDefinition: "Microsoft.Storage/storageAccounts/fileServices", + MetricNamespace: "Microsoft.Storage/storageAccounts/fileServices", ResourceName: "rn1/default", } @@ -84,7 +84,7 @@ func TestURLBuilder(t *testing.T) { ub := &urlBuilder{ DefaultSubscription: "default-sub", ResourceGroup: "rg", - MetricDefinition: "Microsoft.NetApp/netAppAccounts/capacityPools/volumes", + MetricNamespace: "Microsoft.NetApp/netAppAccounts/capacityPools/volumes", ResourceName: "rn1/rn2/rn3", } diff --git a/pkg/tsdb/azuremonitor/types/types.go b/pkg/tsdb/azuremonitor/types/types.go index bb5aaf22dca..bcab47c199b 100644 --- a/pkg/tsdb/azuremonitor/types/types.go +++ b/pkg/tsdb/azuremonitor/types/types.go @@ -54,13 +54,14 @@ type DatasourceInfo struct { // AzureMonitorQuery is the query for all the services as they have similar queries // with a url, a querystring and an alias field type AzureMonitorQuery struct { - URL string - UrlComponents map[string]string - Target string - Params url.Values - RefID string - Alias string - TimeRange backend.TimeRange + ResourceName string + ResourceURI string + URL string + Target string + Params url.Values + RefID string + Alias string + TimeRange backend.TimeRange } // AzureMonitorResponse is the json response from the Azure Monitor API @@ -111,9 +112,12 @@ type AzureResponseTable struct { // AzureMonitorJSONQuery is the frontend JSON query model for an Azure Monitor query. type AzureMonitorJSONQuery struct { AzureMonitor struct { - ResourceURI string `json:"resourceUri"` + ResourceURI string `json:"resourceUri"` + // These are used to reconstruct a resource URI MetricNamespace string `json:"metricNamespace"` MetricName string `json:"metricName"` + ResourceGroup string `json:"resourceGroup"` + ResourceName string `json:"resourceName"` Aggregation string `json:"aggregation"` Alias string `json:"alias"` @@ -121,19 +125,13 @@ type AzureMonitorJSONQuery struct { TimeGrain string `json:"timeGrain"` Top string `json:"top"` - // Legecy "resource" fields from before the resource picker provided just a single ResourceURI - // These are used for pre-resource picker queries to reconstruct a resource URI - // Deprecated - MetricDefinition string `json:"metricDefinition"` - // Deprecated - ResourceGroup string `json:"resourceGroup"` - // Deprecated - ResourceName string `json:"resourceName"` - AllowedTimeGrainsMs []int64 `json:"allowedTimeGrainsMs"` Dimension string `json:"dimension"` // old model DimensionFilter string `json:"dimensionFilter"` // old model Format string `json:"format"` + + // Deprecated, MetricNamespace should be used instead + MetricDefinition string `json:"metricDefinition"` } `json:"azureMonitor"` Subscription string `json:"subscription"` } diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/__mocks__/datasource.ts b/public/app/plugins/datasource/grafana-azure-monitor-datasource/__mocks__/datasource.ts index 602c11756f7..a6d66c28ed6 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/__mocks__/datasource.ts +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/__mocks__/datasource.ts @@ -30,7 +30,6 @@ export default function createMockDatasource(overrides?: DeepPartial getSubscriptions: jest.fn().mockResolvedValue([]), getResourceGroups: jest.fn().mockResolvedValueOnce([]), - getMetricDefinitions: jest.fn().mockResolvedValueOnce([]), getResourceNames: jest.fn().mockResolvedValueOnce([]), azureLogAnalyticsDatasource: { diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/__mocks__/query.ts b/public/app/plugins/datasource/grafana-azure-monitor-datasource/__mocks__/query.ts index 9da3bf31761..e190a0c2168 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/__mocks__/query.ts +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/__mocks__/query.ts @@ -35,7 +35,6 @@ export default function createMockQuery(overrides?: Partial): allowedTimeGrainsMs: [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], // dimensionFilter: '*', dimensionFilters: [], - metricDefinition: 'Microsoft.Compute/virtualMachines', metricName: 'Metric A', metricNamespace: 'Microsoft.Compute/virtualMachines', resourceGroup: 'grafanastaging', diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_monitor/azure_monitor_datasource.test.ts b/public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_monitor/azure_monitor_datasource.test.ts index 3f638ba2ef9..0871335fae2 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_monitor/azure_monitor_datasource.test.ts +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_monitor/azure_monitor_datasource.test.ts @@ -34,6 +34,23 @@ describe('AzureMonitorDatasource', () => { ctx.ds = new AzureMonitorDatasource(ctx.instanceSettings); }); + describe('applyTemplateVariables', () => { + it('should migrate metricDefinition to metricNamespace', () => { + const query = createMockQuery({ + azureMonitor: { + metricNamespace: undefined, + metricDefinition: 'microsoft.insights/components', + }, + }); + const templatedQuery = ctx.ds.azureMonitorDatasource.applyTemplateVariables(query, {}); + expect(templatedQuery).toMatchObject({ + azureMonitor: { + metricNamespace: 'microsoft.insights/components', + }, + }); + }); + }); + describe('When performing getMetricNamespaces', () => { const response = { value: [ @@ -128,18 +145,18 @@ describe('AzureMonitorDatasource', () => { const expected = basePath + '/providers/microsoft.insights/components/resource1' + - '/providers/microsoft.insights/metricdefinitions?api-version=2018-01-01&metricnamespace=default'; + '/providers/microsoft.insights/metricdefinitions?api-version=2018-01-01&metricnamespace=microsoft.insights%2Fcomponents'; expect(path).toBe(expected); return Promise.resolve(response); }); }); - it('should return list of Metric Definitions', () => { + it('should return list of Metric Names', () => { return ctx.ds.azureMonitorDatasource .getMetricNames({ resourceUri: '/subscriptions/mock-subscription-id/resourceGroups/nodeapp/providers/microsoft.insights/components/resource1', - metricNamespace: 'default', + metricNamespace: 'microsoft.insights/components', }) .then((results: Array<{ text: string; value: string }>) => { expect(results.length).toEqual(2); @@ -193,7 +210,7 @@ describe('AzureMonitorDatasource', () => { const expected = basePath + '/providers/microsoft.insights/components/resource1' + - '/providers/microsoft.insights/metricdefinitions?api-version=2018-01-01&metricnamespace=default'; + '/providers/microsoft.insights/metricdefinitions?api-version=2018-01-01&metricnamespace=microsoft.insights%2Fcomponents'; expect(path).toBe(expected); return Promise.resolve(response); }); @@ -204,7 +221,7 @@ describe('AzureMonitorDatasource', () => { .getMetricMetadata({ resourceUri: '/subscriptions/mock-subscription-id/resourceGroups/nodeapp/providers/microsoft.insights/components/resource1', - metricNamespace: 'default', + metricNamespace: 'microsoft.insights/components', metricName: 'UsedCapacity', }) .then((results) => { @@ -232,7 +249,6 @@ describe('AzureMonitorDatasource', () => { 'resourceGroup', 'resourceName', 'metricNamespace', - 'metricDefinition', 'timeGrain', 'aggregation', 'top', @@ -317,74 +333,15 @@ describe('AzureMonitorDatasource', () => { }); }); - describe('When performing getMetricDefinitions', () => { - const response = { - value: [ - { - name: 'test', - type: 'Microsoft.Network/networkInterfaces', - }, - { - location: 'northeurope', - name: 'northeur', - type: 'Microsoft.Compute/virtualMachines', - }, - { - location: 'westcentralus', - name: 'us', - type: 'Microsoft.Compute/virtualMachines', - }, - { - name: 'IHaveNoMetrics', - type: 'IShouldBeFilteredOut', - }, - { - name: 'storageTest', - type: 'Microsoft.Storage/storageAccounts', - }, - ], - }; - - beforeEach(() => { - ctx.ds.azureMonitorDatasource.getResource = jest.fn().mockImplementation((path: string) => { - const basePath = 'azuremonitor/subscriptions/mock-subscription-id/resourceGroups'; - expect(path).toBe(basePath + '/nodesapp/resources?api-version=2021-04-01'); - return Promise.resolve(response); - }); - }); - - it('should return list of Metric Definitions with no duplicates and no unsupported namespaces', () => { - return ctx.ds - .getMetricDefinitions('mock-subscription-id', 'nodesapp') - .then((results: Array<{ text: string; value: string }>) => { - expect(results.length).toEqual(7); - expect(results[0].text).toEqual('Network interfaces'); - expect(results[0].value).toEqual('Microsoft.Network/networkInterfaces'); - expect(results[1].text).toEqual('Virtual machines'); - expect(results[1].value).toEqual('Microsoft.Compute/virtualMachines'); - expect(results[2].text).toEqual('Storage accounts'); - expect(results[2].value).toEqual('Microsoft.Storage/storageAccounts'); - expect(results[3].text).toEqual('Microsoft.Storage/storageAccounts/blobServices'); - expect(results[3].value).toEqual('Microsoft.Storage/storageAccounts/blobServices'); - expect(results[4].text).toEqual('Microsoft.Storage/storageAccounts/fileServices'); - expect(results[4].value).toEqual('Microsoft.Storage/storageAccounts/fileServices'); - expect(results[5].text).toEqual('Microsoft.Storage/storageAccounts/tableServices'); - expect(results[5].value).toEqual('Microsoft.Storage/storageAccounts/tableServices'); - expect(results[6].text).toEqual('Microsoft.Storage/storageAccounts/queueServices'); - expect(results[6].value).toEqual('Microsoft.Storage/storageAccounts/queueServices'); - }); - }); - }); - describe('When performing getResourceNames', () => { let subscription = 'mock-subscription-id'; let resourceGroup = 'nodeapp'; - let metricDefinition = 'microsoft.insights/components'; + let metricNamespace = 'microsoft.insights/components'; beforeEach(() => { subscription = 'mock-subscription-id'; resourceGroup = 'nodeapp'; - metricDefinition = 'microsoft.insights/components'; + metricNamespace = 'microsoft.insights/components'; }); describe('and there are no special cases', () => { @@ -396,7 +353,7 @@ describe('AzureMonitorDatasource', () => { }, { name: resourceGroup, - type: metricDefinition, + type: metricNamespace, }, ], }; @@ -405,7 +362,7 @@ describe('AzureMonitorDatasource', () => { ctx.ds.azureMonitorDatasource.getResource = jest.fn().mockImplementation((path: string) => { const basePath = `azuremonitor/subscriptions/${subscription}/resourceGroups`; expect(path).toBe( - `${basePath}/${resourceGroup}/resources?api-version=2021-04-01&$filter=resourceType eq '${metricDefinition}'` + `${basePath}/${resourceGroup}/resources?api-version=2021-04-01&$filter=resourceType eq '${metricNamespace}'` ); return Promise.resolve(response); }); @@ -413,7 +370,7 @@ describe('AzureMonitorDatasource', () => { it('should return list of Resource Names', () => { return ctx.ds - .getResourceNames(subscription, resourceGroup, metricDefinition) + .getResourceNames(subscription, resourceGroup, metricNamespace) .then((results: Array<{ text: string; value: string }>) => { expect(results.length).toEqual(1); expect(results[0].text).toEqual('nodeapp'); @@ -422,9 +379,9 @@ describe('AzureMonitorDatasource', () => { }); it('should return ignore letter case', () => { - metricDefinition = 'microsoft.insights/Components'; + metricNamespace = 'microsoft.insights/Components'; return ctx.ds - .getResourceNames(subscription, resourceGroup, metricDefinition) + .getResourceNames(subscription, resourceGroup, metricNamespace) .then((results: Array<{ text: string; value: string }>) => { expect(results.length).toEqual(1); expect(results[0].text).toEqual('nodeapp'); @@ -448,26 +405,26 @@ describe('AzureMonitorDatasource', () => { }; it('should return list of Resource Names', () => { - metricDefinition = 'Microsoft.Storage/storageAccounts/blobServices'; - const validMetricDefinition = startsWith(metricDefinition, 'Microsoft.Storage/storageAccounts/') + metricNamespace = 'Microsoft.Storage/storageAccounts/blobServices'; + const validMetricNamespace = startsWith(metricNamespace, 'Microsoft.Storage/storageAccounts/') ? 'Microsoft.Storage/storageAccounts' - : metricDefinition; + : metricNamespace; ctx.ds.azureMonitorDatasource.getResource = jest.fn().mockImplementation((path: string) => { const basePath = `azuremonitor/subscriptions/${subscription}/resourceGroups`; expect(path).toBe( basePath + - `/${resourceGroup}/resources?api-version=2021-04-01&$filter=resourceType eq '${validMetricDefinition}'` + `/${resourceGroup}/resources?api-version=2021-04-01&$filter=resourceType eq '${validMetricNamespace}'` ); return Promise.resolve(response); }); return ctx.ds - .getResourceNames(subscription, resourceGroup, metricDefinition) + .getResourceNames(subscription, resourceGroup, metricNamespace) .then((results: Array<{ text: string; value: string }>) => { expect(results.length).toEqual(1); expect(results[0].text).toEqual('storagetest/default'); expect(results[0].value).toEqual('storagetest/default'); expect(ctx.ds.azureMonitorDatasource.getResource).toHaveBeenCalledWith( - `azuremonitor/subscriptions/${subscription}/resourceGroups/${resourceGroup}/resources?api-version=2021-04-01&$filter=resourceType eq '${validMetricDefinition}'` + `azuremonitor/subscriptions/${subscription}/resourceGroups/${resourceGroup}/resources?api-version=2021-04-01&$filter=resourceType eq '${validMetricNamespace}'` ); }); }); @@ -479,7 +436,7 @@ describe('AzureMonitorDatasource', () => { value: [ { name: `${resourceGroup}1`, - type: metricDefinition, + type: metricNamespace, }, ], nextLink: `https://management.azure.com/resourceuri?$skiptoken=${skipToken}`, @@ -488,7 +445,7 @@ describe('AzureMonitorDatasource', () => { value: [ { name: `${resourceGroup}2`, - type: metricDefinition, + type: metricNamespace, }, ], }; @@ -497,7 +454,7 @@ describe('AzureMonitorDatasource', () => { const fn = jest.fn(); ctx.ds.azureMonitorDatasource.getResource = fn; const basePath = `azuremonitor/subscriptions/${subscription}/resourceGroups`; - const expectedPath = `${basePath}/${resourceGroup}/resources?api-version=2021-04-01&$filter=resourceType eq '${metricDefinition}'`; + const expectedPath = `${basePath}/${resourceGroup}/resources?api-version=2021-04-01&$filter=resourceType eq '${metricNamespace}'`; // first page fn.mockImplementationOnce((path: string) => { expect(path).toBe(expectedPath); @@ -512,7 +469,7 @@ describe('AzureMonitorDatasource', () => { it('should return list of Resource Names', () => { return ctx.ds - .getResourceNames(subscription, resourceGroup, metricDefinition) + .getResourceNames(subscription, resourceGroup, metricNamespace) .then((results: Array<{ text: string; value: string }>) => { expect(results.length).toEqual(2); expect(results[0].value).toEqual(`${resourceGroup}1`); @@ -530,7 +487,7 @@ describe('AzureMonitorDatasource', () => { }, { name: resourceGroup, - type: metricDefinition, + type: metricNamespace, }, ], }; @@ -593,7 +550,7 @@ describe('AzureMonitorDatasource', () => { const expected = basePath + '/providers/microsoft.insights/components/resource1' + - '/providers/microsoft.insights/metricdefinitions?api-version=2018-01-01&metricnamespace=default'; + '/providers/microsoft.insights/metricdefinitions?api-version=2018-01-01&metricnamespace=microsoft.insights%2Fcomponents'; expect(path).toBe(expected); return Promise.resolve(response); }); @@ -604,9 +561,8 @@ describe('AzureMonitorDatasource', () => { .getMetricNames({ subscription: 'mock-subscription-id', resourceGroup: 'nodeapp', - metricDefinition: 'microsoft.insights/components', + metricNamespace: 'microsoft.insights/components', resourceName: 'resource1', - metricNamespace: 'default', }) .then((results: Array<{ text: string; value: string }>) => { expect(results.length).toEqual(2); @@ -660,7 +616,7 @@ describe('AzureMonitorDatasource', () => { const expected = basePath + '/providers/microsoft.insights/components/resource1' + - '/providers/microsoft.insights/metricdefinitions?api-version=2018-01-01&metricnamespace=default'; + '/providers/microsoft.insights/metricdefinitions?api-version=2018-01-01&metricnamespace=microsoft.insights%2Fcomponents'; expect(path).toBe(expected); return Promise.resolve(response); }); @@ -671,9 +627,8 @@ describe('AzureMonitorDatasource', () => { .getMetricMetadata({ subscription: 'mock-subscription-id', resourceGroup: 'nodeapp', - metricDefinition: 'microsoft.insights/components', + metricNamespace: 'microsoft.insights/components', resourceName: 'resource1', - metricNamespace: 'default', metricName: 'UsedCapacity', }) .then((results) => { @@ -729,7 +684,7 @@ describe('AzureMonitorDatasource', () => { const expected = basePath + '/providers/microsoft.insights/components/resource1' + - '/providers/microsoft.insights/metricdefinitions?api-version=2018-01-01&metricnamespace=default'; + '/providers/microsoft.insights/metricdefinitions?api-version=2018-01-01&metricnamespace=microsoft.insights%2Fcomponents'; expect(path).toBe(expected); return Promise.resolve(response); }); @@ -740,9 +695,8 @@ describe('AzureMonitorDatasource', () => { .getMetricMetadata({ subscription: 'mock-subscription-id', resourceGroup: 'nodeapp', - metricDefinition: 'microsoft.insights/components', + metricNamespace: 'microsoft.insights/components', resourceName: 'resource1', - metricNamespace: 'default', metricName: 'Transactions', }) .then((results: any) => { @@ -800,9 +754,8 @@ describe('AzureMonitorDatasource', () => { .getMetricMetadata({ subscription: 'mock-subscription-id', resourceGroup: 'nodeapp', - metricDefinition: 'microsoft.insights/components', + metricNamespace: 'microsoft.insights/components', resourceName: 'resource1', - metricNamespace: 'default', metricName: 'FreeCapacity', }) .then((results: any) => { diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_monitor/azure_monitor_datasource.ts b/public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_monitor/azure_monitor_datasource.ts index 125a83a74b9..14b67f0609a 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_monitor/azure_monitor_datasource.ts +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_monitor/azure_monitor_datasource.ts @@ -4,12 +4,10 @@ import { DataSourceInstanceSettings, ScopedVars } from '@grafana/data'; import { DataSourceWithBackend, getTemplateSrv, TemplateSrv } from '@grafana/runtime'; import { getTimeSrv, TimeSrv } from 'app/features/dashboard/services/TimeSrv'; -import { resourceTypeDisplayNames, supportedMetricNamespaces } from '../azureMetadata'; import { getAuthType, getAzureCloud, getAzurePortalUrl } from '../credentials'; import TimegrainConverter from '../time_grain_converter'; import { AzureDataSourceJsonData, - AzureMonitorMetricDefinitionsResponse, AzureMonitorMetricNamespacesResponse, AzureMonitorMetricNamesResponse, AzureMonitorMetricsMetadataResponse, @@ -20,8 +18,10 @@ import { GetMetricNamespacesQuery, GetMetricNamesQuery, GetMetricMetadataQuery, + AzureMetricQuery, } from '../types'; import { routeNames } from '../utils/common'; +import migrateQuery from '../utils/migrateQuery'; import ResponseParser from './response_parser'; import UrlBuilder from './url_builder'; @@ -66,7 +66,7 @@ export default class AzureMonitorDatasource extends DataSourceWithBackend> { @@ -152,83 +157,31 @@ export default class AzureMonitorDatasource extends DataSourceWithBackend { - return ResponseParser.parseResponseValues(result, 'type', 'type'); - }) - .then((result) => - result.filter((t) => { - for (let i = 0; i < supportedMetricNamespaces.length; i++) { - if (t.value.toLowerCase() === supportedMetricNamespaces[i].toLowerCase()) { - return true; - } - } - return false; - }) - ) - .then((result) => { - let shouldHardcodeBlobStorage = false; - for (let i = 0; i < result.length; i++) { - if (result[i].value === 'Microsoft.Storage/storageAccounts') { - shouldHardcodeBlobStorage = true; - break; - } - } - - if (shouldHardcodeBlobStorage) { - result.push({ - text: 'Microsoft.Storage/storageAccounts/blobServices', - value: 'Microsoft.Storage/storageAccounts/blobServices', - }); - result.push({ - text: 'Microsoft.Storage/storageAccounts/fileServices', - value: 'Microsoft.Storage/storageAccounts/fileServices', - }); - result.push({ - text: 'Microsoft.Storage/storageAccounts/tableServices', - value: 'Microsoft.Storage/storageAccounts/tableServices', - }); - result.push({ - text: 'Microsoft.Storage/storageAccounts/queueServices', - value: 'Microsoft.Storage/storageAccounts/queueServices', - }); - } - - return result.map((v) => ({ - value: v.value, - text: resourceTypeDisplayNames[v.value.toLowerCase()] || v.value, - })); - }); - } - - getResourceNames(subscriptionId: string, resourceGroup?: string, metricDefinition?: string, skipToken?: string) { - const validMetricDefinition = startsWith(metricDefinition, 'Microsoft.Storage/storageAccounts/') + getResourceNames(subscriptionId: string, resourceGroup?: string, metricNamespace?: string, skipToken?: string) { + const validMetricNamespace = startsWith(metricNamespace, 'Microsoft.Storage/storageAccounts/') ? 'Microsoft.Storage/storageAccounts' - : metricDefinition; + : metricNamespace; let url = `${this.resourcePath}/subscriptions/${subscriptionId}`; if (resourceGroup) { url += `/resourceGroups/${resourceGroup}`; } url += `/resources?api-version=${this.listByResourceGroupApiVersion}`; - if (validMetricDefinition) { - url += `&$filter=resourceType eq '${validMetricDefinition}'`; + if (validMetricNamespace) { + url += `&$filter=resourceType eq '${validMetricNamespace}'`; } if (skipToken) { url += `&$skiptoken=${skipToken}`; } return this.getResource(url).then(async (result: any) => { let list: Array<{ text: string; value: string }> = []; - if (startsWith(metricDefinition, 'Microsoft.Storage/storageAccounts/')) { + if (startsWith(metricNamespace, 'Microsoft.Storage/storageAccounts/')) { list = ResponseParser.parseResourceNames(result, 'Microsoft.Storage/storageAccounts'); for (let i = 0; i < list.length; i++) { list[i].text += '/default'; list[i].value += '/default'; } } else { - list = ResponseParser.parseResourceNames(result, metricDefinition); + list = ResponseParser.parseResourceNames(result, metricNamespace); } if (result.nextLink) { @@ -238,7 +191,7 @@ export default class AzureMonitorDatasource extends DataSourceWithBackend { + static parseResourceNames(result: any, metricNamespace?: string): Array<{ text: string; value: string }> { const list: Array<{ text: string; value: string }> = []; if (!result) { @@ -43,7 +43,7 @@ export default class ResponseParser { for (let i = 0; i < result.value.length; i++) { if ( typeof result.value[i].type === 'string' && - (!metricDefinition || result.value[i].type.toLocaleLowerCase() === metricDefinition.toLocaleLowerCase()) + (!metricNamespace || result.value[i].type.toLocaleLowerCase() === metricNamespace.toLocaleLowerCase()) ) { list.push({ text: result.value[i].name, diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_monitor/url_builder.test.ts b/public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_monitor/url_builder.test.ts index e59c3a40c3a..0a6cb613e16 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_monitor/url_builder.test.ts +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_monitor/url_builder.test.ts @@ -19,12 +19,12 @@ describe('AzureMonitorUrlBuilder', () => { describe('buildResourceUri', () => { it('builds a resource uri when the required properties are provided', () => { expect( - UrlBuilder.buildResourceUri('sub', 'group', 'Microsoft.NetApp/netAppAccounts', 'name', templateSrv) + UrlBuilder.buildResourceUri('sub', 'group', templateSrv, 'Microsoft.NetApp/netAppAccounts', 'name') ).toEqual('/subscriptions/sub/resourceGroups/group/providers/Microsoft.NetApp/netAppAccounts/name'); }); it('builds a resource uri correctly when a template variable is used as namespace', () => { - expect(UrlBuilder.buildResourceUri('sub', 'group', '$ns', 'name', templateSrv)).toEqual( + expect(UrlBuilder.buildResourceUri('sub', 'group', templateSrv, '$ns', 'name')).toEqual( '/subscriptions/sub/resourceGroups/group/providers/$ns/name' ); }); @@ -34,9 +34,9 @@ describe('AzureMonitorUrlBuilder', () => { UrlBuilder.buildResourceUri( 'sub', 'group', + templateSrv, 'Microsoft.Storage/storageAccounts/tableServices', - 'name', - templateSrv + 'name' ) ).toEqual( '/subscriptions/sub/resourceGroups/group/providers/Microsoft.Storage/storageAccounts/name/tableServices/default' @@ -56,25 +56,25 @@ describe('AzureMonitorUrlBuilder', () => { templateSrv = getTemplateSrv(); it('builds a resource uri without specifying a subresource (default)', () => { - expect(UrlBuilder.buildResourceUri('sub', 'group', '$ns/tableServices', 'name', templateSrv)).toEqual( + expect(UrlBuilder.buildResourceUri('sub', 'group', templateSrv, '$ns/tableServices', 'name')).toEqual( '/subscriptions/sub/resourceGroups/group/providers/$ns/name/tableServices/default' ); }); it('builds a resource uri specifying a subresource (default)', () => { - expect(UrlBuilder.buildResourceUri('sub', 'group', '$ns/tableServices', 'name/default', templateSrv)).toEqual( + expect(UrlBuilder.buildResourceUri('sub', 'group', templateSrv, '$ns/tableServices', 'name/default')).toEqual( '/subscriptions/sub/resourceGroups/group/providers/$ns/name/tableServices/default' ); }); it('builds a resource uri specifying a resource template variable', () => { - expect(UrlBuilder.buildResourceUri('sub', 'group', '$ns/tableServices', '$rs/default', templateSrv)).toEqual( + expect(UrlBuilder.buildResourceUri('sub', 'group', templateSrv, '$ns/tableServices', '$rs/default')).toEqual( '/subscriptions/sub/resourceGroups/group/providers/$ns/$rs/tableServices/default' ); }); it('builds a resource uri specifying multiple template variables', () => { - expect(UrlBuilder.buildResourceUri('sub', 'group', '$ns/$ns2', '$rs/$rs2', templateSrv)).toEqual( + expect(UrlBuilder.buildResourceUri('sub', 'group', templateSrv, '$ns/$ns2', '$rs/$rs2')).toEqual( '/subscriptions/sub/resourceGroups/group/providers/$ns/$rs/$ns2/$rs2' ); }); @@ -123,7 +123,7 @@ describe('AzureMonitorUrlBuilder', () => { { subscription: 'sub1', resourceGroup: 'rg', - metricDefinition: 'Microsoft.NetApp/netAppAccounts/capacityPools/volumes', + metricNamespace: 'Microsoft.NetApp/netAppAccounts/capacityPools/volumes', resourceName: 'rn1/rn2/rn3', }, templateSrv @@ -143,7 +143,7 @@ describe('AzureMonitorUrlBuilder', () => { { subscription: 'sub1', resourceGroup: 'rg', - metricDefinition: 'Microsoft.Sql/servers/databases', + metricNamespace: 'Microsoft.Sql/servers/databases', resourceName: 'rn1/rn2', }, templateSrv @@ -163,7 +163,7 @@ describe('AzureMonitorUrlBuilder', () => { { subscription: 'sub1', resourceGroup: 'rg', - metricDefinition: 'Microsoft.Sql/servers', + metricNamespace: 'Microsoft.Sql/servers', resourceName: 'rn', }, templateSrv @@ -175,7 +175,7 @@ describe('AzureMonitorUrlBuilder', () => { }); }); - describe('when metric definition is Microsoft.NetApp/netAppAccounts/capacityPools/volumes and the metricNamespace is default', () => { + describe('when metric definition is Microsoft.NetApp/netAppAccounts/capacityPools/volumes and the metricNamespace', () => { it('should build the getMetricNames url in the even longer format', () => { const url = UrlBuilder.buildAzureMonitorGetMetricNamesUrl( '', @@ -183,20 +183,19 @@ describe('AzureMonitorUrlBuilder', () => { { subscription: 'sub1', resourceGroup: 'rg', - metricDefinition: 'Microsoft.NetApp/netAppAccounts/capacityPools/volumes', + metricNamespace: 'Microsoft.NetApp/netAppAccounts/capacityPools/volumes', resourceName: 'rn1/rn2/rn3', - metricNamespace: 'default', }, templateSrv ); expect(url).toBe( '/subscriptions/sub1/resourceGroups/rg/providers/Microsoft.NetApp/netAppAccounts/rn1/capacityPools/rn2/volumes/rn3/' + - 'providers/microsoft.insights/metricdefinitions?api-version=2017-05-01-preview&metricnamespace=default' + 'providers/microsoft.insights/metricdefinitions?api-version=2017-05-01-preview&metricnamespace=Microsoft.NetApp%2FnetAppAccounts%2FcapacityPools%2Fvolumes' ); }); }); - describe('when metric definition is Microsoft.Sql/servers/databases and the metricNamespace is default', () => { + describe('when metric definition is Microsoft.Sql/servers/databases and the metricNamespace', () => { it('should build the getMetricNames url in the longer format', () => { const url = UrlBuilder.buildAzureMonitorGetMetricNamesUrl( '', @@ -204,20 +203,19 @@ describe('AzureMonitorUrlBuilder', () => { { subscription: 'sub1', resourceGroup: 'rg', - metricDefinition: 'Microsoft.Sql/servers/databases', + metricNamespace: 'Microsoft.Sql/servers/databases', resourceName: 'rn1/rn2', - metricNamespace: 'default', }, templateSrv ); expect(url).toBe( '/subscriptions/sub1/resourceGroups/rg/providers/Microsoft.Sql/servers/rn1/databases/rn2/' + - 'providers/microsoft.insights/metricdefinitions?api-version=2017-05-01-preview&metricnamespace=default' + 'providers/microsoft.insights/metricdefinitions?api-version=2017-05-01-preview&metricnamespace=Microsoft.Sql%2Fservers%2Fdatabases' ); }); }); - describe('when metric definition is Microsoft.Sql/servers and the metricNamespace is default', () => { + describe('when metric definition is Microsoft.Sql/servers and the metricNamespace', () => { it('should build the getMetricNames url in the shorter format', () => { const url = UrlBuilder.buildAzureMonitorGetMetricNamesUrl( '', @@ -225,20 +223,19 @@ describe('AzureMonitorUrlBuilder', () => { { subscription: 'sub1', resourceGroup: 'rg', - metricDefinition: 'Microsoft.Sql/servers', + metricNamespace: 'Microsoft.Sql/servers', resourceName: 'rn', - metricNamespace: 'default', }, templateSrv ); expect(url).toBe( '/subscriptions/sub1/resourceGroups/rg/providers/Microsoft.Sql/servers/rn/' + - 'providers/microsoft.insights/metricdefinitions?api-version=2017-05-01-preview&metricnamespace=default' + 'providers/microsoft.insights/metricdefinitions?api-version=2017-05-01-preview&metricnamespace=Microsoft.Sql%2Fservers' ); }); }); - describe('when metric definition is Microsoft.Storage/storageAccounts/blobServices and the metricNamespace is default', () => { + describe('when metric definition is Microsoft.Storage/storageAccounts/blobServices and the metricNamespace', () => { it('should build the getMetricNames url in the longer format', () => { const url = UrlBuilder.buildAzureMonitorGetMetricNamesUrl( '', @@ -246,20 +243,19 @@ describe('AzureMonitorUrlBuilder', () => { { subscription: 'sub1', resourceGroup: 'rg', - metricDefinition: 'Microsoft.Storage/storageAccounts/blobServices', + metricNamespace: 'Microsoft.Storage/storageAccounts/blobServices', resourceName: 'rn1/default', - metricNamespace: 'default', }, templateSrv ); expect(url).toBe( '/subscriptions/sub1/resourceGroups/rg/providers/Microsoft.Storage/storageAccounts/rn1/blobServices/default/' + - 'providers/microsoft.insights/metricdefinitions?api-version=2017-05-01-preview&metricnamespace=default' + 'providers/microsoft.insights/metricdefinitions?api-version=2017-05-01-preview&metricnamespace=Microsoft.Storage%2FstorageAccounts%2FblobServices' ); }); }); - describe('when metric definition is Microsoft.Storage/storageAccounts/fileServices and the metricNamespace is default', () => { + describe('when metric definition is Microsoft.Storage/storageAccounts/fileServices and the metricNamespace', () => { it('should build the getMetricNames url in the longer format', () => { const url = UrlBuilder.buildAzureMonitorGetMetricNamesUrl( '', @@ -267,20 +263,19 @@ describe('AzureMonitorUrlBuilder', () => { { subscription: 'sub1', resourceGroup: 'rg', - metricDefinition: 'Microsoft.Storage/storageAccounts/fileServices', + metricNamespace: 'Microsoft.Storage/storageAccounts/fileServices', resourceName: 'rn1/default', - metricNamespace: 'default', }, templateSrv ); expect(url).toBe( '/subscriptions/sub1/resourceGroups/rg/providers/Microsoft.Storage/storageAccounts/rn1/fileServices/default/' + - 'providers/microsoft.insights/metricdefinitions?api-version=2017-05-01-preview&metricnamespace=default' + 'providers/microsoft.insights/metricdefinitions?api-version=2017-05-01-preview&metricnamespace=Microsoft.Storage%2FstorageAccounts%2FfileServices' ); }); }); - describe('when metric definition is Microsoft.Storage/storageAccounts/tableServices and the metricNamespace is default', () => { + describe('when metric definition is Microsoft.Storage/storageAccounts/tableServices and the metricNamespace', () => { it('should build the getMetricNames url in the longer format', () => { const url = UrlBuilder.buildAzureMonitorGetMetricNamesUrl( '', @@ -288,20 +283,19 @@ describe('AzureMonitorUrlBuilder', () => { { subscription: 'sub1', resourceGroup: 'rg', - metricDefinition: 'Microsoft.Storage/storageAccounts/tableServices', + metricNamespace: 'Microsoft.Storage/storageAccounts/tableServices', resourceName: 'rn1/default', - metricNamespace: 'default', }, templateSrv ); expect(url).toBe( '/subscriptions/sub1/resourceGroups/rg/providers/Microsoft.Storage/storageAccounts/rn1/tableServices/default/' + - 'providers/microsoft.insights/metricdefinitions?api-version=2017-05-01-preview&metricnamespace=default' + 'providers/microsoft.insights/metricdefinitions?api-version=2017-05-01-preview&metricnamespace=Microsoft.Storage%2FstorageAccounts%2FtableServices' ); }); }); - describe('when metric definition is Microsoft.Storage/storageAccounts/queueServices and the metricNamespace is default', () => { + describe('when metric definition is Microsoft.Storage/storageAccounts/queueServices and the metricNamespace', () => { it('should build the getMetricNames url in the longer format', () => { const url = UrlBuilder.buildAzureMonitorGetMetricNamesUrl( '', @@ -309,35 +303,14 @@ describe('AzureMonitorUrlBuilder', () => { { subscription: 'sub1', resourceGroup: 'rg', - metricDefinition: 'Microsoft.Storage/storageAccounts/queueServices', + metricNamespace: 'Microsoft.Storage/storageAccounts/queueServices', resourceName: 'rn1/default', - metricNamespace: 'default', }, templateSrv ); expect(url).toBe( '/subscriptions/sub1/resourceGroups/rg/providers/Microsoft.Storage/storageAccounts/rn1/queueServices/default/' + - 'providers/microsoft.insights/metricdefinitions?api-version=2017-05-01-preview&metricnamespace=default' - ); - }); - }); - - describe('when metric definition does not contain a metric namespace', () => { - it('should build the getMetricNames url in the longer format', () => { - const url = UrlBuilder.buildAzureMonitorGetMetricNamesUrl( - '', - '2017-05-01-preview', - { - subscription: 'sub1', - resourceGroup: 'rg', - metricDefinition: 'microsoft.compute/virtualmachines', - resourceName: 'rn1', - }, - templateSrv - ); - expect(url).toBe( - '/subscriptions/sub1/resourceGroups/rg/providers/microsoft.compute/virtualmachines/rn1/' + - 'providers/microsoft.insights/metricdefinitions?api-version=2017-05-01-preview' + 'providers/microsoft.insights/metricdefinitions?api-version=2017-05-01-preview&metricnamespace=Microsoft.Storage%2FstorageAccounts%2FqueueServices' ); }); }); diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_monitor/url_builder.ts b/public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_monitor/url_builder.ts index 25c92753dc5..a4280935fa0 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_monitor/url_builder.ts +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_monitor/url_builder.ts @@ -6,33 +6,42 @@ export default class UrlBuilder { static buildResourceUri( subscriptionId: string, resourceGroup: string, - metricDefinition: string, - resourceName: string, - templateSrv: TemplateSrv + templateSrv: TemplateSrv, + metricNamespace?: string, + resourceName?: string ) { - const metricDefinitionProcessed = templateSrv.replace(metricDefinition); - const metricDefinitionArray = metricDefinition.split('/'); - const resourceNameProcessed = templateSrv.replace(resourceName); - const resourceNameArray = resourceName.split('/'); - const provider = metricDefinitionArray.shift(); - const urlArray = ['/subscriptions', subscriptionId, 'resourceGroups', resourceGroup, 'providers', provider]; + const urlArray = ['/subscriptions', subscriptionId, 'resourceGroups', resourceGroup]; - if ( - metricDefinitionProcessed.startsWith('Microsoft.Storage/storageAccounts/') && - !resourceNameProcessed.endsWith('default') - ) { - resourceNameArray.push('default'); + if (metricNamespace && resourceName) { + const metricNamespaceProcessed = templateSrv.replace(metricNamespace); + const metricNamespaceArray = metricNamespace.split('/'); + const resourceNameProcessed = templateSrv.replace(resourceName); + const resourceNameArray = resourceName.split('/'); + const provider = metricNamespaceArray.shift(); + if (provider) { + urlArray.push('providers', provider); + } + + if ( + metricNamespaceProcessed.startsWith('Microsoft.Storage/storageAccounts/') && + !resourceNameProcessed.endsWith('default') + ) { + resourceNameArray.push('default'); + } + + if (resourceNameArray.length > metricNamespaceArray.length) { + const parentResource = resourceNameArray.shift(); + if (parentResource) { + urlArray.push(parentResource); + } + } + + for (const i in metricNamespaceArray) { + urlArray.push(metricNamespaceArray[i]); + urlArray.push(resourceNameArray[i]); + } } - if (resourceNameArray.length > metricDefinitionArray.length) { - const parentResource = resourceNameArray.shift(); - urlArray.push(parentResource); - } - - for (const i in metricDefinitionArray) { - urlArray.push(metricDefinitionArray[i]); - urlArray.push(resourceNameArray[i]); - } return urlArray.join('/'); } @@ -47,13 +56,13 @@ export default class UrlBuilder { if ('resourceUri' in query) { resourceUri = query.resourceUri; } else { - const { subscription, resourceGroup, metricDefinition, resourceName } = query; + const { subscription, resourceGroup, metricNamespace, resourceName } = query; resourceUri = UrlBuilder.buildResourceUri( subscription, resourceGroup, - metricDefinition, - resourceName, - templateSrv + templateSrv, + metricNamespace, + resourceName ); } @@ -72,13 +81,13 @@ export default class UrlBuilder { if ('resourceUri' in query) { resourceUri = query.resourceUri; } else { - const { subscription, resourceGroup, metricDefinition, resourceName } = query; + const { subscription, resourceGroup, metricNamespace, resourceName } = query; resourceUri = UrlBuilder.buildResourceUri( subscription, resourceGroup, - metricDefinition, - resourceName, - templateSrv + templateSrv, + metricNamespace, + resourceName ); } diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/dataHooks.test.ts b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/dataHooks.test.ts index fa49e55939d..59ea8076024 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/dataHooks.test.ts +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/dataHooks.test.ts @@ -128,10 +128,6 @@ describe('AzureMonitor: metrics dataHooks', () => { opt('Web App - Development', 'web-app-development'), ]); - datasource.getMetricDefinitions = jest - .fn() - .mockResolvedValue([opt('Virtual Machine', 'azure/vm'), opt('Database', 'azure/db')]); - datasource.getResourceNames = jest .fn() .mockResolvedValue([opt('Web server', 'web-server'), opt('Job server', 'job-server')]); diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/setQueryValue.test.ts b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/setQueryValue.test.ts index e1edaff0c30..d1a4d4f9155 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/setQueryValue.test.ts +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/setQueryValue.test.ts @@ -12,10 +12,7 @@ describe('setResource', () => { const q = createMockQuery(); expect(q.azureMonitor?.metricNamespace).not.toEqual(undefined); expect(q.azureMonitor?.metricName).not.toEqual(undefined); - expect(q.azureMonitor?.metricDefinition).not.toEqual(undefined); expect(q.azureMonitor?.aggregation).not.toEqual(undefined); - expect(q.azureMonitor?.metricDefinition).not.toEqual(undefined); - expect(q.azureMonitor?.metricDefinition).not.toEqual(undefined); expect(q.azureMonitor?.timeGrain).not.toEqual(''); expect(q.azureMonitor?.timeGrain).not.toEqual([]); const newQ = setResource(createMockQuery(), '/new-uri'); @@ -23,7 +20,6 @@ describe('setResource', () => { metricNamespace: undefined, metricName: undefined, aggregation: undefined, - metricDefinition: undefined, timeGrain: '', dimensionFilters: [], }); diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/setQueryValue.ts b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/setQueryValue.ts index bcc5d3e8a85..5bec09a6203 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/setQueryValue.ts +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/MetricsQueryEditor/setQueryValue.ts @@ -9,7 +9,6 @@ export function setResource(query: AzureMonitorQuery, resourceURI: string | unde metricNamespace: undefined, metricName: undefined, aggregation: undefined, - metricDefinition: undefined, timeGrain: '', dimensionFilters: [], }, diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/SubscriptionField.tsx b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/SubscriptionField.tsx index 36279ac6272..271583cead7 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/SubscriptionField.tsx +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/SubscriptionField.tsx @@ -36,7 +36,6 @@ const SubscriptionField: React.FC = ({ newQuery.azureMonitor = { ...newQuery.azureMonitor, resourceGroup: undefined, - metricDefinition: undefined, metricNamespace: undefined, resourceName: undefined, metricName: undefined, diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/datasource.ts b/public/app/plugins/datasource/grafana-azure-monitor-datasource/datasource.ts index 40de38a9d07..22079829f99 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/datasource.ts +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/datasource.ts @@ -147,13 +147,6 @@ export default class Datasource extends DataSourceWithBackend { subscriptions: query.match(/^Subscriptions\(\)/i), resourceGroups: query.match(/^ResourceGroups\(\)/i), resourceGroupsWithSub: query.match(/^ResourceGroups\(([^\)]+?)(,\s?([^,]+?))?\)/i), - metricDefinitions: query.match(/^Namespaces\(([^\)]+?)(,\s?([^,]+?))?\)/i), - metricDefinitionsWithSub: query.match(/^Namespaces\(([^,]+?),\s?([^,]+?)\)/i), + namespaces: query.match(/^Namespaces\(([^\)]+?)(,\s?([^,]+?))?\)/i), + namespacesWithSub: query.match(/^Namespaces\(([^,]+?),\s?([^,]+?)\)/i), resourceNames: query.match(/^ResourceNames\(([^,]+?),\s?([^,]+?)\)/i), resourceNamesWithSub: query.match(/^ResourceNames\(([^,]+?),\s?([^,]+?),\s?(.+?)\)/i), metricNamespace: query.match(/^MetricNamespace\(([^,]+?),\s?([^,]+?),\s?([^,]+?)\)/i), @@ -95,22 +94,22 @@ const createGrafanaTemplateVariableQuery = (rawQuery: string, datasource: DataSo return queryDetails; } - if (matchesForQuery.metricDefinitionsWithSub) { - const queryDetails: MetricDefinitionsQuery = { - kind: 'MetricDefinitionsQuery', + if (matchesForQuery.namespacesWithSub) { + const queryDetails: MetricNamespaceQuery = { + kind: 'MetricNamespaceQuery', rawQuery, - subscription: matchesForQuery.metricDefinitionsWithSub[1], - resourceGroup: matchesForQuery.metricDefinitionsWithSub[2], + subscription: matchesForQuery.namespacesWithSub[1], + resourceGroup: matchesForQuery.namespacesWithSub[2], }; return queryDetails; } - if (matchesForQuery.metricDefinitions && defaultSubscriptionId) { - const queryDetails: MetricDefinitionsQuery = { - kind: 'MetricDefinitionsQuery', + if (matchesForQuery.namespaces && defaultSubscriptionId) { + const queryDetails: MetricNamespaceQuery = { + kind: 'MetricNamespaceQuery', rawQuery, subscription: defaultSubscriptionId, - resourceGroup: matchesForQuery.metricDefinitions[1], + resourceGroup: matchesForQuery.namespaces[1], }; return queryDetails; } @@ -121,7 +120,7 @@ const createGrafanaTemplateVariableQuery = (rawQuery: string, datasource: DataSo rawQuery, subscription: matchesForQuery.resourceNamesWithSub[1], resourceGroup: matchesForQuery.resourceNamesWithSub[2], - metricDefinition: matchesForQuery.resourceNamesWithSub[3], + metricNamespace: matchesForQuery.resourceNamesWithSub[3], }; return queryDetails; } @@ -132,7 +131,7 @@ const createGrafanaTemplateVariableQuery = (rawQuery: string, datasource: DataSo rawQuery, subscription: defaultSubscriptionId, resourceGroup: matchesForQuery.resourceNames[1], - metricDefinition: matchesForQuery.resourceNames[2], + metricNamespace: matchesForQuery.resourceNames[2], }; return queryDetails; } @@ -143,7 +142,7 @@ const createGrafanaTemplateVariableQuery = (rawQuery: string, datasource: DataSo rawQuery, subscription: matchesForQuery.metricNamespaceWithSub[1], resourceGroup: matchesForQuery.metricNamespaceWithSub[2], - metricDefinition: matchesForQuery.metricNamespaceWithSub[3], + metricNamespace: matchesForQuery.metricNamespaceWithSub[3], resourceName: matchesForQuery.metricNamespaceWithSub[4], }; return queryDetails; @@ -155,7 +154,7 @@ const createGrafanaTemplateVariableQuery = (rawQuery: string, datasource: DataSo rawQuery, subscription: defaultSubscriptionId, resourceGroup: matchesForQuery.metricNamespace[1], - metricDefinition: matchesForQuery.metricNamespace[2], + metricNamespace: matchesForQuery.metricNamespace[2], resourceName: matchesForQuery.metricNamespace[3], }; return queryDetails; @@ -168,9 +167,8 @@ const createGrafanaTemplateVariableQuery = (rawQuery: string, datasource: DataSo rawQuery, subscription: defaultSubscriptionId, resourceGroup: matchesForQuery.metricNames[1], - metricDefinition: matchesForQuery.metricNames[2], + metricNamespace: matchesForQuery.metricNames[2], resourceName: matchesForQuery.metricNames[3], - metricNamespace: matchesForQuery.metricNames[4], }; return queryDetails; } @@ -182,9 +180,8 @@ const createGrafanaTemplateVariableQuery = (rawQuery: string, datasource: DataSo rawQuery, subscription: matchesForQuery.metricNamesWithSub[1], resourceGroup: matchesForQuery.metricNamesWithSub[2], - metricDefinition: matchesForQuery.metricNamesWithSub[3], + metricNamespace: matchesForQuery.metricNamesWithSub[3], resourceName: matchesForQuery.metricNamesWithSub[4], - metricNamespace: matchesForQuery.metricNamesWithSub[5], }; return queryDetails; } @@ -270,9 +267,6 @@ const migrateGrafanaTemplateVariableFn = (query: AzureMonitorQuery) => { if ('resourceGroup' in grafanaTemplateVariableFn) { migratedQuery.resourceGroup = grafanaTemplateVariableFn.resourceGroup; } - if ('metricDefinition' in grafanaTemplateVariableFn) { - migratedQuery.namespace = grafanaTemplateVariableFn.metricDefinition; - } if ('metricNamespace' in grafanaTemplateVariableFn) { migratedQuery.namespace = grafanaTemplateVariableFn.metricNamespace; } @@ -287,9 +281,6 @@ const migrateGrafanaTemplateVariableFn = (query: AzureMonitorQuery) => { case 'ResourceGroupsQuery': migratedQuery.queryType = AzureQueryType.ResourceGroupsQuery; break; - case 'MetricDefinitionsQuery': - migratedQuery.queryType = AzureQueryType.NamespacesQuery; - break; case 'ResourceNamesQuery': migratedQuery.queryType = AzureQueryType.ResourceNamesQuery; break; diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/grafanaTemplateVariables.test.ts b/public/app/plugins/datasource/grafana-azure-monitor-datasource/grafanaTemplateVariables.test.ts index d478ea5d893..33819e29751 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/grafanaTemplateVariables.test.ts +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/grafanaTemplateVariables.test.ts @@ -45,7 +45,7 @@ describe('migrateStringQueriesToObjectQueries', () => { refId: 'A', queryType: AzureQueryType.GrafanaTemplateVariableFn, grafanaTemplateVariableFn: { - kind: 'MetricDefinitionsQuery', + kind: 'MetricNamespaceQuery', rawQuery: 'Namespaces(rg)', subscription: 'defaultSubscriptionId', resourceGroup: 'rg', @@ -59,7 +59,7 @@ describe('migrateStringQueriesToObjectQueries', () => { refId: 'A', queryType: AzureQueryType.GrafanaTemplateVariableFn, grafanaTemplateVariableFn: { - kind: 'MetricDefinitionsQuery', + kind: 'MetricNamespaceQuery', rawQuery: 'Namespaces(subId, rg)', subscription: 'subId', resourceGroup: 'rg', @@ -77,7 +77,7 @@ describe('migrateStringQueriesToObjectQueries', () => { rawQuery: 'ResourceNames(rg, md)', subscription: 'defaultSubscriptionId', resourceGroup: 'rg', - metricDefinition: 'md', + metricNamespace: 'md', }, subscription: 'defaultSubscriptionId', }, @@ -92,7 +92,7 @@ describe('migrateStringQueriesToObjectQueries', () => { rawQuery: 'ResourceNames(subId, rg, md)', subscription: 'subId', resourceGroup: 'rg', - metricDefinition: 'md', + metricNamespace: 'md', }, subscription: 'defaultSubscriptionId', }, @@ -107,7 +107,7 @@ describe('migrateStringQueriesToObjectQueries', () => { rawQuery: 'MetricNamespace(rg, md, rn)', subscription: 'defaultSubscriptionId', resourceGroup: 'rg', - metricDefinition: 'md', + metricNamespace: 'md', resourceName: 'rn', }, subscription: 'defaultSubscriptionId', @@ -123,7 +123,7 @@ describe('migrateStringQueriesToObjectQueries', () => { rawQuery: 'MetricNamespace(subId, rg, md, rn)', subscription: 'subId', resourceGroup: 'rg', - metricDefinition: 'md', + metricNamespace: 'md', resourceName: 'rn', }, subscription: 'defaultSubscriptionId', @@ -139,9 +139,8 @@ describe('migrateStringQueriesToObjectQueries', () => { rawQuery: 'MetricNames(rg, md, rn, mn)', subscription: 'defaultSubscriptionId', resourceGroup: 'rg', - metricDefinition: 'md', + metricNamespace: 'md', resourceName: 'rn', - metricNamespace: 'mn', }, subscription: 'defaultSubscriptionId', }, @@ -156,9 +155,8 @@ describe('migrateStringQueriesToObjectQueries', () => { rawQuery: 'MetricNames(subId, rg, md, rn, mn)', subscription: 'subId', resourceGroup: 'rg', - metricDefinition: 'md', + metricNamespace: 'md', resourceName: 'rn', - metricNamespace: 'mn', }, subscription: 'defaultSubscriptionId', }, @@ -293,7 +291,7 @@ describe('migrateStringQueriesToObjectQueries', () => { refId: 'A', queryType: AzureQueryType.GrafanaTemplateVariableFn, grafanaTemplateVariableFn: { - kind: 'MetricDefinitionsQuery', + kind: 'MetricNamespaceQuery', rawQuery: 'Namespaces(rg)', subscription: 'defaultSubscriptionId', resourceGroup: 'rg', @@ -312,7 +310,7 @@ describe('migrateStringQueriesToObjectQueries', () => { refId: 'A', queryType: AzureQueryType.GrafanaTemplateVariableFn, grafanaTemplateVariableFn: { - kind: 'MetricDefinitionsQuery', + kind: 'MetricNamespaceQuery', rawQuery: 'Namespaces(subId, rg)', subscription: 'subId', resourceGroup: 'rg', @@ -335,7 +333,7 @@ describe('migrateStringQueriesToObjectQueries', () => { rawQuery: 'ResourceNames(rg, md)', subscription: 'defaultSubscriptionId', resourceGroup: 'rg', - metricDefinition: 'md', + metricNamespace: 'md', }, subscription: 'defaultSubscriptionId', }, @@ -356,7 +354,7 @@ describe('migrateStringQueriesToObjectQueries', () => { rawQuery: 'ResourceNames(subId, rg, md)', subscription: 'subId', resourceGroup: 'rg', - metricDefinition: 'md', + metricNamespace: 'md', }, subscription: 'defaultSubscriptionId', }, @@ -377,7 +375,7 @@ describe('migrateStringQueriesToObjectQueries', () => { rawQuery: 'MetricNamespace(rg, md, rn)', subscription: 'defaultSubscriptionId', resourceGroup: 'rg', - metricDefinition: 'md', + metricNamespace: 'md', resourceName: 'rn', }, subscription: 'defaultSubscriptionId', @@ -400,7 +398,7 @@ describe('migrateStringQueriesToObjectQueries', () => { rawQuery: 'MetricNamespace(subId, rg, md, rn)', subscription: 'subId', resourceGroup: 'rg', - metricDefinition: 'md', + metricNamespace: 'md', resourceName: 'rn', }, subscription: 'defaultSubscriptionId', @@ -423,9 +421,8 @@ describe('migrateStringQueriesToObjectQueries', () => { rawQuery: 'MetricNames(rg, md, rn, mn)', subscription: 'defaultSubscriptionId', resourceGroup: 'rg', - metricDefinition: 'md', + metricNamespace: 'md', resourceName: 'rn', - metricNamespace: 'mn', }, subscription: 'defaultSubscriptionId', }, @@ -434,7 +431,7 @@ describe('migrateStringQueriesToObjectQueries', () => { queryType: AzureQueryType.MetricNamesQuery, subscription: 'defaultSubscriptionId', resourceGroup: 'rg', - namespace: 'mn', + namespace: 'md', resource: 'rn', }, }, @@ -447,9 +444,8 @@ describe('migrateStringQueriesToObjectQueries', () => { rawQuery: 'MetricNames(subId, rg, md, rn, mn)', subscription: 'subId', resourceGroup: 'rg', - metricDefinition: 'md', + metricNamespace: 'md', resourceName: 'rn', - metricNamespace: 'mn', }, subscription: 'defaultSubscriptionId', }, @@ -458,7 +454,7 @@ describe('migrateStringQueriesToObjectQueries', () => { queryType: AzureQueryType.MetricNamesQuery, subscription: 'subId', resourceGroup: 'rg', - namespace: 'mn', + namespace: 'md', resource: 'rn', }, }, diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/types/query.ts b/public/app/plugins/datasource/grafana-azure-monitor-datasource/types/query.ts index 9d54d2f733d..ba2829d6f4b 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/types/query.ts +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/types/query.ts @@ -46,10 +46,8 @@ export interface AzureMetricQuery { resourceUri?: string; resourceGroup?: string; - /** Resource type */ - metricDefinition?: string; - resourceName?: string; + /** Resource type */ metricNamespace?: string; metricName?: string; timeGrain?: string; @@ -67,6 +65,9 @@ export interface AzureMetricQuery { /** @deprecated This property was migrated to dimensionFilters and should only be accessed in the migration */ dimensionFilter?: string; + + /** @deprecated Use metricNamespace instead */ + metricDefinition?: string; } /** diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/types/templateVariables.ts b/public/app/plugins/datasource/grafana-azure-monitor-datasource/types/templateVariables.ts index be2e257b916..94938af4b70 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/types/templateVariables.ts +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/types/templateVariables.ts @@ -3,7 +3,6 @@ export type GrafanaTemplateVariableQueryType = | 'AppInsightsGroupByQuery' | 'SubscriptionsQuery' | 'ResourceGroupsQuery' - | 'MetricDefinitionsQuery' | 'ResourceNamesQuery' | 'MetricNamespaceQuery' | 'MetricNamesQuery' @@ -31,29 +30,23 @@ export interface ResourceGroupsQuery extends BaseGrafanaTemplateVariableQuery { kind: 'ResourceGroupsQuery'; subscription: string; } -export interface MetricDefinitionsQuery extends BaseGrafanaTemplateVariableQuery { - kind: 'MetricDefinitionsQuery'; - subscription: string; - resourceGroup: string; -} export interface ResourceNamesQuery extends BaseGrafanaTemplateVariableQuery { kind: 'ResourceNamesQuery'; subscription: string; resourceGroup: string; - metricDefinition: string; + metricNamespace: string; } export interface MetricNamespaceQuery extends BaseGrafanaTemplateVariableQuery { kind: 'MetricNamespaceQuery'; subscription: string; resourceGroup: string; - metricDefinition: string; - resourceName: string; + metricNamespace?: string; + resourceName?: string; } export interface MetricNamesQuery extends BaseGrafanaTemplateVariableQuery { kind: 'MetricNamesQuery'; subscription: string; resourceGroup: string; - metricDefinition: string; resourceName: string; metricNamespace: string; } @@ -67,7 +60,6 @@ export type GrafanaTemplateVariableQuery = | AppInsightsGroupByQuery | SubscriptionsQuery | ResourceGroupsQuery - | MetricDefinitionsQuery | ResourceNamesQuery | MetricNamespaceQuery | MetricNamesQuery diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/types/types.ts b/public/app/plugins/datasource/grafana-azure-monitor-datasource/types/types.ts index bdb5d9d09d6..48cd438c07e 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/types/types.ts +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/types/types.ts @@ -129,14 +129,6 @@ export interface AzureMonitorLocalizedValue { localizedValue: string; } -export interface AzureMonitorMetricDefinitionsResponse { - data: { - value: Array<{ name: string; type: string; location?: string }>; - }; - status: number; - statusText: string; -} - export interface AzureMonitorResourceGroupsResponse { data: { value: Array<{ name: string }>; @@ -233,8 +225,8 @@ export interface AzureGetMetricNamespacesQuery { export interface LegacyAzureGetMetricNamespacesQuery { subscription: string; resourceGroup: string; - metricDefinition: string; - resourceName: string; + metricNamespace?: string; + resourceName?: string; } export interface AzureGetMetricNamesQuery { @@ -245,9 +237,8 @@ export interface AzureGetMetricNamesQuery { export interface LegacyAzureGetMetricNamesQuery { subscription: string; resourceGroup: string; - metricDefinition: string; resourceName: string; - metricNamespace?: string; + metricNamespace: string; } export interface AzureGetMetricMetadataQuery { @@ -259,7 +250,6 @@ export interface AzureGetMetricMetadataQuery { export interface LegacyAzureGetMetricMetadataQuery { subscription: string; resourceGroup: string; - metricDefinition: string; resourceName: string; metricNamespace: string; metricName: string; diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/utils/migrateQuery.test.ts b/public/app/plugins/datasource/grafana-azure-monitor-datasource/utils/migrateQuery.test.ts index 9c047a84b71..af9b517834f 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/utils/migrateQuery.test.ts +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/utils/migrateQuery.test.ts @@ -33,7 +33,6 @@ const azureMonitorQueryV7 = { aggregation: 'Average', allowedTimeGrainsMs: [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], dimensionFilters: [{ dimension: 'dependency/success', filter: '', operator: 'eq' }], - metricDefinition: 'microsoft.insights/components', metricName: 'dependencies/duration', metricNamespace: 'microsoft.insights/components', resourceGroup: 'cloud-datasources', @@ -54,7 +53,6 @@ const azureMonitorQueryV8 = { azureMonitor: { aggregation: 'Average', dimensionFilters: [], - metricDefinition: 'microsoft.insights/components', metricName: 'dependencies/duration', metricNamespace: 'microsoft.insights/components', resourceGroup: 'cloud-datasources', @@ -82,7 +80,6 @@ const modernMetricsQuery: AzureMonitorQuery = { alias: '{{ dimensionvalue }}', allowedTimeGrainsMs: [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000], dimensionFilters: [{ dimension: 'dependency/success', filters: ['*'], operator: 'eq' }], - metricDefinition: 'microsoft.insights/components', metricName: 'dependencies/duration', metricNamespace: 'microsoft.insights/components', resourceGroup: 'cloud-datasources', @@ -158,7 +155,7 @@ describe('AzureMonitor: migrateQuery', () => { ...azureMonitorQueryV8, azureMonitor: { ...azureMonitorQueryV8.azureMonitor, - metricDefinition: '$ns', + metricNamespace: '$ns', }, }; const result = migrateQuery(query, templateSrv, setErrorMock); @@ -295,5 +292,20 @@ describe('AzureMonitor: migrateQuery', () => { }) ); }); + + it('correctly migrates a metric definition', () => { + const result = migrateQuery( + { ...azureMonitorQueryV8, azureMonitor: { metricDefinition: 'ms.ns/mn' } }, + templateSrv + ); + expect(result).toMatchObject( + expect.objectContaining({ + azureMonitor: expect.objectContaining({ + metricNamespace: 'ms.ns/mn', + metricDefinition: undefined, + }), + }) + ); + }); }); }); diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/utils/migrateQuery.ts b/public/app/plugins/datasource/grafana-azure-monitor-datasource/utils/migrateQuery.ts index 6492f204d27..c6613c05e46 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/utils/migrateQuery.ts +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/utils/migrateQuery.ts @@ -16,7 +16,7 @@ const OLD_DEFAULT_DROPDOWN_VALUE = 'select'; export default function migrateQuery( query: AzureMonitorQuery, templateSrv: TemplateSrv, - setError: (errorSource: string, error: AzureMonitorErrorish) => void + setError?: (errorSource: string, error: AzureMonitorErrorish) => void ): AzureMonitorQuery { let workingQuery = query; @@ -81,6 +81,7 @@ function migrateToDefaultNamespace(query: AzureMonitorQuery): AzureMonitorQuery azureMonitor: { ...query.azureMonitor, metricNamespace: query.azureMonitor.metricDefinition, + metricDefinition: undefined, }, }; } @@ -116,13 +117,13 @@ function migrateResourceUri( } const { subscription } = query; - const { resourceGroup, metricDefinition, resourceName } = azureMonitorQuery; - if (!(subscription && resourceGroup && metricDefinition && resourceName)) { + const { resourceGroup, metricNamespace, resourceName } = azureMonitorQuery; + if (!(subscription && resourceGroup && metricNamespace && resourceName)) { return query; } - const metricDefinitionArray = metricDefinition.split('/'); - if (metricDefinitionArray.some((p) => templateSrv.replace(p).split('/').length > 2)) { + const metricNamespaceArray = metricNamespace.split('/'); + if (metricNamespaceArray.some((p) => templateSrv.replace(p).split('/').length > 2)) { // If a metric definition includes template variable with a subresource e.g. // Microsoft.Storage/storageAccounts/libraries, it's not possible to generate a valid // resource URI @@ -173,9 +174,9 @@ function migrateResourceUri( const resourceUri = UrlBuilder.buildResourceUri( subscription, resourceGroup, - metricDefinition, - resourceName, - templateSrv + templateSrv, + metricNamespace, + resourceName ); return { diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/variables.test.ts b/public/app/plugins/datasource/grafana-azure-monitor-datasource/variables.test.ts index 339bde53363..cf42c890f0f 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/variables.test.ts +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/variables.test.ts @@ -98,14 +98,16 @@ describe('VariableSupport', () => { }); }); - it('can fetch metricDefinitions with a default subscriptionId', (done) => { + it('can fetch metricNamespaces with a default subscriptionId', (done) => { const expectedResults = ['test']; const variableSupport = new VariableSupport( createMockDatasource({ azureLogAnalyticsDatasource: { defaultSubscriptionId: 'defaultSubscriptionId', }, - getMetricDefinitions: jest.fn().mockResolvedValueOnce(expectedResults), + azureMonitorDatasource: { + getMetricNamespaces: jest.fn().mockResolvedValue(expectedResults), + }, }) ); const mockRequest = { @@ -114,7 +116,7 @@ describe('VariableSupport', () => { refId: 'A', queryType: AzureQueryType.GrafanaTemplateVariableFn, grafanaTemplateVariableFn: { - kind: 'MetricDefinitionsQuery', + kind: 'MetricNamespaceQuery', rawQuery: 'Namespaces(resourceGroup)', }, } as AzureMonitorQuery, @@ -127,11 +129,13 @@ describe('VariableSupport', () => { }); }); - it('can fetch metricDefinitions with a subscriptionId', (done) => { + it('can fetch metricNamespaces with a subscriptionId', (done) => { const expectedResults = ['test']; const variableSupport = new VariableSupport( createMockDatasource({ - getMetricDefinitions: jest.fn().mockResolvedValueOnce(expectedResults), + azureMonitorDatasource: { + getMetricNamespaces: jest.fn().mockResolvedValue(expectedResults), + }, }) ); const mockRequest = { @@ -140,7 +144,7 @@ describe('VariableSupport', () => { refId: 'A', queryType: AzureQueryType.GrafanaTemplateVariableFn, grafanaTemplateVariableFn: { - kind: 'MetricDefinitionsQuery', + kind: 'MetricNamespaceQuery', rawQuery: 'Namespaces(resourceGroup, subscriptionId)', }, } as AzureMonitorQuery, @@ -170,7 +174,7 @@ describe('VariableSupport', () => { queryType: AzureQueryType.GrafanaTemplateVariableFn, grafanaTemplateVariableFn: { kind: 'ResourceNamesQuery', - rawQuery: 'ResourceNames(resourceGroup, metricDefinition)', + rawQuery: 'ResourceNames(resourceGroup, metricNamespace)', }, } as AzureMonitorQuery, ], @@ -196,7 +200,7 @@ describe('VariableSupport', () => { queryType: AzureQueryType.GrafanaTemplateVariableFn, grafanaTemplateVariableFn: { kind: 'ResourceNamesQuery', - rawQuery: 'ResourceNames(subscriptionId, resourceGroup, metricDefinition)', + rawQuery: 'ResourceNames(subscriptionId, resourceGroup, metricNamespace)', }, } as AzureMonitorQuery, ], @@ -227,7 +231,7 @@ describe('VariableSupport', () => { queryType: AzureQueryType.GrafanaTemplateVariableFn, grafanaTemplateVariableFn: { kind: 'MetricNamespaceQuery', - rawQuery: 'metricNamespace(resourceGroup, metricDefinition, resourceName)', + rawQuery: 'metricNamespace(resourceGroup, metricNamespace, resourceName)', }, } as AzureMonitorQuery, ], @@ -255,7 +259,7 @@ describe('VariableSupport', () => { queryType: AzureQueryType.GrafanaTemplateVariableFn, grafanaTemplateVariableFn: { kind: 'MetricNamespaceQuery', - rawQuery: 'metricNamespace(subscriptionId, resourceGroup, metricDefinition, resourceName)', + rawQuery: 'metricNamespace(subscriptionId, resourceGroup, metricNamespace, resourceName)', }, } as AzureMonitorQuery, ], @@ -286,7 +290,7 @@ describe('VariableSupport', () => { queryType: AzureQueryType.GrafanaTemplateVariableFn, grafanaTemplateVariableFn: { kind: 'MetricNamesQuery', - rawQuery: 'metricNames(resourceGroup, metricDefinition, resourceName, metricNamespace)', + rawQuery: 'metricNames(resourceGroup, metricNamespace, resourceName, metricNamespace)', }, } as AzureMonitorQuery, ], @@ -314,7 +318,7 @@ describe('VariableSupport', () => { queryType: AzureQueryType.GrafanaTemplateVariableFn, grafanaTemplateVariableFn: { kind: 'MetricNamesQuery', - rawQuery: 'metricNames(subscription, resourceGroup, metricDefinition, resourceName, metricNamespace)', + rawQuery: 'metricNames(subscription, resourceGroup, metricNamespace, resourceName, metricNamespace)', }, } as AzureMonitorQuery, ], @@ -393,7 +397,7 @@ describe('VariableSupport', () => { if (sub === 'subscriptionId' && rg === 'resourceGroup') { return Promise.resolve(expectedResults); } - return Promise.resolve([`getMetricDefinitions unexpected input: ${sub}, ${rg}`]); + return Promise.resolve([`getmetricNamespaces unexpected input: ${sub}, ${rg}`]); }), }) ); @@ -443,7 +447,7 @@ describe('VariableSupport', () => { queryType: AzureQueryType.GrafanaTemplateVariableFn, grafanaTemplateVariableFn: { kind: 'MetricNamesQuery', - rawQuery: 'metricNames(resourceGroup, metricDefinition, resourceName, metricNamespace)', + rawQuery: 'metricNames(resourceGroup, metricNamespace, resourceName, metricNamespace)', }, } as AzureMonitorQuery, ], diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/variables.ts b/public/app/plugins/datasource/grafana-azure-monitor-datasource/variables.ts index 19375c755ac..7f043337edd 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/variables.ts +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/variables.ts @@ -111,18 +111,11 @@ export class VariableSupport extends CustomVariableSupport