Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[v10.0.x] AzureMonitor: Fix metric names for multi-resources. #70994

Merged
merged 1 commit into from Jun 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -317,7 +317,7 @@ describe('AzureMonitorDatasource', () => {
],
};

beforeEach(() => {
it('should return list of Metric Names', () => {
ctx.ds.azureMonitorDatasource.getResource = jest.fn().mockImplementation((path: string) => {
const basePath = 'azuremonitor/subscriptions/mock-subscription-id/resourceGroups/nodeapp';
const expected =
Expand All @@ -327,9 +327,6 @@ describe('AzureMonitorDatasource', () => {
expect(path).toBe(expected);
return Promise.resolve(response);
});
});

it('should return list of Metric Names', () => {
return ctx.ds.azureMonitorDatasource
.getMetricNames({
resourceUri:
Expand All @@ -344,6 +341,33 @@ describe('AzureMonitorDatasource', () => {
expect(results[1].value).toEqual('FreeCapacity');
});
});

it('should return list of Metric Names appropriate when multiple resources are selected', () => {
ctx.ds.azureMonitorDatasource.getResource = jest.fn().mockImplementation((path: string) => {
const basePath = 'azuremonitor/subscriptions/mock-subscription-id/resourceGroups/nodeapp';
const expected =
basePath +
'/providers/microsoft.insights/metricdefinitions?api-version=2017-12-01-preview&metricnamespace=microsoft.insights%2Fcomponents&region=region';
expect(path).toBe(expected);
return Promise.resolve(response);
});
return ctx.ds.azureMonitorDatasource
.getMetricNames(
{
resourceUri: '/subscriptions/mock-subscription-id/resourceGroups/nodeapp',
metricNamespace: 'microsoft.insights/components',
},
true,
'region'
)
.then((results: Array<{ text: string; value: string }>) => {
expect(results.length).toEqual(2);
expect(results[0].text).toEqual('Used capacity');
expect(results[0].value).toEqual('UsedCapacity');
expect(results[1].text).toEqual('Free capacity');
expect(results[1].value).toEqual('FreeCapacity');
});
});
});

describe('When performing getMetricMetadata', () => {
Expand Down
Expand Up @@ -265,27 +265,33 @@ export default class AzureMonitorDatasource extends DataSourceWithBackend<AzureM
});
}

getMetricNames(query: GetMetricNamesQuery) {
getMetricNames(query: GetMetricNamesQuery, multipleResources?: boolean, region?: string) {
const apiVersion = multipleResources ? this.apiPreviewVersion : this.apiVersion;
const url = UrlBuilder.buildAzureMonitorGetMetricNamesUrl(
this.resourcePath,
this.apiVersion,
apiVersion,
// Only use the first query, as the metric names should be the same for all queries
this.replaceSingleTemplateVariables(query),
this.templateSrv
this.templateSrv,
multipleResources,
region
);
return this.getResource(url).then((result: AzureMonitorMetricNamesResponse) => {
return ResponseParser.parseResponseValues(result, 'name.localizedValue', 'name.value');
});
}

getMetricMetadata(query: GetMetricMetadataQuery) {
getMetricMetadata(query: GetMetricMetadataQuery, multipleResources?: boolean, region?: string) {
const { metricName } = query;
const apiVersion = multipleResources ? this.apiPreviewVersion : this.apiVersion;
const url = UrlBuilder.buildAzureMonitorGetMetricNamesUrl(
this.resourcePath,
this.apiVersion,
apiVersion,
// Only use the first query, as the metric metadata should be the same for all queries
this.replaceSingleTemplateVariables(query),
this.templateSrv
this.templateSrv,
multipleResources,
region
);
return this.getResource(url).then((result: AzureMonitorMetricsMetadataResponse) => {
return ResponseParser.parseMetadata(result, this.templateSrv.replace(metricName));
Expand Down
Expand Up @@ -398,5 +398,23 @@ describe('AzureMonitorUrlBuilder', () => {
);
});
});
describe('when multiple resources are selected', () => {
it('passes metricNamespace as query param', () => {
const url = UrlBuilder.buildAzureMonitorGetMetricNamesUrl(
'',
'2017-05-01-preview',
{
resourceUri: '/subscriptions/sub/resource-uri/resource',
metricNamespace: 'Microsoft.Sql/servers',
},
templateSrv,
true,
'region'
);
expect(url).toBe(
'/subscriptions/sub/resource-uri/resource/providers/microsoft.insights/metricdefinitions?api-version=2017-05-01-preview&metricnamespace=Microsoft.Sql%2Fservers&region=region'
);
});
});
});
});
Expand Up @@ -3,14 +3,12 @@ import { TemplateSrv } from '@grafana/runtime';
import { AzureMonitorResource, GetMetricNamespacesQuery, GetMetricNamesQuery } from '../types';

export default class UrlBuilder {
static buildResourceUri(templateSrv: TemplateSrv, resource: AzureMonitorResource) {
static buildResourceUri(templateSrv: TemplateSrv, resource: AzureMonitorResource, multipleResources?: boolean) {
const urlArray = [];
const { subscription, resourceGroup, metricNamespace, resourceName } = resource;

if (subscription) {
urlArray.push('/subscriptions', subscription);

if (resourceGroup) {
if (resourceGroup && !multipleResources) {
urlArray.push('resourceGroups', resourceGroup);

if (metricNamespace && resourceName) {
Expand Down Expand Up @@ -78,26 +76,40 @@ export default class UrlBuilder {
baseUrl: string,
apiVersion: string,
query: GetMetricNamesQuery,
templateSrv: TemplateSrv
templateSrv: TemplateSrv,
multipleResources?: boolean,
region?: string
) {
let resourceUri: string;
const { customNamespace } = query;
const { customNamespace, metricNamespace } = query;
if ('resourceUri' in query) {
resourceUri = query.resourceUri;
} else {
const { subscription, resourceGroup, metricNamespace, resourceName } = query;
resourceUri = UrlBuilder.buildResourceUri(templateSrv, {
subscription,
resourceGroup,
metricNamespace,
resourceName,
});
resourceUri = UrlBuilder.buildResourceUri(
templateSrv,
{
subscription,
resourceGroup,
metricNamespace,
resourceName,
},
multipleResources
);
}
let url = `${baseUrl}${resourceUri}/providers/microsoft.insights/metricdefinitions?api-version=${apiVersion}`;
if (customNamespace) {
url += `&metricnamespace=${encodeURIComponent(customNamespace)}`;
}

if (multipleResources && !customNamespace && metricNamespace) {
url += `&metricnamespace=${encodeURIComponent(metricNamespace)}`;

if (region) {
url += `&region=${region}`;
}
}

return url;
}
}
Expand Up @@ -88,25 +88,31 @@ export const useMetricNames: DataHook = (query, datasource, onChange, setError)
const { subscription } = query;
const { metricNamespace, metricName, resources, customNamespace } = query.azureMonitor ?? {};
const { resourceGroup, resourceName } = getResourceGroupAndName(resources);
const multipleResources = (resources && resources.length > 1) ?? false;
const region = query.azureMonitor?.region ?? '';

return useAsyncState(
async () => {
if (!subscription || !metricNamespace || !resourceGroup || !resourceName) {
return;
}
const results = await datasource.azureMonitorDatasource.getMetricNames({
subscription,
resourceGroup,
resourceName,
metricNamespace,
customNamespace,
});
const results = await datasource.azureMonitorDatasource.getMetricNames(
{
subscription,
resourceGroup,
resourceName,
metricNamespace,
customNamespace,
},
multipleResources,
region
);
const options = formatOptions(results, metricName);

return options;
},
setError,
[subscription, resourceGroup, resourceName, metricNamespace, customNamespace]
[subscription, resourceGroup, resourceName, metricNamespace, customNamespace, multipleResources]
);
};

Expand All @@ -124,6 +130,7 @@ export const useMetricMetadata = (query: AzureMonitorQuery, datasource: Datasour
const { subscription } = query;
const { resources, metricNamespace, metricName, aggregation, timeGrain, customNamespace } = query.azureMonitor ?? {};
const { resourceGroup, resourceName } = getResourceGroupAndName(resources);
const multipleResources = (resources && resources.length > 1) ?? false;

// Fetch new metric metadata when the fields change
useEffect(() => {
Expand All @@ -133,7 +140,10 @@ export const useMetricMetadata = (query: AzureMonitorQuery, datasource: Datasour
}

datasource.azureMonitorDatasource
.getMetricMetadata({ subscription, resourceGroup, resourceName, metricNamespace, metricName, customNamespace })
.getMetricMetadata(
{ subscription, resourceGroup, resourceName, metricNamespace, metricName, customNamespace },
multipleResources
)
.then((metadata) => {
// TODO: Move the aggregationTypes and timeGrain defaults into `getMetricMetadata`
const aggregations = (metadata.supportedAggTypes || [metadata.primaryAggType]).map((v) => ({
Expand All @@ -150,7 +160,16 @@ export const useMetricMetadata = (query: AzureMonitorQuery, datasource: Datasour
primaryAggType: metadata.primaryAggType,
});
});
}, [datasource, subscription, resourceGroup, resourceName, metricNamespace, metricName, customNamespace]);
}, [
datasource,
subscription,
resourceGroup,
resourceName,
metricNamespace,
metricName,
customNamespace,
multipleResources,
]);

// Update the query state in response to the meta data changing
useEffect(() => {
Expand Down