mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
CloudWatch: Add account support to variable queries (#63822)
Co-authored-by: Erik Sundell <erik.sundell87@gmail.com>
This commit is contained in:
parent
33f66e6350
commit
59ac0a03fe
@ -6,9 +6,10 @@ import { InlineField } from '@grafana/ui';
|
||||
|
||||
import { Dimensions } from '..';
|
||||
import { CloudWatchDatasource } from '../../datasource';
|
||||
import { useDimensionKeys, useMetrics, useNamespaces, useRegions } from '../../hooks';
|
||||
import { useAccountOptions, useDimensionKeys, useMetrics, useNamespaces, useRegions } from '../../hooks';
|
||||
import { migrateVariableQuery } from '../../migrations/variableQueryMigrations';
|
||||
import { CloudWatchJsonData, CloudWatchQuery, VariableQuery, VariableQueryType } from '../../types';
|
||||
import { ALL_ACCOUNTS_OPTION } from '../Account';
|
||||
|
||||
import { MultiFilter } from './MultiFilter';
|
||||
import { VariableQueryField } from './VariableQueryField';
|
||||
@ -41,11 +42,13 @@ export const VariableQueryEditor = ({ query, datasource, onChange }: Props) => {
|
||||
const metrics = useMetrics(datasource, { region, namespace });
|
||||
const dimensionKeys = useDimensionKeys(datasource, { region, namespace, metricName });
|
||||
const keysForDimensionFilter = useDimensionKeys(datasource, { region, namespace, metricName, dimensionFilters });
|
||||
const accountState = useAccountOptions(datasource.resources, query.region);
|
||||
|
||||
const onRegionChange = async (region: string) => {
|
||||
const validatedQuery = await sanitizeQuery({
|
||||
...parsedQuery,
|
||||
region,
|
||||
accountId: undefined,
|
||||
});
|
||||
onQueryChange(validatedQuery);
|
||||
};
|
||||
@ -98,6 +101,12 @@ export const VariableQueryEditor = ({ query, datasource, onChange }: Props) => {
|
||||
VariableQueryType.LogGroups,
|
||||
VariableQueryType.Accounts,
|
||||
].includes(parsedQuery.queryType);
|
||||
const hasAccountIDField = [
|
||||
VariableQueryType.Metrics,
|
||||
VariableQueryType.DimensionKeys,
|
||||
VariableQueryType.DimensionValues,
|
||||
VariableQueryType.LogGroups,
|
||||
].includes(parsedQuery.queryType);
|
||||
const hasNamespaceField = [
|
||||
VariableQueryType.Metrics,
|
||||
VariableQueryType.DimensionKeys,
|
||||
@ -108,7 +117,9 @@ export const VariableQueryEditor = ({ query, datasource, onChange }: Props) => {
|
||||
<VariableQueryField
|
||||
value={parsedQuery.queryType}
|
||||
options={queryTypes}
|
||||
onChange={(value: VariableQueryType) => onQueryChange({ ...parsedQuery, queryType: value })}
|
||||
onChange={(value: VariableQueryType) =>
|
||||
onQueryChange({ ...parsedQuery, queryType: value, accountId: undefined })
|
||||
}
|
||||
label="Query type"
|
||||
inputId={`variable-query-type-${query.refId}`}
|
||||
/>
|
||||
@ -122,6 +133,18 @@ export const VariableQueryEditor = ({ query, datasource, onChange }: Props) => {
|
||||
inputId={`variable-query-region-${query.refId}`}
|
||||
/>
|
||||
)}
|
||||
{hasAccountIDField &&
|
||||
accountState.value &&
|
||||
accountState.value?.length > 0 &&
|
||||
config.featureToggles.cloudWatchCrossAccountQuerying && (
|
||||
<VariableQueryField
|
||||
label="Account"
|
||||
value={query.accountId ?? null}
|
||||
onChange={(accountId?: string) => onQueryChange({ ...parsedQuery, accountId })}
|
||||
options={[ALL_ACCOUNTS_OPTION, ...accountState?.value]}
|
||||
allowCustomValue={false}
|
||||
/>
|
||||
)}
|
||||
{hasNamespaceField && (
|
||||
<VariableQueryField
|
||||
value={namespace}
|
||||
|
@ -37,7 +37,7 @@ export class ResourcesAPI extends CloudWatchRequest {
|
||||
|
||||
getAccounts({ region }: ResourceRequest): Promise<Account[]> {
|
||||
return this.memoizedGetRequest<Array<ResourceResponse<Account>>>('accounts', {
|
||||
region: this.templateSrv.replace(region),
|
||||
region: this.templateSrv.replace(this.getActualRegion(region)),
|
||||
}).then((accounts) => accounts.map((a) => a.value));
|
||||
}
|
||||
|
||||
|
@ -39,6 +39,7 @@ export interface DescribeLogGroupsRequest extends ResourceRequest {
|
||||
logGroupPattern?: string;
|
||||
limit?: number;
|
||||
listAllLogGroups?: boolean;
|
||||
accountId?: string;
|
||||
}
|
||||
|
||||
export interface Account {
|
||||
|
@ -304,6 +304,7 @@ export interface VariableQuery extends DataQuery {
|
||||
resourceType: string;
|
||||
tags?: MultiFilters;
|
||||
logGroupPrefix?: string;
|
||||
accountId?: string;
|
||||
}
|
||||
|
||||
export interface LegacyAnnotationQuery extends MetricStat, DataQuery {
|
||||
|
@ -23,9 +23,9 @@ const defaultQuery: VariableQuery = {
|
||||
const mock = setupMockedDataSource({ variables: [labelsVariable, dimensionVariable, fieldsVariable] });
|
||||
mock.datasource.resources.getRegions = jest.fn().mockResolvedValue([{ label: 'a', value: 'a' }]);
|
||||
mock.datasource.resources.getNamespaces = jest.fn().mockResolvedValue([{ label: 'b', value: 'b' }]);
|
||||
mock.datasource.resources.getMetrics = jest.fn().mockResolvedValue([{ label: 'c', value: 'c' }]);
|
||||
mock.datasource.resources.getDimensionKeys = jest.fn().mockResolvedValue([{ label: 'd', value: 'd' }]);
|
||||
mock.datasource.resources.getAccounts = jest.fn().mockResolvedValue([]);
|
||||
const getMetrics = jest.fn().mockResolvedValue([{ label: 'c', value: 'c' }]);
|
||||
const getDimensionKeys = jest.fn().mockResolvedValue([{ label: 'd', value: 'd' }]);
|
||||
const getDimensionValues = jest.fn().mockResolvedValue([{ label: 'e', value: 'e' }]);
|
||||
const getEbsVolumeIds = jest.fn().mockResolvedValue([{ label: 'f', value: 'f' }]);
|
||||
const getEc2InstanceAttribute = jest.fn().mockResolvedValue([{ label: 'g', value: 'g' }]);
|
||||
@ -48,12 +48,26 @@ describe('variables', () => {
|
||||
});
|
||||
|
||||
it('should run metrics', async () => {
|
||||
const result = await variables.execute({ ...defaultQuery, queryType: VariableQueryType.Metrics });
|
||||
mock.datasource.resources.getMetrics = getMetrics;
|
||||
const query = { ...defaultQuery, queryType: VariableQueryType.Metrics, accountId: '123' };
|
||||
const result = await variables.execute(query);
|
||||
expect(getMetrics).toBeCalledWith({
|
||||
region: query.region,
|
||||
namespace: 'foo',
|
||||
accountId: query.accountId,
|
||||
});
|
||||
expect(result).toEqual([{ text: 'c', value: 'c', expandable: true }]);
|
||||
});
|
||||
|
||||
it('should run dimension keys', async () => {
|
||||
const result = await variables.execute({ ...defaultQuery, queryType: VariableQueryType.DimensionKeys });
|
||||
mock.datasource.resources.getDimensionKeys = getDimensionKeys;
|
||||
const query = { ...defaultQuery, queryType: VariableQueryType.DimensionKeys, accountId: '123' };
|
||||
const result = await variables.execute(query);
|
||||
expect(getDimensionKeys).toBeCalledWith({
|
||||
region: query.region,
|
||||
namespace: query.namespace,
|
||||
accountId: query.accountId,
|
||||
});
|
||||
expect(result).toEqual([{ text: 'd', value: 'd', expandable: true }]);
|
||||
});
|
||||
|
||||
@ -86,6 +100,7 @@ describe('variables', () => {
|
||||
metricName: 'abc',
|
||||
dimensionKey: 'efg',
|
||||
dimensionFilters: { a: 'b' },
|
||||
accountId: '123',
|
||||
};
|
||||
beforeEach(() => {
|
||||
mock.datasource.resources.getDimensionValues = getDimensionValues;
|
||||
@ -111,6 +126,7 @@ describe('variables', () => {
|
||||
metricName: query.metricName,
|
||||
dimensionKey: query.dimensionKey,
|
||||
dimensionFilters: query.dimensionFilters,
|
||||
accountId: query.accountId,
|
||||
});
|
||||
expect(result).toEqual([{ text: 'e', value: 'e', expandable: true }]);
|
||||
});
|
||||
@ -218,12 +234,14 @@ describe('variables', () => {
|
||||
...defaultQuery,
|
||||
queryType: VariableQueryType.LogGroups,
|
||||
logGroupPrefix: '$fields',
|
||||
accountId: '123',
|
||||
};
|
||||
await variables.execute(query);
|
||||
expect(getLogGroups).toBeCalledWith({
|
||||
region: query.region,
|
||||
logGroupNamePrefix: 'templatedField',
|
||||
listAllLogGroups: true,
|
||||
accountId: query.accountId,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -62,10 +62,12 @@ export class CloudWatchVariableSupport extends CustomVariableSupport<CloudWatchD
|
||||
return [];
|
||||
}
|
||||
}
|
||||
async handleLogGroupsQuery({ region, logGroupPrefix }: VariableQuery) {
|
||||
|
||||
async handleLogGroupsQuery({ region, logGroupPrefix, accountId }: VariableQuery) {
|
||||
const interpolatedPrefix = this.resources.templateSrv.replace(logGroupPrefix);
|
||||
return this.resources
|
||||
.getLogGroups({
|
||||
accountId,
|
||||
region,
|
||||
logGroupNamePrefix: interpolatedPrefix,
|
||||
listAllLogGroups: true,
|
||||
@ -89,25 +91,33 @@ export class CloudWatchVariableSupport extends CustomVariableSupport<CloudWatchD
|
||||
return this.resources.getNamespaces().then((namespaces) => namespaces.map(selectableValueToMetricFindOption));
|
||||
}
|
||||
|
||||
async handleMetricsQuery({ namespace, region }: VariableQuery) {
|
||||
async handleMetricsQuery({ namespace, region, accountId }: VariableQuery) {
|
||||
return this.resources
|
||||
.getMetrics({ namespace, region })
|
||||
.getMetrics({ namespace, region, accountId })
|
||||
.then((metrics) => metrics.map(selectableValueToMetricFindOption));
|
||||
}
|
||||
|
||||
async handleDimensionKeysQuery({ namespace, region }: VariableQuery) {
|
||||
async handleDimensionKeysQuery({ namespace, region, accountId }: VariableQuery) {
|
||||
return this.resources
|
||||
.getDimensionKeys({ namespace, region })
|
||||
.getDimensionKeys({ namespace, region, accountId })
|
||||
.then((keys) => keys.map(selectableValueToMetricFindOption));
|
||||
}
|
||||
|
||||
async handleDimensionValuesQuery({ namespace, region, dimensionKey, metricName, dimensionFilters }: VariableQuery) {
|
||||
async handleDimensionValuesQuery({
|
||||
namespace,
|
||||
accountId,
|
||||
region,
|
||||
dimensionKey,
|
||||
metricName,
|
||||
dimensionFilters,
|
||||
}: VariableQuery) {
|
||||
if (!dimensionKey || !metricName) {
|
||||
return [];
|
||||
}
|
||||
return this.resources
|
||||
.getDimensionValues({
|
||||
region,
|
||||
accountId,
|
||||
namespace,
|
||||
metricName,
|
||||
dimensionKey,
|
||||
|
Loading…
Reference in New Issue
Block a user