From f1e390ebf9053971cb62bbbbe55366bf8d024e65 Mon Sep 17 00:00:00 2001 From: Konrad Lalik Date: Wed, 18 May 2022 11:32:38 +0200 Subject: [PATCH] Alerting: Fix Loki buildinfo request error (#49073) (#49144) * Skip buildinfo fetching for Loki data sources * Fix and add tests * Fix linter * Improve typings * Improve Loki's buildinfo notice * Fix rename, improve prom app display name (cherry picked from commit 43ab0c1f957425d74905d121f390d175a7da9d26) --- .../alerting/unified/RuleEditor.test.tsx | 40 ++++++------ .../alerting/unified/RuleList.test.tsx | 26 ++++---- .../alerting/unified/api/buildInfo.test.ts | 54 +++++++++++++--- .../alerting/unified/api/buildInfo.ts | 63 ++++++++++++------- .../alerting/unified/state/actions.ts | 6 +- .../datasource/prometheus/datasource.tsx | 20 +++--- public/app/types/unified-alerting-dto.ts | 4 +- 7 files changed, 137 insertions(+), 76 deletions(-) diff --git a/public/app/features/alerting/unified/RuleEditor.test.tsx b/public/app/features/alerting/unified/RuleEditor.test.tsx index e11aefd9e36..9090abf8091 100644 --- a/public/app/features/alerting/unified/RuleEditor.test.tsx +++ b/public/app/features/alerting/unified/RuleEditor.test.tsx @@ -16,7 +16,7 @@ import { GrafanaAlertStateDecision, PromApplication } from 'app/types/unified-al import { searchFolders } from '../../../../app/features/manage-dashboards/state/actions'; import RuleEditor from './RuleEditor'; -import { fetchBuildInfo } from './api/buildInfo'; +import { discoverFeatures } from './api/buildInfo'; import { fetchRulerRules, fetchRulerRulesGroup, fetchRulerRulesNamespace, setRulerRuleGroup } from './api/ruler'; import { ExpressionEditorProps } from './components/rule-editor/ExpressionEditor'; import { mockDataSource, MockDataSourceSrv } from './mocks'; @@ -47,7 +47,7 @@ const mocks = { getAllDataSources: jest.mocked(getAllDataSources), searchFolders: jest.mocked(searchFolders), api: { - fetchBuildInfo: jest.mocked(fetchBuildInfo), + discoverFeatures: jest.mocked(discoverFeatures), fetchRulerRulesGroup: jest.mocked(fetchRulerRulesGroup), setRulerRuleGroup: jest.mocked(setRulerRuleGroup), fetchRulerRulesNamespace: jest.mocked(fetchRulerRulesNamespace), @@ -136,8 +136,8 @@ describe('RuleEditor', () => { }); mocks.searchFolders.mockResolvedValue([]); - mocks.api.fetchBuildInfo.mockResolvedValue({ - application: PromApplication.Cortex, + mocks.api.discoverFeatures.mockResolvedValue({ + application: PromApplication.Lotex, features: { rulerApiEnabled: true, }, @@ -146,9 +146,9 @@ describe('RuleEditor', () => { await renderRuleEditor(); await waitFor(() => expect(mocks.searchFolders).toHaveBeenCalled()); - await waitFor(() => expect(mocks.api.fetchBuildInfo).toHaveBeenCalled()); - userEvent.type(await ui.inputs.name.find(), 'my great new rule'); - userEvent.click(await ui.buttons.lotexAlert.get()); + await waitFor(() => expect(mocks.api.discoverFeatures).toHaveBeenCalled()); + await userEvent.type(await ui.inputs.name.find(), 'my great new rule'); + await userEvent.click(await ui.buttons.lotexAlert.get()); const dataSourceSelect = ui.inputs.dataSource.get(); userEvent.click(byRole('combobox').get(dataSourceSelect)); await clickSelectOption(dataSourceSelect, 'Prom (default)'); @@ -235,7 +235,7 @@ describe('RuleEditor', () => { }, ] as DashboardSearchHit[]); - mocks.api.fetchBuildInfo.mockResolvedValue({ + mocks.api.discoverFeatures.mockResolvedValue({ application: PromApplication.Prometheus, features: { rulerApiEnabled: false, @@ -245,7 +245,7 @@ describe('RuleEditor', () => { // fill out the form await renderRuleEditor(); await waitFor(() => expect(mocks.searchFolders).toHaveBeenCalled()); - await waitFor(() => expect(mocks.api.fetchBuildInfo).toHaveBeenCalled()); + await waitFor(() => expect(mocks.api.discoverFeatures).toHaveBeenCalled()); userEvent.type(await ui.inputs.name.find(), 'my great new rule'); @@ -329,8 +329,8 @@ describe('RuleEditor', () => { }); mocks.searchFolders.mockResolvedValue([]); - mocks.api.fetchBuildInfo.mockResolvedValue({ - application: PromApplication.Cortex, + mocks.api.discoverFeatures.mockResolvedValue({ + application: PromApplication.Lotex, features: { rulerApiEnabled: true, }, @@ -338,9 +338,9 @@ describe('RuleEditor', () => { await renderRuleEditor(); await waitFor(() => expect(mocks.searchFolders).toHaveBeenCalled()); - await waitFor(() => expect(mocks.api.fetchBuildInfo).toHaveBeenCalled()); - userEvent.type(await ui.inputs.name.find(), 'my great new recording rule'); - userEvent.click(await ui.buttons.lotexRecordingRule.get()); + await waitFor(() => expect(mocks.api.discoverFeatures).toHaveBeenCalled()); + await userEvent.type(await ui.inputs.name.find(), 'my great new recording rule'); + await userEvent.click(await ui.buttons.lotexRecordingRule.get()); const dataSourceSelect = ui.inputs.dataSource.get(); userEvent.click(byRole('combobox').get(dataSourceSelect)); @@ -449,7 +449,7 @@ describe('RuleEditor', () => { await renderRuleEditor(uid); await waitFor(() => expect(mocks.searchFolders).toHaveBeenCalled()); - await waitFor(() => expect(mocks.api.fetchBuildInfo).toHaveBeenCalled()); + await waitFor(() => expect(mocks.api.discoverFeatures).toHaveBeenCalled()); await waitFor(() => expect(mocks.searchFolders).toHaveBeenCalled()); // check that it's filled in @@ -551,10 +551,10 @@ describe('RuleEditor', () => { ), }; - mocks.api.fetchBuildInfo.mockImplementation(async (dataSourceName) => { + mocks.api.discoverFeatures.mockImplementation(async (dataSourceName) => { if (dataSourceName === 'loki with ruler' || dataSourceName === 'cortex with ruler') { return { - application: PromApplication.Cortex, + application: PromApplication.Lotex, features: { rulerApiEnabled: true, alertManagerConfigApi: false, @@ -565,7 +565,7 @@ describe('RuleEditor', () => { } if (dataSourceName === 'loki with local rule store') { return { - application: PromApplication.Cortex, + application: PromApplication.Lotex, features: { rulerApiEnabled: false, alertManagerConfigApi: false, @@ -576,7 +576,7 @@ describe('RuleEditor', () => { } if (dataSourceName === 'cortex without ruler api') { return { - application: PromApplication.Cortex, + application: PromApplication.Lotex, features: { rulerApiEnabled: false, alertManagerConfigApi: false, @@ -613,7 +613,7 @@ describe('RuleEditor', () => { // render rule editor, select mimir/loki managed alerts await renderRuleEditor(); - await waitFor(() => expect(mocks.api.fetchBuildInfo).toHaveBeenCalled()); + await waitFor(() => expect(mocks.api.discoverFeatures).toHaveBeenCalled()); await waitFor(() => expect(mocks.searchFolders).toHaveBeenCalled()); await ui.inputs.name.find(); diff --git a/public/app/features/alerting/unified/RuleList.test.tsx b/public/app/features/alerting/unified/RuleList.test.tsx index b13b738d74b..b289857095d 100644 --- a/public/app/features/alerting/unified/RuleList.test.tsx +++ b/public/app/features/alerting/unified/RuleList.test.tsx @@ -12,7 +12,7 @@ import { AccessControlAction } from 'app/types'; import { PromAlertingRuleState, PromApplication } from 'app/types/unified-alerting-dto'; import RuleList from './RuleList'; -import { fetchBuildInfo } from './api/buildInfo'; +import { discoverFeatures } from './api/buildInfo'; import { fetchRules } from './api/prometheus'; import { deleteNamespace, deleteRulerRulesGroup, fetchRulerRules, setRulerRuleGroup } from './api/ruler'; import { @@ -48,7 +48,7 @@ const mocks = { getAllDataSourcesMock: jest.mocked(getAllDataSources), api: { - fetchBuildInfo: jest.mocked(fetchBuildInfo), + discoverFeatures: jest.mocked(discoverFeatures), fetchRules: jest.mocked(fetchRules), fetchRulerRules: jest.mocked(fetchRulerRules), deleteGroup: jest.mocked(deleteRulerRulesGroup), @@ -125,7 +125,7 @@ describe('RuleList', () => { setDataSourceSrv(new MockDataSourceSrv(dataSources)); - mocks.api.fetchBuildInfo.mockResolvedValue({ + mocks.api.discoverFeatures.mockResolvedValue({ application: PromApplication.Prometheus, features: { rulerApiEnabled: true, @@ -217,8 +217,8 @@ describe('RuleList', () => { mocks.getAllDataSourcesMock.mockReturnValue([dataSources.prom]); setDataSourceSrv(new MockDataSourceSrv({ prom: dataSources.prom })); - mocks.api.fetchBuildInfo.mockResolvedValue({ - application: PromApplication.Cortex, + mocks.api.discoverFeatures.mockResolvedValue({ + application: PromApplication.Lotex, features: { rulerApiEnabled: true, }, @@ -359,8 +359,8 @@ describe('RuleList', () => { mocks.getAllDataSourcesMock.mockReturnValue([dataSources.prom]); setDataSourceSrv(new MockDataSourceSrv({ prom: dataSources.prom })); - mocks.api.fetchBuildInfo.mockResolvedValue({ - application: PromApplication.Cortex, + mocks.api.discoverFeatures.mockResolvedValue({ + application: PromApplication.Lotex, features: { rulerApiEnabled: true, }, @@ -504,8 +504,8 @@ describe('RuleList', () => { mocks.getAllDataSourcesMock.mockReturnValue(Object.values(testDatasources)); setDataSourceSrv(new MockDataSourceSrv(testDatasources)); - mocks.api.fetchBuildInfo.mockResolvedValue({ - application: PromApplication.Cortex, + mocks.api.discoverFeatures.mockResolvedValue({ + application: PromApplication.Lotex, features: { rulerApiEnabled: true, }, @@ -690,8 +690,8 @@ describe('RuleList', () => { mocks.getAllDataSourcesMock.mockReturnValue([dataSources.prom]); setDataSourceSrv(new MockDataSourceSrv({ prom: dataSources.prom })); - mocks.api.fetchBuildInfo.mockResolvedValue({ - application: PromApplication.Cortex, + mocks.api.discoverFeatures.mockResolvedValue({ + application: PromApplication.Lotex, features: { rulerApiEnabled: true, }, @@ -717,8 +717,8 @@ describe('RuleList', () => { mocks.getAllDataSourcesMock.mockReturnValue([dataSources.prom]); setDataSourceSrv(new MockDataSourceSrv({ prom: dataSources.prom })); - mocks.api.fetchBuildInfo.mockResolvedValue({ - application: PromApplication.Cortex, + mocks.api.discoverFeatures.mockResolvedValue({ + application: PromApplication.Lotex, features: { rulerApiEnabled: true, }, diff --git a/public/app/features/alerting/unified/api/buildInfo.test.ts b/public/app/features/alerting/unified/api/buildInfo.test.ts index 48ea249e8bc..1bbbafcc220 100644 --- a/public/app/features/alerting/unified/api/buildInfo.test.ts +++ b/public/app/features/alerting/unified/api/buildInfo.test.ts @@ -2,7 +2,7 @@ import { of, throwError } from 'rxjs'; import { PromApplication } from 'app/types/unified-alerting-dto'; -import { fetchDataSourceBuildInfo } from './buildInfo'; +import { discoverDataSourceFeatures } from './buildInfo'; import { fetchRules } from './prometheus'; import { fetchTestRulerRulesGroup } from './ruler'; @@ -22,7 +22,7 @@ const mocks = { beforeEach(() => jest.clearAllMocks()); -describe('buildInfo', () => { +describe('discoverDataSourceFeatures', () => { describe('When buildinfo returns 200 response', () => { it('Should return Prometheus with disabled ruler API when application and features fields are missing', async () => { fetch.mockReturnValue( @@ -36,7 +36,11 @@ describe('buildInfo', () => { }) ); - const response = await fetchDataSourceBuildInfo({ url: '/datasource/proxy', name: 'Prometheus' }); + const response = await discoverDataSourceFeatures({ + url: '/datasource/proxy', + name: 'Prometheus', + type: 'prometheus', + }); expect(response.application).toBe(PromApplication.Prometheus); expect(response.features.rulerApiEnabled).toBe(false); @@ -63,7 +67,11 @@ describe('buildInfo', () => { }) ); - const response = await fetchDataSourceBuildInfo({ url: '/datasource/proxy', name: 'Prometheus' }); + const response = await discoverDataSourceFeatures({ + url: '/datasource/proxy', + name: 'Prometheus', + type: 'prometheus', + }); expect(response.application).toBe(PromApplication.Mimir); expect(response.features.rulerApiEnabled).toBe(rulerApiEnabled); @@ -71,6 +79,28 @@ describe('buildInfo', () => { expect(mocks.fetchTestRulerRulesGroup).not.toHaveBeenCalled(); } ); + + it('When the data source is Loki should not call the buildinfo endpoint', async () => { + await discoverDataSourceFeatures({ url: '/datasource/proxy', name: 'Loki', type: 'loki' }); + + expect(fetch).not.toBeCalled(); + }); + + it('When the data source is Loki should test Prom and Ruler API endpoints to discover available features', async () => { + mocks.fetchTestRulerRulesGroup.mockResolvedValue(null); + mocks.fetchRules.mockResolvedValue([]); + + const response = await discoverDataSourceFeatures({ url: '/datasource/proxy', name: 'Loki', type: 'loki' }); + + expect(response.application).toBe(PromApplication.Lotex); + expect(response.features.rulerApiEnabled).toBe(true); + + expect(mocks.fetchTestRulerRulesGroup).toHaveBeenCalledTimes(1); + expect(mocks.fetchTestRulerRulesGroup).toHaveBeenCalledWith('Loki'); + + expect(mocks.fetchRules).toHaveBeenCalledTimes(1); + expect(mocks.fetchRules).toHaveBeenCalledWith('Loki'); + }); }); describe('When buildinfo returns 404 error', () => { @@ -89,9 +119,13 @@ describe('buildInfo', () => { }); mocks.fetchRules.mockResolvedValue([]); - const response = await fetchDataSourceBuildInfo({ url: '/datasource/proxy', name: 'Cortex' }); + const response = await discoverDataSourceFeatures({ + url: '/datasource/proxy', + name: 'Cortex', + type: 'prometheus', + }); - expect(response.application).toBe(PromApplication.Cortex); + expect(response.application).toBe(PromApplication.Lotex); expect(response.features.rulerApiEnabled).toBe(false); expect(mocks.fetchTestRulerRulesGroup).toHaveBeenCalledTimes(1); @@ -111,9 +145,13 @@ describe('buildInfo', () => { mocks.fetchTestRulerRulesGroup.mockResolvedValue(null); mocks.fetchRules.mockResolvedValue([]); - const response = await fetchDataSourceBuildInfo({ url: '/datasource/proxy', name: 'Cortex' }); + const response = await discoverDataSourceFeatures({ + url: '/datasource/proxy', + name: 'Cortex', + type: 'prometheus', + }); - expect(response.application).toBe(PromApplication.Cortex); + expect(response.application).toBe(PromApplication.Lotex); expect(response.features.rulerApiEnabled).toBe(true); expect(mocks.fetchTestRulerRulesGroup).toHaveBeenCalledTimes(1); diff --git a/public/app/features/alerting/unified/api/buildInfo.ts b/public/app/features/alerting/unified/api/buildInfo.ts index 39ef33d5940..cc5a06039a1 100644 --- a/public/app/features/alerting/unified/api/buildInfo.ts +++ b/public/app/features/alerting/unified/api/buildInfo.ts @@ -1,7 +1,7 @@ import { lastValueFrom } from 'rxjs'; import { getBackendSrv } from '@grafana/runtime'; -import { PromApplication, PromBuildInfo, PromBuildInfoResponse } from 'app/types/unified-alerting-dto'; +import { PromApplication, PromApiFeatures, PromBuildInfoResponse } from 'app/types/unified-alerting-dto'; import { isFetchError } from '../utils/alertmanager'; import { RULER_NOT_SUPPORTED_MSG } from '../utils/constants'; @@ -18,27 +18,22 @@ import { fetchTestRulerRulesGroup } from './ruler'; * Prometheus and Mimir expose a `buildinfo` endpoint, Cortex does not. * Mimir reports which "features" are enabled or available via the buildinfo endpoint, Prometheus does not. */ -export async function fetchDataSourceBuildInfo(dsSettings: { url: string; name: string }): Promise { - const { url, name } = dsSettings; +export async function discoverDataSourceFeatures(dsSettings: { + url: string; + name: string; + type: 'prometheus' | 'loki'; +}): Promise { + const { url, name, type } = dsSettings; - const response = await lastValueFrom( - getBackendSrv().fetch({ - url: `${url}/api/v1/status/buildinfo`, - showErrorAlert: false, - showSuccessAlert: false, - }) - ).catch((e) => { - if ('status' in e && e.status === 404) { - return null; // Cortex does not support buildinfo endpoint, we return an empty response - } - - throw e; - }); + // The current implementation of Loki's build info endpoint is useless + // because it doesn't provide information about Loki's available features (e.g. Ruler API) + // It's better to skip fetching it for Loki and go the Cortex path (manual discovery) + const buildInfoResponse = type === 'prometheus' ? await fetchPromBuildInfo(url) : undefined; // check if the component returns buildinfo - const hasBuildInfo = response !== null; + const hasBuildInfo = buildInfoResponse !== undefined; - // we are dealing with a Cortex datasource since the response for buildinfo came up empty + // we are dealing with a Cortex or Loki datasource since the response for buildinfo came up empty if (!hasBuildInfo) { // check if we can fetch rules via the prometheus compatible api const promRulesSupported = await hasPromRulesSupport(name); @@ -50,7 +45,7 @@ export async function fetchDataSourceBuildInfo(dsSettings: { url: string; name: const rulerSupported = await hasRulerSupport(name); return { - application: PromApplication.Cortex, + application: PromApplication.Lotex, features: { rulerApiEnabled: rulerSupported, }, @@ -58,7 +53,7 @@ export async function fetchDataSourceBuildInfo(dsSettings: { url: string; name: } // if no features are reported but buildinfo was return we're talking to Prometheus - const { features } = response.data.data; + const { features } = buildInfoResponse.data; if (!features) { return { application: PromApplication.Prometheus, @@ -80,17 +75,39 @@ export async function fetchDataSourceBuildInfo(dsSettings: { url: string; name: /** * Attempt to fetch buildinfo from our component */ -export async function fetchBuildInfo(dataSourceName: string): Promise { +export async function discoverFeatures(dataSourceName: string): Promise { const dsConfig = getDataSourceByName(dataSourceName); if (!dsConfig) { throw new Error(`Cannot find data source configuration for ${dataSourceName}`); } - const { url, name } = dsConfig; + const { url, name, type } = dsConfig; if (!url) { throw new Error(`The data souce url cannot be empty.`); } - return fetchDataSourceBuildInfo({ name, url }); + if (type !== 'prometheus' && type !== 'loki') { + throw new Error(`The build info request is not available for ${type}. Only 'prometheus' and 'loki' are supported`); + } + + return discoverDataSourceFeatures({ name, url, type }); +} + +async function fetchPromBuildInfo(url: string): Promise { + const response = await lastValueFrom( + getBackendSrv().fetch({ + url: `${url}/api/v1/status/buildinfo`, + showErrorAlert: false, + showSuccessAlert: false, + }) + ).catch((e) => { + if ('status' in e && e.status === 404) { + return undefined; // Cortex does not support buildinfo endpoint, we return an empty response + } + + throw e; + }); + + return response?.data; } /** diff --git a/public/app/features/alerting/unified/state/actions.ts b/public/app/features/alerting/unified/state/actions.ts index 51486d9859b..32e6afba392 100644 --- a/public/app/features/alerting/unified/state/actions.ts +++ b/public/app/features/alerting/unified/state/actions.ts @@ -43,7 +43,7 @@ import { updateAlertManagerConfig, } from '../api/alertmanager'; import { fetchAnnotations } from '../api/annotations'; -import { fetchBuildInfo } from '../api/buildInfo'; +import { discoverFeatures } from '../api/buildInfo'; import { fetchNotifiers } from '../api/grafana'; import { FetchPromRulesFilter, fetchRules } from '../api/prometheus'; import { @@ -231,12 +231,12 @@ export const fetchRulesSourceBuildInfoAction = createAsyncThunk( } const { id, name } = ds; - const buildInfo = await fetchBuildInfo(name); + const buildInfo = await discoverFeatures(name); const rulerConfig: RulerDataSourceConfig | undefined = buildInfo.features.rulerApiEnabled ? { dataSourceName: name, - apiVersion: buildInfo.application === PromApplication.Cortex ? 'legacy' : 'config', + apiVersion: buildInfo.application === PromApplication.Lotex ? 'legacy' : 'config', } : undefined; diff --git a/public/app/plugins/datasource/prometheus/datasource.tsx b/public/app/plugins/datasource/prometheus/datasource.tsx index b0a9b914beb..420d203c817 100644 --- a/public/app/plugins/datasource/prometheus/datasource.tsx +++ b/public/app/plugins/datasource/prometheus/datasource.tsx @@ -34,10 +34,10 @@ import { } from '@grafana/runtime'; import { Badge, BadgeColor, Tooltip } from '@grafana/ui'; import { safeStringifyValue } from 'app/core/utils/explore'; -import { fetchDataSourceBuildInfo } from 'app/features/alerting/unified/api/buildInfo'; +import { discoverDataSourceFeatures } from 'app/features/alerting/unified/api/buildInfo'; import { getTimeSrv, TimeSrv } from 'app/features/dashboard/services/TimeSrv'; import { getTemplateSrv, TemplateSrv } from 'app/features/templating/template_srv'; -import { PromApplication, PromBuildInfo } from 'app/types/unified-alerting-dto'; +import { PromApplication, PromApiFeatures } from 'app/types/unified-alerting-dto'; import { addLabelToQuery } from './add_label_to_query'; import PrometheusLanguageProvider from './language_provider'; @@ -827,7 +827,7 @@ export class PrometheusDatasource async getBuildInfo() { try { - const buildInfo = await fetchDataSourceBuildInfo(this); + const buildInfo = await discoverDataSourceFeatures({ url: this.url, name: this.name, type: 'prometheus' }); return buildInfo; } catch (error) { // We don't want to break the rest of functionality if build info does not work correctly @@ -835,7 +835,7 @@ export class PrometheusDatasource } } - getBuildInfoMessage(buildInfo: PromBuildInfo) { + getBuildInfoMessage(buildInfo: PromApiFeatures) { const enabled = ; const disabled = ; const unsupported = ( @@ -850,17 +850,23 @@ export class PrometheusDatasource ); const LOGOS = { - [PromApplication.Cortex]: '/public/app/plugins/datasource/prometheus/img/cortex_logo.svg', + [PromApplication.Lotex]: '/public/app/plugins/datasource/prometheus/img/cortex_logo.svg', [PromApplication.Mimir]: '/public/app/plugins/datasource/prometheus/img/mimir_logo.svg', [PromApplication.Prometheus]: '/public/app/plugins/datasource/prometheus/img/prometheus_logo.svg', }; const COLORS: Record = { - [PromApplication.Cortex]: 'blue', + [PromApplication.Lotex]: 'blue', [PromApplication.Mimir]: 'orange', [PromApplication.Prometheus]: 'red', }; + const AppDisplayNames: Record = { + [PromApplication.Lotex]: 'Cortex', + [PromApplication.Mimir]: 'Mimir', + [PromApplication.Prometheus]: 'Prometheus', + }; + // this will inform the user about what "subtype" the datasource is; Mimir, Cortex or vanilla Prometheus const applicationSubType = ( {' '} - {buildInfo.application} + {buildInfo.application ? AppDisplayNames[buildInfo.application] : 'Unknown'} } color={COLORS[buildInfo.application ?? PromApplication.Prometheus]} diff --git a/public/app/types/unified-alerting-dto.ts b/public/app/types/unified-alerting-dto.ts index 64127def8d8..3bff074676c 100644 --- a/public/app/types/unified-alerting-dto.ts +++ b/public/app/types/unified-alerting-dto.ts @@ -24,7 +24,7 @@ export enum PromRuleType { Recording = 'recording', } export enum PromApplication { - Cortex = 'Cortex', + Lotex = 'Lotex', Mimir = 'Mimir', Prometheus = 'Prometheus', } @@ -44,7 +44,7 @@ export interface PromBuildInfoResponse { status: 'success'; } -export interface PromBuildInfo { +export interface PromApiFeatures { application?: PromApplication; features: { rulerApiEnabled: boolean;