Skip to content

Commit a8ec291

Browse files
Discontinue archiving broken cluster settings
Currently unknown or invalid cluster settings get archived. For a better user experience, we stop archving broken cluster settings. Instead, we will fail to recover the cluster state. The solution for users in an upgrade case would be to rollback to the previous version, address the settings that would be unknown or invalid the next major version, and then proceed with the upgrade. Closes #28026
1 parent 5518640 commit a8ec291

File tree

4 files changed

+62
-27
lines changed

4 files changed

+62
-27
lines changed

docs/reference/migration/migrate_7_0/cluster.asciidoc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,9 @@ primary shards of the opened index to be allocated.
1414

1515
==== Shard preferences `_primary`, `_primary_first`, `_replica`, and `_replica_first` are removed
1616
These shard preferences are removed in favour of the `_prefer_nodes` and `_only_nodes` preferences.
17+
18+
==== Discontinue archiving broken cluster settings
19+
We will no longer archive unknown or invalid cluster settings (prepending "archived." to a broken setting's name).
20+
Instead, we will fail to recover a cluster state with broken cluster settings.
21+
The solution for users in an upgrade case would be to rollback to the previous version,
22+
address the settings that would be unknown or invalid in the next major version, and then proceed with the upgrade.

server/src/main/java/org/elasticsearch/common/settings/AbstractScopedSettings.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -681,6 +681,44 @@ public Settings archiveUnknownOrInvalidSettings(
681681
}
682682
}
683683

684+
685+
/**
686+
* Checks invalid or unknown settings. Any setting that is not recognized or fails validation
687+
* will be processed by consumers.
688+
* An exception will be thrown if any invalid or unknown setting is found.
689+
*
690+
* @param settings the {@link Settings} instance to scan for unknown or invalid settings
691+
* @param unknownConsumer callback on unknown settings (consumer receives unknown key and its
692+
* associated value)
693+
* @param invalidConsumer callback on invalid settings (consumer receives invalid key, its
694+
* associated value and an exception)
695+
*/
696+
public void checkUnknownOrInvalidSettings(
697+
final Settings settings,
698+
final Consumer<Map.Entry<String, String>> unknownConsumer,
699+
final BiConsumer<Map.Entry<String, String>, IllegalArgumentException> invalidConsumer) {
700+
List<String> failedKeys = new ArrayList<>();
701+
for (String key : settings.keySet()) {
702+
try {
703+
Setting<?> setting = get(key);
704+
if (setting != null) {
705+
setting.get(settings);
706+
} else {
707+
if (!isPrivateSetting(key)) {
708+
failedKeys.add(key);
709+
unknownConsumer.accept(new Entry(key, settings));
710+
}
711+
}
712+
} catch (IllegalArgumentException ex) {
713+
failedKeys.add(key);
714+
invalidConsumer.accept(new Entry(key, settings), ex);
715+
}
716+
}
717+
if (failedKeys.size() > 0) {
718+
throw new IllegalStateException("Invalid or unknown settings: " + String.join(", ", failedKeys));
719+
}
720+
}
721+
684722
private static final class Entry implements Map.Entry<String, String> {
685723

686724
private final String key;

server/src/main/java/org/elasticsearch/gateway/Gateway.java

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -137,27 +137,25 @@ public void performStateRecovery(final GatewayStateRecoveredListener listener) t
137137
}
138138
}
139139
final ClusterSettings clusterSettings = clusterService.getClusterSettings();
140-
metaDataBuilder.persistentSettings(
141-
clusterSettings.archiveUnknownOrInvalidSettings(
142-
metaDataBuilder.persistentSettings(),
143-
e -> logUnknownSetting("persistent", e),
144-
(e, ex) -> logInvalidSetting("persistent", e, ex)));
145-
metaDataBuilder.transientSettings(
146-
clusterSettings.archiveUnknownOrInvalidSettings(
147-
metaDataBuilder.transientSettings(),
148-
e -> logUnknownSetting("transient", e),
149-
(e, ex) -> logInvalidSetting("transient", e, ex)));
140+
clusterSettings.checkUnknownOrInvalidSettings(
141+
metaDataBuilder.persistentSettings(),
142+
e -> logUnknownSetting("persistent", e),
143+
(e, ex) -> logInvalidSetting("persistent", e, ex));
144+
clusterSettings.checkUnknownOrInvalidSettings(
145+
metaDataBuilder.transientSettings(),
146+
e -> logUnknownSetting("transient", e),
147+
(e, ex) -> logInvalidSetting("transient", e, ex));
150148
ClusterState.Builder builder = clusterService.newClusterStateBuilder();
151149
builder.metaData(metaDataBuilder);
152150
listener.onSuccess(builder.build());
153151
}
154152

