Skip to content

Commit fd48faa

Browse files
authored
Migrate to data tiers should always ensure a TIER_PREFERENCE is set (#79100)
1 parent d380148 commit fd48faa

File tree

4 files changed

+194
-110
lines changed

4 files changed

+194
-110
lines changed

server/src/main/java/org/elasticsearch/cluster/metadata/Metadata.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,21 +39,21 @@
3939
import org.elasticsearch.common.settings.Setting;
4040
import org.elasticsearch.common.settings.Setting.Property;
4141
import org.elasticsearch.common.settings.Settings;
42-
import org.elasticsearch.xcontent.NamedObjectNotFoundException;
43-
import org.elasticsearch.xcontent.NamedXContentRegistry;
44-
import org.elasticsearch.xcontent.ToXContent;
45-
import org.elasticsearch.xcontent.ToXContentFragment;
46-
import org.elasticsearch.xcontent.XContentBuilder;
47-
import org.elasticsearch.xcontent.XContentFactory;
4842
import org.elasticsearch.common.xcontent.XContentHelper;
49-
import org.elasticsearch.xcontent.XContentParser;
5043
import org.elasticsearch.common.xcontent.XContentParserUtils;
5144
import org.elasticsearch.core.Nullable;
5245
import org.elasticsearch.gateway.MetadataStateFormat;
5346
import org.elasticsearch.index.Index;
5447
import org.elasticsearch.index.IndexNotFoundException;
5548
import org.elasticsearch.plugins.MapperPlugin;
5649
import org.elasticsearch.rest.RestStatus;
50+
import org.elasticsearch.xcontent.NamedObjectNotFoundException;
51+
import org.elasticsearch.xcontent.NamedXContentRegistry;
52+
import org.elasticsearch.xcontent.ToXContent;
53+
import org.elasticsearch.xcontent.ToXContentFragment;
54+
import org.elasticsearch.xcontent.XContentBuilder;
55+
import org.elasticsearch.xcontent.XContentFactory;
56+
import org.elasticsearch.xcontent.XContentParser;
5757

5858
import java.io.IOException;
5959
import java.util.ArrayList;
@@ -427,7 +427,7 @@ public ImmutableOpenMap<String, MappingMetadata> findMappings(String[] concreteI
427427
/**
428428
* Finds the parent data streams, if any, for the specified concrete indices.
429429
*/
430-
public ImmutableOpenMap<String, IndexAbstraction.DataStream> findDataStreams(String[] concreteIndices) {
430+
public ImmutableOpenMap<String, IndexAbstraction.DataStream> findDataStreams(String... concreteIndices) {
431431
assert concreteIndices != null;
432432
final ImmutableOpenMap.Builder<String, IndexAbstraction.DataStream> builder = ImmutableOpenMap.builder();
433433
final SortedMap<String, IndexAbstraction> lookup = getIndicesLookup();

x-pack/plugin/ilm/qa/multi-node/src/javaRestTest/java/org/elasticsearch/xpack/MigrateToDataTiersIT.java

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77

88
package org.elasticsearch.xpack;
99

10+
import com.fasterxml.jackson.databind.JsonNode;
11+
import com.fasterxml.jackson.databind.ObjectMapper;
12+
1013
import org.apache.http.entity.ContentType;
1114
import org.apache.http.entity.StringEntity;
1215
import org.apache.http.util.EntityUtils;
@@ -36,8 +39,8 @@
3639
import org.junit.Before;
3740

3841
import java.io.IOException;
39-
import java.util.ArrayList;
4042
import java.util.HashMap;
43+
import java.util.List;
4144
import java.util.Locale;
4245
import java.util.Map;
4346
import java.util.concurrent.TimeUnit;
@@ -49,6 +52,7 @@
4952
import static org.elasticsearch.xpack.TimeSeriesRestDriver.getOnlyIndexSettings;
5053
import static org.elasticsearch.xpack.TimeSeriesRestDriver.getStepKeyForIndex;
5154
import static org.hamcrest.Matchers.anEmptyMap;
55+
import static org.hamcrest.Matchers.contains;
5256
import static org.hamcrest.Matchers.containsInAnyOrder;
5357
import static org.hamcrest.Matchers.containsString;
5458
import static org.hamcrest.Matchers.equalTo;
@@ -134,9 +138,9 @@ public void testMigrateToDataTiersAction() throws Exception {
134138
createNewSingletonPolicy(client(), rolloverOnlyPolicyName, "hot", new RolloverAction(null, null, null, 1L));
135139

136140
String rolloverIndexPrefix = "rolloverpolicytest_index";
137-
for (int i = 1; i < randomIntBetween(2, 5); i++) {
138-
// assign the rollover-only policy to a few other indices - these indices and the rollover-only policy should not be migrated
139-
// in any way
141+
for (int i = 1; i <= 2; i++) {
142+
// assign the rollover-only policy to a few other indices - these indices will end up getting caught by the catch-all
143+
// tier preference migration
140144
createIndexWithSettings(client(), rolloverIndexPrefix + "-00000" + i, alias + i, Settings.builder()
141145
.put(IndexMetadata.SETTING_NUMBER_OF_SHARDS, 1)
142146
.put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 0)
@@ -167,10 +171,10 @@ public void testMigrateToDataTiersAction() throws Exception {
167171
assertOK(migrateDeploymentResponse);
168172

169173
Map<String, Object> migrateResponseAsMap = responseAsMap(migrateDeploymentResponse);
170-
assertThat((ArrayList<String>) migrateResponseAsMap.get(MigrateToDataTiersResponse.MIGRATED_ILM_POLICIES.getPreferredName()),
171-
containsInAnyOrder(policy));
172-
assertThat((ArrayList<String>) migrateResponseAsMap.get(MigrateToDataTiersResponse.MIGRATED_INDICES.getPreferredName()),
173-
containsInAnyOrder(index, indexWithDataWarmRouting));
174+
assertThat((List<String>) migrateResponseAsMap.get(MigrateToDataTiersResponse.MIGRATED_ILM_POLICIES.getPreferredName()),
175+
contains(policy));
176+
assertThat((List<String>) migrateResponseAsMap.get(MigrateToDataTiersResponse.MIGRATED_INDICES.getPreferredName()),
177+
containsInAnyOrder(index, indexWithDataWarmRouting, rolloverIndexPrefix + "-000001", rolloverIndexPrefix + "-000002"));
174178
assertThat(migrateResponseAsMap.get(MigrateToDataTiersResponse.REMOVED_LEGACY_TEMPLATE.getPreferredName()),
175179
is(templateName));
176180

@@ -209,6 +213,13 @@ public void testMigrateToDataTiersAction() throws Exception {
209213
assertThat(cachedPhaseDefinition, containsString(ShrinkAction.NAME));
210214
assertThat(cachedPhaseDefinition, containsString(SetPriorityAction.NAME));
211215
assertThat(cachedPhaseDefinition, containsString(ForceMergeAction.NAME));
216+
217+
// ENFORCE_DEFAULT_TIER_PREFERENCE has been set to true
218+
Request getSettingsRequest = new Request("GET", "_cluster/settings");
219+
Response getSettingsResponse = client().performRequest(getSettingsRequest);
220+
ObjectMapper mapper = new ObjectMapper();
221+
JsonNode json = mapper.readTree(getSettingsResponse.getEntity().getContent());
222+
assertTrue(json.at("/persistent/cluster/routing/allocation/enforce_default_tier_preference").asBoolean());
212223
}
213224

214225
@SuppressWarnings("unchecked")
@@ -274,9 +285,9 @@ public void testMigrationDryRun() throws Exception {
274285

275286
// response should contain the correct "to migrate" entities
276287
Map<String, Object> migrateResponseAsMap = responseAsMap(migrateDeploymentResponse);
277-
assertThat((ArrayList<String>) migrateResponseAsMap.get(MigrateToDataTiersResponse.MIGRATED_ILM_POLICIES.getPreferredName()),
288+
assertThat((List<String>) migrateResponseAsMap.get(MigrateToDataTiersResponse.MIGRATED_ILM_POLICIES.getPreferredName()),
278289
containsInAnyOrder(policy));
279-
assertThat((ArrayList<String>) migrateResponseAsMap.get(MigrateToDataTiersResponse.MIGRATED_INDICES.getPreferredName()),
290+
assertThat((List<String>) migrateResponseAsMap.get(MigrateToDataTiersResponse.MIGRATED_INDICES.getPreferredName()),
280291
containsInAnyOrder(index, indexWithDataWarmRouting));
281292
assertThat(migrateResponseAsMap.get(MigrateToDataTiersResponse.REMOVED_LEGACY_TEMPLATE.getPreferredName()),
282293
is(templateName));

x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/cluster/metadata/MetadataMigrateToDataTiersRoutingService.java

Lines changed: 56 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@
1515
import org.elasticsearch.cluster.ClusterState;
1616
import org.elasticsearch.cluster.metadata.IndexMetadata;
1717
import org.elasticsearch.cluster.metadata.Metadata;
18+
import org.elasticsearch.cluster.routing.allocation.DataTier;
1819
import org.elasticsearch.common.Strings;
1920
import org.elasticsearch.common.settings.Settings;
20-
import org.elasticsearch.xcontent.NamedXContentRegistry;
2121
import org.elasticsearch.core.Nullable;
2222
import org.elasticsearch.core.Tuple;
2323
import org.elasticsearch.license.XPackLicenseState;
24-
import org.elasticsearch.cluster.routing.allocation.DataTier;
24+
import org.elasticsearch.xcontent.NamedXContentRegistry;
2525
import org.elasticsearch.xpack.core.ilm.AllocateAction;
2626
import org.elasticsearch.xpack.core.ilm.IndexLifecycleMetadata;
2727
import org.elasticsearch.xpack.core.ilm.LifecycleAction;
@@ -48,6 +48,7 @@
4848
import static org.elasticsearch.cluster.metadata.IndexMetadata.INDEX_ROUTING_EXCLUDE_GROUP_SETTING;
4949
import static org.elasticsearch.cluster.metadata.IndexMetadata.INDEX_ROUTING_INCLUDE_GROUP_SETTING;
5050
import static org.elasticsearch.cluster.metadata.IndexMetadata.INDEX_ROUTING_REQUIRE_GROUP_SETTING;
51+
import static org.elasticsearch.cluster.routing.allocation.DataTier.ENFORCE_DEFAULT_TIER_PREFERENCE;
5152
import static org.elasticsearch.cluster.routing.allocation.DataTier.TIER_PREFERENCE;
5253
import static org.elasticsearch.xpack.core.ilm.LifecycleExecutionState.ILM_CUSTOM_METADATA_KEY;
5354
import static org.elasticsearch.xpack.core.ilm.OperationMode.STOPPED;
@@ -127,6 +128,18 @@ public static Tuple<ClusterState, MigratedEntities> migrateToDataTiersRouting(Cl
127128
}
128129

129130
Metadata.Builder mb = Metadata.builder(currentState.metadata());
131+
132+
// set ENFORCE_DEFAULT_TIER_PREFERENCE to true (in the persistent settings)
133+
mb.persistentSettings(Settings.builder()
134+
.put(mb.persistentSettings())
135+
.put(ENFORCE_DEFAULT_TIER_PREFERENCE, true)
136+
.build());
137+
138+
// and remove it from the transient settings, just in case it was there
139+
Settings.Builder transientSettingsBuilder = Settings.builder().put(mb.transientSettings());
140+
transientSettingsBuilder.remove(ENFORCE_DEFAULT_TIER_PREFERENCE);
141+
mb.transientSettings(transientSettingsBuilder.build());
142+
130143
String removedIndexTemplateName = null;
131144
if (Strings.hasText(indexTemplateToDelete)) {
132145
if (currentState.metadata().getTemplates().containsKey(indexTemplateToDelete)) {
@@ -376,20 +389,34 @@ static List<String> migrateIndices(Metadata.Builder mb, ClusterState currentStat
376389
for (ObjectObjectCursor<String, IndexMetadata> index : currentState.metadata().indices()) {
377390
IndexMetadata indexMetadata = index.value;
378391
Settings currentSettings = indexMetadata.getSettings();
392+
393+
boolean removeNodeAttrIndexRoutingSettings = true;
394+
395+
// migrate using the `require` setting
379396
Settings newSettings = maybeMigrateRoutingSettingToTierPreference(nodeAttrIndexRequireRoutingSetting, indexMetadata);
397+
380398
if (newSettings.equals(currentSettings)) {
381-
// migrating based on the `require` setting was not successful so let's check if the index used the `include` routing
399+
// migrating based on the `require` setting was not successful, so let's check if the index used the `include` routing
382400
// setting to configure the allocations and try to migrate it
383401
newSettings = maybeMigrateRoutingSettingToTierPreference(nodeAttrIndexIncludeRoutingSetting, indexMetadata);
384402
}
403+
if (newSettings.equals(currentSettings)) {
404+
removeNodeAttrIndexRoutingSettings = false;
405+
// migrating based on the `include` setting was not successful,
406+
// so, last stop, we just inject a tier preference regardless of anything else
407+
newSettings = migrateToDefaultTierPreference(currentState, indexMetadata);
408+
}
385409

386410
if (newSettings.equals(currentSettings) == false) {
387-
// we converted either the require or the include routing setting to tier preference
388-
// so let's clear all the routing settings for the given attribute
389411
Settings.Builder finalSettings = Settings.builder().put(newSettings);
390-
finalSettings.remove(nodeAttrIndexExcludeRoutingSetting);
391-
finalSettings.remove(nodeAttrIndexRequireRoutingSetting);
392-
finalSettings.remove(nodeAttrIndexIncludeRoutingSetting);
412+
413+
if (removeNodeAttrIndexRoutingSettings) {
414+
// we converted either the `require` or the `include` routing setting to tier preference
415+
// so let's clear all the routing settings for the given attribute
416+
finalSettings.remove(nodeAttrIndexExcludeRoutingSetting);
417+
finalSettings.remove(nodeAttrIndexRequireRoutingSetting);
418+
finalSettings.remove(nodeAttrIndexIncludeRoutingSetting);
419+
}
393420

394421
mb.put(IndexMetadata.builder(indexMetadata)
395422
.settings(finalSettings)
@@ -413,9 +440,11 @@ private static Settings maybeMigrateRoutingSettingToTierPreference(String attrib
413440
if (currentIndexSettings.keySet().contains(attributeBasedRoutingSettingName) == false) {
414441
return currentIndexSettings;
415442
}
416-
// look at the value, get the correct tiers config and update the settings and index metadata
443+
417444
Settings.Builder newSettingsBuilder = Settings.builder().put(currentIndexSettings);
418445
String indexName = indexMetadata.getIndex().getName();
446+
447+
// look at the value, get the correct tiers config and update the settings
419448
if (currentIndexSettings.keySet().contains(TIER_PREFERENCE)) {
420449
newSettingsBuilder.remove(attributeBasedRoutingSettingName);
421450
logger.debug("index [{}]: removed setting [{}]", indexName, attributeBasedRoutingSettingName);
@@ -428,7 +457,7 @@ private static Settings maybeMigrateRoutingSettingToTierPreference(String attrib
428457
newSettingsBuilder.remove(attributeBasedRoutingSettingName);
429458
logger.debug("index [{}]: removed setting [{}]", indexName, attributeBasedRoutingSettingName);
430459
logger.debug("index [{}]: configured setting [{}] to [{}]", indexName,
431-
TIER_PREFERENCE, convertedTierPreference);
460+
TIER_PREFERENCE, convertedTierPreference);
432461
} else {
433462
// log warning and do *not* remove setting, return the settings unchanged
434463
logger.warn("index [{}]: could not convert attribute based setting [{}] value of [{}] to a tier preference " +
@@ -440,6 +469,23 @@ private static Settings maybeMigrateRoutingSettingToTierPreference(String attrib
440469
return newSettingsBuilder.build();
441470
}
442471

472+
private static Settings migrateToDefaultTierPreference(ClusterState currentState, IndexMetadata indexMetadata) {
473+
Settings currentIndexSettings = indexMetadata.getSettings();
474+
List<String> tierPreference = DataTier.parseTierList(currentIndexSettings.get(DataTier.TIER_PREFERENCE));
475+
if (tierPreference.isEmpty() == false) {
476+
return currentIndexSettings;
477+
}
478+
479+
Settings.Builder newSettingsBuilder = Settings.builder().put(currentIndexSettings);
480+
String indexName = indexMetadata.getIndex().getName();
481+
482+
boolean isDataStream = currentState.metadata().findDataStreams(indexName).isEmpty() == false;
483+
String convertedTierPreference = isDataStream ? DataTier.DATA_HOT : DataTier.DATA_CONTENT;
484+
newSettingsBuilder.put(TIER_PREFERENCE, convertedTierPreference);
485+
logger.debug("index [{}]: configured setting [{}] to [{}]", indexName, TIER_PREFERENCE, convertedTierPreference);
486+
return newSettingsBuilder.build();
487+
}
488+
443489
/**
444490
* Converts the provided node attribute value to the corresponding `_tier_preference` configuration.
445491
* Known (and convertible) attribute values are:

0 commit comments

Comments
 (0)