From b05b5d5e3bbfa48410ecba900c86ac13f654cd82 Mon Sep 17 00:00:00 2001 From: Tom Pickles Date: Mon, 21 Jun 2021 20:05:13 +0800 Subject: [PATCH] AzureMonitor: Fix queries with Microsoft.NetApp/../../volumes resources (#32661) * Extend description of existing tests (#28350) * Tests for building MetricNamespaces URL (#28350) * Added tests that break the URL builder (#28350) * Arbitrary length of metric definition (#28350) * Change var to const as requested (#32661) * Adding tests to datasource url builder (#28350) * Fixes to datasource url builder (#28350) * Fixed linting issue that broke build (#28350) --- pkg/tsdb/azuremonitor/url-builder.go | 18 +++-- pkg/tsdb/azuremonitor/url-builder_test.go | 12 +++ .../azure_monitor/url_builder.test.ts | 79 +++++++++++++++++-- .../azure_monitor/url_builder.ts | 47 +++++------ 4 files changed, 116 insertions(+), 40 deletions(-) diff --git a/pkg/tsdb/azuremonitor/url-builder.go b/pkg/tsdb/azuremonitor/url-builder.go index 09dd4277bb7..a595daf8bad 100644 --- a/pkg/tsdb/azuremonitor/url-builder.go +++ b/pkg/tsdb/azuremonitor/url-builder.go @@ -23,13 +23,17 @@ func (ub *urlBuilder) Build() string { subscription = ub.DefaultSubscription } - if strings.Count(ub.MetricDefinition, "/") > 1 { - rn := strings.Split(ub.ResourceName, "/") - lastIndex := strings.LastIndex(ub.MetricDefinition, "/") - service := ub.MetricDefinition[lastIndex+1:] - md := ub.MetricDefinition[0:lastIndex] - return fmt.Sprintf("%s/resourceGroups/%s/providers/%s/%s/%s/%s/providers/microsoft.insights/metrics", subscription, ub.ResourceGroup, md, rn[0], service, rn[1]) + metricDefinitionArray := strings.Split(ub.MetricDefinition, "/") + resourceNameArray := strings.Split(ub.ResourceName, "/") + provider := metricDefinitionArray[0] + metricDefinitionArray = metricDefinitionArray[1:] + + urlArray := []string{subscription, "resourceGroups", ub.ResourceGroup, "providers", provider} + + for i := range metricDefinitionArray { + urlArray = append(urlArray, metricDefinitionArray[i]) + urlArray = append(urlArray, resourceNameArray[i]) } - return fmt.Sprintf("%s/resourceGroups/%s/providers/%s/%s/providers/microsoft.insights/metrics", subscription, ub.ResourceGroup, ub.MetricDefinition, ub.ResourceName) + return fmt.Sprintf("%s/providers/microsoft.insights/metrics", strings.Join(urlArray[:], "/")) } diff --git a/pkg/tsdb/azuremonitor/url-builder_test.go b/pkg/tsdb/azuremonitor/url-builder_test.go index 68a29f96e3a..c4e40cd0ef5 100644 --- a/pkg/tsdb/azuremonitor/url-builder_test.go +++ b/pkg/tsdb/azuremonitor/url-builder_test.go @@ -56,5 +56,17 @@ func TestURLBuilder(t *testing.T) { url := ub.Build() So(url, ShouldEqual, "default-sub/resourceGroups/rg/providers/Microsoft.Storage/storageAccounts/rn1/fileServices/default/providers/microsoft.insights/metrics") }) + + Convey("when metric definition is Microsoft.NetApp/netAppAccounts/capacityPools/volumes", func() { + ub := &urlBuilder{ + DefaultSubscription: "default-sub", + ResourceGroup: "rg", + MetricDefinition: "Microsoft.NetApp/netAppAccounts/capacityPools/volumes", + ResourceName: "rn1/rn2/rn3", + } + + url := ub.Build() + So(url, ShouldEqual, "default-sub/resourceGroups/rg/providers/Microsoft.NetApp/netAppAccounts/rn1/capacityPools/rn2/volumes/rn3/providers/microsoft.insights/metrics") + }) }) } 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 0762266dc32..9ed28795078 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 @@ -1,7 +1,76 @@ import UrlBuilder from './url_builder'; describe('AzureMonitorUrlBuilder', () => { + describe('when metric definition is Microsoft.NetApp/netAppAccounts/capacityPools/volumes', () => { + it('should build the getMetricNamespaces url in the even longer format', () => { + const url = UrlBuilder.buildAzureMonitorGetMetricNamespacesUrl( + '', + 'sub1', + 'rg', + 'Microsoft.NetApp/netAppAccounts/capacityPools/volumes', + 'rn1/rn2/rn3', + '2017-05-01-preview' + ); + expect(url).toBe( + '/sub1/resourceGroups/rg/providers/Microsoft.NetApp/netAppAccounts/rn1/capacityPools/rn2/volumes/rn3/' + + 'providers/microsoft.insights/metricNamespaces?api-version=2017-05-01-preview' + ); + }); + }); + describe('when metric definition is Microsoft.Sql/servers/databases', () => { + it('should build the getMetricNamespaces url in the longer format', () => { + const url = UrlBuilder.buildAzureMonitorGetMetricNamespacesUrl( + '', + 'sub1', + 'rg', + 'Microsoft.Sql/servers/databases', + 'rn1/rn2', + '2017-05-01-preview' + ); + expect(url).toBe( + '/sub1/resourceGroups/rg/providers/Microsoft.Sql/servers/rn1/databases/rn2/' + + 'providers/microsoft.insights/metricNamespaces?api-version=2017-05-01-preview' + ); + }); + }); + + describe('when metric definition is Microsoft.Sql/servers', () => { + it('should build the getMetricNamespaces url in the shorter format', () => { + const url = UrlBuilder.buildAzureMonitorGetMetricNamespacesUrl( + '', + 'sub1', + 'rg', + 'Microsoft.Sql/servers', + 'rn', + '2017-05-01-preview' + ); + expect(url).toBe( + '/sub1/resourceGroups/rg/providers/Microsoft.Sql/servers/rn/' + + 'providers/microsoft.insights/metricNamespaces?api-version=2017-05-01-preview' + ); + }); + }); + + describe('when metric definition is Microsoft.NetApp/netAppAccounts/capacityPools/volumes and the metricNamespace is default', () => { + it('should build the getMetricNames url in the even longer format', () => { + const url = UrlBuilder.buildAzureMonitorGetMetricNamesUrl( + '', + 'sub1', + 'rg', + 'Microsoft.NetApp/netAppAccounts/capacityPools/volumes', + 'rn1/rn2/rn3', + 'default', + '2017-05-01-preview' + ); + expect(url).toBe( + '/sub1/resourceGroups/rg/providers/Microsoft.NetApp/netAppAccounts/rn1/capacityPools/rn2/volumes/rn3/' + + 'providers/microsoft.insights/metricdefinitions?api-version=2017-05-01-preview&metricnamespace=default' + ); + }); + }); + + describe('when metric definition is Microsoft.Sql/servers/databases and the metricNamespace is default', () => { it('should build the getMetricNames url in the longer format', () => { const url = UrlBuilder.buildAzureMonitorGetMetricNamesUrl( '', @@ -19,7 +88,7 @@ describe('AzureMonitorUrlBuilder', () => { }); }); - describe('when metric definition is Microsoft.Sql/servers', () => { + describe('when metric definition is Microsoft.Sql/servers and the metricNamespace is default', () => { it('should build the getMetricNames url in the shorter format', () => { const url = UrlBuilder.buildAzureMonitorGetMetricNamesUrl( '', @@ -37,7 +106,7 @@ describe('AzureMonitorUrlBuilder', () => { }); }); - describe('when metric definition is Microsoft.Storage/storageAccounts/blobServices', () => { + describe('when metric definition is Microsoft.Storage/storageAccounts/blobServices and the metricNamespace is default', () => { it('should build the getMetricNames url in the longer format', () => { const url = UrlBuilder.buildAzureMonitorGetMetricNamesUrl( '', @@ -55,7 +124,7 @@ describe('AzureMonitorUrlBuilder', () => { }); }); - describe('when metric definition is Microsoft.Storage/storageAccounts/fileServices', () => { + describe('when metric definition is Microsoft.Storage/storageAccounts/fileServices and the metricNamespace is default', () => { it('should build the getMetricNames url in the longer format', () => { const url = UrlBuilder.buildAzureMonitorGetMetricNamesUrl( '', @@ -73,7 +142,7 @@ describe('AzureMonitorUrlBuilder', () => { }); }); - describe('when metric definition is Microsoft.Storage/storageAccounts/tableServices', () => { + describe('when metric definition is Microsoft.Storage/storageAccounts/tableServices and the metricNamespace is default', () => { it('should build the getMetricNames url in the longer format', () => { const url = UrlBuilder.buildAzureMonitorGetMetricNamesUrl( '', @@ -91,7 +160,7 @@ describe('AzureMonitorUrlBuilder', () => { }); }); - describe('when metric definition is Microsoft.Storage/storageAccounts/queueServices', () => { + describe('when metric definition is Microsoft.Storage/storageAccounts/queueServices and the metricNamespace is default', () => { it('should build the getMetricNames url in the longer format', () => { const url = UrlBuilder.buildAzureMonitorGetMetricNamesUrl( '', 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 e8cb3afcc1c..a477dd23ef4 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 @@ -7,20 +7,16 @@ export default class UrlBuilder { resourceName: string, apiVersion: string ) { - if ((metricDefinition.match(/\//g) || []).length > 1) { - const rn = resourceName.split('/'); - const service = metricDefinition.substring(metricDefinition.lastIndexOf('/') + 1); - const md = metricDefinition.substring(0, metricDefinition.lastIndexOf('/')); - return ( - `${baseUrl}/${subscriptionId}/resourceGroups/${resourceGroup}/providers/${md}/${rn[0]}/${service}/${rn[1]}` + - `/providers/microsoft.insights/metricNamespaces?api-version=${apiVersion}` - ); + const metricDefinitionArray = metricDefinition.split('/'); + const resourceNameArray = resourceName.split('/'); + const provider = metricDefinitionArray.shift(); + const urlArray = [baseUrl, subscriptionId, 'resourceGroups', resourceGroup, 'providers', provider]; + for (const i in metricDefinitionArray) { + urlArray.push(metricDefinitionArray[i]); + urlArray.push(resourceNameArray[i]); } - - return ( - `${baseUrl}/${subscriptionId}/resourceGroups/${resourceGroup}/providers/${metricDefinition}/${resourceName}` + - `/providers/microsoft.insights/metricNamespaces?api-version=${apiVersion}` - ); + const urlPrefix = urlArray.join('/'); + return `${urlPrefix}/providers/microsoft.insights/metricNamespaces?api-version=${apiVersion}`; } static buildAzureMonitorGetMetricNamesUrl( @@ -32,23 +28,18 @@ export default class UrlBuilder { metricNamespace: string, apiVersion: string ) { - if ((metricDefinition.match(/\//g) || []).length > 1) { - const rn = resourceName.split('/'); - const service = metricDefinition.substring(metricDefinition.lastIndexOf('/') + 1); - const md = metricDefinition.substring(0, metricDefinition.lastIndexOf('/')); - return ( - `${baseUrl}/${subscriptionId}/resourceGroups/${resourceGroup}/providers/${md}/${rn[0]}/${service}/${rn[1]}` + - `/providers/microsoft.insights/metricdefinitions?api-version=${apiVersion}&metricnamespace=${encodeURIComponent( - metricNamespace - )}` - ); + const metricDefinitionArray = metricDefinition.split('/'); + const resourceNameArray = resourceName.split('/'); + const provider = metricDefinitionArray.shift(); + const urlArray = [baseUrl, subscriptionId, 'resourceGroups', resourceGroup, 'providers', provider]; + for (const i in metricDefinitionArray) { + urlArray.push(metricDefinitionArray[i]); + urlArray.push(resourceNameArray[i]); } - + const urlPrefix = urlArray.join('/'); return ( - `${baseUrl}/${subscriptionId}/resourceGroups/${resourceGroup}/providers/${metricDefinition}/${resourceName}` + - `/providers/microsoft.insights/metricdefinitions?api-version=${apiVersion}&metricnamespace=${encodeURIComponent( - metricNamespace - )}` + `${urlPrefix}/providers/microsoft.insights/metricdefinitions?api-version=${apiVersion}` + + `&metricnamespace=${encodeURIComponent(metricNamespace)}` ); } }