155153
private void logUnknownSetting(String settingType, Map.Entry<String, String> e) {
156-
logger.warn("ignoring unknown {} setting: [{}] with value [{}]; archiving", settingType, e.getKey(), e.getValue());
154+
logger.warn("unknown {} setting: [{}] with value [{}]", settingType, e.getKey(), e.getValue());
157155
}
158156

159157
private void logInvalidSetting(String settingType, Map.Entry<String, String> e, IllegalArgumentException ex) {
160-
logger.warn(() -> new ParameterizedMessage("ignoring invalid {} setting: [{}] with value [{}]; archiving",
158+
logger.warn(() -> new ParameterizedMessage("invalid {} setting: [{}] with value [{}]",
161159
settingType, e.getKey(), e.getValue()), ex);
162160
}
163161

server/src/test/java/org/elasticsearch/gateway/GatewayIndexStateIT.java

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@
4949
import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
5050
import org.elasticsearch.test.ESIntegTestCase.Scope;
5151
import org.elasticsearch.test.InternalTestCluster.RestartCallback;
52+
import org.junit.Rule;
53+
import org.junit.rules.ExpectedException;
5254

5355
import java.io.IOException;
5456
import java.util.List;
@@ -64,6 +66,8 @@
6466
@ClusterScope(scope = Scope.TEST, numDataNodes = 0)
6567
public class GatewayIndexStateIT extends ESIntegTestCase {
6668

69+
@Rule
70+
public ExpectedException expectedException = ExpectedException.none();
6771
private final Logger logger = Loggers.getLogger(GatewayIndexStateIT.class);
6872

6973
public void testMappingMetaDataParsed() throws Exception {
@@ -479,7 +483,7 @@ public void testRecoverMissingAnalyzer() throws Exception {
479483
assertThat(ex.getCause().getMessage(), containsString("analyzer [test] not found for field [field1]"));
480484
}
481485

482-
public void testArchiveBrokenClusterSettings() throws Exception {
486+
public void testFailBrokenClusterSettings() throws Exception {
483487
logger.info("--> starting one node");
484488
internalCluster().startNode();
485489
client().prepareIndex("test", "type1", "1").setSource("field1", "value1").setRefreshPolicy(IMMEDIATE).get();
@@ -502,20 +506,9 @@ public void testArchiveBrokenClusterSettings() throws Exception {
502506
.put(ElectMasterService.DISCOVERY_ZEN_MINIMUM_MASTER_NODES_SETTING.getKey(), "broken").build()).build();
503507
MetaData.FORMAT.write(brokenMeta, nodeEnv.nodeDataPaths());
504508
}
505-
internalCluster().fullRestart();
506-
ensureYellow("test"); // wait for state recovery
507-
state = client().admin().cluster().prepareState().get().getState();
508-
assertEquals("true", state.metaData().persistentSettings().get("archived.this.is.unknown"));
509-
assertEquals("broken", state.metaData().persistentSettings().get("archived."
510-
+ ElectMasterService.DISCOVERY_ZEN_MINIMUM_MASTER_NODES_SETTING.getKey()));
511509

512-
// delete these settings
513-
client().admin().cluster().prepareUpdateSettings().setPersistentSettings(Settings.builder().putNull("archived.*")).get();
514-
515-
state = client().admin().cluster().prepareState().get().getState();
516-
assertNull(state.metaData().persistentSettings().get("archived.this.is.unknown"));
517-
assertNull(state.metaData().persistentSettings().get("archived."
518-
+ ElectMasterService.DISCOVERY_ZEN_MINIMUM_MASTER_NODES_SETTING.getKey()));
519-
assertHitCount(client().prepareSearch().setQuery(matchAllQuery()).get(), 1L);
510+
expectedException.expect(ElasticsearchException.class);
511+
internalCluster().fullRestart();
520512
}
513+
521514
}

0 commit comments

Comments
 (0)