[v10.0.x] AzureMonitor: Fix metric names for multi-resources. (#70994)
AzureMonitor: Fix metric names for multi-resources. (#70864)
When building a query for multiple resources only a subset of metrics
are valid and that selection is only available via the API version `2017-12-01-preview`.
fixes #68603
(cherry picked from commit f32f1859a0)
Co-authored-by: Adam Simpson <adam@adamsimpson.net>
This commit is contained in:
co-authored by
Adam Simpson
parent
47ac8e353c
commit
df3e56aedb
+28
-4
@@ -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 =
|
||||
@@ -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:
|
||||
@@ -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®ion=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', () => {
|
||||
|
||||
+12
-6
@@ -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));
|
||||
|
||||
@@ -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®ion=region'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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) {
|
||||
@@ -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 += `®ion=${region}`;
|
||||
}
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
||||
+29
-10
@@ -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]
|
||||
);
|
||||
};
|
||||
|
||||
@@ -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(() => {
|
||||
@@ -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) => ({
|
||||
@@ -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(() => {
|
||||
|
||||
Reference in New Issue
Block a user