mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
AzureMonitor: Automate location retrieval (#59602)
* Automate location retrieval - Add function to retrieve provider information - Add function to retrieve subscription locations - Add parsers for each function - Add types - Update resourcePickerData with new functions - Remove old location metadata file * Improve types - Add types for responses - Use correct name parameter - Update response parser (parseProvider unnecessary) * Fix tests - Add necessary mocks * Fix logic and ensure maps are consistent * Add tests * Review * Lint issue
This commit is contained in:
parent
020b9960c8
commit
c52d4e2a64
@ -24,6 +24,17 @@ export default function createMockDatasource(overrides?: DeepPartial<Datasource>
|
||||
supportedTimeGrains: [],
|
||||
dimensions: [],
|
||||
}),
|
||||
getProvider: jest.fn().mockResolvedValueOnce({
|
||||
namespace: 'Microsoft.Insights',
|
||||
resourceTypes: [
|
||||
{ resourceType: 'logs', locations: ['North Europe'], apiVersions: ['2022-11-11'], capabilities: '' },
|
||||
],
|
||||
}),
|
||||
getLocations: jest
|
||||
.fn()
|
||||
.mockResolvedValueOnce(
|
||||
new Map([['northeurope', { displayName: 'North Europe', name: 'northeurope', supportsLogs: false }]])
|
||||
),
|
||||
},
|
||||
|
||||
getAzureLogAnalyticsWorkspaces: jest.fn().mockResolvedValueOnce([]),
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { ResourceRowGroup, ResourceRowType } from '../components/ResourcePicker/types';
|
||||
import { AzureMonitorLocations } from '../types';
|
||||
|
||||
export const createMockSubscriptions = (): ResourceRowGroup => [
|
||||
{
|
||||
@ -117,3 +118,6 @@ export const mockSearchResults = (): ResourceRowGroup => [
|
||||
location: 'northeurope',
|
||||
},
|
||||
];
|
||||
|
||||
export const mockGetValidLocations = (): Map<string, AzureMonitorLocations> =>
|
||||
new Map([['northeurope', { displayName: 'North Europe', name: 'northeurope', supportsLogs: true }]]);
|
||||
|
@ -1,3 +1,2 @@
|
||||
export * from './locations';
|
||||
export * from './resourceTypes';
|
||||
export * from './logsResourceTypes';
|
||||
|
@ -1,359 +0,0 @@
|
||||
// Unfortunately this list is manually maintained as there's no (nice) automated way to get
|
||||
// data from Azure.
|
||||
|
||||
export const locationMetadata = [
|
||||
{
|
||||
location: 'eastus',
|
||||
displayName: 'East US',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'eastus2',
|
||||
displayName: 'East US 2',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'southcentralus',
|
||||
displayName: 'South Central US',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'westus2',
|
||||
displayName: 'West US 2',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'westus3',
|
||||
displayName: 'West US 3',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'australiaeast',
|
||||
displayName: 'Australia East',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'southeastasia',
|
||||
displayName: 'Southeast Asia',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'northeurope',
|
||||
displayName: 'North Europe',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'uksouth',
|
||||
displayName: 'UK South',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'westeurope',
|
||||
displayName: 'West Europe',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'centralus',
|
||||
displayName: 'Central US',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'northcentralus',
|
||||
displayName: 'North Central US',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'westus',
|
||||
displayName: 'West US',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'southafricanorth',
|
||||
displayName: 'South Africa North',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'centralindia',
|
||||
displayName: 'Central India',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'eastasia',
|
||||
displayName: 'East Asia',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'japaneast',
|
||||
displayName: 'Japan East',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'jioindiawest',
|
||||
displayName: 'Jio India West',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'koreacentral',
|
||||
displayName: 'Korea Central',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'canadacentral',
|
||||
displayName: 'Canada Central',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'francecentral',
|
||||
displayName: 'France Central',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'germanywestcentral',
|
||||
displayName: 'Germany West Central',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'norwayeast',
|
||||
displayName: 'Norway East',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'switzerlandnorth',
|
||||
displayName: 'Switzerland North',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'uaenorth',
|
||||
displayName: 'UAE North',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'brazilsouth',
|
||||
displayName: 'Brazil South',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'centralusstage',
|
||||
displayName: 'Central US (Stage)',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'eastusstage',
|
||||
displayName: 'East US (Stage)',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'eastus2stage',
|
||||
displayName: 'East US 2 (Stage)',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'northcentralusstage',
|
||||
displayName: 'North Central US (Stage)',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'southcentralusstage',
|
||||
displayName: 'South Central US (Stage)',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'westusstage',
|
||||
displayName: 'West US (Stage)',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'westus2stage',
|
||||
displayName: 'West US 2 (Stage)',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'asia',
|
||||
displayName: 'Asia',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'asiapacific',
|
||||
displayName: 'Asia Pacific',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'australia',
|
||||
displayName: 'Australia',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'brazil',
|
||||
displayName: 'Brazil',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'canada',
|
||||
displayName: 'Canada',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'europe',
|
||||
displayName: 'Europe',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'global',
|
||||
displayName: 'Global',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'india',
|
||||
displayName: 'India',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'japan',
|
||||
displayName: 'Japan',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'uk',
|
||||
displayName: 'United Kingdom',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'unitedstates',
|
||||
displayName: 'United States',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'eastasiastage',
|
||||
displayName: 'East Asia (Stage)',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'southeastasiastage',
|
||||
displayName: 'Southeast Asia (Stage)',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'westcentralus',
|
||||
displayName: 'West Central US',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'southafricawest',
|
||||
displayName: 'South Africa West',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'australiacentral',
|
||||
displayName: 'Australia Central',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'australiacentral2',
|
||||
displayName: 'Australia Central 2',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'australiasoutheast',
|
||||
displayName: 'Australia Southeast',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'japanwest',
|
||||
displayName: 'Japan West',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'koreasouth',
|
||||
displayName: 'Korea South',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'southindia',
|
||||
displayName: 'South India',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'westindia',
|
||||
displayName: 'West India',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'canadaeast',
|
||||
displayName: 'Canada East',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'francesouth',
|
||||
displayName: 'France South',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'germanynorth',
|
||||
displayName: 'Germany North',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'norwaywest',
|
||||
displayName: 'Norway West',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'switzerlandwest',
|
||||
displayName: 'Switzerland West',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'ukwest',
|
||||
displayName: 'UK West',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'uaecentral',
|
||||
displayName: 'UAE Central',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'brazilsoutheast',
|
||||
displayName: 'Brazil Southeast',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'chinaeast',
|
||||
displayName: 'China Eest',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'chinaeast2',
|
||||
displayName: 'China Eest 2',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'chinanorth',
|
||||
displayName: 'China North',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'chinanorth2',
|
||||
displayName: 'China North 2',
|
||||
supportsLogs: true,
|
||||
},
|
||||
{
|
||||
location: 'chinanorth3',
|
||||
displayName: 'China North 3',
|
||||
supportsLogs: true,
|
||||
},
|
||||
];
|
||||
|
||||
export const logsSupportedLocationsKusto = locationMetadata
|
||||
.filter((v) => v.supportsLogs)
|
||||
.map((v) => `"${v.location}"`)
|
||||
.join(',');
|
||||
|
||||
// Object, keyed by location ID
|
||||
export const locationDisplayNames: Record<string, string> = locationMetadata.reduce(
|
||||
(acc, location) => ({
|
||||
...acc,
|
||||
[location.location]: location.displayName,
|
||||
}),
|
||||
{}
|
||||
);
|
@ -7,7 +7,7 @@ import createMockQuery from '../__mocks__/query';
|
||||
import { createTemplateVariables } from '../__mocks__/utils';
|
||||
import { singleVariable, subscriptionsVariable } from '../__mocks__/variables';
|
||||
import AzureMonitorDatasource from '../datasource';
|
||||
import { AzureDataSourceJsonData, AzureQueryType } from '../types';
|
||||
import { AzureDataSourceJsonData, AzureMonitorLocationsResponse, AzureQueryType } from '../types';
|
||||
|
||||
const templateSrv = new TemplateSrv();
|
||||
|
||||
@ -351,6 +351,89 @@ describe('AzureMonitorDatasource', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('When performing getLocations', () => {
|
||||
const sub1Response: AzureMonitorLocationsResponse = {
|
||||
value: [
|
||||
{
|
||||
id: '/subscriptions/mock-subscription-id-1/locations/northeurope',
|
||||
name: 'northeurope',
|
||||
displayName: 'North Europe',
|
||||
regionalDisplayName: '(Europe) North Europe',
|
||||
metadata: {
|
||||
regionType: 'Physical',
|
||||
regionCategory: 'Recommended',
|
||||
geographyGroup: 'EU',
|
||||
longitude: '-0',
|
||||
latitude: '0',
|
||||
physicalLocation: 'Europe',
|
||||
pairedRegion: [],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const sub2Response: AzureMonitorLocationsResponse = {
|
||||
value: [
|
||||
{
|
||||
id: '/subscriptions/mock-subscription-id-2/locations/eastus2',
|
||||
name: 'eastus2',
|
||||
displayName: 'East US 2',
|
||||
regionalDisplayName: '(US) East US 2',
|
||||
metadata: {
|
||||
regionType: 'Physical',
|
||||
regionCategory: 'Recommended',
|
||||
geographyGroup: 'US',
|
||||
longitude: '-0',
|
||||
latitude: '0',
|
||||
physicalLocation: 'US',
|
||||
pairedRegion: [],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
ctx.ds.azureMonitorDatasource.getResource = jest.fn().mockImplementation((path: string) => {
|
||||
const expectedPaths = [1, 2].map(
|
||||
(sub) => `azuremonitor/subscriptions/mock-subscription-id-${sub}/locations?api-version=2020-01-01`
|
||||
);
|
||||
expect(expectedPaths).toContain(path);
|
||||
if (path.includes('mock-subscription-id-1')) {
|
||||
return Promise.resolve(sub1Response);
|
||||
} else {
|
||||
return Promise.resolve(sub2Response);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should return a locations map', async () => {
|
||||
const result = await ctx.ds.azureMonitorDatasource.getLocations(['mock-subscription-id-1']);
|
||||
|
||||
expect(result.size).toBe(1);
|
||||
expect(result.has('northeurope')).toBe(true);
|
||||
expect(result.get('northeurope')?.name).toBe('northeurope');
|
||||
expect(result.get('northeurope')?.displayName).toBe('North Europe');
|
||||
expect(result.get('northeurope')?.supportsLogs).toBe(undefined);
|
||||
});
|
||||
|
||||
it('should return a locations map with locations deduped', async () => {
|
||||
const result = await ctx.ds.azureMonitorDatasource.getLocations([
|
||||
'mock-subscription-id-1',
|
||||
'mock-subscription-id-2',
|
||||
]);
|
||||
|
||||
expect(result.size).toBe(2);
|
||||
expect(result.has('northeurope')).toBe(true);
|
||||
expect(result.get('northeurope')?.name).toBe('northeurope');
|
||||
expect(result.get('northeurope')?.displayName).toBe('North Europe');
|
||||
expect(result.get('northeurope')?.supportsLogs).toBe(undefined);
|
||||
expect(result.has('eastus2')).toBe(true);
|
||||
expect(result.get('eastus2')?.name).toBe('eastus2');
|
||||
expect(result.get('eastus2')?.displayName).toBe('East US 2');
|
||||
expect(result.get('eastus2')?.supportsLogs).toBe(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Legacy Azure Monitor Query Object data fetchers', () => {
|
||||
describe('When performing getSubscriptions', () => {
|
||||
const response = {
|
||||
|
@ -19,6 +19,9 @@ import {
|
||||
GetMetricNamesQuery,
|
||||
GetMetricMetadataQuery,
|
||||
AzureMetricQuery,
|
||||
AzureMonitorLocations,
|
||||
AzureMonitorProvidersResponse,
|
||||
AzureMonitorLocationsResponse,
|
||||
} from '../types';
|
||||
import { routeNames } from '../utils/common';
|
||||
import migrateQuery from '../utils/migrateQuery';
|
||||
@ -36,6 +39,8 @@ export default class AzureMonitorDatasource extends DataSourceWithBackend<AzureM
|
||||
apiVersion = '2018-01-01';
|
||||
apiPreviewVersion = '2017-12-01-preview';
|
||||
listByResourceGroupApiVersion = '2021-04-01';
|
||||
providerApiVersion = '2021-04-01';
|
||||
locationsApiVersion = '2020-01-01';
|
||||
defaultSubscriptionId?: string;
|
||||
resourcePath: string;
|
||||
azurePortalUrl: string;
|
||||
@ -296,4 +301,26 @@ export default class AzureMonitorDatasource extends DataSourceWithBackend<AzureM
|
||||
|
||||
return workingQuery;
|
||||
}
|
||||
|
||||
async getProvider(providerName: string) {
|
||||
return await this.getResource<AzureMonitorProvidersResponse>(
|
||||
`${routeNames.azureMonitor}/providers/${providerName}?api-version=${this.providerApiVersion}`
|
||||
);
|
||||
}
|
||||
|
||||
async getLocations(subscriptions: string[]) {
|
||||
const locationMap = new Map<string, AzureMonitorLocations>();
|
||||
for (const subscription of subscriptions) {
|
||||
const subLocations = ResponseParser.parseLocations(
|
||||
await this.getResource<AzureMonitorLocationsResponse>(
|
||||
`${routeNames.azureMonitor}/subscriptions/${subscription}/locations?api-version=${this.locationsApiVersion}`
|
||||
)
|
||||
);
|
||||
for (const location of subLocations) {
|
||||
locationMap.set(location.name, location);
|
||||
}
|
||||
}
|
||||
|
||||
return locationMap;
|
||||
}
|
||||
}
|
||||
|
@ -3,9 +3,11 @@ import { find, get } from 'lodash';
|
||||
import TimeGrainConverter from '../time_grain_converter';
|
||||
import {
|
||||
AzureMonitorLocalizedValue,
|
||||
AzureMonitorLocations,
|
||||
AzureMonitorMetricAvailabilityMetadata,
|
||||
AzureMonitorMetricsMetadataResponse,
|
||||
AzureMonitorOption,
|
||||
AzureMonitorLocationsResponse,
|
||||
} from '../types';
|
||||
export default class ResponseParser {
|
||||
static parseResponseValues(
|
||||
@ -170,4 +172,18 @@ export default class ResponseParser {
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
static parseLocations(result: AzureMonitorLocationsResponse) {
|
||||
const locations: AzureMonitorLocations[] = [];
|
||||
|
||||
if (!result) {
|
||||
return locations;
|
||||
}
|
||||
|
||||
for (const location of result.value) {
|
||||
locations.push({ name: location.name, displayName: location.displayName, supportsLogs: undefined });
|
||||
}
|
||||
|
||||
return locations;
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import createMockQuery from '../../__mocks__/query';
|
||||
import {
|
||||
createMockResourceGroupsBySubscription,
|
||||
createMockSubscriptions,
|
||||
mockGetValidLocations,
|
||||
mockResourcesByResourceGroup,
|
||||
} from '../../__mocks__/resourcePickerRows';
|
||||
import ResourcePickerData from '../../resourcePicker/resourcePickerData';
|
||||
@ -44,7 +45,7 @@ export function createMockResourcePickerData() {
|
||||
mockResourcePicker.getResourcesForResourceGroup = jest.fn().mockResolvedValue(mockResourcesByResourceGroup());
|
||||
mockResourcePicker.getResourceURIFromWorkspace = jest.fn().mockReturnValue('');
|
||||
mockResourcePicker.getResourceURIDisplayProperties = jest.fn().mockResolvedValue({});
|
||||
|
||||
mockResourcePicker.getLogsLocations = jest.fn().mockResolvedValue(mockGetValidLocations());
|
||||
return mockResourcePicker;
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@ import {
|
||||
} from '../__mocks__/argResourcePickerResponse';
|
||||
import createMockDatasource from '../__mocks__/datasource';
|
||||
import { createMockInstanceSetttings } from '../__mocks__/instanceSettings';
|
||||
import { mockGetValidLocations } from '../__mocks__/resourcePickerRows';
|
||||
import { AzureGraphResponse } from '../types';
|
||||
|
||||
import ResourcePickerData from './resourcePickerData';
|
||||
@ -21,9 +22,13 @@ const createResourcePickerData = (responses: AzureGraphResponse[]) => {
|
||||
postResource.mockResolvedValueOnce(res);
|
||||
});
|
||||
resourcePickerData.postResource = postResource;
|
||||
|
||||
return { resourcePickerData, postResource };
|
||||
const logLocationsMap = mockGetValidLocations();
|
||||
const getLogsLocations = jest.spyOn(resourcePickerData, 'getLogsLocations').mockResolvedValue(logLocationsMap);
|
||||
resourcePickerData.logLocationsMap = logLocationsMap;
|
||||
resourcePickerData.logLocations = Array.from(logLocationsMap.values()).map((location) => `"${location.name}"`);
|
||||
return { resourcePickerData, postResource, mockDatasource, getValidLocations: getLogsLocations };
|
||||
};
|
||||
|
||||
describe('AzureMonitor resourcePickerData', () => {
|
||||
describe('getSubscriptions', () => {
|
||||
it('makes 1 call to ARG with the correct path and query arguments', async () => {
|
||||
@ -375,4 +380,35 @@ describe('AzureMonitor resourcePickerData', () => {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('getValidLocations', () => {
|
||||
it('returns a locations map', async () => {
|
||||
const { resourcePickerData, getValidLocations } = createResourcePickerData([createMockARGSubscriptionResponse()]);
|
||||
getValidLocations.mockRestore();
|
||||
const subscriptions = await resourcePickerData.getSubscriptions();
|
||||
const locations = await resourcePickerData.getLogsLocations(subscriptions);
|
||||
|
||||
expect(locations.size).toBe(1);
|
||||
expect(locations.has('northeurope')).toBe(true);
|
||||
expect(locations.get('northeurope')?.name).toBe('northeurope');
|
||||
expect(locations.get('northeurope')?.displayName).toBe('North Europe');
|
||||
expect(locations.get('northeurope')?.supportsLogs).toBe(true);
|
||||
});
|
||||
|
||||
it('returns the raw locations map if provider is undefined', async () => {
|
||||
const { resourcePickerData, mockDatasource, getValidLocations } = createResourcePickerData([
|
||||
createMockARGSubscriptionResponse(),
|
||||
]);
|
||||
getValidLocations.mockRestore();
|
||||
mockDatasource.azureMonitorDatasource.getProvider = jest.fn().mockResolvedValue(undefined);
|
||||
const subscriptions = await resourcePickerData.getSubscriptions();
|
||||
const locations = await resourcePickerData.getLogsLocations(subscriptions);
|
||||
|
||||
expect(locations.size).toBe(1);
|
||||
expect(locations.has('northeurope')).toBe(true);
|
||||
expect(locations.get('northeurope')?.name).toBe('northeurope');
|
||||
expect(locations.get('northeurope')?.displayName).toBe('North Europe');
|
||||
expect(locations.get('northeurope')?.supportsLogs).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -3,12 +3,7 @@ import { uniq } from 'lodash';
|
||||
import { DataSourceInstanceSettings } from '@grafana/data';
|
||||
import { DataSourceWithBackend } from '@grafana/runtime';
|
||||
|
||||
import {
|
||||
locationDisplayNames,
|
||||
logsSupportedLocationsKusto,
|
||||
logsResourceTypes,
|
||||
resourceTypeDisplayNames,
|
||||
} from '../azureMetadata';
|
||||
import { logsResourceTypes, resourceTypeDisplayNames } from '../azureMetadata';
|
||||
import AzureMonitorDatasource from '../azure_monitor/azure_monitor_datasource';
|
||||
import { ResourceRow, ResourceRowGroup, ResourceRowType } from '../components/ResourcePicker/types';
|
||||
import { addResources, parseResourceDetails, parseResourceURI } from '../components/ResourcePicker/utils';
|
||||
@ -16,6 +11,7 @@ import {
|
||||
AzureDataSourceJsonData,
|
||||
AzureGraphResponse,
|
||||
AzureMetricResource,
|
||||
AzureMonitorLocations,
|
||||
AzureMonitorQuery,
|
||||
AzureResourceGraphOptions,
|
||||
AzureResourceSummaryItem,
|
||||
@ -36,6 +32,8 @@ export default class ResourcePickerData extends DataSourceWithBackend<AzureMonit
|
||||
resultLimit = 200;
|
||||
azureMonitorDatasource;
|
||||
supportedMetricNamespaces = '';
|
||||
logLocationsMap: Map<string, AzureMonitorLocations> = new Map();
|
||||
logLocations: string[] = [];
|
||||
|
||||
constructor(
|
||||
instanceSettings: DataSourceInstanceSettings<AzureDataSourceJsonData>,
|
||||
@ -51,6 +49,12 @@ export default class ResourcePickerData extends DataSourceWithBackend<AzureMonit
|
||||
currentSelection?: AzureMetricResource
|
||||
): Promise<ResourceRowGroup> {
|
||||
const subscriptions = await this.getSubscriptions();
|
||||
|
||||
if (this.logLocationsMap.size === 0) {
|
||||
this.logLocationsMap = await this.getLogsLocations(subscriptions);
|
||||
this.logLocations = Array.from(this.logLocationsMap.values()).map((location) => `"${location.name}"`);
|
||||
}
|
||||
|
||||
if (!currentSelection) {
|
||||
return subscriptions;
|
||||
}
|
||||
@ -119,7 +123,7 @@ export default class ResourcePickerData extends DataSourceWithBackend<AzureMonit
|
||||
resourceGroupName: item.resourceGroup,
|
||||
type,
|
||||
typeLabel: resourceTypeDisplayNames[item.type] || item.type,
|
||||
location: locationDisplayNames[item.location] || item.location,
|
||||
location: this.logLocationsMap.get(item.location)?.displayName || item.location,
|
||||
};
|
||||
});
|
||||
};
|
||||
@ -222,10 +226,13 @@ export default class ResourcePickerData extends DataSourceWithBackend<AzureMonit
|
||||
resourceGroupId: string,
|
||||
type: ResourcePickerQueryType
|
||||
): Promise<ResourceRowGroup> {
|
||||
if (!this.logLocations) {
|
||||
return [];
|
||||
}
|
||||
const { data: response } = await this.makeResourceGraphRequest<RawAzureResourceItem[]>(`
|
||||
resources
|
||||
| where id hasprefix "${resourceGroupId}"
|
||||
${await this.filterByType(type)} and location in (${logsSupportedLocationsKusto})
|
||||
${await this.filterByType(type)} and location in (${this.logLocations})
|
||||
`);
|
||||
|
||||
return response.map((item) => {
|
||||
@ -240,7 +247,7 @@ export default class ResourcePickerData extends DataSourceWithBackend<AzureMonit
|
||||
resourceGroupName: item.resourceGroup,
|
||||
type: ResourceRowType.Resource,
|
||||
typeLabel: resourceTypeDisplayNames[item.type] || item.type,
|
||||
location: locationDisplayNames[item.location] || item.location,
|
||||
location: this.logLocationsMap.get(item.location)?.displayName || item.location,
|
||||
};
|
||||
});
|
||||
}
|
||||
@ -359,4 +366,34 @@ export default class ResourcePickerData extends DataSourceWithBackend<AzureMonit
|
||||
}
|
||||
this.supportedMetricNamespaces = uniq(supportedMetricNamespaces).join(',');
|
||||
}
|
||||
|
||||
async getLogsLocations(subscriptions: ResourceRowGroup): Promise<Map<string, AzureMonitorLocations>> {
|
||||
const subscriptionIds = subscriptions.map((sub) => sub.id);
|
||||
const locations = await this.azureMonitorDatasource.getLocations(subscriptionIds);
|
||||
const insightsProvider = await this.azureMonitorDatasource.getProvider('Microsoft.Insights');
|
||||
const logsProvider = insightsProvider?.resourceTypes.find((provider) => provider.resourceType === 'logs');
|
||||
|
||||
if (!logsProvider) {
|
||||
return locations;
|
||||
}
|
||||
|
||||
const logsLocations = logsProvider.locations.map((location) => ({
|
||||
displayName: location,
|
||||
name: '',
|
||||
supportsLogs: true,
|
||||
}));
|
||||
|
||||
const logLocationsMap = new Map<string, AzureMonitorLocations>();
|
||||
|
||||
for (const logLocation of logsLocations) {
|
||||
const name =
|
||||
Array.from(locations.values()).find((location) => logLocation.displayName === location.displayName)?.name || '';
|
||||
|
||||
if (name !== '') {
|
||||
logLocationsMap.set(name, { ...logLocation, name });
|
||||
}
|
||||
}
|
||||
|
||||
return logLocationsMap;
|
||||
}
|
||||
}
|
||||
|
@ -258,3 +258,48 @@ export interface LegacyAzureGetMetricMetadataQuery {
|
||||
customNamespace?: string;
|
||||
metricName: string;
|
||||
}
|
||||
|
||||
export interface AzureMonitorLocations {
|
||||
displayName: string;
|
||||
name: string;
|
||||
supportsLogs?: boolean;
|
||||
}
|
||||
|
||||
export interface AzureMonitorProvidersResponse {
|
||||
namespace: string;
|
||||
resourceTypes: ProviderResourceType[];
|
||||
}
|
||||
|
||||
export interface ProviderResourceType {
|
||||
resourceType: string;
|
||||
locations: string[];
|
||||
apiVersions: string[];
|
||||
capabilities: string;
|
||||
}
|
||||
|
||||
export interface AzureMonitorLocationsResponse {
|
||||
value: Location[];
|
||||
}
|
||||
|
||||
interface Location {
|
||||
id: string;
|
||||
name: string;
|
||||
displayName: string;
|
||||
regionalDisplayName: string;
|
||||
metadata: LocationMetadata;
|
||||
}
|
||||
|
||||
interface LocationMetadata {
|
||||
regionType: string;
|
||||
regionCategory: string;
|
||||
geographyGroup: string;
|
||||
longitude: string;
|
||||
latitude: string;
|
||||
physicalLocation: string;
|
||||
pairedRegion: LocationPairedRegion[];
|
||||
}
|
||||
|
||||
interface LocationPairedRegion {
|
||||
name: string;
|
||||
id: string;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user