mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Cloudwatch: Break out resource requests from datasource file (#55358)
* break out resource requests from datasource file * fix lint issues
This commit is contained in:
parent
4df41972f1
commit
caba98590d
@ -56,7 +56,7 @@ exports[`no enzyme tests`] = {
|
|||||||
"public/app/features/dimensions/editors/ThresholdsEditor/ThresholdsEditor.test.tsx:145048794": [
|
"public/app/features/dimensions/editors/ThresholdsEditor/ThresholdsEditor.test.tsx:145048794": [
|
||||||
[0, 17, 13, "RegExp match", "2409514259"]
|
[0, 17, 13, "RegExp match", "2409514259"]
|
||||||
],
|
],
|
||||||
"public/app/plugins/datasource/cloudwatch/components/ConfigEditor.test.tsx:3543762762": [
|
"public/app/plugins/datasource/cloudwatch/components/ConfigEditor.test.tsx:2210656642": [
|
||||||
[1, 19, 13, "RegExp match", "2409514259"]
|
[1, 19, 13, "RegExp match", "2409514259"]
|
||||||
]
|
]
|
||||||
}`
|
}`
|
||||||
@ -5905,12 +5905,18 @@ exports[`better eslint`] = {
|
|||||||
"public/app/plugins/datasource/cloud-monitoring/types.ts:5381": [
|
"public/app/plugins/datasource/cloud-monitoring/types.ts:5381": [
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||||
],
|
],
|
||||||
"public/app/plugins/datasource/cloudwatch/__mocks__/LogsQueryRunner.ts:5381": [
|
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
|
||||||
],
|
|
||||||
"public/app/plugins/datasource/cloudwatch/__mocks__/monarch/Monaco.ts:5381": [
|
"public/app/plugins/datasource/cloudwatch/__mocks__/monarch/Monaco.ts:5381": [
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||||
],
|
],
|
||||||
|
"public/app/plugins/datasource/cloudwatch/api.ts:5381": [
|
||||||
|
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
|
||||||
|
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
|
||||||
|
[0, 0, 0, "Unexpected any. Specify a different type.", "2"],
|
||||||
|
[0, 0, 0, "Unexpected any. Specify a different type.", "3"],
|
||||||
|
[0, 0, 0, "Unexpected any. Specify a different type.", "4"],
|
||||||
|
[0, 0, 0, "Unexpected any. Specify a different type.", "5"],
|
||||||
|
[0, 0, 0, "Unexpected any. Specify a different type.", "6"]
|
||||||
|
],
|
||||||
"public/app/plugins/datasource/cloudwatch/components/ConfigEditor.test.tsx:5381": [
|
"public/app/plugins/datasource/cloudwatch/components/ConfigEditor.test.tsx:5381": [
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||||
],
|
],
|
||||||
@ -5953,15 +5959,7 @@ exports[`better eslint`] = {
|
|||||||
[0, 0, 0, "Do not use any type assertions.", "1"]
|
[0, 0, 0, "Do not use any type assertions.", "1"]
|
||||||
],
|
],
|
||||||
"public/app/plugins/datasource/cloudwatch/datasource.ts:5381": [
|
"public/app/plugins/datasource/cloudwatch/datasource.ts:5381": [
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
|
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
|
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "2"],
|
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "3"],
|
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "4"],
|
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "5"],
|
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "6"],
|
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "7"],
|
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "8"]
|
|
||||||
],
|
],
|
||||||
"public/app/plugins/datasource/cloudwatch/guards.ts:5381": [
|
"public/app/plugins/datasource/cloudwatch/guards.ts:5381": [
|
||||||
[0, 0, 0, "Do not use any type assertions.", "0"]
|
[0, 0, 0, "Do not use any type assertions.", "0"]
|
||||||
@ -5985,9 +5983,6 @@ exports[`better eslint`] = {
|
|||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
|
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "1"]
|
[0, 0, 0, "Unexpected any. Specify a different type.", "1"]
|
||||||
],
|
],
|
||||||
"public/app/plugins/datasource/cloudwatch/metric-math/completion/CompletionItemProvider.test.ts:5381": [
|
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
|
||||||
],
|
|
||||||
"public/app/plugins/datasource/cloudwatch/query-runner/CloudWatchLogsQueryRunner.ts:5381": [
|
"public/app/plugins/datasource/cloudwatch/query-runner/CloudWatchLogsQueryRunner.ts:5381": [
|
||||||
[0, 0, 0, "Do not use any type assertions.", "0"],
|
[0, 0, 0, "Do not use any type assertions.", "0"],
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "1"]
|
[0, 0, 0, "Unexpected any. Specify a different type.", "1"]
|
||||||
|
@ -77,8 +77,8 @@ export function setupMockedDataSource({
|
|||||||
const datasource = new CloudWatchDatasource(CloudWatchSettings, templateService, timeSrv);
|
const datasource = new CloudWatchDatasource(CloudWatchSettings, templateService, timeSrv);
|
||||||
datasource.getVariables = () => ['test'];
|
datasource.getVariables = () => ['test'];
|
||||||
|
|
||||||
datasource.getNamespaces = jest.fn().mockResolvedValue([]);
|
datasource.api.getNamespaces = jest.fn().mockResolvedValue([]);
|
||||||
datasource.getRegions = jest.fn().mockResolvedValue([]);
|
datasource.api.getRegions = jest.fn().mockResolvedValue([]);
|
||||||
datasource.logsQueryRunner.defaultLogGroups = [];
|
datasource.logsQueryRunner.defaultLogGroups = [];
|
||||||
const fetchMock = jest.fn().mockReturnValue(of({}));
|
const fetchMock = jest.fn().mockReturnValue(of({}));
|
||||||
setBackendSrv({
|
setBackendSrv({
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { of } from 'rxjs';
|
import { of } from 'rxjs';
|
||||||
|
|
||||||
import { DataFrame } from '@grafana/data';
|
import { CustomVariableModel, DataFrame } from '@grafana/data';
|
||||||
import { BackendDataSourceResponse, getBackendSrv, setBackendSrv } from '@grafana/runtime';
|
import { BackendDataSourceResponse, getBackendSrv, setBackendSrv } from '@grafana/runtime';
|
||||||
import { getTimeSrv } from 'app/features/dashboard/services/TimeSrv';
|
import { getTimeSrv } from 'app/features/dashboard/services/TimeSrv';
|
||||||
import { TemplateSrv } from 'app/features/templating/template_srv';
|
import { TemplateSrv } from 'app/features/templating/template_srv';
|
||||||
@ -16,7 +16,7 @@ export function setupMockedLogsQueryRunner({
|
|||||||
},
|
},
|
||||||
variables,
|
variables,
|
||||||
mockGetVariableName = true,
|
mockGetVariableName = true,
|
||||||
}: { data?: BackendDataSourceResponse; variables?: any; mockGetVariableName?: boolean } = {}) {
|
}: { data?: BackendDataSourceResponse; variables?: CustomVariableModel[]; mockGetVariableName?: boolean } = {}) {
|
||||||
let templateService = new TemplateSrv();
|
let templateService = new TemplateSrv();
|
||||||
if (variables) {
|
if (variables) {
|
||||||
templateService = setupMockedTemplateService(variables);
|
templateService = setupMockedTemplateService(variables);
|
||||||
|
111
public/app/plugins/datasource/cloudwatch/api.ts
Normal file
111
public/app/plugins/datasource/cloudwatch/api.ts
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
import { DataSourceInstanceSettings } from '@grafana/data';
|
||||||
|
import { getBackendSrv, BackendSrv } from '@grafana/runtime';
|
||||||
|
import { TemplateSrv } from 'app/features/templating/template_srv';
|
||||||
|
|
||||||
|
import { CloudWatchRequest } from './query-runner/CloudWatchRequest';
|
||||||
|
import { CloudWatchJsonData, Dimensions } from './types';
|
||||||
|
|
||||||
|
export class CloudWatchAPI extends CloudWatchRequest {
|
||||||
|
private backendSrv: BackendSrv;
|
||||||
|
constructor(instanceSettings: DataSourceInstanceSettings<CloudWatchJsonData>, templateSrv: TemplateSrv) {
|
||||||
|
super(instanceSettings, templateSrv);
|
||||||
|
this.backendSrv = getBackendSrv();
|
||||||
|
}
|
||||||
|
|
||||||
|
resourceRequest(subtype: string, parameters?: any): Promise<Array<{ text: any; label: any; value: any }>> {
|
||||||
|
return this.backendSrv.get(`/api/datasources/${this.instanceSettings.id}/resources/${subtype}`, parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
getRegions(): Promise<Array<{ label: string; value: string; text: string }>> {
|
||||||
|
return this.resourceRequest('regions').then((regions: any) => [
|
||||||
|
{ label: 'default', value: 'default', text: 'default' },
|
||||||
|
...regions,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
getNamespaces() {
|
||||||
|
return this.resourceRequest('namespaces');
|
||||||
|
}
|
||||||
|
|
||||||
|
async getMetrics(namespace: string | undefined, region?: string) {
|
||||||
|
if (!namespace) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.resourceRequest('metrics', {
|
||||||
|
region: this.templateSrv.replace(this.getActualRegion(region)),
|
||||||
|
namespace: this.templateSrv.replace(namespace),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAllMetrics(region: string): Promise<Array<{ metricName: string; namespace: string }>> {
|
||||||
|
const values = await this.resourceRequest('all-metrics', {
|
||||||
|
region: this.templateSrv.replace(this.getActualRegion(region)),
|
||||||
|
});
|
||||||
|
|
||||||
|
return values.map((v) => ({ metricName: v.value, namespace: v.text }));
|
||||||
|
}
|
||||||
|
|
||||||
|
async getDimensionKeys(
|
||||||
|
namespace: string | undefined,
|
||||||
|
region: string,
|
||||||
|
dimensionFilters: Dimensions = {},
|
||||||
|
metricName = ''
|
||||||
|
) {
|
||||||
|
if (!namespace) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.resourceRequest('dimension-keys', {
|
||||||
|
region: this.templateSrv.replace(this.getActualRegion(region)),
|
||||||
|
namespace: this.templateSrv.replace(namespace),
|
||||||
|
dimensionFilters: JSON.stringify(this.convertDimensionFormat(dimensionFilters, {})),
|
||||||
|
metricName,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async getDimensionValues(
|
||||||
|
region: string,
|
||||||
|
namespace: string | undefined,
|
||||||
|
metricName: string | undefined,
|
||||||
|
dimensionKey: string,
|
||||||
|
filterDimensions: {}
|
||||||
|
) {
|
||||||
|
if (!namespace || !metricName) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const values = await this.resourceRequest('dimension-values', {
|
||||||
|
region: this.templateSrv.replace(this.getActualRegion(region)),
|
||||||
|
namespace: this.templateSrv.replace(namespace),
|
||||||
|
metricName: this.templateSrv.replace(metricName.trim()),
|
||||||
|
dimensionKey: this.templateSrv.replace(dimensionKey),
|
||||||
|
dimensions: JSON.stringify(this.convertDimensionFormat(filterDimensions, {})),
|
||||||
|
});
|
||||||
|
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
getEbsVolumeIds(region: string, instanceId: string) {
|
||||||
|
return this.resourceRequest('ebs-volume-ids', {
|
||||||
|
region: this.templateSrv.replace(this.getActualRegion(region)),
|
||||||
|
instanceId: this.templateSrv.replace(instanceId),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getEc2InstanceAttribute(region: string, attributeName: string, filters: any) {
|
||||||
|
return this.resourceRequest('ec2-instance-attribute', {
|
||||||
|
region: this.templateSrv.replace(this.getActualRegion(region)),
|
||||||
|
attributeName: this.templateSrv.replace(attributeName),
|
||||||
|
filters: JSON.stringify(this.convertMultiFilterFormat(filters, 'filter key')),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getResourceARNs(region: string, resourceType: string, tags: any) {
|
||||||
|
return this.resourceRequest('resource-arns', {
|
||||||
|
region: this.templateSrv.replace(this.getActualRegion(region)),
|
||||||
|
resourceType: this.templateSrv.replace(resourceType),
|
||||||
|
tags: JSON.stringify(this.convertMultiFilterFormat(tags, 'tag name')),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,7 @@ import { uniq } from 'lodash';
|
|||||||
import { getTemplateSrv, TemplateSrv } from '@grafana/runtime';
|
import { getTemplateSrv, TemplateSrv } from '@grafana/runtime';
|
||||||
import type { Monaco, monacoTypes } from '@grafana/ui';
|
import type { Monaco, monacoTypes } from '@grafana/ui';
|
||||||
|
|
||||||
import { CloudWatchDatasource } from '../../datasource';
|
import { CloudWatchAPI } from '../../api';
|
||||||
import { CompletionItemProvider } from '../../monarch/CompletionItemProvider';
|
import { CompletionItemProvider } from '../../monarch/CompletionItemProvider';
|
||||||
import { LinkedToken } from '../../monarch/LinkedToken';
|
import { LinkedToken } from '../../monarch/LinkedToken';
|
||||||
import { TRIGGER_SUGGEST } from '../../monarch/commands';
|
import { TRIGGER_SUGGEST } from '../../monarch/commands';
|
||||||
@ -34,9 +34,9 @@ type CompletionItem = monacoTypes.languages.CompletionItem;
|
|||||||
export class SQLCompletionItemProvider extends CompletionItemProvider {
|
export class SQLCompletionItemProvider extends CompletionItemProvider {
|
||||||
region: string;
|
region: string;
|
||||||
|
|
||||||
constructor(datasource: CloudWatchDatasource, templateSrv: TemplateSrv = getTemplateSrv()) {
|
constructor(api: CloudWatchAPI, templateSrv: TemplateSrv = getTemplateSrv()) {
|
||||||
super(datasource, templateSrv);
|
super(api, templateSrv);
|
||||||
this.region = datasource.getActualRegion();
|
this.region = api.getActualRegion() ?? '';
|
||||||
this.getStatementPosition = getStatementPosition;
|
this.getStatementPosition = getStatementPosition;
|
||||||
this.getSuggestionKinds = getSuggestionKinds;
|
this.getSuggestionKinds = getSuggestionKinds;
|
||||||
this.tokenTypes = SQLTokenTypes;
|
this.tokenTypes = SQLTokenTypes;
|
||||||
@ -112,14 +112,14 @@ export class SQLCompletionItemProvider extends CompletionItemProvider {
|
|||||||
const namespaceToken = getNamespaceToken(currentToken);
|
const namespaceToken = getNamespaceToken(currentToken);
|
||||||
if (namespaceToken?.value) {
|
if (namespaceToken?.value) {
|
||||||
// if a namespace is specified, only suggest metrics for the namespace
|
// if a namespace is specified, only suggest metrics for the namespace
|
||||||
const metrics = await this.datasource.getMetrics(
|
const metrics = await this.api.getMetrics(
|
||||||
this.templateSrv.replace(namespaceToken?.value.replace(/\"/g, '')),
|
this.templateSrv.replace(namespaceToken?.value.replace(/\"/g, '')),
|
||||||
this.templateSrv.replace(this.region)
|
this.templateSrv.replace(this.region)
|
||||||
);
|
);
|
||||||
metrics.map((m) => addSuggestion(m.value));
|
metrics.map((m) => addSuggestion(m.value));
|
||||||
} else {
|
} else {
|
||||||
// If no namespace is specified in the query, just list all metrics
|
// If no namespace is specified in the query, just list all metrics
|
||||||
const metrics = await this.datasource.getAllMetrics(this.templateSrv.replace(this.region));
|
const metrics = await this.api.getAllMetrics(this.templateSrv.replace(this.region));
|
||||||
uniq(metrics.map((m) => m.metricName)).map((m) => addSuggestion(m, { insertText: m }));
|
uniq(metrics.map((m) => m.metricName)).map((m) => addSuggestion(m, { insertText: m }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -147,12 +147,12 @@ export class SQLCompletionItemProvider extends CompletionItemProvider {
|
|||||||
let namespaces = [];
|
let namespaces = [];
|
||||||
if (metricNameToken?.value) {
|
if (metricNameToken?.value) {
|
||||||
// if a metric is specified, only suggest namespaces that actually have that metric
|
// if a metric is specified, only suggest namespaces that actually have that metric
|
||||||
const metrics = await this.datasource.getAllMetrics(this.region);
|
const metrics = await this.api.getAllMetrics(this.region);
|
||||||
const metricName = this.templateSrv.replace(metricNameToken.value);
|
const metricName = this.templateSrv.replace(metricNameToken.value);
|
||||||
namespaces = metrics.filter((m) => m.metricName === metricName).map((m) => m.namespace);
|
namespaces = metrics.filter((m) => m.metricName === metricName).map((m) => m.namespace);
|
||||||
} else {
|
} else {
|
||||||
// if no metric is specified, just suggest all namespaces
|
// if no metric is specified, just suggest all namespaces
|
||||||
const ns = await this.datasource.getNamespaces();
|
const ns = await this.api.getNamespaces();
|
||||||
namespaces = ns.map((n) => n.value);
|
namespaces = ns.map((n) => n.value);
|
||||||
}
|
}
|
||||||
namespaces.map((n) => addSuggestion(`"${n}"`, { insertText: `"${n}"` }));
|
namespaces.map((n) => addSuggestion(`"${n}"`, { insertText: `"${n}"` }));
|
||||||
@ -179,7 +179,7 @@ export class SQLCompletionItemProvider extends CompletionItemProvider {
|
|||||||
dimensionFilter = (labelKeyTokens || []).reduce((acc, curr) => {
|
dimensionFilter = (labelKeyTokens || []).reduce((acc, curr) => {
|
||||||
return { ...acc, [curr.value]: null };
|
return { ...acc, [curr.value]: null };
|
||||||
}, {});
|
}, {});
|
||||||
const keys = await this.datasource.getDimensionKeys(
|
const keys = await this.api.getDimensionKeys(
|
||||||
this.templateSrv.replace(namespaceToken.value.replace(/\"/g, '')),
|
this.templateSrv.replace(namespaceToken.value.replace(/\"/g, '')),
|
||||||
this.templateSrv.replace(this.region),
|
this.templateSrv.replace(this.region),
|
||||||
dimensionFilter,
|
dimensionFilter,
|
||||||
@ -199,7 +199,7 @@ export class SQLCompletionItemProvider extends CompletionItemProvider {
|
|||||||
const metricNameToken = getMetricNameToken(currentToken);
|
const metricNameToken = getMetricNameToken(currentToken);
|
||||||
const labelKey = currentToken?.getPreviousNonWhiteSpaceToken()?.getPreviousNonWhiteSpaceToken();
|
const labelKey = currentToken?.getPreviousNonWhiteSpaceToken()?.getPreviousNonWhiteSpaceToken();
|
||||||
if (namespaceToken?.value && labelKey?.value && metricNameToken?.value) {
|
if (namespaceToken?.value && labelKey?.value && metricNameToken?.value) {
|
||||||
const values = await this.datasource.getDimensionValues(
|
const values = await this.api.getDimensionValues(
|
||||||
this.templateSrv.replace(this.region),
|
this.templateSrv.replace(this.region),
|
||||||
this.templateSrv.replace(namespaceToken.value.replace(/\"/g, '')),
|
this.templateSrv.replace(namespaceToken.value.replace(/\"/g, '')),
|
||||||
this.templateSrv.replace(metricNameToken.value),
|
this.templateSrv.replace(metricNameToken.value),
|
||||||
@ -266,12 +266,12 @@ export class SQLCompletionItemProvider extends CompletionItemProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// always suggest template variables
|
this.templateSrv.getVariables().map((v) => {
|
||||||
this.templateVariables.map((v) => {
|
const variable = `$${v.name}`;
|
||||||
addSuggestion(v, {
|
addSuggestion(variable, {
|
||||||
range,
|
range,
|
||||||
label: v,
|
label: variable,
|
||||||
insertText: v,
|
insertText: variable,
|
||||||
kind: monaco.languages.CompletionItemKind.Variable,
|
kind: monaco.languages.CompletionItemKind.Variable,
|
||||||
sortText: CompletionItemPriority.Low,
|
sortText: CompletionItemPriority.Low,
|
||||||
});
|
});
|
||||||
|
@ -29,10 +29,10 @@ const q: CloudWatchQuery = {
|
|||||||
alarmNamePrefix: '',
|
alarmNamePrefix: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
ds.datasource.getRegions = jest.fn().mockResolvedValue([]);
|
ds.datasource.api.getRegions = jest.fn().mockResolvedValue([]);
|
||||||
ds.datasource.getNamespaces = jest.fn().mockResolvedValue([]);
|
ds.datasource.api.getNamespaces = jest.fn().mockResolvedValue([]);
|
||||||
ds.datasource.getMetrics = jest.fn().mockResolvedValue([]);
|
ds.datasource.api.getMetrics = jest.fn().mockResolvedValue([]);
|
||||||
ds.datasource.getDimensionKeys = jest.fn().mockResolvedValue([]);
|
ds.datasource.api.getDimensionKeys = jest.fn().mockResolvedValue([]);
|
||||||
ds.datasource.getVariables = jest.fn().mockReturnValue([]);
|
ds.datasource.getVariables = jest.fn().mockReturnValue([]);
|
||||||
|
|
||||||
const props: QueryEditorProps<CloudWatchDatasource, CloudWatchQuery, CloudWatchJsonData> = {
|
const props: QueryEditorProps<CloudWatchDatasource, CloudWatchQuery, CloudWatchJsonData> = {
|
||||||
@ -51,7 +51,7 @@ describe('AnnotationQueryEditor', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should return an error component in case CloudWatchQuery is not CloudWatchAnnotationQuery', async () => {
|
it('should return an error component in case CloudWatchQuery is not CloudWatchAnnotationQuery', async () => {
|
||||||
ds.datasource.getDimensionValues = jest.fn().mockResolvedValue([[{ label: 'dimVal1', value: 'dimVal1' }]]);
|
ds.datasource.api.getDimensionValues = jest.fn().mockResolvedValue([[{ label: 'dimVal1', value: 'dimVal1' }]]);
|
||||||
render(
|
render(
|
||||||
<AnnotationQueryEditor {...props} query={{ ...props.query, queryMode: 'Metrics' } as CloudWatchMetricsQuery} />
|
<AnnotationQueryEditor {...props} query={{ ...props.query, queryMode: 'Metrics' } as CloudWatchMetricsQuery} />
|
||||||
);
|
);
|
||||||
@ -59,7 +59,7 @@ describe('AnnotationQueryEditor', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should not display wildcard option in dimension value dropdown', async () => {
|
it('should not display wildcard option in dimension value dropdown', async () => {
|
||||||
ds.datasource.getDimensionValues = jest.fn().mockResolvedValue([[{ label: 'dimVal1', value: 'dimVal1' }]]);
|
ds.datasource.api.getDimensionValues = jest.fn().mockResolvedValue([[{ label: 'dimVal1', value: 'dimVal1' }]]);
|
||||||
(props.query as CloudWatchAnnotationQuery).dimensions = { instanceId: 'instance-123' };
|
(props.query as CloudWatchAnnotationQuery).dimensions = { instanceId: 'instance-123' };
|
||||||
render(<AnnotationQueryEditor {...props} />);
|
render(<AnnotationQueryEditor {...props} />);
|
||||||
const valueElement = screen.getByText('instance-123');
|
const valueElement = screen.getByText('instance-123');
|
||||||
|
@ -52,7 +52,7 @@ export default class CloudWatchLink extends Component<Props, State> {
|
|||||||
source: query.logGroupNames ?? [],
|
source: query.logGroupNames ?? [],
|
||||||
};
|
};
|
||||||
|
|
||||||
return encodeUrl(urlProps, datasource.getActualRegion(query.region));
|
return encodeUrl(urlProps, datasource.api.getActualRegion(query.region));
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -12,12 +12,14 @@ import { ConfigEditor, Props } from './ConfigEditor';
|
|||||||
jest.mock('app/features/plugins/datasource_srv', () => ({
|
jest.mock('app/features/plugins/datasource_srv', () => ({
|
||||||
getDatasourceSrv: () => ({
|
getDatasourceSrv: () => ({
|
||||||
loadDatasource: jest.fn().mockResolvedValue({
|
loadDatasource: jest.fn().mockResolvedValue({
|
||||||
getRegions: jest.fn().mockResolvedValue([
|
api: {
|
||||||
{
|
getRegions: jest.fn().mockResolvedValue([
|
||||||
label: 'ap-east-1',
|
{
|
||||||
value: 'ap-east-1',
|
label: 'ap-east-1',
|
||||||
},
|
value: 'ap-east-1',
|
||||||
]),
|
},
|
||||||
|
]),
|
||||||
|
},
|
||||||
getActualRegion: jest.fn().mockReturnValue('ap-east-1'),
|
getActualRegion: jest.fn().mockReturnValue('ap-east-1'),
|
||||||
getVariables: jest.fn().mockReturnValue([]),
|
getVariables: jest.fn().mockReturnValue([]),
|
||||||
logsQueryRunner: {
|
logsQueryRunner: {
|
||||||
|
@ -63,7 +63,7 @@ export const ConfigEditor: FC<Props> = (props: Props) => {
|
|||||||
{...props}
|
{...props}
|
||||||
loadRegions={
|
loadRegions={
|
||||||
datasource &&
|
datasource &&
|
||||||
(() => datasource!.getRegions().then((r) => r.filter((r) => r.value !== 'default').map((v) => v.value)))
|
(() => datasource.api.getRegions().then((r) => r.filter((r) => r.value !== 'default').map((v) => v.value)))
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<InlineField label="Namespaces of Custom Metrics" labelWidth={28} tooltip="Namespaces of Custom Metrics.">
|
<InlineField label="Namespaces of Custom Metrics" labelWidth={28} tooltip="Namespaces of Custom Metrics.">
|
||||||
|
@ -10,9 +10,9 @@ const ds = setupMockedDataSource({
|
|||||||
variables: [],
|
variables: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
ds.datasource.getNamespaces = jest.fn().mockResolvedValue([]);
|
ds.datasource.api.getNamespaces = jest.fn().mockResolvedValue([]);
|
||||||
ds.datasource.getMetrics = jest.fn().mockResolvedValue([]);
|
ds.datasource.api.getMetrics = jest.fn().mockResolvedValue([]);
|
||||||
ds.datasource.getDimensionKeys = jest.fn().mockResolvedValue([]);
|
ds.datasource.api.getDimensionKeys = jest.fn().mockResolvedValue([]);
|
||||||
ds.datasource.getVariables = jest.fn().mockReturnValue([]);
|
ds.datasource.getVariables = jest.fn().mockReturnValue([]);
|
||||||
const q: CloudWatchMetricsQuery = {
|
const q: CloudWatchMetricsQuery = {
|
||||||
id: '',
|
id: '',
|
||||||
|
@ -50,7 +50,7 @@ export const FilterItem: FunctionComponent<Props> = ({
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
return datasource
|
return datasource.api
|
||||||
.getDimensionValues(region, namespace, metricName, filter.key, dimensionsExcludingCurrentKey)
|
.getDimensionValues(region, namespace, metricName, filter.key, dimensionsExcludingCurrentKey)
|
||||||
.then((result: Array<SelectableValue<string>>) => {
|
.then((result: Array<SelectableValue<string>>) => {
|
||||||
if (result.length && !disableExpressions) {
|
if (result.length && !disableExpressions) {
|
||||||
|
@ -98,7 +98,7 @@ export const LogGroupSelector: React.FC<LogGroupSelectorProps> = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
setLoadingLogGroups(true);
|
setLoadingLogGroups(true);
|
||||||
return fetchLogGroupOptions(datasource.getActualRegion(region))
|
return fetchLogGroupOptions(datasource.getActualRegion(region) ?? '')
|
||||||
.then((logGroups) => {
|
.then((logGroups) => {
|
||||||
const newSelectedLogGroups = intersection(
|
const newSelectedLogGroups = intersection(
|
||||||
selectedLogGroups,
|
selectedLogGroups,
|
||||||
|
@ -11,9 +11,9 @@ const ds = setupMockedDataSource({
|
|||||||
variables: [],
|
variables: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
ds.datasource.getNamespaces = jest.fn().mockResolvedValue([]);
|
ds.datasource.api.getNamespaces = jest.fn().mockResolvedValue([]);
|
||||||
ds.datasource.getMetrics = jest.fn().mockResolvedValue([]);
|
ds.datasource.api.getMetrics = jest.fn().mockResolvedValue([]);
|
||||||
ds.datasource.getDimensionKeys = jest.fn().mockResolvedValue([]);
|
ds.datasource.api.getDimensionKeys = jest.fn().mockResolvedValue([]);
|
||||||
ds.datasource.getVariables = jest.fn().mockReturnValue([]);
|
ds.datasource.getVariables = jest.fn().mockReturnValue([]);
|
||||||
const metricStat: MetricStat = {
|
const metricStat: MetricStat = {
|
||||||
region: 'us-east-2',
|
region: 'us-east-2',
|
||||||
@ -121,8 +121,8 @@ describe('MetricStatEditor', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
propsNamespaceMetrics.datasource.getNamespaces = jest.fn().mockResolvedValue(namespaces);
|
propsNamespaceMetrics.datasource.api.getNamespaces = jest.fn().mockResolvedValue(namespaces);
|
||||||
propsNamespaceMetrics.datasource.getMetrics = jest.fn().mockResolvedValue(metrics);
|
propsNamespaceMetrics.datasource.api.getMetrics = jest.fn().mockResolvedValue(metrics);
|
||||||
onChange.mockClear();
|
onChange.mockClear();
|
||||||
onRunQuery.mockClear();
|
onRunQuery.mockClear();
|
||||||
});
|
});
|
||||||
@ -148,7 +148,7 @@ describe('MetricStatEditor', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should remove metricName from metricStat if it does not exist in new namespace', async () => {
|
it('should remove metricName from metricStat if it does not exist in new namespace', async () => {
|
||||||
propsNamespaceMetrics.datasource.getMetrics = jest
|
propsNamespaceMetrics.datasource.api.getMetrics = jest
|
||||||
.fn()
|
.fn()
|
||||||
.mockImplementation((namespace: string, region: string) => {
|
.mockImplementation((namespace: string, region: string) => {
|
||||||
let mockMetrics =
|
let mockMetrics =
|
||||||
|
@ -6,6 +6,7 @@ import { EditorField, EditorFieldGroup, EditorRow, EditorRows, EditorSwitch, Sel
|
|||||||
import { Dimensions } from '..';
|
import { Dimensions } from '..';
|
||||||
import { CloudWatchDatasource } from '../../datasource';
|
import { CloudWatchDatasource } from '../../datasource';
|
||||||
import { useDimensionKeys, useMetrics, useNamespaces } from '../../hooks';
|
import { useDimensionKeys, useMetrics, useNamespaces } from '../../hooks';
|
||||||
|
import { standardStatistics } from '../../standardStatistics';
|
||||||
import { MetricStat } from '../../types';
|
import { MetricStat } from '../../types';
|
||||||
import { appendTemplateVariables, toOption } from '../../utils/utils';
|
import { appendTemplateVariables, toOption } from '../../utils/utils';
|
||||||
|
|
||||||
@ -46,7 +47,7 @@ export function MetricStatEditor({
|
|||||||
if (!metricName) {
|
if (!metricName) {
|
||||||
return metricStat;
|
return metricStat;
|
||||||
}
|
}
|
||||||
await datasource.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)) {
|
if (!result.find((metric) => metric.value === metricName)) {
|
||||||
metricName = '';
|
metricName = '';
|
||||||
}
|
}
|
||||||
@ -89,15 +90,15 @@ export function MetricStatEditor({
|
|||||||
<Select
|
<Select
|
||||||
inputId={`${refId}-metric-stat-editor-select-statistic`}
|
inputId={`${refId}-metric-stat-editor-select-statistic`}
|
||||||
allowCustomValue
|
allowCustomValue
|
||||||
value={toOption(metricStat.statistic ?? datasource.standardStatistics[0])}
|
value={toOption(metricStat.statistic ?? standardStatistics[0])}
|
||||||
options={appendTemplateVariables(
|
options={appendTemplateVariables(
|
||||||
datasource,
|
datasource,
|
||||||
datasource.standardStatistics.filter((s) => s !== metricStat.statistic).map(toOption)
|
standardStatistics.filter((s) => s !== metricStat.statistic).map(toOption)
|
||||||
)}
|
)}
|
||||||
onChange={({ value: statistic }) => {
|
onChange={({ value: statistic }) => {
|
||||||
if (
|
if (
|
||||||
!statistic ||
|
!statistic ||
|
||||||
(!datasource.standardStatistics.includes(statistic) &&
|
(!standardStatistics.includes(statistic) &&
|
||||||
!/^p\d{2}(?:\.\d{1,2})?$/.test(statistic) &&
|
!/^p\d{2}(?:\.\d{1,2})?$/.test(statistic) &&
|
||||||
!statistic.startsWith('$'))
|
!statistic.startsWith('$'))
|
||||||
) {
|
) {
|
||||||
|
@ -46,10 +46,10 @@ const setup = () => {
|
|||||||
|
|
||||||
const datasource = new CloudWatchDatasource(instanceSettings, templateSrv as any, {} as any);
|
const datasource = new CloudWatchDatasource(instanceSettings, templateSrv as any, {} as any);
|
||||||
datasource.metricFindQuery = async () => [{ value: 'test', label: 'test', text: 'test' }];
|
datasource.metricFindQuery = async () => [{ value: 'test', label: 'test', text: 'test' }];
|
||||||
datasource.getNamespaces = jest.fn().mockResolvedValue([]);
|
datasource.api.getNamespaces = jest.fn().mockResolvedValue([]);
|
||||||
datasource.getMetrics = jest.fn().mockResolvedValue([]);
|
datasource.api.getMetrics = jest.fn().mockResolvedValue([]);
|
||||||
datasource.getRegions = jest.fn().mockResolvedValue([]);
|
datasource.api.getRegions = jest.fn().mockResolvedValue([]);
|
||||||
datasource.getDimensionKeys = jest.fn().mockResolvedValue([]);
|
datasource.api.getDimensionKeys = jest.fn().mockResolvedValue([]);
|
||||||
|
|
||||||
const props: Props = {
|
const props: Props = {
|
||||||
query: {
|
query: {
|
||||||
@ -150,7 +150,7 @@ describe('QueryEditor', () => {
|
|||||||
if (props.query.queryMode !== 'Metrics') {
|
if (props.query.queryMode !== 'Metrics') {
|
||||||
fail(`expected props.query.queryMode to be 'Metrics', got '${props.query.queryMode}' instead`);
|
fail(`expected props.query.queryMode to be 'Metrics', got '${props.query.queryMode}' instead`);
|
||||||
}
|
}
|
||||||
props.datasource.getDimensionValues = jest.fn().mockResolvedValue([[{ label: 'dimVal1', value: 'dimVal1' }]]);
|
props.datasource.api.getDimensionValues = jest.fn().mockResolvedValue([[{ label: 'dimVal1', value: 'dimVal1' }]]);
|
||||||
props.query.metricQueryType = MetricQueryType.Search;
|
props.query.metricQueryType = MetricQueryType.Search;
|
||||||
props.query.metricEditorMode = MetricEditorMode.Builder;
|
props.query.metricEditorMode = MetricEditorMode.Builder;
|
||||||
props.query.dimensions = { instanceId: 'instance-123' };
|
props.query.dimensions = { instanceId: 'instance-123' };
|
||||||
|
@ -10,7 +10,7 @@ import MetricsQueryHeader from './MetricsQueryHeader';
|
|||||||
const ds = setupMockedDataSource({
|
const ds = setupMockedDataSource({
|
||||||
variables: [],
|
variables: [],
|
||||||
});
|
});
|
||||||
ds.datasource.getRegions = jest.fn().mockResolvedValue([]);
|
ds.datasource.api.getRegions = jest.fn().mockResolvedValue([]);
|
||||||
const query: CloudWatchMetricsQuery = {
|
const query: CloudWatchMetricsQuery = {
|
||||||
id: '',
|
id: '',
|
||||||
region: 'us-east-2',
|
region: 'us-east-2',
|
||||||
|
@ -9,7 +9,7 @@ import QueryHeader from './QueryHeader';
|
|||||||
const ds = setupMockedDataSource({
|
const ds = setupMockedDataSource({
|
||||||
variables: [],
|
variables: [],
|
||||||
});
|
});
|
||||||
ds.datasource.getRegions = jest.fn().mockResolvedValue([]);
|
ds.datasource.api.getRegions = jest.fn().mockResolvedValue([]);
|
||||||
|
|
||||||
describe('QueryHeader', () => {
|
describe('QueryHeader', () => {
|
||||||
it('should display metric options for metrics', async () => {
|
it('should display metric options for metrics', async () => {
|
||||||
|
@ -22,10 +22,10 @@ const makeSQLQuery = (sql?: SQLExpression): CloudWatchMetricsQuery => ({
|
|||||||
|
|
||||||
describe('Cloudwatch SQLBuilderEditor', () => {
|
describe('Cloudwatch SQLBuilderEditor', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
datasource.getNamespaces = jest.fn().mockResolvedValue([]);
|
datasource.api.getNamespaces = jest.fn().mockResolvedValue([]);
|
||||||
datasource.getMetrics = jest.fn().mockResolvedValue([]);
|
datasource.api.getMetrics = jest.fn().mockResolvedValue([]);
|
||||||
datasource.getDimensionKeys = jest.fn().mockResolvedValue([]);
|
datasource.api.getDimensionKeys = jest.fn().mockResolvedValue([]);
|
||||||
datasource.getDimensionValues = jest.fn().mockResolvedValue([]);
|
datasource.api.getDimensionValues = jest.fn().mockResolvedValue([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
const baseProps = {
|
const baseProps = {
|
||||||
@ -47,7 +47,7 @@ describe('Cloudwatch SQLBuilderEditor', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
render(<SQLBuilderEditor {...baseProps} query={query} />);
|
render(<SQLBuilderEditor {...baseProps} query={query} />);
|
||||||
await waitFor(() => expect(datasource.getNamespaces).toHaveBeenCalled());
|
await waitFor(() => expect(datasource.api.getNamespaces).toHaveBeenCalled());
|
||||||
|
|
||||||
expect(screen.getByText('AWS/EC2')).toBeInTheDocument();
|
expect(screen.getByText('AWS/EC2')).toBeInTheDocument();
|
||||||
expect(screen.getByLabelText('With schema')).not.toBeChecked();
|
expect(screen.getByLabelText('With schema')).not.toBeChecked();
|
||||||
@ -68,7 +68,7 @@ describe('Cloudwatch SQLBuilderEditor', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
render(<SQLBuilderEditor {...baseProps} query={query} />);
|
render(<SQLBuilderEditor {...baseProps} query={query} />);
|
||||||
await waitFor(() => expect(datasource.getNamespaces).toHaveBeenCalled());
|
await waitFor(() => expect(datasource.api.getNamespaces).toHaveBeenCalled());
|
||||||
|
|
||||||
expect(screen.getByText('AWS/EC2')).toBeInTheDocument();
|
expect(screen.getByText('AWS/EC2')).toBeInTheDocument();
|
||||||
expect(screen.getByLabelText('With schema')).toBeChecked();
|
expect(screen.getByLabelText('With schema')).toBeChecked();
|
||||||
@ -95,7 +95,12 @@ describe('Cloudwatch SQLBuilderEditor', () => {
|
|||||||
|
|
||||||
render(<SQLBuilderEditor {...baseProps} query={query} />);
|
render(<SQLBuilderEditor {...baseProps} query={query} />);
|
||||||
await waitFor(() =>
|
await waitFor(() =>
|
||||||
expect(datasource.getDimensionKeys).toHaveBeenCalledWith('AWS/EC2', query.region, { InstanceId: null }, undefined)
|
expect(datasource.api.getDimensionKeys).toHaveBeenCalledWith(
|
||||||
|
'AWS/EC2',
|
||||||
|
query.region,
|
||||||
|
{ InstanceId: null },
|
||||||
|
undefined
|
||||||
|
)
|
||||||
);
|
);
|
||||||
expect(screen.getByText('AWS/EC2')).toBeInTheDocument();
|
expect(screen.getByText('AWS/EC2')).toBeInTheDocument();
|
||||||
expect(screen.getByLabelText('With schema')).toBeChecked();
|
expect(screen.getByLabelText('With schema')).toBeChecked();
|
||||||
@ -117,7 +122,7 @@ describe('Cloudwatch SQLBuilderEditor', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
render(<SQLBuilderEditor {...baseProps} query={query} />);
|
render(<SQLBuilderEditor {...baseProps} query={query} />);
|
||||||
await waitFor(() => expect(datasource.getNamespaces).toHaveBeenCalled());
|
await waitFor(() => expect(datasource.api.getNamespaces).toHaveBeenCalled());
|
||||||
|
|
||||||
expect(screen.getByText('AVERAGE')).toBeInTheDocument();
|
expect(screen.getByText('AVERAGE')).toBeInTheDocument();
|
||||||
expect(screen.getByText('CPUUtilization')).toBeInTheDocument();
|
expect(screen.getByText('CPUUtilization')).toBeInTheDocument();
|
||||||
@ -133,7 +138,7 @@ describe('Cloudwatch SQLBuilderEditor', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
render(<SQLBuilderEditor {...baseProps} query={query} />);
|
render(<SQLBuilderEditor {...baseProps} query={query} />);
|
||||||
await waitFor(() => expect(datasource.getNamespaces).toHaveBeenCalled());
|
await waitFor(() => expect(datasource.api.getNamespaces).toHaveBeenCalled());
|
||||||
|
|
||||||
expect(screen.getByText('AVG')).toBeInTheDocument();
|
expect(screen.getByText('AVG')).toBeInTheDocument();
|
||||||
const directionElement = screen.getByLabelText('Direction');
|
const directionElement = screen.getByLabelText('Direction');
|
||||||
@ -145,7 +150,7 @@ describe('Cloudwatch SQLBuilderEditor', () => {
|
|||||||
const query = makeSQLQuery({});
|
const query = makeSQLQuery({});
|
||||||
|
|
||||||
render(<SQLBuilderEditor {...baseProps} query={query} />);
|
render(<SQLBuilderEditor {...baseProps} query={query} />);
|
||||||
await waitFor(() => expect(datasource.getNamespaces).toHaveBeenCalled());
|
await waitFor(() => expect(datasource.api.getNamespaces).toHaveBeenCalled());
|
||||||
|
|
||||||
expect(screen.queryByText('AVG')).toBeNull();
|
expect(screen.queryByText('AVG')).toBeNull();
|
||||||
const directionElement = screen.getByLabelText('Direction');
|
const directionElement = screen.getByLabelText('Direction');
|
||||||
|
@ -60,15 +60,15 @@ const metrics = [
|
|||||||
|
|
||||||
describe('Cloudwatch SQLBuilderSelectRow', () => {
|
describe('Cloudwatch SQLBuilderSelectRow', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
datasource.getNamespaces = jest.fn().mockResolvedValue(namespaces);
|
datasource.api.getNamespaces = jest.fn().mockResolvedValue(namespaces);
|
||||||
datasource.getMetrics = jest.fn().mockResolvedValue([]);
|
datasource.api.getMetrics = jest.fn().mockResolvedValue([]);
|
||||||
datasource.getDimensionKeys = jest.fn().mockResolvedValue([]);
|
datasource.api.getDimensionKeys = jest.fn().mockResolvedValue([]);
|
||||||
datasource.getDimensionValues = jest.fn().mockResolvedValue([]);
|
datasource.api.getDimensionValues = jest.fn().mockResolvedValue([]);
|
||||||
onQueryChange.mockReset();
|
onQueryChange.mockReset();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should not reset metricName when selecting a namespace if metric exist in new namespace', async () => {
|
it('Should not reset metricName when selecting a namespace if metric exist in new namespace', async () => {
|
||||||
datasource.getMetrics = jest.fn().mockResolvedValue(metrics);
|
datasource.api.getMetrics = jest.fn().mockResolvedValue(metrics);
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
render(<SQLBuilderSelectRow {...baseProps} />);
|
render(<SQLBuilderSelectRow {...baseProps} />);
|
||||||
@ -103,7 +103,7 @@ describe('Cloudwatch SQLBuilderSelectRow', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('Should reset metricName when selecting a namespace if metric does not exist in new namespace', async () => {
|
it('Should reset metricName when selecting a namespace if metric does not exist in new namespace', async () => {
|
||||||
datasource.getMetrics = jest.fn().mockImplementation((namespace: string, region: string) => {
|
datasource.api.getMetrics = jest.fn().mockImplementation((namespace: string, region: string) => {
|
||||||
let mockMetrics =
|
let mockMetrics =
|
||||||
namespace === 'n1' && region === baseProps.query.region
|
namespace === 'n1' && region === baseProps.query.region
|
||||||
? metrics
|
? metrics
|
||||||
|
@ -62,7 +62,7 @@ const SQLBuilderSelectRow: React.FC<SQLBuilderSelectRowProps> = ({ datasource, q
|
|||||||
|
|
||||||
const validateMetricName = async (query: CloudWatchMetricsQuery) => {
|
const validateMetricName = async (query: CloudWatchMetricsQuery) => {
|
||||||
let { region, sql } = query;
|
let { region, sql } = query;
|
||||||
await datasource.getMetrics(query.namespace, region).then((result: Array<SelectableValue<string>>) => {
|
await datasource.api.getMetrics(query.namespace, region).then((result: Array<SelectableValue<string>>) => {
|
||||||
if (!result.some((metric) => metric.value === metricName)) {
|
if (!result.some((metric) => metric.value === metricName)) {
|
||||||
sql = removeMetricName(query).sql;
|
sql = removeMetricName(query).sql;
|
||||||
}
|
}
|
||||||
|
@ -108,7 +108,7 @@ const FilterItem: React.FC<FilterItemProps> = (props) => {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
return datasource
|
return datasource.api
|
||||||
.getDimensionValues(query.region, namespace, metricName, filter.property.name, {})
|
.getDimensionValues(query.region, namespace, metricName, filter.property.name, {})
|
||||||
.then((result: Array<SelectableValue<string>>) => {
|
.then((result: Array<SelectableValue<string>>) => {
|
||||||
return appendTemplateVariables(datasource, result);
|
return appendTemplateVariables(datasource, result);
|
||||||
|
@ -22,22 +22,22 @@ const defaultQuery = {
|
|||||||
|
|
||||||
const ds = setupMockedDataSource();
|
const ds = setupMockedDataSource();
|
||||||
|
|
||||||
ds.datasource.getRegions = jest.fn().mockResolvedValue([
|
ds.datasource.api.getRegions = jest.fn().mockResolvedValue([
|
||||||
{ label: 'a1', value: 'a1' },
|
{ label: 'a1', value: 'a1' },
|
||||||
{ label: 'b1', value: 'b1' },
|
{ label: 'b1', value: 'b1' },
|
||||||
{ label: 'c1', value: 'c1' },
|
{ label: 'c1', value: 'c1' },
|
||||||
]);
|
]);
|
||||||
ds.datasource.getNamespaces = jest.fn().mockResolvedValue([
|
ds.datasource.api.getNamespaces = jest.fn().mockResolvedValue([
|
||||||
{ label: 'x2', value: 'x2' },
|
{ label: 'x2', value: 'x2' },
|
||||||
{ label: 'y2', value: 'y2' },
|
{ label: 'y2', value: 'y2' },
|
||||||
{ label: 'z2', value: 'z2' },
|
{ label: 'z2', value: 'z2' },
|
||||||
]);
|
]);
|
||||||
ds.datasource.getMetrics = jest.fn().mockResolvedValue([
|
ds.datasource.api.getMetrics = jest.fn().mockResolvedValue([
|
||||||
{ label: 'h3', value: 'h3' },
|
{ label: 'h3', value: 'h3' },
|
||||||
{ label: 'i3', value: 'i3' },
|
{ label: 'i3', value: 'i3' },
|
||||||
{ label: 'j3', value: 'j3' },
|
{ label: 'j3', value: 'j3' },
|
||||||
]);
|
]);
|
||||||
ds.datasource.getDimensionKeys = jest
|
ds.datasource.api.getDimensionKeys = jest
|
||||||
.fn()
|
.fn()
|
||||||
.mockImplementation((_namespace: string, region: string, dimensionFilters?: Dimensions) => {
|
.mockImplementation((_namespace: string, region: string, dimensionFilters?: Dimensions) => {
|
||||||
if (!!dimensionFilters) {
|
if (!!dimensionFilters) {
|
||||||
@ -55,12 +55,12 @@ ds.datasource.getDimensionKeys = jest
|
|||||||
}
|
}
|
||||||
return Promise.resolve([{ label: 't4', value: 't4' }]);
|
return Promise.resolve([{ label: 't4', value: 't4' }]);
|
||||||
});
|
});
|
||||||
ds.datasource.getDimensionValues = jest.fn().mockResolvedValue([
|
ds.datasource.api.getDimensionValues = jest.fn().mockResolvedValue([
|
||||||
{ label: 'foo', value: 'foo' },
|
{ label: 'foo', value: 'foo' },
|
||||||
{ label: 'bar', value: 'bar' },
|
{ label: 'bar', value: 'bar' },
|
||||||
]);
|
]);
|
||||||
ds.datasource.getVariables = jest.fn().mockReturnValue([]);
|
ds.datasource.getVariables = jest.fn().mockReturnValue([]);
|
||||||
ds.datasource.getEc2InstanceAttribute = jest.fn().mockReturnValue([]);
|
ds.datasource.api.getEc2InstanceAttribute = jest.fn().mockReturnValue([]);
|
||||||
|
|
||||||
const onChange = jest.fn();
|
const onChange = jest.fn();
|
||||||
const defaultProps: Props = {
|
const defaultProps: Props = {
|
||||||
@ -141,7 +141,7 @@ describe('VariableEditor', () => {
|
|||||||
await select(keySelect, 'v4', {
|
await select(keySelect, 'v4', {
|
||||||
container: document.body,
|
container: document.body,
|
||||||
});
|
});
|
||||||
expect(ds.datasource.getDimensionKeys).toHaveBeenCalledWith('z2', 'a1', {}, '');
|
expect(ds.datasource.api.getDimensionKeys).toHaveBeenCalledWith('z2', 'a1', {}, '');
|
||||||
expect(onChange).toHaveBeenCalledWith({
|
expect(onChange).toHaveBeenCalledWith({
|
||||||
...defaultQuery,
|
...defaultQuery,
|
||||||
queryType: VariableQueryType.DimensionValues,
|
queryType: VariableQueryType.DimensionValues,
|
||||||
@ -224,8 +224,8 @@ describe('VariableEditor', () => {
|
|||||||
container: document.body,
|
container: document.body,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(ds.datasource.getMetrics).toHaveBeenCalledWith('z2', 'b1');
|
expect(ds.datasource.api.getMetrics).toHaveBeenCalledWith('z2', 'b1');
|
||||||
expect(ds.datasource.getDimensionKeys).toHaveBeenCalledWith('z2', 'b1');
|
expect(ds.datasource.api.getDimensionKeys).toHaveBeenCalledWith('z2', 'b1');
|
||||||
expect(props.onChange).toHaveBeenCalledWith({
|
expect(props.onChange).toHaveBeenCalledWith({
|
||||||
...defaultQuery,
|
...defaultQuery,
|
||||||
refId: 'CloudWatchVariableQueryEditor-VariableQuery',
|
refId: 'CloudWatchVariableQueryEditor-VariableQuery',
|
||||||
|
@ -65,14 +65,14 @@ export const VariableQueryEditor = ({ query, datasource, onChange }: Props) => {
|
|||||||
const sanitizeQuery = async (query: VariableQuery) => {
|
const sanitizeQuery = async (query: VariableQuery) => {
|
||||||
let { metricName, dimensionKey, dimensionFilters, namespace, region } = query;
|
let { metricName, dimensionKey, dimensionFilters, namespace, region } = query;
|
||||||
if (metricName) {
|
if (metricName) {
|
||||||
await datasource.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)) {
|
if (!result.find((metric) => metric.value === metricName)) {
|
||||||
metricName = '';
|
metricName = '';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (dimensionKey) {
|
if (dimensionKey) {
|
||||||
await datasource.getDimensionKeys(namespace, region).then((result: Array<SelectableValue<string>>) => {
|
await datasource.api.getDimensionKeys(namespace, region).then((result: Array<SelectableValue<string>>) => {
|
||||||
if (!result.find((key) => key.value === dimensionKey)) {
|
if (!result.find((key) => key.value === dimensionKey)) {
|
||||||
dimensionKey = '';
|
dimensionKey = '';
|
||||||
dimensionFilters = {};
|
dimensionFilters = {};
|
||||||
|
@ -204,7 +204,7 @@ describe('datasource', () => {
|
|||||||
describe('resource requests', () => {
|
describe('resource requests', () => {
|
||||||
it('should map resource response to metric response', async () => {
|
it('should map resource response to metric response', async () => {
|
||||||
const datasource = setupMockedDataSource().datasource;
|
const datasource = setupMockedDataSource().datasource;
|
||||||
datasource.doMetricResourceRequest = jest.fn().mockResolvedValue([
|
datasource.api.resourceRequest = jest.fn().mockResolvedValue([
|
||||||
{
|
{
|
||||||
text: 'AWS/EC2',
|
text: 'AWS/EC2',
|
||||||
value: 'CPUUtilization',
|
value: 'CPUUtilization',
|
||||||
@ -214,7 +214,7 @@ describe('datasource', () => {
|
|||||||
value: 'CPUPercentage',
|
value: 'CPUPercentage',
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
const allMetrics = await datasource.getAllMetrics('us-east-2');
|
const allMetrics = await datasource.api.getAllMetrics('us-east-2');
|
||||||
expect(allMetrics[0].metricName).toEqual('CPUUtilization');
|
expect(allMetrics[0].metricName).toEqual('CPUUtilization');
|
||||||
expect(allMetrics[0].namespace).toEqual('AWS/EC2');
|
expect(allMetrics[0].namespace).toEqual('AWS/EC2');
|
||||||
expect(allMetrics[1].metricName).toEqual('CPUPercentage');
|
expect(allMetrics[1].metricName).toEqual('CPUPercentage');
|
||||||
|
@ -18,6 +18,7 @@ import { getTemplateSrv, TemplateSrv } from 'app/features/templating/template_sr
|
|||||||
import { RowContextOptions } from '../../../features/logs/components/LogRowContextProvider';
|
import { RowContextOptions } from '../../../features/logs/components/LogRowContextProvider';
|
||||||
|
|
||||||
import { CloudWatchAnnotationSupport } from './annotationSupport';
|
import { CloudWatchAnnotationSupport } from './annotationSupport';
|
||||||
|
import { CloudWatchAPI } from './api';
|
||||||
import { SQLCompletionItemProvider } from './cloudwatch-sql/completion/CompletionItemProvider';
|
import { SQLCompletionItemProvider } from './cloudwatch-sql/completion/CompletionItemProvider';
|
||||||
import { isCloudWatchAnnotationQuery, isCloudWatchLogsQuery, isCloudWatchMetricsQuery } from './guards';
|
import { isCloudWatchAnnotationQuery, isCloudWatchLogsQuery, isCloudWatchMetricsQuery } from './guards';
|
||||||
import { CloudWatchLanguageProvider } from './language_provider';
|
import { CloudWatchLanguageProvider } from './language_provider';
|
||||||
@ -31,7 +32,6 @@ import {
|
|||||||
CloudWatchLogsQuery,
|
CloudWatchLogsQuery,
|
||||||
CloudWatchMetricsQuery,
|
CloudWatchMetricsQuery,
|
||||||
CloudWatchQuery,
|
CloudWatchQuery,
|
||||||
Dimensions,
|
|
||||||
} from './types';
|
} from './types';
|
||||||
import { CloudWatchVariableSupport } from './variables';
|
import { CloudWatchVariableSupport } from './variables';
|
||||||
|
|
||||||
@ -39,18 +39,18 @@ export class CloudWatchDatasource
|
|||||||
extends DataSourceWithBackend<CloudWatchQuery, CloudWatchJsonData>
|
extends DataSourceWithBackend<CloudWatchQuery, CloudWatchJsonData>
|
||||||
implements DataSourceWithLogsContextSupport<CloudWatchLogsQuery>
|
implements DataSourceWithLogsContextSupport<CloudWatchLogsQuery>
|
||||||
{
|
{
|
||||||
defaultRegion: any;
|
defaultRegion?: string;
|
||||||
languageProvider: CloudWatchLanguageProvider;
|
languageProvider: CloudWatchLanguageProvider;
|
||||||
sqlCompletionItemProvider: SQLCompletionItemProvider;
|
sqlCompletionItemProvider: SQLCompletionItemProvider;
|
||||||
metricMathCompletionItemProvider: MetricMathCompletionItemProvider;
|
metricMathCompletionItemProvider: MetricMathCompletionItemProvider;
|
||||||
|
|
||||||
type = 'cloudwatch';
|
type = 'cloudwatch';
|
||||||
standardStatistics = ['Average', 'Maximum', 'Minimum', 'Sum', 'SampleCount'];
|
|
||||||
|
|
||||||
private metricsQueryRunner: CloudWatchMetricsQueryRunner;
|
private metricsQueryRunner: CloudWatchMetricsQueryRunner;
|
||||||
private annotationQueryRunner: CloudWatchAnnotationQueryRunner;
|
private annotationQueryRunner: CloudWatchAnnotationQueryRunner;
|
||||||
// this member should be private too, but we need to fix https://github.com/grafana/grafana/issues/55243 to enable that
|
// this member should be private too, but we need to fix https://github.com/grafana/grafana/issues/55243 to enable that
|
||||||
logsQueryRunner: CloudWatchLogsQueryRunner;
|
logsQueryRunner: CloudWatchLogsQueryRunner;
|
||||||
|
api: CloudWatchAPI;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
instanceSettings: DataSourceInstanceSettings<CloudWatchJsonData>,
|
instanceSettings: DataSourceInstanceSettings<CloudWatchJsonData>,
|
||||||
@ -59,18 +59,17 @@ export class CloudWatchDatasource
|
|||||||
) {
|
) {
|
||||||
super(instanceSettings);
|
super(instanceSettings);
|
||||||
this.defaultRegion = instanceSettings.jsonData.defaultRegion;
|
this.defaultRegion = instanceSettings.jsonData.defaultRegion;
|
||||||
|
this.api = new CloudWatchAPI(instanceSettings, templateSrv);
|
||||||
this.languageProvider = new CloudWatchLanguageProvider(this);
|
this.languageProvider = new CloudWatchLanguageProvider(this);
|
||||||
this.sqlCompletionItemProvider = new SQLCompletionItemProvider(this, this.templateSrv);
|
this.sqlCompletionItemProvider = new SQLCompletionItemProvider(this.api, this.templateSrv);
|
||||||
this.metricMathCompletionItemProvider = new MetricMathCompletionItemProvider(this, this.templateSrv);
|
this.metricMathCompletionItemProvider = new MetricMathCompletionItemProvider(this.api, this.templateSrv);
|
||||||
this.variables = new CloudWatchVariableSupport(this);
|
|
||||||
this.annotations = CloudWatchAnnotationSupport;
|
|
||||||
this.metricsQueryRunner = new CloudWatchMetricsQueryRunner(instanceSettings, templateSrv);
|
this.metricsQueryRunner = new CloudWatchMetricsQueryRunner(instanceSettings, templateSrv);
|
||||||
this.logsQueryRunner = new CloudWatchLogsQueryRunner(instanceSettings, templateSrv, timeSrv);
|
this.logsQueryRunner = new CloudWatchLogsQueryRunner(instanceSettings, templateSrv, timeSrv);
|
||||||
this.annotationQueryRunner = new CloudWatchAnnotationQueryRunner(instanceSettings, templateSrv);
|
this.annotationQueryRunner = new CloudWatchAnnotationQueryRunner(instanceSettings, templateSrv);
|
||||||
|
this.variables = new CloudWatchVariableSupport(this.api, this.logsQueryRunner);
|
||||||
|
this.annotations = CloudWatchAnnotationSupport;
|
||||||
}
|
}
|
||||||
|
|
||||||
// datasource api
|
|
||||||
|
|
||||||
filterQuery(query: CloudWatchQuery) {
|
filterQuery(query: CloudWatchQuery) {
|
||||||
return query.hide !== true || (isCloudWatchMetricsQuery(query) && query.id !== '');
|
return query.hide !== true || (isCloudWatchMetricsQuery(query) && query.id !== '');
|
||||||
}
|
}
|
||||||
@ -79,18 +78,31 @@ export class CloudWatchDatasource
|
|||||||
options = cloneDeep(options);
|
options = cloneDeep(options);
|
||||||
|
|
||||||
let queries = options.targets.filter(this.filterQuery);
|
let queries = options.targets.filter(this.filterQuery);
|
||||||
const { logQueries, metricsQueries, annotationQueries } = getTargetsByQueryMode(queries);
|
|
||||||
|
const logQueries: CloudWatchLogsQuery[] = [];
|
||||||
|
const metricsQueries: CloudWatchMetricsQuery[] = [];
|
||||||
|
const annotationQueries: CloudWatchAnnotationQuery[] = [];
|
||||||
|
|
||||||
|
queries.forEach((query) => {
|
||||||
|
if (isCloudWatchAnnotationQuery(query)) {
|
||||||
|
annotationQueries.push(query);
|
||||||
|
} else if (isCloudWatchLogsQuery(query)) {
|
||||||
|
logQueries.push(query);
|
||||||
|
} else {
|
||||||
|
metricsQueries.push(query);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const dataQueryResponses: Array<Observable<DataQueryResponse>> = [];
|
const dataQueryResponses: Array<Observable<DataQueryResponse>> = [];
|
||||||
if (logQueries.length > 0) {
|
if (logQueries.length) {
|
||||||
dataQueryResponses.push(this.logsQueryRunner.handleLogQueries(logQueries, options));
|
dataQueryResponses.push(this.logsQueryRunner.handleLogQueries(logQueries, options));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (metricsQueries.length > 0) {
|
if (metricsQueries.length) {
|
||||||
dataQueryResponses.push(this.metricsQueryRunner.handleMetricQueries(metricsQueries, options));
|
dataQueryResponses.push(this.metricsQueryRunner.handleMetricQueries(metricsQueries, options));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (annotationQueries.length > 0) {
|
if (annotationQueries.length) {
|
||||||
dataQueryResponses.push(this.annotationQueryRunner.handleAnnotationQuery(annotationQueries, options));
|
dataQueryResponses.push(this.annotationQueryRunner.handleAnnotationQuery(annotationQueries, options));
|
||||||
}
|
}
|
||||||
// No valid targets, return the empty result to save a round trip.
|
// No valid targets, return the empty result to save a round trip.
|
||||||
@ -111,8 +123,9 @@ export class CloudWatchDatasource
|
|||||||
|
|
||||||
return queries.map((query) => ({
|
return queries.map((query) => ({
|
||||||
...query,
|
...query,
|
||||||
region: this.getActualRegion(
|
region: this.metricsQueryRunner.replaceVariableAndDisplayWarningIfMulti(
|
||||||
this.metricsQueryRunner.replaceVariableAndDisplayWarningIfMulti(query.region, scopedVars)
|
this.getActualRegion(query.region),
|
||||||
|
scopedVars
|
||||||
),
|
),
|
||||||
...(isCloudWatchMetricsQuery(query) &&
|
...(isCloudWatchMetricsQuery(query) &&
|
||||||
this.metricsQueryRunner.interpolateMetricsQueryVariables(query, scopedVars)),
|
this.metricsQueryRunner.interpolateMetricsQueryVariables(query, scopedVars)),
|
||||||
@ -155,134 +168,10 @@ export class CloudWatchDatasource
|
|||||||
return this.templateSrv.getVariables().map((v) => `$${v.name}`);
|
return this.templateSrv.getVariables().map((v) => `$${v.name}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
getDefaultRegion() {
|
|
||||||
return this.defaultRegion;
|
|
||||||
}
|
|
||||||
|
|
||||||
getActualRegion(region?: string) {
|
getActualRegion(region?: string) {
|
||||||
if (region === 'default' || region === undefined || region === '') {
|
if (region === 'default' || region === undefined || region === '') {
|
||||||
return this.getDefaultRegion();
|
return this.defaultRegion;
|
||||||
}
|
}
|
||||||
return region;
|
return region;
|
||||||
}
|
}
|
||||||
|
|
||||||
doMetricResourceRequest(subtype: string, parameters?: any): Promise<Array<{ text: any; label: any; value: any }>> {
|
|
||||||
return this.getResource(subtype, parameters);
|
|
||||||
}
|
|
||||||
|
|
||||||
// resource requests
|
|
||||||
getRegions(): Promise<Array<{ label: string; value: string; text: string }>> {
|
|
||||||
return this.doMetricResourceRequest('regions').then((regions: any) => [
|
|
||||||
{ label: 'default', value: 'default', text: 'default' },
|
|
||||||
...regions,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
getNamespaces() {
|
|
||||||
return this.doMetricResourceRequest('namespaces');
|
|
||||||
}
|
|
||||||
|
|
||||||
async getMetrics(namespace: string | undefined, region?: string) {
|
|
||||||
if (!namespace) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.doMetricResourceRequest('metrics', {
|
|
||||||
region: this.templateSrv.replace(this.getActualRegion(region)),
|
|
||||||
namespace: this.templateSrv.replace(namespace),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async getAllMetrics(region: string): Promise<Array<{ metricName: string; namespace: string }>> {
|
|
||||||
const values = await this.doMetricResourceRequest('all-metrics', {
|
|
||||||
region: this.templateSrv.replace(this.getActualRegion(region)),
|
|
||||||
});
|
|
||||||
|
|
||||||
return values.map((v) => ({ metricName: v.value, namespace: v.text }));
|
|
||||||
}
|
|
||||||
|
|
||||||
async getDimensionKeys(
|
|
||||||
namespace: string | undefined,
|
|
||||||
region: string,
|
|
||||||
dimensionFilters: Dimensions = {},
|
|
||||||
metricName = ''
|
|
||||||
) {
|
|
||||||
if (!namespace) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.doMetricResourceRequest('dimension-keys', {
|
|
||||||
region: this.templateSrv.replace(this.getActualRegion(region)),
|
|
||||||
namespace: this.templateSrv.replace(namespace),
|
|
||||||
dimensionFilters: JSON.stringify(this.metricsQueryRunner.convertDimensionFormat(dimensionFilters, {})),
|
|
||||||
metricName,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async getDimensionValues(
|
|
||||||
region: string,
|
|
||||||
namespace: string | undefined,
|
|
||||||
metricName: string | undefined,
|
|
||||||
dimensionKey: string,
|
|
||||||
filterDimensions: {}
|
|
||||||
) {
|
|
||||||
if (!namespace || !metricName) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
const values = await this.doMetricResourceRequest('dimension-values', {
|
|
||||||
region: this.templateSrv.replace(this.getActualRegion(region)),
|
|
||||||
namespace: this.templateSrv.replace(namespace),
|
|
||||||
metricName: this.templateSrv.replace(metricName.trim()),
|
|
||||||
dimensionKey: this.templateSrv.replace(dimensionKey),
|
|
||||||
dimensions: JSON.stringify(this.metricsQueryRunner.convertDimensionFormat(filterDimensions, {})),
|
|
||||||
});
|
|
||||||
|
|
||||||
return values;
|
|
||||||
}
|
|
||||||
|
|
||||||
getEbsVolumeIds(region: string, instanceId: string) {
|
|
||||||
return this.doMetricResourceRequest('ebs-volume-ids', {
|
|
||||||
region: this.templateSrv.replace(this.getActualRegion(region)),
|
|
||||||
instanceId: this.templateSrv.replace(instanceId),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getEc2InstanceAttribute(region: string, attributeName: string, filters: any) {
|
|
||||||
return this.doMetricResourceRequest('ec2-instance-attribute', {
|
|
||||||
region: this.templateSrv.replace(this.getActualRegion(region)),
|
|
||||||
attributeName: this.templateSrv.replace(attributeName),
|
|
||||||
filters: JSON.stringify(this.metricsQueryRunner.convertMultiFilterFormat(filters, 'filter key')),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getResourceARNs(region: string, resourceType: string, tags: any) {
|
|
||||||
return this.doMetricResourceRequest('resource-arns', {
|
|
||||||
region: this.templateSrv.replace(this.getActualRegion(region)),
|
|
||||||
resourceType: this.templateSrv.replace(resourceType),
|
|
||||||
tags: JSON.stringify(this.metricsQueryRunner.convertMultiFilterFormat(tags, 'tag name')),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getTargetsByQueryMode(targets: CloudWatchQuery[]) {
|
|
||||||
const logQueries: CloudWatchLogsQuery[] = [];
|
|
||||||
const metricsQueries: CloudWatchMetricsQuery[] = [];
|
|
||||||
const annotationQueries: CloudWatchAnnotationQuery[] = [];
|
|
||||||
|
|
||||||
targets.forEach((query) => {
|
|
||||||
if (isCloudWatchAnnotationQuery(query)) {
|
|
||||||
annotationQueries.push(query);
|
|
||||||
} else if (isCloudWatchLogsQuery(query)) {
|
|
||||||
logQueries.push(query);
|
|
||||||
} else {
|
|
||||||
metricsQueries.push(query);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
logQueries,
|
|
||||||
metricsQueries,
|
|
||||||
annotationQueries,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ export const useRegions = (datasource: CloudWatchDatasource): [Array<SelectableV
|
|||||||
options: datasource.getVariables().map(toOption),
|
options: datasource.getVariables().map(toOption),
|
||||||
};
|
};
|
||||||
|
|
||||||
datasource
|
datasource.api
|
||||||
.getRegions()
|
.getRegions()
|
||||||
.then((regions: Array<SelectableValue<string>>) => setRegions([...regions, variableOptionGroup]))
|
.then((regions: Array<SelectableValue<string>>) => setRegions([...regions, variableOptionGroup]))
|
||||||
.finally(() => setRegionsIsLoading(false));
|
.finally(() => setRegionsIsLoading(false));
|
||||||
@ -31,7 +31,7 @@ export const useRegions = (datasource: CloudWatchDatasource): [Array<SelectableV
|
|||||||
export const useNamespaces = (datasource: CloudWatchDatasource) => {
|
export const useNamespaces = (datasource: CloudWatchDatasource) => {
|
||||||
const [namespaces, setNamespaces] = useState<Array<SelectableValue<string>>>([]);
|
const [namespaces, setNamespaces] = useState<Array<SelectableValue<string>>>([]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
datasource.getNamespaces().then((namespaces) => {
|
datasource.api.getNamespaces().then((namespaces) => {
|
||||||
setNamespaces(appendTemplateVariables(datasource, namespaces));
|
setNamespaces(appendTemplateVariables(datasource, namespaces));
|
||||||
});
|
});
|
||||||
}, [datasource]);
|
}, [datasource]);
|
||||||
@ -42,7 +42,7 @@ export const useNamespaces = (datasource: CloudWatchDatasource) => {
|
|||||||
export const useMetrics = (datasource: CloudWatchDatasource, region: string, namespace: string | undefined) => {
|
export const useMetrics = (datasource: CloudWatchDatasource, region: string, namespace: string | undefined) => {
|
||||||
const [metrics, setMetrics] = useState<Array<SelectableValue<string>>>([]);
|
const [metrics, setMetrics] = useState<Array<SelectableValue<string>>>([]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
datasource.getMetrics(namespace, region).then((result: Array<SelectableValue<string>>) => {
|
datasource.api.getMetrics(namespace, region).then((result: Array<SelectableValue<string>>) => {
|
||||||
setMetrics(appendTemplateVariables(datasource, result));
|
setMetrics(appendTemplateVariables(datasource, result));
|
||||||
});
|
});
|
||||||
}, [datasource, region, namespace]);
|
}, [datasource, region, namespace]);
|
||||||
@ -61,7 +61,7 @@ export const useDimensionKeys = (
|
|||||||
|
|
||||||
// doing deep comparison to avoid making new api calls to list metrics unless dimension filter object props changes
|
// doing deep comparison to avoid making new api calls to list metrics unless dimension filter object props changes
|
||||||
useDeepCompareEffect(() => {
|
useDeepCompareEffect(() => {
|
||||||
datasource
|
datasource.api
|
||||||
.getDimensionKeys(namespace, region, dimensionFilter, metricName)
|
.getDimensionKeys(namespace, region, dimensionFilter, metricName)
|
||||||
.then((result: Array<SelectableValue<string>>) => {
|
.then((result: Array<SelectableValue<string>>) => {
|
||||||
setDimensionKeys(appendTemplateVariables(datasource, result));
|
setDimensionKeys(appendTemplateVariables(datasource, result));
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { getTemplateSrv } from '@grafana/runtime';
|
|
||||||
import { Monaco, monacoTypes } from '@grafana/ui';
|
import { Monaco, monacoTypes } from '@grafana/ui';
|
||||||
|
|
||||||
|
import { setupMockedTemplateService } from '../../__mocks__/CloudWatchDataSource';
|
||||||
import * as MetricMathTestData from '../../__mocks__/metric-math-test-data';
|
import * as MetricMathTestData from '../../__mocks__/metric-math-test-data';
|
||||||
import MonacoMock from '../../__mocks__/monarch/Monaco';
|
import MonacoMock from '../../__mocks__/monarch/Monaco';
|
||||||
import TextModel from '../../__mocks__/monarch/TextModel';
|
import TextModel from '../../__mocks__/monarch/TextModel';
|
||||||
import { CloudWatchDatasource } from '../../datasource';
|
import { CloudWatchAPI } from '../../api';
|
||||||
import cloudWatchMetricMathLanguageDefinition from '../definition';
|
import cloudWatchMetricMathLanguageDefinition from '../definition';
|
||||||
import {
|
import {
|
||||||
METRIC_MATH_FNS,
|
METRIC_MATH_FNS,
|
||||||
@ -19,10 +19,9 @@ import { MetricMathCompletionItemProvider } from './CompletionItemProvider';
|
|||||||
const getSuggestions = async (value: string, position: monacoTypes.IPosition) => {
|
const getSuggestions = async (value: string, position: monacoTypes.IPosition) => {
|
||||||
const setup = new MetricMathCompletionItemProvider(
|
const setup = new MetricMathCompletionItemProvider(
|
||||||
{
|
{
|
||||||
getVariables: () => [],
|
|
||||||
getActualRegion: () => 'us-east-2',
|
getActualRegion: () => 'us-east-2',
|
||||||
} as any as CloudWatchDatasource,
|
} as CloudWatchAPI,
|
||||||
getTemplateSrv()
|
setupMockedTemplateService([])
|
||||||
);
|
);
|
||||||
const monaco = MonacoMock as Monaco;
|
const monaco = MonacoMock as Monaco;
|
||||||
const provider = setup.getCompletionProvider(monaco, cloudWatchMetricMathLanguageDefinition);
|
const provider = setup.getCompletionProvider(monaco, cloudWatchMetricMathLanguageDefinition);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { getTemplateSrv, TemplateSrv } from '@grafana/runtime';
|
import { getTemplateSrv, TemplateSrv } from '@grafana/runtime';
|
||||||
import type { Monaco, monacoTypes } from '@grafana/ui';
|
import type { Monaco, monacoTypes } from '@grafana/ui';
|
||||||
|
|
||||||
import { CloudWatchDatasource } from '../../datasource';
|
import { CloudWatchAPI } from '../../api';
|
||||||
import { CompletionItemProvider } from '../../monarch/CompletionItemProvider';
|
import { CompletionItemProvider } from '../../monarch/CompletionItemProvider';
|
||||||
import { LinkedToken } from '../../monarch/LinkedToken';
|
import { LinkedToken } from '../../monarch/LinkedToken';
|
||||||
import { TRIGGER_SUGGEST } from '../../monarch/commands';
|
import { TRIGGER_SUGGEST } from '../../monarch/commands';
|
||||||
@ -21,8 +21,8 @@ import { MetricMathTokenTypes } from './types';
|
|||||||
type CompletionItem = monacoTypes.languages.CompletionItem;
|
type CompletionItem = monacoTypes.languages.CompletionItem;
|
||||||
|
|
||||||
export class MetricMathCompletionItemProvider extends CompletionItemProvider {
|
export class MetricMathCompletionItemProvider extends CompletionItemProvider {
|
||||||
constructor(datasource: CloudWatchDatasource, templateSrv: TemplateSrv = getTemplateSrv()) {
|
constructor(api: CloudWatchAPI, templateSrv: TemplateSrv = getTemplateSrv()) {
|
||||||
super(datasource, templateSrv);
|
super(api, templateSrv);
|
||||||
this.getStatementPosition = getStatementPosition;
|
this.getStatementPosition = getStatementPosition;
|
||||||
this.getSuggestionKinds = getSuggestionKinds;
|
this.getSuggestionKinds = getSuggestionKinds;
|
||||||
this.tokenTypes = MetricMathTokenTypes;
|
this.tokenTypes = MetricMathTokenTypes;
|
||||||
@ -110,11 +110,12 @@ export class MetricMathCompletionItemProvider extends CompletionItemProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// always suggest template variables
|
// always suggest template variables
|
||||||
this.templateVariables.map((v) => {
|
this.templateSrv.getVariables().map((v) => {
|
||||||
addSuggestion(v, {
|
const variable = `$${v.name}`;
|
||||||
|
addSuggestion(variable, {
|
||||||
range,
|
range,
|
||||||
label: v,
|
label: variable,
|
||||||
insertText: v,
|
insertText: variable,
|
||||||
kind: monaco.languages.CompletionItemKind.Variable,
|
kind: monaco.languages.CompletionItemKind.Variable,
|
||||||
sortText: CompletionItemPriority.Low,
|
sortText: CompletionItemPriority.Low,
|
||||||
});
|
});
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { getTemplateSrv, TemplateSrv } from '@grafana/runtime';
|
import { getTemplateSrv, TemplateSrv } from '@grafana/runtime';
|
||||||
import type { Monaco, monacoTypes } from '@grafana/ui';
|
import type { Monaco, monacoTypes } from '@grafana/ui';
|
||||||
|
|
||||||
import { CloudWatchDatasource } from '../datasource';
|
import { CloudWatchAPI } from '../api';
|
||||||
|
|
||||||
import { LinkedToken } from './LinkedToken';
|
import { LinkedToken } from './LinkedToken';
|
||||||
import { linkedTokenBuilder } from './linkedTokenBuilder';
|
import { linkedTokenBuilder } from './linkedTokenBuilder';
|
||||||
@ -18,15 +18,13 @@ CompletionItemProvider is an extendable class which needs to implement :
|
|||||||
- getSuggestions
|
- getSuggestions
|
||||||
*/
|
*/
|
||||||
export class CompletionItemProvider implements Completeable {
|
export class CompletionItemProvider implements Completeable {
|
||||||
templateVariables: string[];
|
api: CloudWatchAPI;
|
||||||
datasource: CloudWatchDatasource;
|
|
||||||
templateSrv: TemplateSrv;
|
templateSrv: TemplateSrv;
|
||||||
tokenTypes: TokenTypes;
|
tokenTypes: TokenTypes;
|
||||||
|
|
||||||
constructor(datasource: CloudWatchDatasource, templateSrv: TemplateSrv = getTemplateSrv()) {
|
constructor(api: CloudWatchAPI, templateSrv: TemplateSrv = getTemplateSrv()) {
|
||||||
this.datasource = datasource;
|
this.api = api;
|
||||||
this.templateSrv = templateSrv;
|
this.templateSrv = templateSrv;
|
||||||
this.templateVariables = this.datasource.getVariables();
|
|
||||||
this.templateSrv = templateSrv;
|
this.templateSrv = templateSrv;
|
||||||
|
|
||||||
// implement with more specific tokens when extending this class
|
// implement with more specific tokens when extending this class
|
||||||
|
@ -6,10 +6,10 @@ import { TemplateSrv } from 'app/features/templating/template_srv';
|
|||||||
|
|
||||||
import { CloudWatchAnnotationQuery, CloudWatchJsonData, CloudWatchQuery } from '../types';
|
import { CloudWatchAnnotationQuery, CloudWatchJsonData, CloudWatchQuery } from '../types';
|
||||||
|
|
||||||
import { CloudWatchQueryRunner } from './CloudWatchQueryRunner';
|
import { CloudWatchRequest } from './CloudWatchRequest';
|
||||||
|
|
||||||
// This class handles execution of CloudWatch annotation queries
|
// This class handles execution of CloudWatch annotation queries
|
||||||
export class CloudWatchAnnotationQueryRunner extends CloudWatchQueryRunner {
|
export class CloudWatchAnnotationQueryRunner extends CloudWatchRequest {
|
||||||
constructor(instanceSettings: DataSourceInstanceSettings<CloudWatchJsonData>, templateSrv: TemplateSrv) {
|
constructor(instanceSettings: DataSourceInstanceSettings<CloudWatchJsonData>, templateSrv: TemplateSrv) {
|
||||||
super(instanceSettings, templateSrv);
|
super(instanceSettings, templateSrv);
|
||||||
}
|
}
|
||||||
|
@ -51,13 +51,13 @@ import { addDataLinksToLogsResponse } from '../utils/datalinks';
|
|||||||
import { runWithRetry } from '../utils/logsRetry';
|
import { runWithRetry } from '../utils/logsRetry';
|
||||||
import { increasingInterval } from '../utils/rxjs/increasingInterval';
|
import { increasingInterval } from '../utils/rxjs/increasingInterval';
|
||||||
|
|
||||||
import { CloudWatchQueryRunner } from './CloudWatchQueryRunner';
|
import { CloudWatchRequest } from './CloudWatchRequest';
|
||||||
|
|
||||||
export const LOG_IDENTIFIER_INTERNAL = '__log__grafana_internal__';
|
export const LOG_IDENTIFIER_INTERNAL = '__log__grafana_internal__';
|
||||||
export const LOGSTREAM_IDENTIFIER_INTERNAL = '__logstream__grafana_internal__';
|
export const LOGSTREAM_IDENTIFIER_INTERNAL = '__logstream__grafana_internal__';
|
||||||
|
|
||||||
// This class handles execution of CloudWatch logs query data queries
|
// This class handles execution of CloudWatch logs query data queries
|
||||||
export class CloudWatchLogsQueryRunner extends CloudWatchQueryRunner {
|
export class CloudWatchLogsQueryRunner extends CloudWatchRequest {
|
||||||
logsTimeout: string;
|
logsTimeout: string;
|
||||||
defaultLogGroups: string[];
|
defaultLogGroups: string[];
|
||||||
logQueries: Record<string, { id: string; region: string; statsQuery: boolean }> = {};
|
logQueries: Record<string, { id: string; region: string; statsQuery: boolean }> = {};
|
||||||
|
@ -34,7 +34,7 @@ import {
|
|||||||
MetricRequest,
|
MetricRequest,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
|
|
||||||
import { CloudWatchQueryRunner } from './CloudWatchQueryRunner';
|
import { CloudWatchRequest } from './CloudWatchRequest';
|
||||||
|
|
||||||
const displayAlert = (datasourceName: string, region: string) =>
|
const displayAlert = (datasourceName: string, region: string) =>
|
||||||
store.dispatch(
|
store.dispatch(
|
||||||
@ -47,9 +47,8 @@ const displayAlert = (datasourceName: string, region: string) =>
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
// This class handles execution of CloudWatch metrics query data queries
|
// This class handles execution of CloudWatch metrics query data queries
|
||||||
export class CloudWatchMetricsQueryRunner extends CloudWatchQueryRunner {
|
export class CloudWatchMetricsQueryRunner extends CloudWatchRequest {
|
||||||
debouncedAlert: (datasourceName: string, region: string) => void = memoizedDebounce(
|
debouncedAlert: (datasourceName: string, region: string) => void = memoizedDebounce(
|
||||||
displayAlert,
|
displayAlert,
|
||||||
AppNotificationTimeout.Error
|
AppNotificationTimeout.Error
|
||||||
|
@ -11,7 +11,7 @@ import { AppNotificationTimeout } from 'app/types';
|
|||||||
import memoizedDebounce from '../memoizedDebounce';
|
import memoizedDebounce from '../memoizedDebounce';
|
||||||
import { CloudWatchJsonData, Dimensions, MetricRequest, MultiFilters, TSDBResponse } from '../types';
|
import { CloudWatchJsonData, Dimensions, MetricRequest, MultiFilters, TSDBResponse } from '../types';
|
||||||
|
|
||||||
export abstract class CloudWatchQueryRunner {
|
export abstract class CloudWatchRequest {
|
||||||
templateSrv: TemplateSrv;
|
templateSrv: TemplateSrv;
|
||||||
ref: DataSourceRef;
|
ref: DataSourceRef;
|
||||||
dsQueryEndpoint = '/api/ds/query';
|
dsQueryEndpoint = '/api/ds/query';
|
@ -0,0 +1 @@
|
|||||||
|
export const standardStatistics = ['Average', 'Maximum', 'Minimum', 'Sum', 'SampleCount'];
|
@ -14,18 +14,18 @@ const defaultQuery: VariableQuery = {
|
|||||||
refId: '',
|
refId: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
const ds = setupMockedDataSource({ variables: [labelsVariable, dimensionVariable] });
|
const mock = setupMockedDataSource({ variables: [labelsVariable, dimensionVariable] });
|
||||||
ds.datasource.getRegions = jest.fn().mockResolvedValue([{ label: 'a', value: 'a' }]);
|
mock.datasource.api.getRegions = jest.fn().mockResolvedValue([{ label: 'a', value: 'a' }]);
|
||||||
ds.datasource.getNamespaces = jest.fn().mockResolvedValue([{ label: 'b', value: 'b' }]);
|
mock.datasource.api.getNamespaces = jest.fn().mockResolvedValue([{ label: 'b', value: 'b' }]);
|
||||||
ds.datasource.getMetrics = jest.fn().mockResolvedValue([{ label: 'c', value: 'c' }]);
|
mock.datasource.api.getMetrics = jest.fn().mockResolvedValue([{ label: 'c', value: 'c' }]);
|
||||||
ds.datasource.getDimensionKeys = jest.fn().mockResolvedValue([{ label: 'd', value: 'd' }]);
|
mock.datasource.api.getDimensionKeys = jest.fn().mockResolvedValue([{ label: 'd', value: 'd' }]);
|
||||||
ds.datasource.logsQueryRunner.describeAllLogGroups = jest.fn().mockResolvedValue(['a', 'b']);
|
mock.datasource.logsQueryRunner.describeAllLogGroups = jest.fn().mockResolvedValue(['a', 'b']);
|
||||||
const getDimensionValues = jest.fn().mockResolvedValue([{ label: 'e', value: 'e' }]);
|
const getDimensionValues = jest.fn().mockResolvedValue([{ label: 'e', value: 'e' }]);
|
||||||
const getEbsVolumeIds = jest.fn().mockResolvedValue([{ label: 'f', value: 'f' }]);
|
const getEbsVolumeIds = jest.fn().mockResolvedValue([{ label: 'f', value: 'f' }]);
|
||||||
const getEc2InstanceAttribute = jest.fn().mockResolvedValue([{ label: 'g', value: 'g' }]);
|
const getEc2InstanceAttribute = jest.fn().mockResolvedValue([{ label: 'g', value: 'g' }]);
|
||||||
const getResourceARNs = jest.fn().mockResolvedValue([{ label: 'h', value: 'h' }]);
|
const getResourceARNs = jest.fn().mockResolvedValue([{ label: 'h', value: 'h' }]);
|
||||||
|
|
||||||
const variables = new CloudWatchVariableSupport(ds.datasource);
|
const variables = new CloudWatchVariableSupport(mock.datasource.api, mock.datasource.logsQueryRunner);
|
||||||
|
|
||||||
describe('variables', () => {
|
describe('variables', () => {
|
||||||
it('should run regions', async () => {
|
it('should run regions', async () => {
|
||||||
@ -57,7 +57,7 @@ describe('variables', () => {
|
|||||||
dimensionFilters: { a: 'b' },
|
dimensionFilters: { a: 'b' },
|
||||||
};
|
};
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
ds.datasource.getDimensionValues = getDimensionValues;
|
mock.datasource.api.getDimensionValues = getDimensionValues;
|
||||||
getDimensionValues.mockClear();
|
getDimensionValues.mockClear();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -87,7 +87,7 @@ describe('variables', () => {
|
|||||||
|
|
||||||
describe('EBS volume ids', () => {
|
describe('EBS volume ids', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
ds.datasource.getEbsVolumeIds = getEbsVolumeIds;
|
mock.datasource.api.getEbsVolumeIds = getEbsVolumeIds;
|
||||||
getEbsVolumeIds.mockClear();
|
getEbsVolumeIds.mockClear();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -116,7 +116,7 @@ describe('variables', () => {
|
|||||||
ec2Filters: { a: ['b'] },
|
ec2Filters: { a: ['b'] },
|
||||||
};
|
};
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
ds.datasource.getEc2InstanceAttribute = getEc2InstanceAttribute;
|
mock.datasource.api.getEc2InstanceAttribute = getEc2InstanceAttribute;
|
||||||
getEc2InstanceAttribute.mockClear();
|
getEc2InstanceAttribute.mockClear();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -141,7 +141,7 @@ describe('variables', () => {
|
|||||||
tags: { a: ['b'] },
|
tags: { a: ['b'] },
|
||||||
};
|
};
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
ds.datasource.getResourceARNs = getResourceARNs;
|
mock.datasource.api.getResourceARNs = getResourceARNs;
|
||||||
getResourceARNs.mockClear();
|
getResourceARNs.mockClear();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -3,17 +3,17 @@ import { map } from 'rxjs/operators';
|
|||||||
|
|
||||||
import { CustomVariableSupport, DataQueryRequest, DataQueryResponse } from '@grafana/data';
|
import { CustomVariableSupport, DataQueryRequest, DataQueryResponse } from '@grafana/data';
|
||||||
|
|
||||||
|
import { CloudWatchAPI } from './api';
|
||||||
import { VariableQueryEditor } from './components/VariableQueryEditor/VariableQueryEditor';
|
import { VariableQueryEditor } from './components/VariableQueryEditor/VariableQueryEditor';
|
||||||
import { CloudWatchDatasource } from './datasource';
|
import { CloudWatchDatasource } from './datasource';
|
||||||
import { migrateVariableQuery } from './migrations/variableQueryMigrations';
|
import { migrateVariableQuery } from './migrations/variableQueryMigrations';
|
||||||
|
import { CloudWatchLogsQueryRunner } from './query-runner/CloudWatchLogsQueryRunner';
|
||||||
|
import { standardStatistics } from './standardStatistics';
|
||||||
import { VariableQuery, VariableQueryType } from './types';
|
import { VariableQuery, VariableQueryType } from './types';
|
||||||
|
|
||||||
export class CloudWatchVariableSupport extends CustomVariableSupport<CloudWatchDatasource, VariableQuery> {
|
export class CloudWatchVariableSupport extends CustomVariableSupport<CloudWatchDatasource, VariableQuery> {
|
||||||
private readonly datasource: CloudWatchDatasource;
|
constructor(private readonly api: CloudWatchAPI, private readonly logsQueryRunner: CloudWatchLogsQueryRunner) {
|
||||||
|
|
||||||
constructor(datasource: CloudWatchDatasource) {
|
|
||||||
super();
|
super();
|
||||||
this.datasource = datasource;
|
|
||||||
this.query = this.query.bind(this);
|
this.query = this.query.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,7 +55,7 @@ export class CloudWatchVariableSupport extends CustomVariableSupport<CloudWatchD
|
|||||||
}
|
}
|
||||||
|
|
||||||
async handleLogGroupsQuery({ region, logGroupPrefix }: VariableQuery) {
|
async handleLogGroupsQuery({ region, logGroupPrefix }: VariableQuery) {
|
||||||
const logGroups = await this.datasource.logsQueryRunner.describeAllLogGroups({
|
const logGroups: string[] = await this.logsQueryRunner.describeAllLogGroups({
|
||||||
region,
|
region,
|
||||||
logGroupNamePrefix: logGroupPrefix,
|
logGroupNamePrefix: logGroupPrefix,
|
||||||
});
|
});
|
||||||
@ -67,7 +67,7 @@ export class CloudWatchVariableSupport extends CustomVariableSupport<CloudWatchD
|
|||||||
}
|
}
|
||||||
|
|
||||||
async handleRegionsQuery() {
|
async handleRegionsQuery() {
|
||||||
const regions = await this.datasource.getRegions();
|
const regions = await this.api.getRegions();
|
||||||
return regions.map((s: { label: string; value: string }) => ({
|
return regions.map((s: { label: string; value: string }) => ({
|
||||||
text: s.label,
|
text: s.label,
|
||||||
value: s.value,
|
value: s.value,
|
||||||
@ -76,7 +76,7 @@ export class CloudWatchVariableSupport extends CustomVariableSupport<CloudWatchD
|
|||||||
}
|
}
|
||||||
|
|
||||||
async handleNamespacesQuery() {
|
async handleNamespacesQuery() {
|
||||||
const namespaces = await this.datasource.getNamespaces();
|
const namespaces = await this.api.getNamespaces();
|
||||||
return namespaces.map((s: { label: string; value: string }) => ({
|
return namespaces.map((s: { label: string; value: string }) => ({
|
||||||
text: s.label,
|
text: s.label,
|
||||||
value: s.value,
|
value: s.value,
|
||||||
@ -85,7 +85,7 @@ export class CloudWatchVariableSupport extends CustomVariableSupport<CloudWatchD
|
|||||||
}
|
}
|
||||||
|
|
||||||
async handleMetricsQuery({ namespace, region }: VariableQuery) {
|
async handleMetricsQuery({ namespace, region }: VariableQuery) {
|
||||||
const metrics = await this.datasource.getMetrics(namespace, region);
|
const metrics = await this.api.getMetrics(namespace, region);
|
||||||
return metrics.map((s: { label: string; value: string }) => ({
|
return metrics.map((s: { label: string; value: string }) => ({
|
||||||
text: s.label,
|
text: s.label,
|
||||||
value: s.value,
|
value: s.value,
|
||||||
@ -94,7 +94,7 @@ export class CloudWatchVariableSupport extends CustomVariableSupport<CloudWatchD
|
|||||||
}
|
}
|
||||||
|
|
||||||
async handleDimensionKeysQuery({ namespace, region }: VariableQuery) {
|
async handleDimensionKeysQuery({ namespace, region }: VariableQuery) {
|
||||||
const keys = await this.datasource.getDimensionKeys(namespace, region);
|
const keys = await this.api.getDimensionKeys(namespace, region);
|
||||||
return keys.map((s: { label: string; value: string }) => ({
|
return keys.map((s: { label: string; value: string }) => ({
|
||||||
text: s.label,
|
text: s.label,
|
||||||
value: s.value,
|
value: s.value,
|
||||||
@ -106,13 +106,7 @@ export class CloudWatchVariableSupport extends CustomVariableSupport<CloudWatchD
|
|||||||
if (!dimensionKey || !metricName) {
|
if (!dimensionKey || !metricName) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
const keys = await this.datasource.getDimensionValues(
|
const keys = await this.api.getDimensionValues(region, namespace, metricName, dimensionKey, dimensionFilters ?? {});
|
||||||
region,
|
|
||||||
namespace,
|
|
||||||
metricName,
|
|
||||||
dimensionKey,
|
|
||||||
dimensionFilters ?? {}
|
|
||||||
);
|
|
||||||
return keys.map((s: { label: string; value: string }) => ({
|
return keys.map((s: { label: string; value: string }) => ({
|
||||||
text: s.label,
|
text: s.label,
|
||||||
value: s.value,
|
value: s.value,
|
||||||
@ -124,7 +118,7 @@ export class CloudWatchVariableSupport extends CustomVariableSupport<CloudWatchD
|
|||||||
if (!instanceID) {
|
if (!instanceID) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
const ids = await this.datasource.getEbsVolumeIds(region, instanceID);
|
const ids = await this.api.getEbsVolumeIds(region, instanceID);
|
||||||
return ids.map((s: { label: string; value: string }) => ({
|
return ids.map((s: { label: string; value: string }) => ({
|
||||||
text: s.label,
|
text: s.label,
|
||||||
value: s.value,
|
value: s.value,
|
||||||
@ -136,7 +130,7 @@ export class CloudWatchVariableSupport extends CustomVariableSupport<CloudWatchD
|
|||||||
if (!attributeName) {
|
if (!attributeName) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
const values = await this.datasource.getEc2InstanceAttribute(region, attributeName, ec2Filters ?? {});
|
const values = await this.api.getEc2InstanceAttribute(region, attributeName, ec2Filters ?? {});
|
||||||
return values.map((s: { label: string; value: string }) => ({
|
return values.map((s: { label: string; value: string }) => ({
|
||||||
text: s.label,
|
text: s.label,
|
||||||
value: s.value,
|
value: s.value,
|
||||||
@ -148,7 +142,7 @@ export class CloudWatchVariableSupport extends CustomVariableSupport<CloudWatchD
|
|||||||
if (!resourceType) {
|
if (!resourceType) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
const keys = await this.datasource.getResourceARNs(region, resourceType, tags ?? {});
|
const keys = await this.api.getResourceARNs(region, resourceType, tags ?? {});
|
||||||
return keys.map((s: { label: string; value: string }) => ({
|
return keys.map((s: { label: string; value: string }) => ({
|
||||||
text: s.label,
|
text: s.label,
|
||||||
value: s.value,
|
value: s.value,
|
||||||
@ -157,7 +151,7 @@ export class CloudWatchVariableSupport extends CustomVariableSupport<CloudWatchD
|
|||||||
}
|
}
|
||||||
|
|
||||||
async handleStatisticsQuery() {
|
async handleStatisticsQuery() {
|
||||||
return this.datasource.standardStatistics.map((s: string) => ({
|
return standardStatistics.map((s: string) => ({
|
||||||
text: s,
|
text: s,
|
||||||
value: s,
|
value: s,
|
||||||
expandable: true,
|
expandable: true,
|
||||||
|
Loading…
Reference in New Issue
Block a user