mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
CloudWatch: Refactor metrics resource request frontend (#57602)
* refactor metric resource request frontend * remove dupe interface
This commit is contained in:
parent
94aa090fb0
commit
237ff2699d
@ -12,7 +12,7 @@ export function setupMockedAPI({
|
||||
response,
|
||||
getMock,
|
||||
}: {
|
||||
getMock?: jest.Func;
|
||||
getMock?: jest.Mock;
|
||||
response?: Array<{ text: string; label: string; value: string }>;
|
||||
variables?: CustomVariableModel[];
|
||||
mockGetVariableName?: boolean;
|
||||
@ -21,7 +21,7 @@ export function setupMockedAPI({
|
||||
|
||||
const timeSrv = getTimeSrv();
|
||||
const api = new CloudWatchAPI(CloudWatchSettings, templateService);
|
||||
const resourceRequestMock = jest.fn().mockReturnValue(response);
|
||||
let resourceRequestMock = getMock ? getMock : jest.fn().mockReturnValue(response);
|
||||
setBackendSrv({
|
||||
...getBackendSrv(),
|
||||
get: resourceRequestMock,
|
||||
|
@ -82,6 +82,7 @@ export function setupMockedDataSource({
|
||||
datasource.api.getNamespaces = jest.fn().mockResolvedValue([]);
|
||||
datasource.api.getRegions = jest.fn().mockResolvedValue([]);
|
||||
datasource.api.getDimensionKeys = jest.fn().mockResolvedValue([]);
|
||||
datasource.api.getMetrics = jest.fn().mockResolvedValue([]);
|
||||
datasource.logsQueryRunner.defaultLogGroups = [];
|
||||
const fetchMock = jest.fn().mockReturnValue(of({}));
|
||||
setBackendSrv({
|
||||
|
@ -61,13 +61,53 @@ describe('api', () => {
|
||||
const { api, resourceRequestMock } = setupMockedAPI({ getMock });
|
||||
resourceRequestMock.mockResolvedValue([]);
|
||||
await Promise.all([
|
||||
api.getMetrics('AWS/EC2', 'us-east-1'),
|
||||
api.getMetrics('AWS/EC2', 'us-east-1'),
|
||||
api.getMetrics('AWS/EC2', 'us-east-2'),
|
||||
api.getMetrics('AWS/EC2', 'us-east-2'),
|
||||
api.getMetrics('AWS/EC2', 'us-east-2'),
|
||||
api.getMetrics({ namespace: 'AWS/EC2', region: 'us-east-1' }),
|
||||
api.getMetrics({ namespace: 'AWS/EC2', region: 'us-east-1' }),
|
||||
api.getMetrics({ namespace: 'AWS/EC2', region: 'us-east-2' }),
|
||||
api.getMetrics({ namespace: 'AWS/EC2', region: 'us-east-2' }),
|
||||
api.getMetrics({ namespace: 'AWS/EC2', region: 'us-east-2' }),
|
||||
]);
|
||||
expect(resourceRequestMock).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('should handle backend srv response mapping', () => {
|
||||
it('when getAllMetrics is called', async () => {
|
||||
const getMock = jest.fn().mockResolvedValue([
|
||||
{
|
||||
namespace: 'AWS/EC2',
|
||||
name: 'CPUUtilization',
|
||||
},
|
||||
{
|
||||
namespace: 'AWS/Redshift',
|
||||
name: 'CPUPercentage',
|
||||
},
|
||||
]);
|
||||
const { api } = setupMockedAPI({ getMock });
|
||||
const allMetrics = await api.getAllMetrics({ region: 'us-east-2' });
|
||||
expect(allMetrics).toEqual([
|
||||
{ metricName: 'CPUUtilization', namespace: 'AWS/EC2' },
|
||||
{ metricName: 'CPUPercentage', namespace: 'AWS/Redshift' },
|
||||
]);
|
||||
});
|
||||
|
||||
it('when getMetrics', async () => {
|
||||
const getMock = jest.fn().mockResolvedValue([
|
||||
{
|
||||
namespace: 'AWS/EC2',
|
||||
name: 'CPUUtilization',
|
||||
},
|
||||
{
|
||||
namespace: 'AWS/EC2',
|
||||
name: 'CPUPercentage',
|
||||
},
|
||||
]);
|
||||
const { api } = setupMockedAPI({ getMock });
|
||||
const allMetrics = await api.getMetrics({ region: 'us-east-2', namespace: 'AWS/EC2' });
|
||||
expect(allMetrics).toEqual([
|
||||
{ label: 'CPUUtilization', value: 'CPUUtilization' },
|
||||
{ label: 'CPUPercentage', value: 'CPUPercentage' },
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -10,6 +10,7 @@ import {
|
||||
DescribeLogGroupsRequest,
|
||||
GetDimensionKeysRequest,
|
||||
GetDimensionValuesRequest,
|
||||
GetMetricsRequest,
|
||||
MetricResponse,
|
||||
MultiFilters,
|
||||
} from './types';
|
||||
@ -59,7 +60,7 @@ export class CloudWatchAPI extends CloudWatchRequest {
|
||||
});
|
||||
}
|
||||
|
||||
async getMetrics(namespace: string | undefined, region?: string): Promise<Array<SelectableValue<string>>> {
|
||||
async getMetrics({ region, namespace }: GetMetricsRequest): Promise<Array<SelectableValue<string>>> {
|
||||
if (!namespace) {
|
||||
return [];
|
||||
}
|
||||
@ -70,12 +71,10 @@ export class CloudWatchAPI extends CloudWatchRequest {
|
||||
}).then((metrics) => metrics.map((m) => ({ label: m.name, value: m.name })));
|
||||
}
|
||||
|
||||
async getAllMetrics(region: string): Promise<Array<{ metricName?: string; namespace: string }>> {
|
||||
const values = await this.memoizedGetRequest<MetricResponse[]>('all-metrics', {
|
||||
async getAllMetrics({ region }: GetMetricsRequest): Promise<Array<{ metricName?: string; namespace: string }>> {
|
||||
return this.memoizedGetRequest<MetricResponse[]>('metrics', {
|
||||
region: this.templateSrv.replace(this.getActualRegion(region)),
|
||||
});
|
||||
|
||||
return values.map((v) => ({ metricName: v.name, namespace: v.namespace }));
|
||||
}).then((metrics) => metrics.map((m) => ({ metricName: m.name, namespace: m.namespace })));
|
||||
}
|
||||
|
||||
async getDimensionKeys({
|
||||
|
@ -112,14 +112,14 @@ export class SQLCompletionItemProvider extends CompletionItemProvider {
|
||||
const namespaceToken = getNamespaceToken(currentToken);
|
||||
if (namespaceToken?.value) {
|
||||
// if a namespace is specified, only suggest metrics for the namespace
|
||||
const metrics = await this.api.getMetrics(
|
||||
this.templateSrv.replace(namespaceToken?.value.replace(/\"/g, '')),
|
||||
this.templateSrv.replace(this.region)
|
||||
);
|
||||
const metrics = await this.api.getMetrics({
|
||||
namespace: namespaceToken?.value.replace(/\"/g, ''),
|
||||
region: this.region,
|
||||
});
|
||||
metrics.forEach((m) => m.value && addSuggestion(m.value));
|
||||
} else {
|
||||
// If no namespace is specified in the query, just list all metrics
|
||||
const metrics = await this.api.getAllMetrics(this.templateSrv.replace(this.region));
|
||||
const metrics = await this.api.getAllMetrics({ region: this.region });
|
||||
uniq(metrics.map((m) => m.metricName)).forEach((m) => m && addSuggestion(m, { insertText: m }));
|
||||
}
|
||||
}
|
||||
@ -147,7 +147,7 @@ export class SQLCompletionItemProvider extends CompletionItemProvider {
|
||||
let namespaces = [];
|
||||
if (metricNameToken?.value) {
|
||||
// if a metric is specified, only suggest namespaces that actually have that metric
|
||||
const metrics = await this.api.getAllMetrics(this.region);
|
||||
const metrics = await this.api.getMetrics({ region: this.region });
|
||||
const metricName = this.templateSrv.replace(metricNameToken.value);
|
||||
namespaces = metrics.filter((m) => m.metricName === metricName).map((m) => m.namespace);
|
||||
} else {
|
||||
|
@ -148,15 +148,13 @@ describe('MetricStatEditor', () => {
|
||||
});
|
||||
|
||||
it('should remove metricName from metricStat if it does not exist in new namespace', async () => {
|
||||
propsNamespaceMetrics.datasource.api.getMetrics = jest
|
||||
.fn()
|
||||
.mockImplementation((namespace: string, region: string) => {
|
||||
let mockMetrics =
|
||||
namespace === 'n1' && region === props.metricStat.region
|
||||
? metrics
|
||||
: [{ value: 'oldNamespaceMetric', label: 'oldNamespaceMetric', text: 'oldNamespaceMetric' }];
|
||||
return Promise.resolve(mockMetrics);
|
||||
});
|
||||
propsNamespaceMetrics.datasource.api.getMetrics = jest.fn().mockImplementation(({ namespace, region }) => {
|
||||
let mockMetrics =
|
||||
namespace === 'n1' && region === props.metricStat.region
|
||||
? metrics
|
||||
: [{ value: 'oldNamespaceMetric', label: 'oldNamespaceMetric', text: 'oldNamespaceMetric' }];
|
||||
return Promise.resolve(mockMetrics);
|
||||
});
|
||||
propsNamespaceMetrics.metricStat.metricName = 'oldNamespaceMetric';
|
||||
propsNamespaceMetrics.metricStat.namespace = 'n2';
|
||||
|
||||
|
@ -48,7 +48,7 @@ export function MetricStatEditor({
|
||||
if (!metricName) {
|
||||
return metricStat;
|
||||
}
|
||||
await datasource.api.getMetrics(namespace, region).then((result: Array<SelectableValue<string>>) => {
|
||||
await datasource.api.getMetrics({ namespace, region }).then((result: Array<SelectableValue<string>>) => {
|
||||
if (!result.find((metric) => metric.value === metricName)) {
|
||||
metricName = '';
|
||||
}
|
||||
|
@ -67,8 +67,8 @@ const SQLBuilderSelectRow: React.FC<SQLBuilderSelectRowProps> = ({ datasource, q
|
||||
};
|
||||
|
||||
const validateMetricName = async (query: CloudWatchMetricsQuery) => {
|
||||
let { region, sql } = query;
|
||||
await datasource.api.getMetrics(query.namespace, region).then((result: Array<SelectableValue<string>>) => {
|
||||
let { region, sql, namespace } = query;
|
||||
await datasource.api.getMetrics({ namespace, region }).then((result: Array<SelectableValue<string>>) => {
|
||||
if (!result.some((metric) => metric.value === metricName)) {
|
||||
sql = removeMetricName(query).sql;
|
||||
}
|
||||
|
@ -230,7 +230,7 @@ describe('VariableEditor', () => {
|
||||
container: document.body,
|
||||
});
|
||||
|
||||
expect(ds.datasource.api.getMetrics).toHaveBeenCalledWith('z2', 'b1');
|
||||
expect(ds.datasource.api.getMetrics).toHaveBeenCalledWith({ namespace: 'z2', region: 'b1' });
|
||||
expect(ds.datasource.api.getDimensionKeys).toHaveBeenCalledWith({ namespace: 'z2', region: 'b1' });
|
||||
expect(props.onChange).toHaveBeenCalledWith({
|
||||
...defaultQuery,
|
||||
|
@ -65,7 +65,7 @@ export const VariableQueryEditor = ({ query, datasource, onChange }: Props) => {
|
||||
const sanitizeQuery = async (query: VariableQuery) => {
|
||||
let { metricName, dimensionKey, dimensionFilters, namespace, region } = query;
|
||||
if (metricName) {
|
||||
await datasource.api.getMetrics(namespace, region).then((result: Array<SelectableValue<string>>) => {
|
||||
await datasource.api.getMetrics({ namespace, region }).then((result: Array<SelectableValue<string>>) => {
|
||||
if (!result.find((metric) => metric.value === metricName)) {
|
||||
metricName = '';
|
||||
}
|
||||
|
@ -215,7 +215,7 @@ describe('datasource', () => {
|
||||
},
|
||||
]),
|
||||
}).datasource;
|
||||
const allMetrics = await datasource.api.getAllMetrics('us-east-2');
|
||||
const allMetrics = await datasource.api.getAllMetrics({ region: 'us-east-2' });
|
||||
expect(allMetrics[0].metricName).toEqual('CPUUtilization');
|
||||
expect(allMetrics[0].namespace).toEqual('AWS/EC2');
|
||||
expect(allMetrics[1].metricName).toEqual('CPUPercentage');
|
||||
|
@ -42,7 +42,7 @@ export const useNamespaces = (datasource: CloudWatchDatasource) => {
|
||||
export const useMetrics = (datasource: CloudWatchDatasource, region: string, namespace: string | undefined) => {
|
||||
const [metrics, setMetrics] = useState<Array<SelectableValue<string>>>([]);
|
||||
useEffect(() => {
|
||||
datasource.api.getMetrics(namespace, region).then((result: Array<SelectableValue<string>>) => {
|
||||
datasource.api.getMetrics({ namespace, region }).then((result: Array<SelectableValue<string>>) => {
|
||||
setMetrics(appendTemplateVariables(datasource, result));
|
||||
});
|
||||
}, [datasource, region, namespace]);
|
||||
|
@ -451,6 +451,11 @@ export interface LegacyAnnotationQuery extends MetricStat, DataQuery {
|
||||
type: string;
|
||||
}
|
||||
|
||||
export interface MetricResponse {
|
||||
name: string;
|
||||
namespace: string;
|
||||
}
|
||||
|
||||
export interface ResourceRequest {
|
||||
region: string;
|
||||
}
|
||||
@ -468,7 +473,6 @@ export interface GetDimensionValuesRequest extends ResourceRequest {
|
||||
dimensionFilters?: Dimensions;
|
||||
}
|
||||
|
||||
export interface MetricResponse {
|
||||
name: string;
|
||||
namespace: string;
|
||||
export interface GetMetricsRequest extends ResourceRequest {
|
||||
namespace?: string;
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ export class CloudWatchVariableSupport extends CustomVariableSupport<CloudWatchD
|
||||
}
|
||||
|
||||
async handleMetricsQuery({ namespace, region }: VariableQuery) {
|
||||
const metrics = await this.api.getMetrics(namespace, region);
|
||||
const metrics = await this.api.getMetrics({ namespace, region });
|
||||
return metrics.map((s) => ({
|
||||
text: s.label,
|
||||
value: s.value,
|
||||
|
Loading…
Reference in New Issue
Block a user