|
23 | 23 | import org.elasticsearch.action.admin.indices.template.put.TransportPutComposableIndexTemplateAction; |
24 | 24 | import org.elasticsearch.action.bulk.BulkRequest; |
25 | 25 | import org.elasticsearch.action.bulk.BulkResponse; |
| 26 | +import org.elasticsearch.action.datastreams.CreateDataStreamAction; |
| 27 | +import org.elasticsearch.action.datastreams.GetDataStreamAction; |
26 | 28 | import org.elasticsearch.action.index.IndexRequest; |
27 | 29 | import org.elasticsearch.action.ingest.PutPipelineRequest; |
28 | 30 | import org.elasticsearch.action.ingest.PutPipelineTransportAction; |
| 31 | +import org.elasticsearch.action.support.IndicesOptions; |
| 32 | +import org.elasticsearch.action.support.master.AcknowledgedRequest; |
29 | 33 | import org.elasticsearch.cluster.block.ClusterBlockException; |
30 | 34 | import org.elasticsearch.cluster.metadata.ComposableIndexTemplate; |
31 | 35 | import org.elasticsearch.cluster.metadata.IndexMetadata; |
|
38 | 42 | import org.elasticsearch.common.time.DateFormatter; |
39 | 43 | import org.elasticsearch.common.time.FormatNames; |
40 | 44 | import org.elasticsearch.common.xcontent.support.XContentMapValues; |
| 45 | +import org.elasticsearch.core.TimeValue; |
41 | 46 | import org.elasticsearch.datastreams.DataStreamsPlugin; |
| 47 | +import org.elasticsearch.index.Index; |
42 | 48 | import org.elasticsearch.index.IndexSettings; |
43 | 49 | import org.elasticsearch.index.mapper.DateFieldMapper; |
44 | 50 | import org.elasticsearch.ingest.common.IngestCommonPlugin; |
|
47 | 53 | import org.elasticsearch.test.ESIntegTestCase; |
48 | 54 | import org.elasticsearch.test.transport.MockTransportService; |
49 | 55 | import org.elasticsearch.xcontent.XContentType; |
| 56 | +import org.elasticsearch.xcontent.json.JsonXContent; |
| 57 | +import org.elasticsearch.xpack.core.LocalStateCompositeXPackPlugin; |
| 58 | +import org.elasticsearch.xpack.core.ilm.LifecyclePolicy; |
| 59 | +import org.elasticsearch.xpack.core.ilm.LifecycleSettings; |
| 60 | +import org.elasticsearch.xpack.core.ilm.OperationMode; |
| 61 | +import org.elasticsearch.xpack.core.ilm.Phase; |
| 62 | +import org.elasticsearch.xpack.core.ilm.StartILMRequest; |
| 63 | +import org.elasticsearch.xpack.core.ilm.StopILMRequest; |
| 64 | +import org.elasticsearch.xpack.core.ilm.action.GetStatusAction; |
| 65 | +import org.elasticsearch.xpack.core.ilm.action.ILMActions; |
| 66 | +import org.elasticsearch.xpack.core.ilm.action.PutLifecycleRequest; |
| 67 | +import org.elasticsearch.xpack.ilm.IndexLifecycle; |
50 | 68 | import org.elasticsearch.xpack.migrate.MigratePlugin; |
51 | 69 | import org.elasticsearch.xpack.migrate.MigrateTemplateRegistry; |
52 | 70 | import org.junit.Before; |
|
57 | 75 | import java.util.List; |
58 | 76 | import java.util.Locale; |
59 | 77 | import java.util.Map; |
| 78 | +import java.util.concurrent.TimeUnit; |
60 | 79 |
|
61 | 80 | import static java.lang.Boolean.parseBoolean; |
62 | 81 | import static org.elasticsearch.cluster.metadata.MetadataIndexTemplateService.DEFAULT_TIMESTAMP_FIELD; |
@@ -93,10 +112,22 @@ protected Collection<Class<? extends Plugin>> nodePlugins() { |
93 | 112 | ReindexPlugin.class, |
94 | 113 | MockTransportService.TestPlugin.class, |
95 | 114 | DataStreamsPlugin.class, |
96 | | - IngestCommonPlugin.class |
| 115 | + IngestCommonPlugin.class, |
| 116 | + IndexLifecycle.class, |
| 117 | + LocalStateCompositeXPackPlugin.class |
97 | 118 | ); |
98 | 119 | } |
99 | 120 |
|
| 121 | + @Override |
| 122 | + protected Settings nodeSettings(int nodeOrdinal, Settings otherSettings) { |
| 123 | + return Settings.builder() |
| 124 | + .put(super.nodeSettings(nodeOrdinal, otherSettings)) |
| 125 | + .put(LifecycleSettings.LIFECYCLE_POLL_INTERVAL, "1s") |
| 126 | + // This just generates less churn and makes it easier to read the log file if needed |
| 127 | + .put(LifecycleSettings.LIFECYCLE_HISTORY_INDEX_ENABLED, false) |
| 128 | + .build(); |
| 129 | + } |
| 130 | + |
100 | 131 | private static String DATA_STREAM_MAPPING = """ |
101 | 132 | { |
102 | 133 | "dynamic": true, |
@@ -588,6 +619,135 @@ public void testTsdbStartEndSet() throws Exception { |
588 | 619 | assertHitCount(prepareSearch(destIndex).setSize(0), 1); |
589 | 620 | } |
590 | 621 |
|
| 622 | + public void testIndexLifecycleSettingNotCopied() throws Exception { |
| 623 | + Map<String, Phase> phases = Map.of( |
| 624 | + "hot", |
| 625 | + new Phase( |
| 626 | + "hot", |
| 627 | + TimeValue.ZERO, |
| 628 | + Map.of( |
| 629 | + "rollover", |
| 630 | + new org.elasticsearch.xpack.core.ilm.RolloverAction(null, null, null, 1L, null, null, null, null, null, null) |
| 631 | + ) |
| 632 | + ) |
| 633 | + ); |
| 634 | + |
| 635 | + var policyName = "my-policy"; |
| 636 | + LifecyclePolicy policy = new LifecyclePolicy(policyName, phases); |
| 637 | + PutLifecycleRequest putLifecycleRequest = new PutLifecycleRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, policy); |
| 638 | + assertAcked(client().execute(ILMActions.PUT, putLifecycleRequest).actionGet()); |
| 639 | + |
| 640 | + // create data stream with a document and wait for ILM to roll it over |
| 641 | + var dataStream = createDataStream(policyName); |
| 642 | + createDocument(dataStream); |
| 643 | + |
| 644 | + assertAcked(safeGet(client().execute(ILMActions.START, new StartILMRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT)))); |
| 645 | + assertBusy(() -> { |
| 646 | + var getIndexResponse = safeGet(indicesAdmin().getIndex(new GetIndexRequest(TEST_REQUEST_TIMEOUT).indices(dataStream))); |
| 647 | + assertTrue(getIndexResponse.indices().length >= 2); |
| 648 | + }); |
| 649 | + stopILM(); |
| 650 | + |
| 651 | + var dataStreams = safeGet( |
| 652 | + indicesAdmin().execute( |
| 653 | + GetDataStreamAction.INSTANCE, |
| 654 | + new GetDataStreamAction.Request(TEST_REQUEST_TIMEOUT, new String[] { dataStream }) |
| 655 | + ) |
| 656 | + ).getDataStreams(); |
| 657 | + |
| 658 | + assertFalse(dataStreams.isEmpty()); |
| 659 | + String writeIndex = dataStreams.get(0).getDataStream().getWriteIndex().getName(); |
| 660 | + List<String> indices = dataStreams.get(0).getDataStream().getIndices().stream().map(Index::getName).toList(); |
| 661 | + assertTrue(indices.size() >= 2); |
| 662 | + |
| 663 | + for (var backingIndex : indices) { |
| 664 | + if (backingIndex.equals(writeIndex) == false) { |
| 665 | + var destIndex = safeGet( |
| 666 | + client().execute(ReindexDataStreamIndexAction.INSTANCE, new ReindexDataStreamIndexAction.Request(backingIndex)) |
| 667 | + ).getDestIndex(); |
| 668 | + var settingsResponse = safeGet( |
| 669 | + indicesAdmin().getSettings(new GetSettingsRequest(TEST_REQUEST_TIMEOUT).indices(backingIndex, destIndex)) |
| 670 | + ); |
| 671 | + assertEquals(policyName, settingsResponse.getSetting(backingIndex, IndexMetadata.LIFECYCLE_NAME)); |
| 672 | + assertNull(settingsResponse.getSetting(destIndex, IndexMetadata.LIFECYCLE_NAME)); |
| 673 | + } |
| 674 | + } |
| 675 | + } |
| 676 | + |
| 677 | + private void stopILM() throws Exception { |
| 678 | + assertAcked(safeGet(client().execute(ILMActions.STOP, new StopILMRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT)))); |
| 679 | + assertBusy(() -> { |
| 680 | + var statusResponse = safeGet( |
| 681 | + client().execute(GetStatusAction.INSTANCE, new AcknowledgedRequest.Plain(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT)) |
| 682 | + ); |
| 683 | + assertEquals(OperationMode.STOPPED, statusResponse.getMode()); |
| 684 | + }); |
| 685 | + } |
| 686 | + |
| 687 | + private String createDataStream(String ilmPolicy) throws Exception { |
| 688 | + String dataStreamName = randomAlphaOfLength(10).toLowerCase(Locale.getDefault()); |
| 689 | + |
| 690 | + Settings settings = ilmPolicy != null ? Settings.builder().put(IndexMetadata.LIFECYCLE_NAME, ilmPolicy).build() : null; |
| 691 | + |
| 692 | + String mapping = """ |
| 693 | + { |
| 694 | + "properties": { |
| 695 | + "@timestamp": { |
| 696 | + "type":"date" |
| 697 | + }, |
| 698 | + "data":{ |
| 699 | + "type":"keyword" |
| 700 | + } |
| 701 | + } |
| 702 | + } |
| 703 | + """; |
| 704 | + Template idxTemplate = new Template(settings, new CompressedXContent(mapping), null); |
| 705 | + |
| 706 | + ComposableIndexTemplate template = ComposableIndexTemplate.builder() |
| 707 | + .indexPatterns(List.of(dataStreamName + "*")) |
| 708 | + .template(idxTemplate) |
| 709 | + .dataStreamTemplate(new ComposableIndexTemplate.DataStreamTemplate(false, false)) |
| 710 | + .build(); |
| 711 | + |
| 712 | + assertAcked( |
| 713 | + client().execute( |
| 714 | + TransportPutComposableIndexTemplateAction.TYPE, |
| 715 | + new TransportPutComposableIndexTemplateAction.Request(dataStreamName + "_template").indexTemplate(template) |
| 716 | + ) |
| 717 | + ); |
| 718 | + assertAcked( |
| 719 | + client().execute( |
| 720 | + CreateDataStreamAction.INSTANCE, |
| 721 | + new CreateDataStreamAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, dataStreamName) |
| 722 | + ) |
| 723 | + ); |
| 724 | + return dataStreamName; |
| 725 | + } |
| 726 | + |
| 727 | + private long createDocument(String dataStreamName) throws Exception { |
| 728 | + // Get some randomized but reasonable timestamps on the data since not all of it is guaranteed to arrive in order. |
| 729 | + long timeSeed = System.currentTimeMillis(); |
| 730 | + long timestamp = randomLongBetween(timeSeed - TimeUnit.HOURS.toMillis(5), timeSeed); |
| 731 | + safeGet( |
| 732 | + client().index( |
| 733 | + new IndexRequest(dataStreamName).opType(DocWriteRequest.OpType.CREATE) |
| 734 | + .source( |
| 735 | + JsonXContent.contentBuilder() |
| 736 | + .startObject() |
| 737 | + .field("@timestamp", timestamp) |
| 738 | + .field("data", randomAlphaOfLength(25)) |
| 739 | + .endObject() |
| 740 | + ) |
| 741 | + ) |
| 742 | + ); |
| 743 | + safeGet( |
| 744 | + indicesAdmin().refresh( |
| 745 | + new RefreshRequest(".ds-" + dataStreamName + "*").indicesOptions(IndicesOptions.lenientExpandOpenHidden()) |
| 746 | + ) |
| 747 | + ); |
| 748 | + return timestamp; |
| 749 | + } |
| 750 | + |
591 | 751 | private static void cleanupMetadataBlocks(String index) { |
592 | 752 | var settings = Settings.builder() |
593 | 753 | .putNull(IndexMetadata.SETTING_READ_ONLY) |
|
0 commit comments