Skip to content

Commit

Permalink
Migrate to data tiers should always ensure a TIER_PREFERENCE is set (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
joegallo authored Oct 15, 2021
1 parent 2d5eea6 commit fa6d466
Show file tree
Hide file tree
Showing 4 changed files with 195 additions and 113 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import org.apache.lucene.util.CollectionUtil;
import org.elasticsearch.ResourceNotFoundException;
import org.elasticsearch.Version;
Expand All @@ -41,21 +40,21 @@
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Setting.Property;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.xcontent.NamedObjectNotFoundException;
import org.elasticsearch.xcontent.NamedXContentRegistry;
import org.elasticsearch.xcontent.ToXContent;
import org.elasticsearch.xcontent.ToXContentFragment;
import org.elasticsearch.xcontent.XContentBuilder;
import org.elasticsearch.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentParserUtils;
import org.elasticsearch.core.Nullable;
import org.elasticsearch.gateway.MetadataStateFormat;
import org.elasticsearch.index.Index;
import org.elasticsearch.index.IndexNotFoundException;
import org.elasticsearch.plugins.MapperPlugin;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.xcontent.NamedObjectNotFoundException;
import org.elasticsearch.xcontent.NamedXContentRegistry;
import org.elasticsearch.xcontent.ToXContent;
import org.elasticsearch.xcontent.ToXContentFragment;
import org.elasticsearch.xcontent.XContentBuilder;
import org.elasticsearch.xcontent.XContentFactory;
import org.elasticsearch.xcontent.XContentParser;

import java.io.IOException;
import java.util.ArrayList;
Expand Down Expand Up @@ -477,7 +476,7 @@ public ImmutableOpenMap<String, ImmutableOpenMap<String, MappingMetadata>> findM
/**
* Finds the parent data streams, if any, for the specified concrete indices.
*/
public ImmutableOpenMap<String, IndexAbstraction.DataStream> findDataStreams(String[] concreteIndices) {
public ImmutableOpenMap<String, IndexAbstraction.DataStream> findDataStreams(String... concreteIndices) {
assert concreteIndices != null;
final ImmutableOpenMap.Builder<String, IndexAbstraction.DataStream> builder = ImmutableOpenMap.builder();
final SortedMap<String, IndexAbstraction> lookup = getIndicesLookup();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@

package org.elasticsearch.xpack;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.util.EntityUtils;
Expand Down Expand Up @@ -36,8 +39,8 @@
import org.junit.Before;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.TimeUnit;
Expand All @@ -49,6 +52,7 @@
import static org.elasticsearch.xpack.TimeSeriesRestDriver.getOnlyIndexSettings;
import static org.elasticsearch.xpack.TimeSeriesRestDriver.getStepKeyForIndex;
import static org.hamcrest.Matchers.anEmptyMap;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
Expand Down Expand Up @@ -134,9 +138,9 @@ public void testMigrateToDataTiersAction() throws Exception {
createNewSingletonPolicy(client(), rolloverOnlyPolicyName, "hot", new RolloverAction(null, null, null, 1L));

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

Map<String, Object> migrateResponseAsMap = responseAsMap(migrateDeploymentResponse);
assertThat((ArrayList<String>) migrateResponseAsMap.get(MigrateToDataTiersResponse.MIGRATED_ILM_POLICIES.getPreferredName()),
containsInAnyOrder(policy));
assertThat((ArrayList<String>) migrateResponseAsMap.get(MigrateToDataTiersResponse.MIGRATED_INDICES.getPreferredName()),
containsInAnyOrder(index, indexWithDataWarmRouting));
assertThat((List<String>) migrateResponseAsMap.get(MigrateToDataTiersResponse.MIGRATED_ILM_POLICIES.getPreferredName()),
contains(policy));
assertThat((List<String>) migrateResponseAsMap.get(MigrateToDataTiersResponse.MIGRATED_INDICES.getPreferredName()),
containsInAnyOrder(index, indexWithDataWarmRouting, rolloverIndexPrefix + "-000001", rolloverIndexPrefix + "-000002"));
assertThat(migrateResponseAsMap.get(MigrateToDataTiersResponse.REMOVED_LEGACY_TEMPLATE.getPreferredName()),
is(templateName));

Expand Down Expand Up @@ -209,6 +213,13 @@ public void testMigrateToDataTiersAction() throws Exception {
assertThat(cachedPhaseDefinition, containsString(ShrinkAction.NAME));
assertThat(cachedPhaseDefinition, containsString(SetPriorityAction.NAME));
assertThat(cachedPhaseDefinition, containsString(ForceMergeAction.NAME));

// ENFORCE_DEFAULT_TIER_PREFERENCE has been set to true
Request getSettingsRequest = new Request("GET", "_cluster/settings");
Response getSettingsResponse = client().performRequest(getSettingsRequest);
ObjectMapper mapper = new ObjectMapper();
JsonNode json = mapper.readTree(getSettingsResponse.getEntity().getContent());
assertTrue(json.at("/persistent/cluster/routing/allocation/enforce_default_tier_preference").asBoolean());
}

@SuppressWarnings("unchecked")
Expand Down Expand Up @@ -274,9 +285,9 @@ public void testMigrationDryRun() throws Exception {

// response should contain the correct "to migrate" entities
Map<String, Object> migrateResponseAsMap = responseAsMap(migrateDeploymentResponse);
assertThat((ArrayList<String>) migrateResponseAsMap.get(MigrateToDataTiersResponse.MIGRATED_ILM_POLICIES.getPreferredName()),
assertThat((List<String>) migrateResponseAsMap.get(MigrateToDataTiersResponse.MIGRATED_ILM_POLICIES.getPreferredName()),
containsInAnyOrder(policy));
assertThat((ArrayList<String>) migrateResponseAsMap.get(MigrateToDataTiersResponse.MIGRATED_INDICES.getPreferredName()),
assertThat((List<String>) migrateResponseAsMap.get(MigrateToDataTiersResponse.MIGRATED_INDICES.getPreferredName()),
containsInAnyOrder(index, indexWithDataWarmRouting));
assertThat(migrateResponseAsMap.get(MigrateToDataTiersResponse.REMOVED_LEGACY_TEMPLATE.getPreferredName()),
is(templateName));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.IndexMetadata;
import org.elasticsearch.cluster.metadata.Metadata;
import org.elasticsearch.cluster.routing.allocation.DataTier;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.xcontent.NamedXContentRegistry;
import org.elasticsearch.core.Nullable;
import org.elasticsearch.core.Tuple;
import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.cluster.routing.allocation.DataTier;
import org.elasticsearch.xcontent.NamedXContentRegistry;
import org.elasticsearch.xpack.core.ilm.AllocateAction;
import org.elasticsearch.xpack.core.ilm.IndexLifecycleMetadata;
import org.elasticsearch.xpack.core.ilm.LifecycleAction;
Expand All @@ -48,6 +48,7 @@
import static org.elasticsearch.cluster.metadata.IndexMetadata.INDEX_ROUTING_EXCLUDE_GROUP_SETTING;
import static org.elasticsearch.cluster.metadata.IndexMetadata.INDEX_ROUTING_INCLUDE_GROUP_SETTING;
import static org.elasticsearch.cluster.metadata.IndexMetadata.INDEX_ROUTING_REQUIRE_GROUP_SETTING;
import static org.elasticsearch.cluster.routing.allocation.DataTier.ENFORCE_DEFAULT_TIER_PREFERENCE;
import static org.elasticsearch.cluster.routing.allocation.DataTier.TIER_PREFERENCE;
import static org.elasticsearch.xpack.core.ilm.LifecycleExecutionState.ILM_CUSTOM_METADATA_KEY;
import static org.elasticsearch.xpack.core.ilm.OperationMode.STOPPED;
Expand Down Expand Up @@ -127,6 +128,18 @@ public static Tuple<ClusterState, MigratedEntities> migrateToDataTiersRouting(Cl
}

Metadata.Builder mb = Metadata.builder(currentState.metadata());

// set ENFORCE_DEFAULT_TIER_PREFERENCE to true (in the persistent settings)
mb.persistentSettings(Settings.builder()
.put(mb.persistentSettings())
.put(ENFORCE_DEFAULT_TIER_PREFERENCE, true)
.build());

// and remove it from the transient settings, just in case it was there
Settings.Builder transientSettingsBuilder = Settings.builder().put(mb.transientSettings());
transientSettingsBuilder.remove(ENFORCE_DEFAULT_TIER_PREFERENCE);
mb.transientSettings(transientSettingsBuilder.build());

String removedIndexTemplateName = null;
if (Strings.hasText(indexTemplateToDelete)) {
if (currentState.metadata().getTemplates().containsKey(indexTemplateToDelete)) {
Expand Down Expand Up @@ -376,20 +389,34 @@ static List<String> migrateIndices(Metadata.Builder mb, ClusterState currentStat
for (ObjectObjectCursor<String, IndexMetadata> index : currentState.metadata().indices()) {
IndexMetadata indexMetadata = index.value;
Settings currentSettings = indexMetadata.getSettings();

boolean removeNodeAttrIndexRoutingSettings = true;

// migrate using the `require` setting
Settings newSettings = maybeMigrateRoutingSettingToTierPreference(nodeAttrIndexRequireRoutingSetting, indexMetadata);

if (newSettings.equals(currentSettings)) {
// migrating based on the `require` setting was not successful so let's check if the index used the `include` routing
// migrating based on the `require` setting was not successful, so let's check if the index used the `include` routing
// setting to configure the allocations and try to migrate it
newSettings = maybeMigrateRoutingSettingToTierPreference(nodeAttrIndexIncludeRoutingSetting, indexMetadata);
}
if (newSettings.equals(currentSettings)) {
removeNodeAttrIndexRoutingSettings = false;
// migrating based on the `include` setting was not successful,
// so, last stop, we just inject a tier preference regardless of anything else
newSettings = migrateToDefaultTierPreference(currentState, indexMetadata);
}

if (newSettings.equals(currentSettings) == false) {
// we converted either the require or the include routing setting to tier preference
// so let's clear all the routing settings for the given attribute
Settings.Builder finalSettings = Settings.builder().put(newSettings);
finalSettings.remove(nodeAttrIndexExcludeRoutingSetting);
finalSettings.remove(nodeAttrIndexRequireRoutingSetting);
finalSettings.remove(nodeAttrIndexIncludeRoutingSetting);

if (removeNodeAttrIndexRoutingSettings) {
// we converted either the `require` or the `include` routing setting to tier preference
// so let's clear all the routing settings for the given attribute
finalSettings.remove(nodeAttrIndexExcludeRoutingSetting);
finalSettings.remove(nodeAttrIndexRequireRoutingSetting);
finalSettings.remove(nodeAttrIndexIncludeRoutingSetting);
}

mb.put(IndexMetadata.builder(indexMetadata)
.settings(finalSettings)
Expand All @@ -413,9 +440,11 @@ private static Settings maybeMigrateRoutingSettingToTierPreference(String attrib
if (currentIndexSettings.keySet().contains(attributeBasedRoutingSettingName) == false) {
return currentIndexSettings;
}
// look at the value, get the correct tiers config and update the settings and index metadata

Settings.Builder newSettingsBuilder = Settings.builder().put(currentIndexSettings);
String indexName = indexMetadata.getIndex().getName();

// look at the value, get the correct tiers config and update the settings
if (currentIndexSettings.keySet().contains(TIER_PREFERENCE)) {
newSettingsBuilder.remove(attributeBasedRoutingSettingName);
logger.debug("index [{}]: removed setting [{}]", indexName, attributeBasedRoutingSettingName);
Expand All @@ -428,7 +457,7 @@ private static Settings maybeMigrateRoutingSettingToTierPreference(String attrib
newSettingsBuilder.remove(attributeBasedRoutingSettingName);
logger.debug("index [{}]: removed setting [{}]", indexName, attributeBasedRoutingSettingName);
logger.debug("index [{}]: configured setting [{}] to [{}]", indexName,
TIER_PREFERENCE, convertedTierPreference);
TIER_PREFERENCE, convertedTierPreference);
} else {
// log warning and do *not* remove setting, return the settings unchanged
logger.warn("index [{}]: could not convert attribute based setting [{}] value of [{}] to a tier preference " +
Expand All @@ -440,6 +469,23 @@ private static Settings maybeMigrateRoutingSettingToTierPreference(String attrib
return newSettingsBuilder.build();
}

private static Settings migrateToDefaultTierPreference(ClusterState currentState, IndexMetadata indexMetadata) {
Settings currentIndexSettings = indexMetadata.getSettings();
List<String> tierPreference = DataTier.parseTierList(currentIndexSettings.get(DataTier.TIER_PREFERENCE));
if (tierPreference.isEmpty() == false) {
return currentIndexSettings;
}

Settings.Builder newSettingsBuilder = Settings.builder().put(currentIndexSettings);
String indexName = indexMetadata.getIndex().getName();

boolean isDataStream = currentState.metadata().findDataStreams(indexName).isEmpty() == false;
String convertedTierPreference = isDataStream ? DataTier.DATA_HOT : DataTier.DATA_CONTENT;
newSettingsBuilder.put(TIER_PREFERENCE, convertedTierPreference);
logger.debug("index [{}]: configured setting [{}] to [{}]", indexName, TIER_PREFERENCE, convertedTierPreference);
return newSettingsBuilder.build();
}

/**
* Converts the provided node attribute value to the corresponding `_tier_preference` configuration.
* Known (and convertible) attribute values are:
Expand Down
Loading

0 comments on commit fa6d466

Please sign in to comment.