From a61bf0d1f10f87758745d5cd4b86a1b6f4fcd407 Mon Sep 17 00:00:00 2001 From: Andreas Christou Date: Tue, 8 Apr 2025 22:25:50 +0100 Subject: [PATCH] [release-11.5.4] Azure: Support more complex variable interpolation (#103651) Azure: Support more complex variable interpolation (#99284) Support more complex variable interpolation - Update test (cherry picked from commit 763f0bac90d6296f034939627e9058bf2071b484) --- .../azure_monitor_datasource.test.ts | 79 ++++++++++++++++++- .../azure_monitor/azure_monitor_datasource.ts | 41 ++++++---- 2 files changed, 104 insertions(+), 16 deletions(-) diff --git a/public/app/plugins/datasource/azuremonitor/azure_monitor/azure_monitor_datasource.test.ts b/public/app/plugins/datasource/azuremonitor/azure_monitor/azure_monitor_datasource.test.ts index 2a51c9dc20b..9df9d831650 100644 --- a/public/app/plugins/datasource/azuremonitor/azure_monitor/azure_monitor_datasource.test.ts +++ b/public/app/plugins/datasource/azuremonitor/azure_monitor/azure_monitor_datasource.test.ts @@ -1,5 +1,8 @@ import { get, set } from 'lodash'; +import { ScopedVars } from '@grafana/data'; +import { VariableInterpolation } from '@grafana/runtime'; + import createMockQuery from '../__mocks__/query'; import { createTemplateVariables } from '../__mocks__/utils'; import { multiVariable } from '../__mocks__/variables'; @@ -138,11 +141,22 @@ describe('AzureMonitorDatasource', () => { it('expand template variables in resource groups and names', () => { const resourceGroup = '$rg'; const resourceName = '$rn'; - replace = (target?: string) => { + replace = ( + target?: string, + _scopedVars?: ScopedVars, + _format?: string | Function, + interpolated?: VariableInterpolation[] + ) => { if (target?.includes('$rg')) { + if (interpolated) { + interpolated.push({ value: 'rg1,rg2', match: '$rg', variableName: 'rg' }); + } return 'rg1,rg2'; } if (target?.includes('$rn')) { + if (interpolated) { + interpolated.push({ value: 'rn1,rn2', match: '$rn', variableName: 'rn' }); + } return 'rn1,rn2'; } return target || ''; @@ -166,6 +180,48 @@ describe('AzureMonitorDatasource', () => { }); }); + it('expand template variables in more complex resource groups and names', () => { + const resourceGroup = 'test-$rg-testGroup'; + const resourceName = 'test-$rn-testResource'; + replace = ( + target?: string, + _scopedVars?: ScopedVars, + _format?: string | Function, + interpolated?: VariableInterpolation[] + ) => { + if (target?.includes('$rg')) { + if (interpolated) { + interpolated.push({ value: 'rg1,rg2', match: '$rg', variableName: 'rg' }); + } + return 'rg1,rg2'; + } + if (target?.includes('$rn')) { + if (interpolated) { + interpolated.push({ value: 'rn1,rn2', match: '$rn', variableName: 'rn' }); + } + return 'rn1,rn2'; + } + return target || ''; + }; + ctx.ds = new AzureMonitorDatasource(ctx.instanceSettings); + const query = createMockQuery({ + azureMonitor: { + resources: [{ resourceGroup, resourceName }], + }, + }); + const templatedQuery = ctx.ds.azureMonitorDatasource.applyTemplateVariables(query, {}); + expect(templatedQuery).toMatchObject({ + azureMonitor: { + resources: [ + { resourceGroup: 'test-rg1-testGroup', resourceName: 'test-rn1-testResource' }, + { resourceGroup: 'test-rg2-testGroup', resourceName: 'test-rn1-testResource' }, + { resourceGroup: 'test-rg1-testGroup', resourceName: 'test-rn2-testResource' }, + { resourceGroup: 'test-rg2-testGroup', resourceName: 'test-rn2-testResource' }, + ], + }, + }); + }); + it('expand template variables for a region', () => { const region = '$reg'; replace = (target?: string) => { @@ -787,10 +843,29 @@ describe('AzureMonitorDatasource', () => { }); it('should return multiple resources from a template variable', () => { - replace = (target?: string) => { + replace = ( + target?: string, + _scopedVars?: ScopedVars, + _format?: string | Function, + interpolated?: VariableInterpolation[] + ) => { if (target?.includes('$reg')) { + if (interpolated) { + interpolated.push({ value: 'eastus', match: '$reg', variableName: 'reg' }); + } return 'eastus'; } + + if (target === `$${multiVariable.id}`) { + if (interpolated) { + interpolated.push({ value: 'foo,bar', match: `$${multiVariable.id}`!, variableName: 'target' }); + } + return 'foo,bar'; + } + + if (interpolated) { + interpolated.push({ value: target ?? '', match: `$${target}`!, variableName: 'target' }); + } return target === `$${multiVariable.id}` ? 'foo,bar' : (target ?? ''); }; const ds = new AzureMonitorDatasource(ctx.instanceSettings); 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 4d77926296b..42da2efb178 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 @@ -2,7 +2,7 @@ import { find, startsWith } from 'lodash'; import { AzureCredentials } from '@grafana/azure-sdk'; import { ScopedVars } from '@grafana/data'; -import { DataSourceWithBackend, getTemplateSrv, TemplateSrv } from '@grafana/runtime'; +import { DataSourceWithBackend, getTemplateSrv, TemplateSrv, VariableInterpolation } from '@grafana/runtime'; import { getCredentials } from '../credentials'; import TimegrainConverter from '../time_grain_converter'; @@ -355,19 +355,32 @@ export default class AzureMonitorDatasource extends DataSourceWithBackend< const workingQueries: Array<{ [K in keyof T]: string }> = [{ ...query }]; const keys = Object.keys(query) as Array; keys.forEach((key) => { - const replaced = this.templateSrv.replace(workingQueries[0][key], scopedVars, 'raw'); - if (replaced.includes(',')) { - const multiple = replaced.split(','); - const currentQueries = [...workingQueries]; - multiple.forEach((value, i) => { - currentQueries.forEach((q) => { - if (i === 0) { - q[key] = value; - } else { - workingQueries.push({ ...q, [key]: value }); - } - }); - }); + const rawValue = workingQueries[0][key]; + let interpolated: VariableInterpolation[] = []; + const replaced = this.templateSrv.replace(rawValue, scopedVars, 'raw', interpolated); + if (interpolated.length > 0) { + for (const variable of interpolated) { + if (variable.found === false) { + continue; + } + if (variable.value.includes(',')) { + const multiple = variable.value.split(','); + const currentQueries = [...workingQueries]; + multiple.forEach((value, i) => { + currentQueries.forEach((q) => { + if (i === 0) { + q[key] = rawValue.replace(variable.match, value); + } else { + workingQueries.push({ ...q, [key]: rawValue.replace(variable.match, value) }); + } + }); + }); + } else { + workingQueries.forEach((q) => { + q[key] = replaced; + }); + } + } } else { workingQueries.forEach((q) => { q[key] = replaced;