From c8b7546e6b7fe83d44ba76dd2c7a2ff133680a05 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Wed, 18 Sep 2024 15:39:28 +0100 Subject: [PATCH] [v11.0.x] AzureMonitor: Improve resource picker efficiency (#93438) AzureMonitor: Improve resource picker efficiency (#93127) * Parameterise region building metric namespace URL - Add parameter for region (this parameter takes precedence over if global is set) - Update tests - Support this parameter on the data source method * Refactor fetchAllNamespaces - Use Set rather than an array for greater performance - Request namespaces across WestEurope, EastUS, and JapanEast concurrently - Update test * Maintain existing behaviour (cherry picked from commit 6a3dbe7d419ea7b3a9048169c819a16fd8082b47) Co-authored-by: Andreas Christou --- .../azure_monitor/azure_monitor_datasource.ts | 5 +-- .../azure_monitor/url_builder.test.ts | 32 +++++++++++++++++ .../azuremonitor/azure_monitor/url_builder.ts | 5 +-- .../resourcePicker/resourcePickerData.test.ts | 28 +++++++++++++-- .../resourcePicker/resourcePickerData.ts | 36 ++++++++++++------- 5 files changed, 87 insertions(+), 19 deletions(-) diff --git a/public/app/plugins/datasource/azuremonitor/azure_monitor/azure_monitor_datasource.ts b/public/app/plugins/datasource/azuremonitor/azure_monitor/azure_monitor_datasource.ts index 4a1f5f61bfa..cd055eb7801 100644 --- a/public/app/plugins/datasource/azuremonitor/azure_monitor/azure_monitor_datasource.ts +++ b/public/app/plugins/datasource/azuremonitor/azure_monitor/azure_monitor_datasource.ts @@ -232,14 +232,15 @@ export default class AzureMonitorDatasource extends DataSourceWithBackend) => { diff --git a/public/app/plugins/datasource/azuremonitor/azure_monitor/url_builder.test.ts b/public/app/plugins/datasource/azuremonitor/azure_monitor/url_builder.test.ts index fddceba7918..f6d0f53e92c 100644 --- a/public/app/plugins/datasource/azuremonitor/azure_monitor/url_builder.test.ts +++ b/public/app/plugins/datasource/azuremonitor/azure_monitor/url_builder.test.ts @@ -142,6 +142,38 @@ describe('AzureMonitorUrlBuilder', () => { '/subscriptions/sub/resource-uri/resource/providers/microsoft.insights/metricNamespaces?api-version=2017-05-01-preview®ion=global' ); }); + + it('builds a getMetricNamesnamespace url with a specific region', () => { + const url = UrlBuilder.buildAzureMonitorGetMetricNamespacesUrl( + '', + '2017-05-01-preview', + { + resourceUri: '/subscriptions/sub/resource-uri/resource', + }, + false, + templateSrv, + 'testregion' + ); + expect(url).toBe( + '/subscriptions/sub/resource-uri/resource/providers/microsoft.insights/metricNamespaces?api-version=2017-05-01-preview®ion=testregion' + ); + }); + + it('builds a getMetricNamesnamespace url with a specific region (overriding global)', () => { + const url = UrlBuilder.buildAzureMonitorGetMetricNamespacesUrl( + '', + '2017-05-01-preview', + { + resourceUri: '/subscriptions/sub/resource-uri/resource', + }, + true, + templateSrv, + 'testregion' + ); + expect(url).toBe( + '/subscriptions/sub/resource-uri/resource/providers/microsoft.insights/metricNamespaces?api-version=2017-05-01-preview®ion=testregion' + ); + }); }); describe('when a resource uri and metric namespace is provided', () => { diff --git a/public/app/plugins/datasource/azuremonitor/azure_monitor/url_builder.ts b/public/app/plugins/datasource/azuremonitor/azure_monitor/url_builder.ts index 15230fb526e..295fcb85ea3 100644 --- a/public/app/plugins/datasource/azuremonitor/azure_monitor/url_builder.ts +++ b/public/app/plugins/datasource/azuremonitor/azure_monitor/url_builder.ts @@ -51,7 +51,8 @@ export default class UrlBuilder { apiVersion: string, query: GetMetricNamespacesQuery, globalRegion: boolean, - templateSrv: TemplateSrv + templateSrv: TemplateSrv, + region?: string ) { let resourceUri: string; @@ -68,7 +69,7 @@ export default class UrlBuilder { } return `${baseUrl}${resourceUri}/providers/microsoft.insights/metricNamespaces?api-version=${apiVersion}${ - globalRegion ? '®ion=global' : '' + region ? `®ion=${region}` : globalRegion ? '®ion=global' : '' }`; } diff --git a/public/app/plugins/datasource/azuremonitor/resourcePicker/resourcePickerData.test.ts b/public/app/plugins/datasource/azuremonitor/resourcePicker/resourcePickerData.test.ts index de358322d43..8764d34a017 100644 --- a/public/app/plugins/datasource/azuremonitor/resourcePicker/resourcePickerData.test.ts +++ b/public/app/plugins/datasource/azuremonitor/resourcePicker/resourcePickerData.test.ts @@ -312,9 +312,33 @@ describe('AzureMonitor resourcePickerData', () => { }, ], }; - const { resourcePickerData, postResource } = createResourcePickerData([mockSubscriptionsResponse, mockResponse]); + const { resourcePickerData, postResource, mockDatasource } = createResourcePickerData([ + mockSubscriptionsResponse, + mockResponse, + ]); const formattedResults = await resourcePickerData.search('vmname', 'metrics'); - expect(postResource).toBeCalledTimes(2); + expect(postResource).toHaveBeenCalledTimes(2); + expect(mockDatasource.azureMonitorDatasource.getMetricNamespaces).toHaveBeenCalledWith( + { + resourceUri: '/subscriptions/1', + }, + false, + 'westeurope' + ); + expect(mockDatasource.azureMonitorDatasource.getMetricNamespaces).toHaveBeenCalledWith( + { + resourceUri: '/subscriptions/1', + }, + false, + 'eastus' + ); + expect(mockDatasource.azureMonitorDatasource.getMetricNamespaces).toHaveBeenCalledWith( + { + resourceUri: '/subscriptions/1', + }, + false, + 'japaneast' + ); const secondCall = postResource.mock.calls[1]; const [_, postBody] = secondCall; expect(postBody.query).not.toContain('union resourcecontainers'); diff --git a/public/app/plugins/datasource/azuremonitor/resourcePicker/resourcePickerData.ts b/public/app/plugins/datasource/azuremonitor/resourcePicker/resourcePickerData.ts index 92c051c97c9..abd86180a94 100644 --- a/public/app/plugins/datasource/azuremonitor/resourcePicker/resourcePickerData.ts +++ b/public/app/plugins/datasource/azuremonitor/resourcePicker/resourcePickerData.ts @@ -1,5 +1,3 @@ -import { uniq } from 'lodash'; - import { DataSourceInstanceSettings } from '@grafana/data'; import { DataSourceWithBackend, reportInteraction } from '@grafana/runtime'; @@ -359,28 +357,40 @@ export default class ResourcePickerData extends DataSourceWithBackend = new Set(); + // We make use of these three regions as they *should* contain every possible namespace + const regions = ['westeurope', 'eastus', 'japaneast']; + const getNamespacesForRegion = async (region: string) => { const namespaces = await this.azureMonitorDatasource.getMetricNamespaces( { - resourceUri: `/subscriptions/${subscription.id}`, + // We only need to run this request against the first available subscription + resourceUri: `/subscriptions/${subscriptions[0].id}`, }, - true + false, + region ); if (namespaces) { - const namespaceVals = namespaces.map((namespace) => `"${namespace.value.toLocaleLowerCase()}"`); - supportedMetricNamespaces = supportedMetricNamespaces.concat(namespaceVals); + for (const namespace of namespaces) { + supportedMetricNamespaces.add(`"${namespace.value.toLocaleLowerCase()}"`); + } } - } + }; - if (supportedMetricNamespaces.length === 0) { + const promises = regions.map((region) => getNamespacesForRegion(region)); + await Promise.all(promises); + + if (supportedMetricNamespaces.size === 0) { throw new Error( 'Unable to resolve a list of valid metric namespaces. Validate the datasource configuration is correct and required permissions have been granted for all subscriptions. Grafana requires at least the Reader role to be assigned.' ); } - this.supportedMetricNamespaces = uniq( - supportedMetricNamespaces.concat(resourceTypes.map((namespace) => `"${namespace}"`)) - ).join(','); + + resourceTypes.forEach((namespace) => { + supportedMetricNamespaces.add(`"${namespace}"`); + }); + + this.supportedMetricNamespaces = Array.from(supportedMetricNamespaces).join(','); } parseRows(resources: Array): ResourceRow[] {