Skip to content

Commit f6550e8

Browse files
authored
Add datastream lifecycle support to indices metadata (#245548)
## Summary Add [Datastream life cycle](https://www.elastic.co/docs/manage-data/lifecycle/data-stream) support to the indices metadata plugin. For data streams using DSL, the plugin now also queries the `data_retention` and includes it in the EBT document. Example document returned by `GET _data_stream/<ds name>/?filter_path=data_streams.name,data_streams.indices,data_streams.lifecycle.enabled,data_streams.lifecycle.data_retention` ```json { "data_streams": [ { "name": "dsl-test", "indices": [ { "index_name": ".ds-dsl-test-2025.12.08-000001", "index_uuid": "h9nu5fEIQJ-ObVemiXTPqg", "managed_by": "Data stream lifecycle", "prefer_ilm": true, "index_mode": "standard" }, { "index_name": ".ds-dsl-test-2025.12.08-000002", "index_uuid": "VKp5OURcTIquxTmatmNz3g", "managed_by": "Data stream lifecycle", "prefer_ilm": true, "index_mode": "standard" } ], "lifecycle": { "enabled": true, "data_retention": "1h" } } ] } ``` ### Checklist Check the PR satisfies following conditions. Reviewers should verify this PR satisfies this list as well. - [ ] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md) - [ ] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [ ] If a plugin configuration key changed, check if it needs to be allowlisted in the cloud and added to the [docker list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker) - [ ] This was checked for breaking HTTP API changes, and any breaking changes have been approved by the breaking-change committee. The `release_note:breaking` label should be applied in these situations. - [ ] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed - [ ] The PR description includes the appropriate Release Notes section, and the correct `release_note:*` label is applied per the [guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) - [ ] Review the [backport guidelines](https://docs.google.com/document/d/1VyN5k91e5OVumlc0Gb9RPa3h1ewuPE705nRtioPiTvY/edit?usp=sharing) and apply applicable `backport:*` labels.
1 parent 5226ed1 commit f6550e8

File tree

6 files changed

+483
-2
lines changed

6 files changed

+483
-2
lines changed

x-pack/platform/plugins/private/indices_metadata/server/lib/ebt/events.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,19 @@ export const DATA_STREAM_EVENT: EventTypeOpts<DataStreams> = {
3131
type: 'keyword',
3232
_meta: { optional: true, description: 'ILM policy associated to the datastream' },
3333
},
34+
dsl: {
35+
properties: {
36+
enabled: {
37+
type: 'boolean',
38+
_meta: { description: 'Whether the data stream is enabled' },
39+
},
40+
data_retention: {
41+
type: 'text',
42+
_meta: { optional: true, description: 'Data retention period' },
43+
},
44+
},
45+
_meta: { optional: true, description: 'Data stream lifecycle settings' },
46+
},
3447
template: {
3548
type: 'keyword',
3649
_meta: { optional: true, description: 'Template associated to the datastream' },

x-pack/platform/plugins/private/indices_metadata/server/lib/services/indices_metadata.test.ts

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ describe('Indices Metadata - IndicesMetadataService', () => {
7171
const mockDataStreams: DataStream[] = [
7272
{
7373
datastream_name: 'test-datastream',
74+
dsl: {
75+
enabled: true,
76+
data_retention: '30d',
77+
},
7478
indices: [{ index_name: 'test-index-1', ilm_policy: 'policy1' }],
7579
},
7680
];
@@ -365,6 +369,60 @@ describe('Indices Metadata - IndicesMetadataService', () => {
365369
expect(receiver.getIlmsStats).toHaveBeenCalledWith(['test-index-1']);
366370
});
367371

372+
it('should publish datastreams with DSL through full metadata flow', async () => {
373+
const datastreamsWithDsl: DataStream[] = [
374+
{
375+
datastream_name: 'logs-test',
376+
dsl: {
377+
enabled: true,
378+
data_retention: '90d',
379+
},
380+
indices: [
381+
{
382+
index_name: '.ds-logs-test-000001',
383+
ilm_policy: 'logs-policy',
384+
},
385+
],
386+
},
387+
];
388+
389+
receiver.getIndices.mockResolvedValue(mockIndexSettings);
390+
receiver.getDataStreams.mockResolvedValue(datastreamsWithDsl);
391+
receiver.getIndexTemplatesStats.mockResolvedValue(mockIndexTemplates);
392+
receiver.getIndicesStats.mockImplementation(async function* () {
393+
yield* mockIndexStats;
394+
});
395+
receiver.isIlmStatsAvailable.mockResolvedValue(true);
396+
receiver.getIlmsStats.mockImplementation(async function* () {
397+
yield {
398+
index_name: '.ds-logs-test-000001',
399+
phase: 'hot',
400+
age: '1d',
401+
policy_name: 'logs-policy',
402+
};
403+
});
404+
receiver.getIlmsPolicies.mockImplementation(async function* () {
405+
yield { policy_name: 'logs-policy', modified_date: '2023-01-01', phases: {} };
406+
});
407+
408+
await service['publishIndicesMetadata'](); // eslint-disable-line dot-notation
409+
410+
expect(sender.reportEBT).toHaveBeenCalledWith(
411+
expect.objectContaining({ eventType: DATA_STREAM_EVENT.eventType }),
412+
{
413+
items: expect.arrayContaining([
414+
expect.objectContaining({
415+
datastream_name: 'logs-test',
416+
dsl: {
417+
enabled: true,
418+
data_retention: '90d',
419+
},
420+
}),
421+
]),
422+
}
423+
);
424+
});
425+
368426
it('should throw error when not initialized', async () => {
369427
const uninitializedService = new IndicesMetadataService(logger, configurationService);
370428

@@ -441,6 +499,116 @@ describe('Indices Metadata - IndicesMetadataService', () => {
441499
expect(result).toBe(1);
442500
expect(logger.debug).toHaveBeenCalledWith('Data streams events sent', { count: 1 });
443501
});
502+
503+
it('should publish datastreams with DSL enabled and retention', () => {
504+
const datastreamsWithDsl: DataStream[] = [
505+
{
506+
datastream_name: 'logs-app-prod',
507+
dsl: {
508+
enabled: true,
509+
data_retention: '7d',
510+
},
511+
indices: [{ index_name: '.ds-logs-app-prod-000001' }],
512+
},
513+
{
514+
datastream_name: 'metrics-system',
515+
dsl: {
516+
enabled: false,
517+
data_retention: undefined,
518+
},
519+
indices: [{ index_name: '.ds-metrics-system-000001' }],
520+
},
521+
];
522+
523+
const result = service['publishDatastreamsStats'](datastreamsWithDsl); // eslint-disable-line dot-notation
524+
525+
expect(sender.reportEBT).toHaveBeenCalledWith(
526+
expect.objectContaining({ eventType: DATA_STREAM_EVENT.eventType }),
527+
{
528+
items: [
529+
expect.objectContaining({
530+
datastream_name: 'logs-app-prod',
531+
dsl: {
532+
enabled: true,
533+
data_retention: '7d',
534+
},
535+
}),
536+
expect.objectContaining({
537+
datastream_name: 'metrics-system',
538+
dsl: {
539+
enabled: false,
540+
data_retention: undefined,
541+
},
542+
}),
543+
],
544+
}
545+
);
546+
expect(result).toBe(2);
547+
});
548+
549+
it('should handle datastreams without DSL field', () => {
550+
const datastreamsWithoutDsl: DataStream[] = [
551+
{
552+
datastream_name: 'legacy-datastream',
553+
indices: [{ index_name: '.ds-legacy-000001' }],
554+
},
555+
];
556+
557+
const result = service['publishDatastreamsStats'](datastreamsWithoutDsl); // eslint-disable-line dot-notation
558+
559+
expect(sender.reportEBT).toHaveBeenCalledWith(
560+
expect.objectContaining({ eventType: DATA_STREAM_EVENT.eventType }),
561+
{
562+
items: [
563+
{
564+
datastream_name: 'legacy-datastream',
565+
indices: [{ index_name: '.ds-legacy-000001' }],
566+
},
567+
],
568+
}
569+
);
570+
expect(result).toBe(1);
571+
});
572+
573+
it('should publish mixed DSL configurations', () => {
574+
const mixedDatastreams: DataStream[] = [
575+
{
576+
datastream_name: 'with-retention',
577+
dsl: { enabled: true, data_retention: '365d' },
578+
indices: [],
579+
},
580+
{
581+
datastream_name: 'enabled-no-retention',
582+
dsl: { enabled: true, data_retention: undefined },
583+
indices: [],
584+
},
585+
{
586+
datastream_name: 'disabled',
587+
dsl: { enabled: false, data_retention: undefined },
588+
indices: [],
589+
},
590+
];
591+
592+
const result = service['publishDatastreamsStats'](mixedDatastreams); // eslint-disable-line dot-notation
593+
594+
expect(sender.reportEBT).toHaveBeenCalledWith(
595+
expect.objectContaining({ eventType: DATA_STREAM_EVENT.eventType }),
596+
{
597+
items: expect.arrayContaining([
598+
expect.objectContaining({
599+
dsl: { enabled: true, data_retention: '365d' },
600+
}),
601+
expect.objectContaining({
602+
dsl: { enabled: true, data_retention: undefined },
603+
}),
604+
expect.objectContaining({
605+
dsl: { enabled: false, data_retention: undefined },
606+
}),
607+
]),
608+
}
609+
);
610+
expect(result).toBe(3);
611+
});
444612
});
445613

446614
describe('publishIndicesSettings', () => {

x-pack/platform/plugins/private/indices_metadata/server/lib/services/indices_metadata.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,7 @@ export class IndicesMetadataService {
257257
this.logger.debug('Indices settings sent', { count: indicesSettings.items.length } as LogMeta);
258258
return indicesSettings.items.length;
259259
}
260+
260261
private async publishIlmStats(indices: string[]): Promise<Set<string>> {
261262
const ilmNames = new Set<string>();
262263
const ilmsStats: IlmsStats = {

x-pack/platform/plugins/private/indices_metadata/server/lib/services/indices_metadata.types.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,16 @@ export interface Index {
114114
export interface DataStreams {
115115
items: DataStream[];
116116
}
117+
118+
export interface DataStreamLifeCycle {
119+
enabled: boolean;
120+
data_retention?: string;
121+
}
122+
117123
export interface DataStream {
118124
datastream_name: string;
119125
ilm_policy?: string;
126+
dsl?: DataStreamLifeCycle;
120127
template?: string;
121128
indices?: Index[];
122129
}

0 commit comments

Comments
 (0)