mirror of
https://github.com/grafana/grafana.git
synced 2026-09-05 04:40:13 -05:00
AzureMonitor: Fixes metric definition for Azure Storage queue/file/blob/table resources. (#49101)
* Appropriately set metric definition - Nested storage account resources (queues/blobs/tables/files) require metric definition of Microsoft.Storage/storageAccounts - Update tests accordingly * Restructure getResourceNames test - Add expect on getResource args * Update to fix issue for new query editor - Reconstruct resourceUri if the resource is a storage account - Correctly push storage namespaces as options for metric namespaces - Filter options appropriately * Fix duplicate options * Fix lint issues * Add comment explaining URI modification
This commit is contained in:
+11
-6
@@ -1,3 +1,5 @@
|
||||
import { startsWith } from 'lodash';
|
||||
|
||||
import { DataSourceInstanceSettings } from '@grafana/data';
|
||||
import { TemplateSrv } from 'app/features/templating/template_srv';
|
||||
|
||||
@@ -445,25 +447,28 @@ describe('AzureMonitorDatasource', () => {
|
||||
],
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
it('should return list of Resource Names', () => {
|
||||
metricDefinition = 'Microsoft.Storage/storageAccounts/blobServices';
|
||||
const validMetricDefinition = startsWith(metricDefinition, 'Microsoft.Storage/storageAccounts/')
|
||||
? 'Microsoft.Storage/storageAccounts'
|
||||
: metricDefinition;
|
||||
ctx.ds.azureMonitorDatasource.getResource = jest.fn().mockImplementation((path: string) => {
|
||||
const basePath = `azuremonitor/subscriptions/${subscription}/resourceGroups`;
|
||||
expect(path).toBe(
|
||||
basePath +
|
||||
`/${resourceGroup}/resources?$filter=resourceType eq '${metricDefinition}'&api-version=2021-04-01`
|
||||
`/${resourceGroup}/resources?$filter=resourceType eq '${validMetricDefinition}'&api-version=2021-04-01`
|
||||
);
|
||||
return Promise.resolve(response);
|
||||
});
|
||||
});
|
||||
|
||||
it('should return list of Resource Names', () => {
|
||||
metricDefinition = 'Microsoft.Storage/storageAccounts/blobServices';
|
||||
return ctx.ds
|
||||
.getResourceNames(subscription, resourceGroup, metricDefinition)
|
||||
.then((results: Array<{ text: string; value: string }>) => {
|
||||
expect(results.length).toEqual(1);
|
||||
expect(results[0].text).toEqual('storagetest/default');
|
||||
expect(results[0].value).toEqual('storagetest/default');
|
||||
expect(ctx.ds.azureMonitorDatasource.getResource).toHaveBeenCalledWith(
|
||||
`azuremonitor/subscriptions/${subscription}/resourceGroups/${resourceGroup}/resources?$filter=resourceType eq '${validMetricDefinition}'&api-version=2021-04-01`
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+26
-5
@@ -1,4 +1,4 @@
|
||||
import { filter, startsWith } from 'lodash';
|
||||
import { filter, find, startsWith } from 'lodash';
|
||||
|
||||
import { DataSourceInstanceSettings, ScopedVars } from '@grafana/data';
|
||||
import { DataSourceWithBackend, getTemplateSrv } from '@grafana/runtime';
|
||||
@@ -207,9 +207,12 @@ export default class AzureMonitorDatasource extends DataSourceWithBackend<AzureM
|
||||
}
|
||||
|
||||
getResourceNames(subscriptionId: string, resourceGroup: string, metricDefinition: string, skipToken?: string) {
|
||||
const validMetricDefinition = startsWith(metricDefinition, 'Microsoft.Storage/storageAccounts/')
|
||||
? 'Microsoft.Storage/storageAccounts'
|
||||
: metricDefinition;
|
||||
let url =
|
||||
`${this.resourcePath}/subscriptions/${subscriptionId}/resourceGroups/${resourceGroup}/resources?` +
|
||||
`$filter=resourceType eq '${metricDefinition}'&` +
|
||||
`$filter=resourceType eq '${validMetricDefinition}'&` +
|
||||
`api-version=${this.listByResourceGroupApiVersion}`;
|
||||
if (skipToken) {
|
||||
url += `&$skiptoken=${skipToken}`;
|
||||
@@ -247,9 +250,27 @@ export default class AzureMonitorDatasource extends DataSourceWithBackend<AzureM
|
||||
this.apiPreviewVersion,
|
||||
this.replaceTemplateVariables(query)
|
||||
);
|
||||
return this.getResource(url).then((result: AzureMonitorMetricNamespacesResponse) => {
|
||||
return ResponseParser.parseResponseValues(result, 'name', 'properties.metricNamespaceName');
|
||||
});
|
||||
return this.getResource(url)
|
||||
.then((result: AzureMonitorMetricNamespacesResponse) => {
|
||||
return ResponseParser.parseResponseValues(result, 'name', 'properties.metricNamespaceName');
|
||||
})
|
||||
.then((result) => {
|
||||
if (url.includes('Microsoft.Storage/storageAccounts')) {
|
||||
const storageNamespaces = [
|
||||
'Microsoft.Storage/storageAccounts',
|
||||
'Microsoft.Storage/storageAccounts/blobServices',
|
||||
'Microsoft.Storage/storageAccounts/fileServices',
|
||||
'Microsoft.Storage/storageAccounts/tableServices',
|
||||
'Microsoft.Storage/storageAccounts/queueServices',
|
||||
];
|
||||
for (const namespace of storageNamespaces) {
|
||||
if (!find(result, ['value', namespace.toLowerCase()])) {
|
||||
result.push({ value: namespace, text: namespace });
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
getMetricNames(query: GetMetricNamesQuery) {
|
||||
|
||||
+4
-2
@@ -31,9 +31,11 @@ const MetricNamespaceField: React.FC<MetricNamespaceFieldProps> = ({
|
||||
);
|
||||
|
||||
const options = useMemo(() => [...metricNamespaces, variableOptionGroup], [metricNamespaces, variableOptionGroup]);
|
||||
const optionValues = metricNamespaces.map((m) => m.value).concat(variableOptionGroup.options.map((p) => p.value));
|
||||
const optionValues = metricNamespaces
|
||||
.map((m) => m.value.toLowerCase())
|
||||
.concat(variableOptionGroup.options.map((p) => p.value));
|
||||
const value = query.azureMonitor?.metricNamespace;
|
||||
if (value && !optionValues.includes(value)) {
|
||||
if (value && !optionValues.includes(value.toLowerCase())) {
|
||||
options.push({ label: value, value });
|
||||
}
|
||||
|
||||
|
||||
+18
@@ -109,6 +109,23 @@ export function setMetricNamespace(query: AzureMonitorQuery, metricNamespace: st
|
||||
return query;
|
||||
}
|
||||
|
||||
let resourceUri = query.azureMonitor?.resourceUri;
|
||||
|
||||
// Storage Account URIs need to be handled differently due to the additional storage services (blob/queue/table/file).
|
||||
// When one of these namespaces is selected it does not form a part of the URI for the storage account and so must be appended.
|
||||
// The 'default' path must also be appended. Without these two paths any API call will fail.
|
||||
if (resourceUri && metricNamespace?.includes('Microsoft.Storage/storageAccounts')) {
|
||||
const splitUri = resourceUri.split('/');
|
||||
const accountNameIndex = splitUri.findIndex((item) => item === 'storageAccounts') + 1;
|
||||
const baseUri = splitUri.slice(0, accountNameIndex + 1).join('/');
|
||||
if (metricNamespace === 'Microsoft.Storage/storageAccounts') {
|
||||
resourceUri = baseUri;
|
||||
} else {
|
||||
const subNamespace = metricNamespace.split('/')[2];
|
||||
resourceUri = `${baseUri}/${subNamespace}/default`;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
...query,
|
||||
azureMonitor: {
|
||||
@@ -118,6 +135,7 @@ export function setMetricNamespace(query: AzureMonitorQuery, metricNamespace: st
|
||||
aggregation: undefined,
|
||||
timeGrain: '',
|
||||
dimensionFilters: [],
|
||||
resourceUri,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
+1
-1
@@ -144,7 +144,7 @@ function formatOptions(
|
||||
const options = rawResults.map(toOption);
|
||||
|
||||
// account for custom values that might have been set in json file like ones crafted with a template variable (ex: "cloud-datasource-resource-$Environment")
|
||||
if (selectedValue && !options.find((option) => option.value === selectedValue)) {
|
||||
if (selectedValue && !options.find((option) => option.value === selectedValue.toLowerCase())) {
|
||||
options.push({ label: selectedValue, value: selectedValue });
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user