Skip to content

Commit 8c370d0

Browse files
committed
Upgrade remote cluster settings (#33537)
This commit adds settings upgraders for the search.remote.* settings that can be in the cluster state to automatically upgrade these settings to cluster.remote.*. Because of the infrastructure that we have here, these settings can be upgraded when recovering the cluster state, but also when a user tries to make a dynamic update for these settings.
1 parent c3ab167 commit 8c370d0

File tree

9 files changed

+216
-13
lines changed

9 files changed

+216
-13
lines changed

qa/full-cluster-restart/src/test/java/org/elasticsearch/upgrades/FullClusterRestartIT.java

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1013,15 +1013,9 @@ private void checkSnapshot(String snapshotName, int count, Version tookOnVersion
10131013
Request clusterSettingsRequest = new Request("GET", "/_cluster/settings");
10141014
clusterSettingsRequest.addParameter("flat_settings", "true");
10151015
Map<String, Object> clusterSettingsResponse = entityAsMap(client().performRequest(clusterSettingsRequest));
1016-
Map<String, Object> expectedClusterSettings = new HashMap<>();
1017-
expectedClusterSettings.put("transient", emptyMap());
1018-
expectedClusterSettings.put("persistent",
1019-
singletonMap("cluster.routing.allocation.exclude.test_attr", getOldClusterVersion().toString()));
1020-
if (expectedClusterSettings.equals(clusterSettingsResponse) == false) {
1021-
NotEqualMessageBuilder builder = new NotEqualMessageBuilder();
1022-
builder.compareMaps(clusterSettingsResponse, expectedClusterSettings);
1023-
fail("settings don't match:\n" + builder.toString());
1024-
}
1016+
@SuppressWarnings("unchecked") final Map<String, Object> persistentSettings =
1017+
(Map<String, Object>)clusterSettingsResponse.get("persistent");
1018+
assertThat(persistentSettings.get("cluster.routing.allocation.exclude.test_attr"), equalTo(getOldClusterVersion().toString()));
10251019

10261020
// Check that the template was restored successfully
10271021
Map<String, Object> getTemplateResponse = entityAsMap(client().performRequest(new Request("GET", "/_template/test_template")));
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.elasticsearch.upgrades;
21+
22+
import org.elasticsearch.Version;
23+
import org.elasticsearch.action.admin.cluster.settings.ClusterGetSettingsResponse;
24+
import org.elasticsearch.client.Request;
25+
import org.elasticsearch.client.Response;
26+
import org.elasticsearch.common.Strings;
27+
import org.elasticsearch.common.settings.Setting;
28+
import org.elasticsearch.common.settings.Settings;
29+
import org.elasticsearch.common.xcontent.XContentBuilder;
30+
import org.elasticsearch.common.xcontent.XContentParser;
31+
import org.elasticsearch.common.xcontent.json.JsonXContent;
32+
import org.elasticsearch.transport.RemoteClusterService;
33+
34+
import java.io.IOException;
35+
import java.util.Collections;
36+
37+
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
38+
import static org.elasticsearch.transport.RemoteClusterAware.SEARCH_REMOTE_CLUSTERS_SEEDS;
39+
import static org.elasticsearch.transport.RemoteClusterService.SEARCH_REMOTE_CLUSTER_SKIP_UNAVAILABLE;
40+
import static org.hamcrest.Matchers.equalTo;
41+
42+
public class FullClusterRestartSettingsUpgradeIT extends AbstractFullClusterRestartTestCase {
43+
44+
public void testRemoteClusterSettingsUpgraded() throws IOException {
45+
assumeTrue("settings automatically upgraded since 6.5.0", getOldClusterVersion().before(Version.V_6_5_0));
46+
if (isRunningAgainstOldCluster()) {
47+
final Request putSettingsRequest = new Request("PUT", "/_cluster/settings");
48+
try (XContentBuilder builder = jsonBuilder()) {
49+
builder.startObject();
50+
{
51+
builder.startObject("persistent");
52+
{
53+
builder.field("search.remote.foo.skip_unavailable", true);
54+
builder.field("search.remote.foo.seeds", Collections.singletonList("localhost:9200"));
55+
}
56+
builder.endObject();
57+
}
58+
builder.endObject();
59+
putSettingsRequest.setJsonEntity(Strings.toString(builder));
60+
}
61+
client().performRequest(putSettingsRequest);
62+
63+
final Request getSettingsRequest = new Request("GET", "/_cluster/settings");
64+
final Response response = client().performRequest(getSettingsRequest);
65+
try (XContentParser parser = createParser(JsonXContent.jsonXContent, response.getEntity().getContent())) {
66+
final ClusterGetSettingsResponse clusterGetSettingsResponse = ClusterGetSettingsResponse.fromXContent(parser);
67+
final Settings settings = clusterGetSettingsResponse.getPersistentSettings();
68+
69+
assertTrue(SEARCH_REMOTE_CLUSTER_SKIP_UNAVAILABLE.getConcreteSettingForNamespace("foo").exists(settings));
70+
assertTrue(SEARCH_REMOTE_CLUSTER_SKIP_UNAVAILABLE.getConcreteSettingForNamespace("foo").get(settings));
71+
assertTrue(SEARCH_REMOTE_CLUSTERS_SEEDS.getConcreteSettingForNamespace("foo").exists(settings));
72+
assertThat(
73+
SEARCH_REMOTE_CLUSTERS_SEEDS.getConcreteSettingForNamespace("foo").get(settings),
74+
equalTo(Collections.singletonList("localhost:9200")));
75+
}
76+
77+
assertSettingDeprecationsAndWarnings(new Setting<?>[]{
78+
SEARCH_REMOTE_CLUSTER_SKIP_UNAVAILABLE.getConcreteSettingForNamespace("foo"),
79+
SEARCH_REMOTE_CLUSTERS_SEEDS.getConcreteSettingForNamespace("foo")});
80+
} else {
81+
final Request getSettingsRequest = new Request("GET", "/_cluster/settings");
82+
final Response getSettingsResponse = client().performRequest(getSettingsRequest);
83+
try (XContentParser parser = createParser(JsonXContent.jsonXContent, getSettingsResponse.getEntity().getContent())) {
84+
final ClusterGetSettingsResponse clusterGetSettingsResponse = ClusterGetSettingsResponse.fromXContent(parser);
85+
final Settings settings = clusterGetSettingsResponse.getPersistentSettings();
86+
87+
assertFalse(SEARCH_REMOTE_CLUSTER_SKIP_UNAVAILABLE.getConcreteSettingForNamespace("foo").exists(settings));
88+
assertTrue(
89+
settings.toString(),
90+
RemoteClusterService.REMOTE_CLUSTER_SKIP_UNAVAILABLE.getConcreteSettingForNamespace("foo").exists(settings));
91+
assertTrue(RemoteClusterService.REMOTE_CLUSTER_SKIP_UNAVAILABLE.getConcreteSettingForNamespace("foo").get(settings));
92+
assertFalse(SEARCH_REMOTE_CLUSTERS_SEEDS.getConcreteSettingForNamespace("foo").exists(settings));
93+
assertTrue(RemoteClusterService.REMOTE_CLUSTERS_SEEDS.getConcreteSettingForNamespace("foo").exists(settings));
94+
assertThat(
95+
RemoteClusterService.REMOTE_CLUSTERS_SEEDS.getConcreteSettingForNamespace("foo").get(settings),
96+
equalTo(Collections.singletonList("localhost:9200")));
97+
}
98+
}
99+
}
100+
101+
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -788,7 +788,8 @@ public Settings upgradeSettings(final Settings settings) {
788788
} else {
789789
// the setting has an upgrader, so mark that we have changed a setting and apply the upgrade logic
790790
changed = true;
791-
if (setting.isListSetting()) {
791+
// noinspection ConstantConditions
792+
if (setting.getConcreteSetting(key).isListSetting()) {
792793
final List<String> value = settings.getAsList(key);
793794
final String upgradedKey = upgrader.getKey(key);
794795
final List<String> upgradedValue = upgrader.getListValue(value);

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,9 @@ public void apply(Settings value, Settings current, Settings previous) {
446446
EnableAssignmentDecider.CLUSTER_TASKS_ALLOCATION_ENABLE_SETTING
447447
)));
448448

449-
public static List<SettingUpgrader<?>> BUILT_IN_SETTING_UPGRADERS = Collections.emptyList();
449+
public static List<SettingUpgrader<?>> BUILT_IN_SETTING_UPGRADERS = Collections.unmodifiableList(Arrays.asList(
450+
RemoteClusterAware.SEARCH_REMOTE_CLUSTER_SEEDS_UPGRADER,
451+
RemoteClusterAware.SEARCH_REMOTE_CLUSTERS_PROXY_UPGRADER,
452+
RemoteClusterService.SEARCH_REMOTE_CLUSTER_SKIP_UNAVAILABLE_UPGRADER));
450453

451454
}

server/src/main/java/org/elasticsearch/transport/RemoteClusterAware.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.elasticsearch.common.component.AbstractComponent;
2929
import org.elasticsearch.common.settings.ClusterSettings;
3030
import org.elasticsearch.common.settings.Setting;
31+
import org.elasticsearch.common.settings.SettingUpgrader;
3132
import org.elasticsearch.common.settings.Settings;
3233
import org.elasticsearch.common.transport.TransportAddress;
3334

@@ -66,6 +67,20 @@ public abstract class RemoteClusterAware extends AbstractComponent {
6667
Setting.Property.Dynamic,
6768
Setting.Property.NodeScope));
6869

70+
public static final SettingUpgrader<List<String>> SEARCH_REMOTE_CLUSTER_SEEDS_UPGRADER = new SettingUpgrader<List<String>>() {
71+
72+
@Override
73+
public Setting<List<String>> getSetting() {
74+
return SEARCH_REMOTE_CLUSTERS_SEEDS;
75+
}
76+
77+
@Override
78+
public String getKey(final String key) {
79+
return key.replaceFirst("^search", "cluster");
80+
}
81+
82+
};
83+
6984
/**
7085
* A list of initial seed nodes to discover eligible nodes from the remote cluster
7186
*/
@@ -105,6 +120,20 @@ public abstract class RemoteClusterAware extends AbstractComponent {
105120
Setting.Property.NodeScope),
106121
REMOTE_CLUSTERS_SEEDS);
107122

123+
public static final SettingUpgrader<String> SEARCH_REMOTE_CLUSTERS_PROXY_UPGRADER = new SettingUpgrader<String>() {
124+
125+
@Override
126+
public Setting<String> getSetting() {
127+
return SEARCH_REMOTE_CLUSTERS_PROXY;
128+
}
129+
130+
@Override
131+
public String getKey(final String key) {
132+
return key.replaceFirst("^search", "cluster");
133+
}
134+
135+
};
136+
108137
/**
109138
* A proxy address for the remote cluster.
110139
* NOTE: this settings is undocumented until we have at last one transport that supports passing

server/src/main/java/org/elasticsearch/transport/RemoteClusterService.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@
1919

2020
package org.elasticsearch.transport;
2121

22-
import java.util.Collection;
23-
import java.util.function.Supplier;
2422
import org.elasticsearch.Version;
2523
import org.elasticsearch.action.ActionListener;
2624
import org.elasticsearch.action.OriginalIndices;
@@ -36,6 +34,7 @@
3634
import org.elasticsearch.common.collect.Tuple;
3735
import org.elasticsearch.common.settings.ClusterSettings;
3836
import org.elasticsearch.common.settings.Setting;
37+
import org.elasticsearch.common.settings.SettingUpgrader;
3938
import org.elasticsearch.common.settings.Settings;
4039
import org.elasticsearch.common.unit.TimeValue;
4140
import org.elasticsearch.common.util.concurrent.CountDown;
@@ -44,6 +43,7 @@
4443

4544
import java.io.Closeable;
4645
import java.io.IOException;
46+
import java.util.Collection;
4747
import java.util.Collections;
4848
import java.util.HashMap;
4949
import java.util.List;
@@ -56,6 +56,7 @@
5656
import java.util.function.BiFunction;
5757
import java.util.function.Function;
5858
import java.util.function.Predicate;
59+
import java.util.function.Supplier;
5960
import java.util.stream.Collectors;
6061

6162
import static org.elasticsearch.common.settings.Setting.boolSetting;
@@ -132,6 +133,20 @@ public final class RemoteClusterService extends RemoteClusterAware implements Cl
132133
key -> boolSetting(key, false, Setting.Property.Deprecated, Setting.Property.Dynamic, Setting.Property.NodeScope),
133134
REMOTE_CLUSTERS_SEEDS);
134135

136+
public static final SettingUpgrader<Boolean> SEARCH_REMOTE_CLUSTER_SKIP_UNAVAILABLE_UPGRADER = new SettingUpgrader<Boolean>() {
137+
138+
@Override
139+
public Setting<Boolean> getSetting() {
140+
return SEARCH_REMOTE_CLUSTER_SKIP_UNAVAILABLE;
141+
}
142+
143+
@Override
144+
public String getKey(final String key) {
145+
return key.replaceFirst("^search", "cluster");
146+
}
147+
148+
};
149+
135150
public static final Setting.AffixSetting<Boolean> REMOTE_CLUSTER_SKIP_UNAVAILABLE =
136151
Setting.affixKeySetting(
137152
"cluster.remote.",

server/src/test/java/org/elasticsearch/common/settings/UpgradeSettingsIT.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.elasticsearch.cluster.metadata.MetaData;
2525
import org.elasticsearch.plugins.Plugin;
2626
import org.elasticsearch.test.ESSingleNodeTestCase;
27+
import org.elasticsearch.transport.RemoteClusterService;
2728
import org.junit.After;
2829

2930
import java.util.Arrays;
@@ -122,4 +123,37 @@ private void runUpgradeSettingsOnUpdateTest(
122123
assertThat(UpgradeSettingsPlugin.newSetting.get(settingsFunction.apply(response.getState().metaData())), equalTo("new." + value));
123124
}
124125

126+
public void testUpgradeRemoteClusterSettings() {
127+
final boolean skipUnavailable = randomBoolean();
128+
client()
129+
.admin()
130+
.cluster()
131+
.prepareUpdateSettings()
132+
.setPersistentSettings(
133+
Settings.builder()
134+
.put("search.remote.foo.skip_unavailable", skipUnavailable)
135+
.putList("search.remote.foo.seeds", Collections.singletonList("localhost:9200"))
136+
.put("search.remote.foo.proxy", "localhost:9200")
137+
.build())
138+
.get();
139+
140+
final ClusterStateResponse response = client().admin().cluster().prepareState().clear().setMetaData(true).get();
141+
142+
final Settings settings = response.getState().metaData().persistentSettings();
143+
assertFalse(RemoteClusterService.SEARCH_REMOTE_CLUSTER_SKIP_UNAVAILABLE.getConcreteSettingForNamespace("foo").exists(settings));
144+
assertTrue(RemoteClusterService.REMOTE_CLUSTER_SKIP_UNAVAILABLE.getConcreteSettingForNamespace("foo").exists(settings));
145+
assertThat(
146+
RemoteClusterService.REMOTE_CLUSTER_SKIP_UNAVAILABLE.getConcreteSettingForNamespace("foo").get(settings),
147+
equalTo(skipUnavailable));
148+
assertFalse(RemoteClusterService.SEARCH_REMOTE_CLUSTERS_SEEDS.getConcreteSettingForNamespace("foo").exists(settings));
149+
assertTrue(RemoteClusterService.REMOTE_CLUSTERS_SEEDS.getConcreteSettingForNamespace("foo").exists(settings));
150+
assertThat(
151+
RemoteClusterService.REMOTE_CLUSTERS_SEEDS.getConcreteSettingForNamespace("foo").get(settings),
152+
equalTo(Collections.singletonList("localhost:9200")));
153+
assertFalse(RemoteClusterService.SEARCH_REMOTE_CLUSTERS_PROXY.getConcreteSettingForNamespace("foo").exists(settings));
154+
assertTrue(RemoteClusterService.REMOTE_CLUSTERS_PROXY.getConcreteSettingForNamespace("foo").exists(settings));
155+
assertThat(
156+
RemoteClusterService.REMOTE_CLUSTERS_PROXY.getConcreteSettingForNamespace("foo").get(settings), equalTo("localhost:9200"));
157+
}
158+
125159
}

x-pack/qa/full-cluster-restart/build.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ subprojects {
194194
systemProperty 'tests.old_cluster_version', version.toString().minus("-SNAPSHOT")
195195
systemProperty 'tests.path.repo', new File(buildDir, "cluster/shared/repo")
196196
exclude 'org/elasticsearch/upgrades/FullClusterRestartIT.class'
197+
exclude 'org/elasticsearch/upgrades/FullClusterRestartSettingsUpgradeIT.class'
197198
exclude 'org/elasticsearch/upgrades/QueryBuilderBWCIT.class'
198199
}
199200

@@ -230,6 +231,7 @@ subprojects {
230231
systemProperty 'tests.old_cluster_version', version.toString().minus("-SNAPSHOT")
231232
systemProperty 'tests.path.repo', new File(buildDir, "cluster/shared/repo")
232233
exclude 'org/elasticsearch/upgrades/FullClusterRestartIT.class'
234+
exclude 'org/elasticsearch/upgrades/FullClusterRestartSettingsUpgradeIT.class'
233235
exclude 'org/elasticsearch/upgrades/QueryBuilderBWCIT.class'
234236
}
235237

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
package org.elasticsearch.xpack.restart;
8+
9+
import org.elasticsearch.common.settings.Settings;
10+
import org.elasticsearch.common.util.concurrent.ThreadContext;
11+
12+
import java.nio.charset.StandardCharsets;
13+
import java.util.Base64;
14+
15+
public class FullClusterRestartSettingsUpgradeIT extends org.elasticsearch.upgrades.FullClusterRestartSettingsUpgradeIT {
16+
17+
@Override
18+
protected Settings restClientSettings() {
19+
final String token =
20+
"Basic " + Base64.getEncoder().encodeToString("test_user:x-pack-test-password".getBytes(StandardCharsets.UTF_8));
21+
return Settings.builder().put(ThreadContext.PREFIX + ".Authorization", token).build();
22+
}
23+
24+
}

0 commit comments

Comments
 (0)