From 3b18c32f74960c0299c3ca202d72c47a4ab4683e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Fri, 20 Aug 2021 14:06:45 +0200 Subject: [PATCH] Avoid using the rule data client for field list --- .../public/pages/alerts/alerts_search_bar.tsx | 19 +++++++--- .../pages/alerts/alerts_table_t_grid.tsx | 8 ++--- .../public/pages/alerts/index.tsx | 36 ++++++++++++++----- x-pack/plugins/observability/server/plugin.ts | 13 +------ .../server/routes/register_routes.ts | 5 +-- .../observability/server/routes/rules.ts | 25 ++++++------- .../observability/server/routes/types.ts | 3 +- .../rule_data_client/rule_data_client.ts | 8 ++--- .../rule_data_plugin_service.mock.ts | 2 +- .../rule_data_plugin_service.ts | 15 ++++---- 10 files changed, 72 insertions(+), 62 deletions(-) diff --git a/x-pack/plugins/observability/public/pages/alerts/alerts_search_bar.tsx b/x-pack/plugins/observability/public/pages/alerts/alerts_search_bar.tsx index f32088e2646b3..01bb01857eaf0 100644 --- a/x-pack/plugins/observability/public/pages/alerts/alerts_search_bar.tsx +++ b/x-pack/plugins/observability/public/pages/alerts/alerts_search_bar.tsx @@ -5,19 +5,20 @@ * 2.0. */ +import { IndexPatternBase } from '@kbn/es-query'; import { i18n } from '@kbn/i18n'; import React, { useMemo, useState } from 'react'; -import { IIndexPattern, SearchBar, TimeHistory } from '../../../../../../src/plugins/data/public'; +import { SearchBar, TimeHistory } from '../../../../../../src/plugins/data/public'; import { Storage } from '../../../../../../src/plugins/kibana_utils/public'; export function AlertsSearchBar({ - dynamicIndexPattern, + dynamicIndexPatterns, rangeFrom, rangeTo, onQueryChange, query, }: { - dynamicIndexPattern: IIndexPattern[]; + dynamicIndexPatterns: IndexPatternBase[]; rangeFrom?: string; rangeTo?: string; query?: string; @@ -31,9 +32,19 @@ export function AlertsSearchBar({ }, []); const [queryLanguage, setQueryLanguage] = useState<'lucene' | 'kuery'>('kuery'); + const compatibleIndexPatterns = useMemo( + () => + dynamicIndexPatterns.map((dynamicIndexPattern) => ({ + title: dynamicIndexPattern.title ?? '', + id: dynamicIndexPattern.id ?? '', + fields: dynamicIndexPattern.fields, + })), + [dynamicIndexPatterns] + ); + return ( 75', })} diff --git a/x-pack/plugins/observability/public/pages/alerts/alerts_table_t_grid.tsx b/x-pack/plugins/observability/public/pages/alerts/alerts_table_t_grid.tsx index 17e8a6ac651ac..3404b628975dd 100644 --- a/x-pack/plugins/observability/public/pages/alerts/alerts_table_t_grid.tsx +++ b/x-pack/plugins/observability/public/pages/alerts/alerts_table_t_grid.tsx @@ -62,7 +62,7 @@ const ALERT_STATUS: typeof ALERT_STATUS_TYPED = ALERT_STATUS_NON_TYPED; const ALERT_REASON: typeof ALERT_REASON_TYPED = ALERT_REASON_NON_TYPED; interface AlertsTableTGridProps { - indexName: string; + indexNames: string[]; rangeFrom: string; rangeTo: string; kuery: string; @@ -276,7 +276,7 @@ function ObservabilityActions({ } export function AlertsTableTGrid(props: AlertsTableTGridProps) { - const { indexName, rangeFrom, rangeTo, kuery, status, setRefetch, addToQuery } = props; + const { indexNames, rangeFrom, rangeTo, kuery, status, setRefetch, addToQuery } = props; const { timelines } = useKibana<{ timelines: TimelinesUIStart }>().services; const [flyoutAlert, setFlyoutAlert] = useState(undefined); @@ -322,7 +322,7 @@ export function AlertsTableTGrid(props: AlertsTableTGridProps) { defaultCellActions: getDefaultCellActions({ addToQuery }), end: rangeTo, filters: [], - indexNames: indexName.split(','), + indexNames, itemsPerPage: 10, itemsPerPageOptions: [10, 25, 50], loadingText: i18n.translate('xpack.observability.alertsTable.loadingTextLabel', { @@ -357,7 +357,7 @@ export function AlertsTableTGrid(props: AlertsTableTGridProps) { }; }, [ casePermissions, - indexName, + indexNames, kuery, leadingControlColumns, rangeFrom, diff --git a/x-pack/plugins/observability/public/pages/alerts/index.tsx b/x-pack/plugins/observability/public/pages/alerts/index.tsx index 1b9d5f87099bc..42d2c884d188b 100644 --- a/x-pack/plugins/observability/public/pages/alerts/index.tsx +++ b/x-pack/plugins/observability/public/pages/alerts/index.tsx @@ -7,8 +7,10 @@ import { EuiButtonEmpty, EuiCallOut, EuiFlexGroup, EuiFlexItem, EuiLink } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import React, { useCallback, useMemo, useRef } from 'react'; +import React, { useCallback, useRef } from 'react'; import { useHistory } from 'react-router-dom'; +import useAsync from 'react-use/lib/useAsync'; +import { IndexPatternBase } from '@kbn/es-query'; import { ParsedTechnicalFields } from '../../../../rule_registry/common/parse_technical_fields'; import type { AlertStatus } from '../../../common/typings'; import { ExperimentalBadge } from '../../components/shared/experimental_badge'; @@ -35,7 +37,7 @@ interface AlertsPageProps { } export function AlertsPage({ routeParams }: AlertsPageProps) { - const { core, ObservabilityPageTemplate } = usePluginContext(); + const { core, plugins, ObservabilityPageTemplate } = usePluginContext(); const { prepend } = core.http.basePath; const history = useHistory(); const refetch = useRef<() => void>(); @@ -60,12 +62,13 @@ export function AlertsPage({ routeParams }: AlertsPageProps) { // observability. For now link to the settings page. const manageRulesHref = prepend('/app/management/insightsAndAlerting/triggersActions/alerts'); - const { data: dynamicIndexPatternResp } = useFetcher(({ signal }) => { + const { data: indexNames = NO_INDEX_NAMES } = useFetcher(({ signal }) => { return callObservabilityApi({ signal, endpoint: 'GET /api/observability/rules/alerts/dynamic_index_pattern', params: { query: { + namespace: 'default', registrationContexts: [ 'observability.apm', 'observability.logs', @@ -78,10 +81,22 @@ export function AlertsPage({ routeParams }: AlertsPageProps) { }); }, []); - const dynamicIndexPattern = useMemo( - () => (dynamicIndexPatternResp ? [dynamicIndexPatternResp] : []), - [dynamicIndexPatternResp] - ); + const dynamicIndexPatternsAsyncState = useAsync(async (): Promise => { + if (indexNames.length === 0) { + return []; + } + + return [ + { + id: 'dynamic-observability-alerts-table-index-pattern', + title: indexNames.join(','), + fields: await plugins.data.indexPatterns.getFieldsForWildcard({ + pattern: indexNames.join(','), + allowNoIndex: true, + }), + }, + ]; + }, [indexNames]); const setStatusFilter = useCallback( (value: AlertStatus) => { @@ -176,7 +191,7 @@ export function AlertsPage({ routeParams }: AlertsPageProps) { 0 ? dynamicIndexPattern[0].title : ''} + indexNames={indexNames} rangeFrom={rangeFrom} rangeTo={rangeTo} kuery={kuery} @@ -209,3 +224,6 @@ export function AlertsPage({ routeParams }: AlertsPageProps) { ); } + +const NO_INDEX_NAMES: string[] = []; +const NO_INDEX_PATTERNS: IndexPatternBase[] = []; diff --git a/x-pack/plugins/observability/server/plugin.ts b/x-pack/plugins/observability/server/plugin.ts index e11a6c027584e..cb4f85a44d12c 100644 --- a/x-pack/plugins/observability/server/plugin.ts +++ b/x-pack/plugins/observability/server/plugin.ts @@ -18,7 +18,7 @@ import { ScopedAnnotationsClientFactory, AnnotationsAPI, } from './lib/annotations/bootstrap_annotations'; -import { Dataset, RuleRegistryPluginSetupContract } from '../../rule_registry/server'; +import { RuleRegistryPluginSetupContract } from '../../rule_registry/server'; import { PluginSetupContract as FeaturesSetup } from '../../features/server'; import { uiSettings } from './ui_settings'; import { registerRoutes } from './routes/register_routes'; @@ -101,16 +101,6 @@ export class ObservabilityPlugin implements Plugin { const start = () => core.getStartServices().then(([coreStart]) => coreStart); const { ruleDataService } = plugins.ruleRegistry; - const ruleDataClient = ruleDataService.initializeIndex({ - feature: 'observability', - registrationContext: 'observability', - dataset: Dataset.alerts, - componentTemplateRefs: [], - componentTemplates: [], - indexTemplate: { - version: 0, - }, - }); registerRoutes({ core: { @@ -119,7 +109,6 @@ export class ObservabilityPlugin implements Plugin { }, logger: this.initContext.logger.get(), repository: getGlobalObservabilityServerRouteRepository(), - ruleDataClient, ruleDataService, }); diff --git a/x-pack/plugins/observability/server/routes/register_routes.ts b/x-pack/plugins/observability/server/routes/register_routes.ts index 03f062a721608..660c38edb8e9d 100644 --- a/x-pack/plugins/observability/server/routes/register_routes.ts +++ b/x-pack/plugins/observability/server/routes/register_routes.ts @@ -13,7 +13,7 @@ import { import { CoreSetup, CoreStart, Logger, RouteRegistrar } from 'kibana/server'; import Boom from '@hapi/boom'; import { RequestAbortedError } from '@elastic/elasticsearch/lib/errors'; -import { IRuleDataClient, RuleDataPluginService } from '../../../rule_registry/server'; +import { RuleDataPluginService } from '../../../rule_registry/server'; import { ObservabilityRequestHandlerContext } from '../types'; import { AbstractObservabilityServerRouteRepository } from './types'; @@ -21,7 +21,6 @@ export function registerRoutes({ repository, core, logger, - ruleDataClient, ruleDataService, }: { core: { @@ -30,7 +29,6 @@ export function registerRoutes({ }; repository: AbstractObservabilityServerRouteRepository; logger: Logger; - ruleDataClient: IRuleDataClient; ruleDataService: RuleDataPluginService; }) { const routes = repository.getRoutes(); @@ -64,7 +62,6 @@ export function registerRoutes({ core, logger, params: decodedParams, - ruleDataClient, ruleDataService, })) as any; diff --git a/x-pack/plugins/observability/server/routes/rules.ts b/x-pack/plugins/observability/server/routes/rules.ts index 86ff582c192b4..a9039e4a66211 100644 --- a/x-pack/plugins/observability/server/routes/rules.ts +++ b/x-pack/plugins/observability/server/routes/rules.ts @@ -17,23 +17,24 @@ const alertsDynamicIndexPatternRoute = createObservabilityServerRoute({ params: t.type({ query: t.type({ registrationContexts: t.array(t.string), + namespace: t.string, }), }), - handler: async ({ context, ruleDataService, ruleDataClient, params }) => { - const { registrationContexts } = params.query; - const spaceId = context.alerting.getRulesClient().getSpaceId(); - const indexNames = registrationContexts.map((registrationContext) => { - const rcIndexName = ruleDataService.getBaseNameByRegistrationContext(registrationContext); - if (rcIndexName) { - return `${rcIndexName}-${spaceId}`; + handler: async ({ ruleDataService, params }) => { + const { namespace, registrationContexts } = params.query; + const indexNames = registrationContexts.flatMap((registrationContext) => { + const indexName = ruleDataService + .getRegisteredIndexInfo(registrationContext) + ?.getPrimaryAlias(namespace); + + if (indexName != null) { + return [indexName]; + } else { + return []; } - return undefined; - }); - const reader = ruleDataClient.getReader({ - indexNames: indexNames.filter((item: string | undefined): item is string => !!item), }); - return reader.getDynamicIndexPattern(); + return indexNames; }, }); diff --git a/x-pack/plugins/observability/server/routes/types.ts b/x-pack/plugins/observability/server/routes/types.ts index 034d6df9e030c..5075b21fdf1fa 100644 --- a/x-pack/plugins/observability/server/routes/types.ts +++ b/x-pack/plugins/observability/server/routes/types.ts @@ -12,7 +12,7 @@ import type { ServerRouteRepository, } from '@kbn/server-route-repository'; import { CoreSetup, CoreStart, KibanaRequest, Logger } from 'kibana/server'; -import { IRuleDataClient, RuleDataPluginService } from '../../../rule_registry/server'; +import { RuleDataPluginService } from '../../../rule_registry/server'; import { ObservabilityServerRouteRepository } from './get_global_observability_server_route_repository'; import { ObservabilityRequestHandlerContext } from '../types'; @@ -24,7 +24,6 @@ export interface ObservabilityRouteHandlerResources { start: () => Promise; setup: CoreSetup; }; - ruleDataClient: IRuleDataClient; ruleDataService: RuleDataPluginService; request: KibanaRequest; context: ObservabilityRequestHandlerContext; diff --git a/x-pack/plugins/rule_registry/server/rule_data_client/rule_data_client.ts b/x-pack/plugins/rule_registry/server/rule_data_client/rule_data_client.ts index 1816163331551..bbfa6abdd1a71 100644 --- a/x-pack/plugins/rule_registry/server/rule_data_client/rule_data_client.ts +++ b/x-pack/plugins/rule_registry/server/rule_data_client/rule_data_client.ts @@ -37,13 +37,9 @@ export class RuleDataClient implements IRuleDataClient { return this.options.isWriteEnabled; } - public getReader(options: { namespace?: string; indexNames?: string[] } = {}): IRuleDataReader { + public getReader(options: { namespace?: string } = {}): IRuleDataReader { const { indexInfo } = this.options; - const { namespace, indexNames } = options; - let indexPattern = indexInfo.getPatternForReading(namespace); - if (indexNames && indexNames.length > 0) { - indexPattern = indexNames.join(','); - } + const indexPattern = indexInfo.getPatternForReading(options.namespace); const waitUntilReady = async () => { const result = await this.options.waitUntilReadyForReading; diff --git a/x-pack/plugins/rule_registry/server/rule_data_plugin_service/rule_data_plugin_service.mock.ts b/x-pack/plugins/rule_registry/server/rule_data_plugin_service/rule_data_plugin_service.mock.ts index 3828be4abb272..f95ed8c6994b6 100644 --- a/x-pack/plugins/rule_registry/server/rule_data_plugin_service/rule_data_plugin_service.mock.ts +++ b/x-pack/plugins/rule_registry/server/rule_data_plugin_service/rule_data_plugin_service.mock.ts @@ -12,7 +12,7 @@ type Schema = PublicMethodsOf; const createRuleDataPluginService = () => { const mocked: jest.Mocked = { - getBaseNameByRegistrationContext: jest.fn(), + getRegisteredIndexInfo: jest.fn(), getResourcePrefix: jest.fn(), getResourceName: jest.fn(), isWriteEnabled: jest.fn(), diff --git a/x-pack/plugins/rule_registry/server/rule_data_plugin_service/rule_data_plugin_service.ts b/x-pack/plugins/rule_registry/server/rule_data_plugin_service/rule_data_plugin_service.ts index 3681fffbf9bd3..734518e86d172 100644 --- a/x-pack/plugins/rule_registry/server/rule_data_plugin_service/rule_data_plugin_service.ts +++ b/x-pack/plugins/rule_registry/server/rule_data_plugin_service/rule_data_plugin_service.ts @@ -29,7 +29,7 @@ export class RuleDataPluginService { private readonly resourceInstaller: ResourceInstaller; private installCommonResources: Promise>; private isInitialized: boolean; - private registrationContextWithBaseName: Map; + private registeredIndices: Map = new Map(); constructor(private readonly options: ConstructorOptions) { this.resourceInstaller = new ResourceInstaller({ @@ -41,7 +41,6 @@ export class RuleDataPluginService { this.installCommonResources = Promise.resolve(right('ok')); this.isInitialized = false; - this.registrationContextWithBaseName = new Map(); } /** @@ -107,7 +106,7 @@ export class RuleDataPluginService { indexOptions, }); - this.registrationContextWithBaseName.set(indexOptions.registrationContext, indexInfo.baseName); + this.registeredIndices.set(indexOptions.registrationContext, indexInfo); const waitUntilClusterClientAvailable = async (): Promise => { try { @@ -154,11 +153,11 @@ export class RuleDataPluginService { } /** - * Initializes alerts-as-data index and starts index bootstrapping right away. - * @param indexOptions Index parameters: names and resources. - * @returns Client for reading and writing data to this index. + * Looks up the index information associated with the given `registrationContext`. + * @param registrationContext + * @returns the IndexInfo or undefined */ - public getBaseNameByRegistrationContext(registrationContext: string): string | undefined { - return this.registrationContextWithBaseName.get(registrationContext); + public getRegisteredIndexInfo(registrationContext: string): IndexInfo | undefined { + return this.registeredIndices.get(registrationContext); } }