diff --git a/x-pack/packages/kbn-streams-schema/src/apis/__snapshots__/read_streams_response.test.ts.snap b/x-pack/packages/kbn-streams-schema/src/apis/__snapshots__/read_streams_response.test.ts.snap index b40f64d66180d..ab836ff0dbfb4 100644 --- a/x-pack/packages/kbn-streams-schema/src/apis/__snapshots__/read_streams_response.test.ts.snap +++ b/x-pack/packages/kbn-streams-schema/src/apis/__snapshots__/read_streams_response.test.ts.snap @@ -15,6 +15,9 @@ Object { "type": "match_only_text", }, }, + "lifecycle": Object { + "type": "dlm", + }, "name": "logs.nginx", "stream": Object { "ingest": Object { @@ -67,6 +70,9 @@ Object { "type": "match_only_text", }, }, + "lifecycle": Object { + "type": "dlm", + }, "name": "logs.nginx", "stream": Object { "ingest": Object { diff --git a/x-pack/packages/kbn-streams-schema/src/fixtures/ingest_read_stream.ts b/x-pack/packages/kbn-streams-schema/src/fixtures/ingest_read_stream.ts index 547c1194333ac..c3acd0e098026 100644 --- a/x-pack/packages/kbn-streams-schema/src/fixtures/ingest_read_stream.ts +++ b/x-pack/packages/kbn-streams-schema/src/fixtures/ingest_read_stream.ts @@ -9,6 +9,7 @@ import { ingestStream } from './ingest_stream'; export const ingestReadStream = { ...ingestStream, + lifecycle: { type: 'dlm' }, inherited_fields: { '@timestamp': { type: 'date', diff --git a/x-pack/packages/kbn-streams-schema/src/fixtures/wired_read_stream.ts b/x-pack/packages/kbn-streams-schema/src/fixtures/wired_read_stream.ts index 177250bd8032a..180b36e7c824e 100644 --- a/x-pack/packages/kbn-streams-schema/src/fixtures/wired_read_stream.ts +++ b/x-pack/packages/kbn-streams-schema/src/fixtures/wired_read_stream.ts @@ -9,6 +9,7 @@ import { wiredStream } from './wired_stream'; export const wiredReadStream = { ...wiredStream, + lifecycle: { type: 'dlm' }, inherited_fields: { '@timestamp': { type: 'date', diff --git a/x-pack/packages/kbn-streams-schema/src/models/common.ts b/x-pack/packages/kbn-streams-schema/src/models/common.ts index 0751d9fed90c9..f3c967e52605a 100644 --- a/x-pack/packages/kbn-streams-schema/src/models/common.ts +++ b/x-pack/packages/kbn-streams-schema/src/models/common.ts @@ -116,3 +116,10 @@ export const elasticsearchAssetSchema = z.array( ); export type ElasticsearchAsset = z.infer; + +export const lifecycleSchema = z.discriminatedUnion('type', [ + z.object({ type: z.literal('dlm'), data_retention: z.optional(z.string()) }), + z.object({ type: z.literal('ilm'), policy: z.string() }), +]); + +export type StreamLifecycle = z.infer; diff --git a/x-pack/packages/kbn-streams-schema/src/models/read_streams/__snapshots__/read_stream.test.ts.snap b/x-pack/packages/kbn-streams-schema/src/models/read_streams/__snapshots__/read_stream.test.ts.snap index 0e3ca0bda8ded..5e1739220f50a 100644 --- a/x-pack/packages/kbn-streams-schema/src/models/read_streams/__snapshots__/read_stream.test.ts.snap +++ b/x-pack/packages/kbn-streams-schema/src/models/read_streams/__snapshots__/read_stream.test.ts.snap @@ -13,6 +13,9 @@ Object { "type": "match_only_text", }, }, + "lifecycle": Object { + "type": "dlm", + }, "name": "logs.nginx", "stream": Object { "ingest": Object { @@ -61,6 +64,9 @@ Object { "type": "match_only_text", }, }, + "lifecycle": Object { + "type": "dlm", + }, "name": "logs.nginx", "stream": Object { "ingest": Object { diff --git a/x-pack/packages/kbn-streams-schema/src/models/read_streams/ingest_read_stream.ts b/x-pack/packages/kbn-streams-schema/src/models/read_streams/ingest_read_stream.ts index b98e45c568432..dac96bced81f8 100644 --- a/x-pack/packages/kbn-streams-schema/src/models/read_streams/ingest_read_stream.ts +++ b/x-pack/packages/kbn-streams-schema/src/models/read_streams/ingest_read_stream.ts @@ -7,11 +7,12 @@ import { z } from '@kbn/zod'; import { ingestStreamDefinitonSchema } from '../streams'; -import { inheritedFieldDefinitionSchema } from '../common'; +import { inheritedFieldDefinitionSchema, lifecycleSchema } from '../common'; export const ingestReadStreamDefinitonSchema = ingestStreamDefinitonSchema .extend({ inherited_fields: inheritedFieldDefinitionSchema.default({}), + lifecycle: lifecycleSchema, }) .strict(); diff --git a/x-pack/packages/kbn-streams-schema/src/models/read_streams/wired_read_stream.ts b/x-pack/packages/kbn-streams-schema/src/models/read_streams/wired_read_stream.ts index 621da441d66b1..96792119dadd7 100644 --- a/x-pack/packages/kbn-streams-schema/src/models/read_streams/wired_read_stream.ts +++ b/x-pack/packages/kbn-streams-schema/src/models/read_streams/wired_read_stream.ts @@ -7,11 +7,12 @@ import { z } from '@kbn/zod'; import { wiredStreamDefinitonSchema } from '../streams'; -import { inheritedFieldDefinitionSchema } from '../common'; +import { inheritedFieldDefinitionSchema, lifecycleSchema } from '../common'; export const wiredReadStreamDefinitonSchema = wiredStreamDefinitonSchema .extend({ inherited_fields: inheritedFieldDefinitionSchema.default({}), + lifecycle: lifecycleSchema, }) .strict(); diff --git a/x-pack/platform/packages/shared/index-lifecycle-management/index_lifecycle_management_common_shared/index.ts b/x-pack/platform/packages/shared/index-lifecycle-management/index_lifecycle_management_common_shared/index.ts index 044ab18aa34df..238f7211204a0 100644 --- a/x-pack/platform/packages/shared/index-lifecycle-management/index_lifecycle_management_common_shared/index.ts +++ b/x-pack/platform/packages/shared/index-lifecycle-management/index_lifecycle_management_common_shared/index.ts @@ -7,3 +7,4 @@ export const ILM_LOCATOR_ID = 'ILM_LOCATOR_ID'; export * from './src/policies'; +export * from './src/locator'; diff --git a/x-pack/platform/packages/shared/index-lifecycle-management/index_lifecycle_management_common_shared/src/locator.ts b/x-pack/platform/packages/shared/index-lifecycle-management/index_lifecycle_management_common_shared/src/locator.ts new file mode 100644 index 0000000000000..6dbd11f27a778 --- /dev/null +++ b/x-pack/platform/packages/shared/index-lifecycle-management/index_lifecycle_management_common_shared/src/locator.ts @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { SerializableRecord } from '@kbn/utility-types'; + +export interface IlmLocatorParams extends SerializableRecord { + page: 'policies_list' | 'policy_edit' | 'policy_create'; + policyName?: string; +} diff --git a/x-pack/platform/packages/shared/index-lifecycle-management/index_lifecycle_management_common_shared/tsconfig.json b/x-pack/platform/packages/shared/index-lifecycle-management/index_lifecycle_management_common_shared/tsconfig.json index 0e4ba01c6d576..682f34938edb4 100644 --- a/x-pack/platform/packages/shared/index-lifecycle-management/index_lifecycle_management_common_shared/tsconfig.json +++ b/x-pack/platform/packages/shared/index-lifecycle-management/index_lifecycle_management_common_shared/tsconfig.json @@ -16,5 +16,6 @@ "target/**/*" ], "kbn_references": [ + "@kbn/utility-types", ] } diff --git a/x-pack/platform/plugins/private/index_lifecycle_management/public/index.ts b/x-pack/platform/plugins/private/index_lifecycle_management/public/index.ts index 40f0a4fb6ebf7..4ac93c91b1b50 100644 --- a/x-pack/platform/plugins/private/index_lifecycle_management/public/index.ts +++ b/x-pack/platform/plugins/private/index_lifecycle_management/public/index.ts @@ -13,6 +13,3 @@ import { IndexLifecycleManagementPlugin } from './plugin'; export const plugin = (initializerContext: PluginInitializerContext) => { return new IndexLifecycleManagementPlugin(initializerContext); }; - -export type { IlmLocatorParams } from './locator'; -export { ILM_LOCATOR_ID } from './locator'; diff --git a/x-pack/platform/plugins/private/index_lifecycle_management/public/locator.ts b/x-pack/platform/plugins/private/index_lifecycle_management/public/locator.ts index 382cbc4ad1838..11848d1f6d451 100644 --- a/x-pack/platform/plugins/private/index_lifecycle_management/public/locator.ts +++ b/x-pack/platform/plugins/private/index_lifecycle_management/public/locator.ts @@ -5,10 +5,9 @@ * 2.0. */ -import type { SerializableRecord } from '@kbn/utility-types'; import { ManagementAppLocator } from '@kbn/management-plugin/common'; import { LocatorDefinition } from '@kbn/share-plugin/public'; -import { ILM_LOCATOR_ID } from '@kbn/index-lifecycle-management-common-shared'; +import { ILM_LOCATOR_ID, IlmLocatorParams } from '@kbn/index-lifecycle-management-common-shared'; import { getPoliciesListPath, getPolicyCreatePath, @@ -18,11 +17,6 @@ import { PLUGIN } from '../common/constants'; export { ILM_LOCATOR_ID }; -export interface IlmLocatorParams extends SerializableRecord { - page: 'policies_list' | 'policy_edit' | 'policy_create'; - policyName?: string; -} - export interface IlmLocatorDefinitionDependencies { managementAppLocator: ManagementAppLocator; } diff --git a/x-pack/platform/plugins/private/index_lifecycle_management/tsconfig.json b/x-pack/platform/plugins/private/index_lifecycle_management/tsconfig.json index 34f3e7a95d191..00e4ec508cf34 100644 --- a/x-pack/platform/plugins/private/index_lifecycle_management/tsconfig.json +++ b/x-pack/platform/plugins/private/index_lifecycle_management/tsconfig.json @@ -28,7 +28,6 @@ "@kbn/test-jest-helpers", "@kbn/core-http-browser-mocks", "@kbn/i18n", - "@kbn/utility-types", "@kbn/analytics", "@kbn/es-ui-shared-plugin", "@kbn/i18n-react", diff --git a/x-pack/solutions/observability/plugins/streams/server/lib/streams/component_templates/generate_layer.ts b/x-pack/solutions/observability/plugins/streams/server/lib/streams/component_templates/generate_layer.ts index 2035ba1b3ae0e..88368bbee2e4c 100644 --- a/x-pack/solutions/observability/plugins/streams/server/lib/streams/component_templates/generate_layer.ts +++ b/x-pack/solutions/observability/plugins/streams/server/lib/streams/component_templates/generate_layer.ts @@ -12,7 +12,7 @@ import { } from '@elastic/elasticsearch/lib/api/types'; import { WiredStreamDefinition } from '@kbn/streams-schema'; import { ASSET_VERSION } from '../../../../common/constants'; -import { logsSettings } from './logs_layer'; +import { logsSettings, logsLifecycle } from './logs_layer'; import { isRoot } from '../helpers/hierarchy'; import { getComponentTemplateName } from './name'; @@ -38,6 +38,7 @@ export function generateLayer( name: getComponentTemplateName(id), template: { settings: isRoot(definition.name) ? logsSettings : {}, + lifecycle: isRoot(definition.name) ? logsLifecycle : undefined, mappings: { subobjects: false, dynamic: false, diff --git a/x-pack/solutions/observability/plugins/streams/server/lib/streams/component_templates/logs_layer.ts b/x-pack/solutions/observability/plugins/streams/server/lib/streams/component_templates/logs_layer.ts index 6b41d04131c56..d629666d80859 100644 --- a/x-pack/solutions/observability/plugins/streams/server/lib/streams/component_templates/logs_layer.ts +++ b/x-pack/solutions/observability/plugins/streams/server/lib/streams/component_templates/logs_layer.ts @@ -5,13 +5,14 @@ * 2.0. */ -import { IndicesIndexSettings } from '@elastic/elasticsearch/lib/api/types'; +import { + IndicesIndexSettings, + IndicesDataStreamLifecycle, +} from '@elastic/elasticsearch/lib/api/types'; export const logsSettings: IndicesIndexSettings = { index: { - lifecycle: { - name: 'logs', - }, + mode: 'logsdb', codec: 'best_compression', mapping: { total_fields: { @@ -21,3 +22,5 @@ export const logsSettings: IndicesIndexSettings = { }, }, }; + +export const logsLifecycle: IndicesDataStreamLifecycle = {}; diff --git a/x-pack/solutions/observability/plugins/streams/server/lib/streams/stream_crud.ts b/x-pack/solutions/observability/plugins/streams/server/lib/streams/stream_crud.ts index 762769487ef96..16b07250d4546 100644 --- a/x-pack/solutions/observability/plugins/streams/server/lib/streams/stream_crud.ts +++ b/x-pack/solutions/observability/plugins/streams/server/lib/streams/stream_crud.ts @@ -17,6 +17,11 @@ import { ListStreamsResponse, isWiredStream, FieldDefinition, + StreamLifecycle, + ReadStreamDefinition, + IngestReadStreamDefinition, + isWiredReadStream, + WiredReadStreamDefinition, } from '@kbn/streams-schema'; import { omit } from 'lodash'; import { STREAMS_INDEX } from '../../../common/constants'; @@ -65,8 +70,9 @@ export async function deleteUnmanagedStreamObjects({ scopedClusterClient, logger, }: DeleteStreamParams) { + const dataStream = await getDataStream({ name: id, scopedClusterClient }); const unmanagedAssets = await getUnmanagedElasticsearchAssets({ - name: id, + dataStream, scopedClusterClient, }); const pipelineName = unmanagedAssets.find((asset) => asset.type === 'ingest_pipeline')?.id; @@ -168,7 +174,7 @@ async function upsertInternalStream({ return scopedClusterClient.asInternalUser.index({ id: definition.name, index: STREAMS_INDEX, - document: { ...omit(definition, 'elasticsearch_assets') }, + document: { ...omit(definition, 'elasticsearch_assets', 'inherited_fields', 'lifecycle') }, refresh: 'wait_for', }); } @@ -233,6 +239,24 @@ async function listManagedStreams({ }); } +function getDataStreamLifecycle(dataStream: IndicesDataStream): StreamLifecycle { + if ( + dataStream.ilm_policy && + (!dataStream.lifecycle || typeof dataStream.prefer_ilm === 'undefined' || dataStream.prefer_ilm) + ) { + return { + type: 'ilm', + policy: dataStream.ilm_policy, + }; + } + return { + type: 'dlm', + data_retention: dataStream.lifecycle?.data_retention + ? String(dataStream.lifecycle.data_retention) + : undefined, + }; +} + export async function listDataStreamsAsStreams({ scopedClusterClient, }: ListStreamsParams): Promise { @@ -259,7 +283,7 @@ export async function readStream({ id, scopedClusterClient, skipAccessCheck, -}: ReadStreamParams): Promise { +}: ReadStreamParams): Promise { try { const response = await scopedClusterClient.asInternalUser.get({ id, @@ -272,7 +296,12 @@ export async function readStream({ throw new DefinitionNotFound(`Stream definition for ${id} not found.`); } } - return definition; + const dataStream = await getDataStream({ name: id, scopedClusterClient }); + return { + ...definition, + inherited_fields: {}, + lifecycle: getDataStreamLifecycle(dataStream), + }; } catch (e) { if (e.meta?.statusCode === 404) { return readDataStreamAsStream({ id, scopedClusterClient, skipAccessCheck }); @@ -282,8 +311,11 @@ export async function readStream({ } export async function readDataStreamAsStream({ id, scopedClusterClient }: ReadStreamParams) { - const definition: IngestStreamDefinition = { + const dataStream = await getDataStream({ name: id, scopedClusterClient }); + const definition: IngestReadStreamDefinition = { name: id, + lifecycle: getDataStreamLifecycle(dataStream), + inherited_fields: {}, stream: { ingest: { routing: [], @@ -293,7 +325,7 @@ export async function readDataStreamAsStream({ id, scopedClusterClient }: ReadSt }; definition.elasticsearch_assets = await getUnmanagedElasticsearchAssets({ - name: id, + dataStream, scopedClusterClient, }); @@ -301,13 +333,16 @@ export async function readDataStreamAsStream({ id, scopedClusterClient }: ReadSt } interface ReadUnmanagedAssetsParams extends BaseParams { - name: string; + dataStream: IndicesDataStream; } -async function getUnmanagedElasticsearchAssets({ +async function getDataStream({ name, scopedClusterClient, -}: ReadUnmanagedAssetsParams) { +}: { + name: string; + scopedClusterClient: IScopedClusterClient; +}) { let dataStream: IndicesDataStream | undefined; try { const response = await scopedClusterClient.asCurrentUser.indices.getDataStream({ name }); @@ -319,11 +354,16 @@ async function getUnmanagedElasticsearchAssets({ throw e; } } - if (!dataStream) { throw new DefinitionNotFound(`Stream definition for ${name} not found.`); } + return dataStream; +} +async function getUnmanagedElasticsearchAssets({ + dataStream, + scopedClusterClient, +}: ReadUnmanagedAssetsParams) { // retrieve linked index template, component template and ingest pipeline const templateName = dataStream.template; const componentTemplates: string[] = []; @@ -356,7 +396,7 @@ async function getUnmanagedElasticsearchAssets({ }, { type: 'data_stream' as const, - id: name, + id: dataStream.name, }, ]; } @@ -383,7 +423,7 @@ export async function readAncestors({ scopedClusterClient, id: ancestorId, skipAccessCheck: true, - }) as unknown as WiredStreamDefinition + }) as unknown as WiredReadStreamDefinition ) ), }; @@ -430,7 +470,7 @@ export async function validateAncestorFields( for (const name in fields) { if ( Object.hasOwn(fields, name) && - isWiredStream(ancestor) && + isWiredReadStream(ancestor) && Object.entries(ancestor.stream.ingest.wired.fields).some( ([ancestorFieldName, attr]) => attr.type !== fields[name].type && ancestorFieldName === name @@ -531,7 +571,7 @@ export async function syncStream({ rootDefinition, logger, }: SyncStreamParams) { - if (!isWiredStream(definition)) { + if (!isWiredStream(definition) && !isWiredReadStream(definition)) { await syncUnmanagedStream({ scopedClusterClient, definition, logger, assetClient }); await upsertInternalStream({ scopedClusterClient, @@ -602,14 +642,12 @@ interface ExecutionPlanStep { } async function syncUnmanagedStream({ scopedClusterClient, definition }: SyncStreamParams) { - if (isWiredStream(definition)) { - throw new Error('Got an unmanaged stream that is marked as managed'); - } if (definition.stream.ingest.routing.length) { throw new Error('Unmanaged streams cannot have managed children, coming soon'); } + const dataStream = await getDataStream({ name: definition.name, scopedClusterClient }); const unmanagedAssets = await getUnmanagedElasticsearchAssets({ - name: definition.name, + dataStream, scopedClusterClient, }); const executionPlan: ExecutionPlanStep[] = []; diff --git a/x-pack/solutions/observability/plugins/streams/server/routes/streams/delete.ts b/x-pack/solutions/observability/plugins/streams/server/routes/streams/delete.ts index cc773523d9719..17a5ecdf511a7 100644 --- a/x-pack/solutions/observability/plugins/streams/server/routes/streams/delete.ts +++ b/x-pack/solutions/observability/plugins/streams/server/routes/streams/delete.ts @@ -9,7 +9,7 @@ import { z } from '@kbn/zod'; import { IScopedClusterClient } from '@kbn/core-elasticsearch-server'; import { Logger } from '@kbn/logging'; import { badRequest, internal, notFound } from '@hapi/boom'; -import { isWiredStream } from '@kbn/streams-schema'; +import { isWiredReadStream } from '@kbn/streams-schema'; import { DefinitionNotFound, ForkConditionMissing, @@ -94,7 +94,7 @@ export async function deleteStream( ) { try { const definition = await readStream({ scopedClusterClient, id }); - if (!isWiredStream(definition)) { + if (!isWiredReadStream(definition)) { await deleteUnmanagedStreamObjects({ scopedClusterClient, id, logger, assetClient }); return; } diff --git a/x-pack/solutions/observability/plugins/streams/server/routes/streams/fork.ts b/x-pack/solutions/observability/plugins/streams/server/routes/streams/fork.ts index 8453045863794..0f99b301621fc 100644 --- a/x-pack/solutions/observability/plugins/streams/server/routes/streams/fork.ts +++ b/x-pack/solutions/observability/plugins/streams/server/routes/streams/fork.ts @@ -7,7 +7,7 @@ import { z } from '@kbn/zod'; import { badRequest, internal, notFound } from '@hapi/boom'; -import { conditionSchema, isWiredStream, WiredStreamDefinition } from '@kbn/streams-schema'; +import { conditionSchema, isWiredReadStream, WiredStreamDefinition } from '@kbn/streams-schema'; import { DefinitionNotFound, ForkConditionMissing, @@ -58,7 +58,7 @@ export const forkStreamsRoute = createServerRoute({ id: params.path.id, }); - if (!isWiredStream(rootDefinition)) { + if (!isWiredReadStream(rootDefinition)) { throw new MalformedStreamId('Cannot fork a stream that is not managed'); } diff --git a/x-pack/solutions/observability/plugins/streams/server/routes/streams/read.ts b/x-pack/solutions/observability/plugins/streams/server/routes/streams/read.ts index f7c967035bd68..cadaaed2a6bdc 100644 --- a/x-pack/solutions/observability/plugins/streams/server/routes/streams/read.ts +++ b/x-pack/solutions/observability/plugins/streams/server/routes/streams/read.ts @@ -9,7 +9,7 @@ import { z } from '@kbn/zod'; import { notFound, internal } from '@hapi/boom'; import { FieldDefinitionConfig, - isWiredStream, + isWiredReadStream, ReadStreamDefinition, WiredReadStreamDefinition, } from '@kbn/streams-schema'; @@ -45,7 +45,7 @@ export const readStreamRoute = createServerRoute({ assetType: 'dashboard', }); - if (!isWiredStream(streamEntity)) { + if (!isWiredReadStream(streamEntity)) { return { ...streamEntity, dashboards, diff --git a/x-pack/solutions/observability/plugins/streams/server/routes/streams/schema/unmapped_fields.ts b/x-pack/solutions/observability/plugins/streams/server/routes/streams/schema/unmapped_fields.ts index 79013f57d9ca5..e069245003304 100644 --- a/x-pack/solutions/observability/plugins/streams/server/routes/streams/schema/unmapped_fields.ts +++ b/x-pack/solutions/observability/plugins/streams/server/routes/streams/schema/unmapped_fields.ts @@ -8,7 +8,7 @@ import { z } from '@kbn/zod'; import { internal, notFound } from '@hapi/boom'; import { getFlattenedObject } from '@kbn/std'; -import { isWiredStream } from '@kbn/streams-schema'; +import { isWiredReadStream } from '@kbn/streams-schema'; import { DefinitionNotFound } from '../../../lib/streams/errors'; import { checkAccess, readAncestors, readStream } from '../../../lib/streams/stream_crud'; import { createServerRoute } from '../../create_server_route'; @@ -71,7 +71,7 @@ export const unmappedFieldsRoute = createServerRoute({ // Mapped fields from the stream's definition and inherited from ancestors const mappedFields = new Set(); - if (isWiredStream(streamEntity)) { + if (isWiredReadStream(streamEntity)) { Object.keys(streamEntity.stream.ingest.wired.fields).forEach((name) => mappedFields.add(name) ); diff --git a/x-pack/solutions/observability/plugins/streams_app/public/components/entity_detail_view/index.tsx b/x-pack/solutions/observability/plugins/streams_app/public/components/entity_detail_view/index.tsx index abd9cf04ea2f0..d1df839bf2ebe 100644 --- a/x-pack/solutions/observability/plugins/streams_app/public/components/entity_detail_view/index.tsx +++ b/x-pack/solutions/observability/plugins/streams_app/public/components/entity_detail_view/index.tsx @@ -8,7 +8,8 @@ import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiLink, EuiPanel, EuiBadge } from import { i18n } from '@kbn/i18n'; import React from 'react'; import { css } from '@emotion/css'; -import { isIngestStream, StreamDefinition } from '@kbn/streams-schema'; +import { ILM_LOCATOR_ID, IlmLocatorParams } from '@kbn/index-lifecycle-management-common-shared'; +import { ReadStreamDefinition, StreamLifecycle, isIngestStream } from '@kbn/streams-schema'; import { useStreamsAppBreadcrumbs } from '../../hooks/use_streams_app_breadcrumbs'; import { useStreamsAppRouter } from '../../hooks/use_streams_app_router'; import { EntityOverviewTabList } from '../entity_overview_tab_list'; @@ -16,6 +17,7 @@ import { LoadingPanel } from '../loading_panel'; import { StreamsAppPageBody } from '../streams_app_page_body'; import { StreamsAppPageHeader } from '../streams_app_page_header'; import { StreamsAppPageHeaderTitle } from '../streams_app_page_header/streams_app_page_header_title'; +import { useKibana } from '../../hooks/use_kibana'; export interface EntityViewTab { name: string; @@ -35,7 +37,7 @@ export function EntityDetailViewWithoutParams({ displayName?: string; id: string; }; - definition?: StreamDefinition; + definition?: ReadStreamDefinition; }) { const router = useStreamsAppRouter(); useStreamsAppBreadcrumbs(() => { @@ -99,7 +101,7 @@ export function EntityDetailViewWithoutParams({ title={ + {entity.displayName} {definition && isIngestStream(definition) ? ( <> @@ -107,12 +109,13 @@ export function EntityDetailViewWithoutParams({ {i18n.translate( 'xpack.streams.entityDetailViewWithoutParams.unmanagedBadgeLabel', - { defaultMessage: 'Unmanaged' } + { defaultMessage: 'Classic' } )} ) : null} - + {definition && } + } /> } @@ -133,3 +136,36 @@ export function EntityDetailViewWithoutParams({ ); } + +function LifecycleBadge({ lifecycle }: { lifecycle: StreamLifecycle }) { + const { + dependencies: { + start: { share }, + }, + } = useKibana(); + const ilmLocator = share.url.locators.get(ILM_LOCATOR_ID); + if (lifecycle.type === 'ilm') { + return ( + + + {i18n.translate('xpack.streams.entityDetailViewWithoutParams.ilmBadgeLabel', { + defaultMessage: 'ILM Policy: {name}', + values: { name: lifecycle.policy }, + })} + + + ); + } + + return ( + + {i18n.translate('xpack.streams.entityDetailViewWithoutParams.dlmBadgeLabel', { + defaultMessage: 'Retention: {retention}', + values: { retention: lifecycle.data_retention || '∞' }, + })} + + ); +} diff --git a/x-pack/solutions/observability/plugins/streams_app/public/components/stream_detail_management/classic.tsx b/x-pack/solutions/observability/plugins/streams_app/public/components/stream_detail_management/classic.tsx index 66e291cb3f61b..9a7b0869b62f1 100644 --- a/x-pack/solutions/observability/plugins/streams_app/public/components/stream_detail_management/classic.tsx +++ b/x-pack/solutions/observability/plugins/streams_app/public/components/stream_detail_management/classic.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; import { i18n } from '@kbn/i18n'; -import { ReadStreamDefinition, StreamDefinition } from '@kbn/streams-schema'; +import { ReadStreamDefinition } from '@kbn/streams-schema'; import { EuiFlexGroup, EuiListGroup, EuiText } from '@elastic/eui'; import { useStreamsAppParams } from '../../hooks/use_streams_app_params'; import { RedirectTo } from '../redirect_to'; @@ -60,7 +60,7 @@ export function ClassicStreamDetailManagement({ return ; } -function UnmanagedStreamOverview({ definition }: { definition: StreamDefinition }) { +function UnmanagedStreamOverview({ definition }: { definition: ReadStreamDefinition }) { const { core: { http: { basePath }, diff --git a/x-pack/solutions/observability/plugins/streams_app/tsconfig.json b/x-pack/solutions/observability/plugins/streams_app/tsconfig.json index 38923832b4b04..ef9abc3a21b51 100644 --- a/x-pack/solutions/observability/plugins/streams_app/tsconfig.json +++ b/x-pack/solutions/observability/plugins/streams_app/tsconfig.json @@ -46,6 +46,7 @@ "@kbn/ui-theme", "@kbn/navigation-plugin", "@kbn/core-notifications-browser", + "@kbn/index-lifecycle-management-common-shared", "@kbn/streams-schema", ] } diff --git a/x-pack/test/api_integration/apis/streams/classic.ts b/x-pack/test/api_integration/apis/streams/classic.ts index af23eb783ead5..b6c184dafedee 100644 --- a/x-pack/test/api_integration/apis/streams/classic.ts +++ b/x-pack/test/api_integration/apis/streams/classic.ts @@ -99,7 +99,11 @@ export default function ({ getService }: FtrProviderContext) { expect(getResponse.body).to.eql({ name: TEST_STREAM_NAME, dashboards: [], - inherited_fields: [], + inherited_fields: {}, + lifecycle: { + policy: 'logs', + type: 'ilm', + }, stream: { ingest: { processing: [ diff --git a/x-pack/test/api_integration/apis/streams/enrichment.ts b/x-pack/test/api_integration/apis/streams/enrichment.ts index 43e8d51962dfb..b5e9f6d8d7751 100644 --- a/x-pack/test/api_integration/apis/streams/enrichment.ts +++ b/x-pack/test/api_integration/apis/streams/enrichment.ts @@ -128,14 +128,10 @@ export default function ({ getService }: FtrProviderContext) { expect(result._source).to.eql({ '@timestamp': '2024-01-01T00:00:10.000Z', message: '2023-01-01T00:00:10.000Z error test', - host: { - name: 'routeme', - }, + 'host.name': 'routeme', inner_timestamp: '2023-01-01T00:00:10.000Z', message2: 'test', - log: { - level: 'error', - }, + 'log.level': 'error', }); }); @@ -164,13 +160,9 @@ export default function ({ getService }: FtrProviderContext) { '@timestamp': '2024-01-01T00:00:11.000Z', message: '2023-01-01T00:00:10.000Z info mylogger this is the message', inner_timestamp: '2023-01-01T00:00:10.000Z', - host: { - name: 'routeme', - }, - log: { - level: 'info', - logger: 'mylogger', - }, + 'host.name': 'routeme', + 'log.level': 'info', + 'log.logger': 'mylogger', message2: 'mylogger this is the message', message3: 'this is the message', }); diff --git a/x-pack/test/api_integration/apis/streams/full_flow.ts b/x-pack/test/api_integration/apis/streams/full_flow.ts index 610f160f7419b..49375b505017c 100644 --- a/x-pack/test/api_integration/apis/streams/full_flow.ts +++ b/x-pack/test/api_integration/apis/streams/full_flow.ts @@ -49,7 +49,8 @@ export default function ({ getService }: FtrProviderContext) { expect(result._source).to.eql({ '@timestamp': '2024-01-01T00:00:00.000Z', message: 'test', - log: { level: 'info', logger: 'nginx' }, + 'log.level': 'info', + 'log.logger': 'nginx', }); }); @@ -86,7 +87,8 @@ export default function ({ getService }: FtrProviderContext) { expect(result._source).to.eql({ '@timestamp': '2024-01-01T00:00:10.000Z', message: 'test', - log: { level: 'info', logger: 'nginx' }, + 'log.level': 'info', + 'log.logger': 'nginx', }); }); @@ -124,7 +126,8 @@ export default function ({ getService }: FtrProviderContext) { expect(result._source).to.eql({ '@timestamp': '2024-01-01T00:00:20.000Z', message: 'test', - log: { level: 'info', logger: 'nginx' }, + 'log.level': 'info', + 'log.logger': 'nginx', }); }); @@ -164,7 +167,8 @@ export default function ({ getService }: FtrProviderContext) { expect(result._source).to.eql({ '@timestamp': '2024-01-01T00:00:20.000Z', message: 'test', - log: { level: 'error', logger: 'nginx' }, + 'log.level': 'error', + 'log.logger': 'nginx', }); });