Add cluster setting to spoof version number returned from MainResponse (#847)
This change adds a new cluster setting "compatibility.override_main_response_version" that when enabled spoofs the version.number returned from MainResponse for REST clients expecting legacy version 7.10.2. Signed-off-by: Marc Handalian <handalm@amazon.com>
This commit is contained in:
parent
ca564fd04f
commit
c1250c963d
|
@ -33,6 +33,7 @@
|
||||||
package org.opensearch.client;
|
package org.opensearch.client;
|
||||||
|
|
||||||
import org.apache.http.client.methods.HttpGet;
|
import org.apache.http.client.methods.HttpGet;
|
||||||
|
import org.opensearch.action.main.TransportMainAction;
|
||||||
import org.opensearch.client.core.MainResponse;
|
import org.opensearch.client.core.MainResponse;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -62,4 +63,25 @@ public class PingAndInfoIT extends OpenSearchRestHighLevelClientTestCase {
|
||||||
assertTrue(versionMap.get("number").toString().startsWith(info.getVersion().getNumber()));
|
assertTrue(versionMap.get("number").toString().startsWith(info.getVersion().getNumber()));
|
||||||
assertEquals(versionMap.get("lucene_version"), info.getVersion().getLuceneVersion());
|
assertEquals(versionMap.get("lucene_version"), info.getVersion().getLuceneVersion());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testInfo_overrideResponseVersion() throws IOException {
|
||||||
|
Request overrideResponseVersionRequest = new Request("PUT", "/_cluster/settings");
|
||||||
|
overrideResponseVersionRequest.setOptions(expectWarnings(TransportMainAction.OVERRIDE_MAIN_RESPONSE_VERSION_DEPRECATION_MESSAGE));
|
||||||
|
overrideResponseVersionRequest.setJsonEntity("{\"persistent\":{\"compatibility\": {\"override_main_response_version\":true}}}");
|
||||||
|
client().performRequest(overrideResponseVersionRequest);
|
||||||
|
|
||||||
|
MainResponse info = highLevelClient().info(RequestOptions.DEFAULT);
|
||||||
|
assertEquals("7.10.2", info.getVersion().getNumber());
|
||||||
|
|
||||||
|
// Set back to default version.
|
||||||
|
Request resetResponseVersionRequest = new Request("PUT", "/_cluster/settings");
|
||||||
|
resetResponseVersionRequest.setJsonEntity("{\"persistent\":{\"compatibility\": {\"override_main_response_version\":null}}}");
|
||||||
|
client().performRequest(resetResponseVersionRequest);
|
||||||
|
|
||||||
|
Map<String, Object> infoAsMap = entityAsMap(adminClient().performRequest(new Request(HttpGet.METHOD_NAME, "/")));
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Map<String, Object> versionMap = (Map<String, Object>) infoAsMap.get("version");
|
||||||
|
info = highLevelClient().info(RequestOptions.DEFAULT);
|
||||||
|
assertTrue(versionMap.get("number").toString().startsWith(info.getVersion().getNumber()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,7 @@ public class MainResponse extends ActionResponse implements ToXContentObject {
|
||||||
private ClusterName clusterName;
|
private ClusterName clusterName;
|
||||||
private String clusterUuid;
|
private String clusterUuid;
|
||||||
private Build build;
|
private Build build;
|
||||||
|
private String versionNumber;
|
||||||
|
|
||||||
MainResponse() {}
|
MainResponse() {}
|
||||||
|
|
||||||
|
@ -68,6 +69,7 @@ public class MainResponse extends ActionResponse implements ToXContentObject {
|
||||||
if (in.getVersion().before(LegacyESVersion.V_7_0_0)) {
|
if (in.getVersion().before(LegacyESVersion.V_7_0_0)) {
|
||||||
in.readBoolean();
|
in.readBoolean();
|
||||||
}
|
}
|
||||||
|
versionNumber = build.getQualifiedVersion();
|
||||||
}
|
}
|
||||||
|
|
||||||
public MainResponse(String nodeName, Version version, ClusterName clusterName, String clusterUuid, Build build) {
|
public MainResponse(String nodeName, Version version, ClusterName clusterName, String clusterUuid, Build build) {
|
||||||
|
@ -76,6 +78,17 @@ public class MainResponse extends ActionResponse implements ToXContentObject {
|
||||||
this.clusterName = clusterName;
|
this.clusterName = clusterName;
|
||||||
this.clusterUuid = clusterUuid;
|
this.clusterUuid = clusterUuid;
|
||||||
this.build = build;
|
this.build = build;
|
||||||
|
this.versionNumber = build.getQualifiedVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
public MainResponse(String nodeName, Version version, ClusterName clusterName, String clusterUuid, Build build,
|
||||||
|
String versionNumber) {
|
||||||
|
this.nodeName = nodeName;
|
||||||
|
this.version = version;
|
||||||
|
this.clusterName = clusterName;
|
||||||
|
this.clusterUuid = clusterUuid;
|
||||||
|
this.build = build;
|
||||||
|
this.versionNumber = versionNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getNodeName() {
|
public String getNodeName() {
|
||||||
|
@ -99,6 +112,10 @@ public class MainResponse extends ActionResponse implements ToXContentObject {
|
||||||
return build;
|
return build;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getVersionNumber() {
|
||||||
|
return versionNumber;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeTo(StreamOutput out) throws IOException {
|
public void writeTo(StreamOutput out) throws IOException {
|
||||||
out.writeString(nodeName);
|
out.writeString(nodeName);
|
||||||
|
@ -123,7 +140,7 @@ public class MainResponse extends ActionResponse implements ToXContentObject {
|
||||||
builder.field("cluster_uuid", clusterUuid);
|
builder.field("cluster_uuid", clusterUuid);
|
||||||
builder.startObject("version")
|
builder.startObject("version")
|
||||||
.field("distribution", build.getDistribution())
|
.field("distribution", build.getDistribution())
|
||||||
.field("number", build.getQualifiedVersion())
|
.field("number", versionNumber)
|
||||||
.field("build_type", build.type().displayName())
|
.field("build_type", build.type().displayName())
|
||||||
.field("build_hash", build.hash())
|
.field("build_hash", build.hash())
|
||||||
.field("build_date", build.date())
|
.field("build_date", build.date())
|
||||||
|
@ -163,6 +180,7 @@ public class MainResponse extends ActionResponse implements ToXContentObject {
|
||||||
.replace("-SNAPSHOT", "")
|
.replace("-SNAPSHOT", "")
|
||||||
.replaceFirst("-(alpha\\d+|beta\\d+|rc\\d+)", "")
|
.replaceFirst("-(alpha\\d+|beta\\d+|rc\\d+)", "")
|
||||||
);
|
);
|
||||||
|
response.versionNumber = response.version.toString();
|
||||||
}, (parser, context) -> parser.map(), new ParseField("version"));
|
}, (parser, context) -> parser.map(), new ParseField("version"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
package org.opensearch.action.main;
|
package org.opensearch.action.main;
|
||||||
|
|
||||||
import org.opensearch.Build;
|
import org.opensearch.Build;
|
||||||
|
import org.opensearch.LegacyESVersion;
|
||||||
import org.opensearch.Version;
|
import org.opensearch.Version;
|
||||||
import org.opensearch.action.ActionListener;
|
import org.opensearch.action.ActionListener;
|
||||||
import org.opensearch.action.support.ActionFilters;
|
import org.opensearch.action.support.ActionFilters;
|
||||||
|
@ -40,6 +41,8 @@ import org.opensearch.action.support.HandledTransportAction;
|
||||||
import org.opensearch.cluster.ClusterState;
|
import org.opensearch.cluster.ClusterState;
|
||||||
import org.opensearch.cluster.service.ClusterService;
|
import org.opensearch.cluster.service.ClusterService;
|
||||||
import org.opensearch.common.inject.Inject;
|
import org.opensearch.common.inject.Inject;
|
||||||
|
import org.opensearch.common.logging.DeprecationLogger;
|
||||||
|
import org.opensearch.common.settings.Setting;
|
||||||
import org.opensearch.common.settings.Settings;
|
import org.opensearch.common.settings.Settings;
|
||||||
import org.opensearch.node.Node;
|
import org.opensearch.node.Node;
|
||||||
import org.opensearch.tasks.Task;
|
import org.opensearch.tasks.Task;
|
||||||
|
@ -47,8 +50,19 @@ import org.opensearch.transport.TransportService;
|
||||||
|
|
||||||
public class TransportMainAction extends HandledTransportAction<MainRequest, MainResponse> {
|
public class TransportMainAction extends HandledTransportAction<MainRequest, MainResponse> {
|
||||||
|
|
||||||
|
private static final DeprecationLogger DEPRECATION_LOGGER = DeprecationLogger.getLogger(TransportMainAction.class);
|
||||||
|
|
||||||
|
public static final String OVERRIDE_MAIN_RESPONSE_VERSION_KEY = "compatibility.override_main_response_version";
|
||||||
|
|
||||||
|
public static final Setting<Boolean> OVERRIDE_MAIN_RESPONSE_VERSION = Setting.boolSetting(
|
||||||
|
OVERRIDE_MAIN_RESPONSE_VERSION_KEY, false, Setting.Property.NodeScope, Setting.Property.Dynamic);
|
||||||
|
|
||||||
|
public static final String OVERRIDE_MAIN_RESPONSE_VERSION_DEPRECATION_MESSAGE = "overriding main response version" +
|
||||||
|
" number will be removed in a future version";
|
||||||
|
|
||||||
private final String nodeName;
|
private final String nodeName;
|
||||||
private final ClusterService clusterService;
|
private final ClusterService clusterService;
|
||||||
|
private volatile String responseVersion;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public TransportMainAction(Settings settings, TransportService transportService,
|
public TransportMainAction(Settings settings, TransportService transportService,
|
||||||
|
@ -56,6 +70,19 @@ public class TransportMainAction extends HandledTransportAction<MainRequest, Mai
|
||||||
super(MainAction.NAME, transportService, actionFilters, MainRequest::new);
|
super(MainAction.NAME, transportService, actionFilters, MainRequest::new);
|
||||||
this.nodeName = Node.NODE_NAME_SETTING.get(settings);
|
this.nodeName = Node.NODE_NAME_SETTING.get(settings);
|
||||||
this.clusterService = clusterService;
|
this.clusterService = clusterService;
|
||||||
|
setResponseVersion(OVERRIDE_MAIN_RESPONSE_VERSION.get(settings));
|
||||||
|
|
||||||
|
clusterService.getClusterSettings().addSettingsUpdateConsumer(OVERRIDE_MAIN_RESPONSE_VERSION,
|
||||||
|
this::setResponseVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setResponseVersion(boolean isResponseVersionOverrideEnabled) {
|
||||||
|
if (isResponseVersionOverrideEnabled) {
|
||||||
|
DEPRECATION_LOGGER.deprecate(OVERRIDE_MAIN_RESPONSE_VERSION.getKey(), OVERRIDE_MAIN_RESPONSE_VERSION_DEPRECATION_MESSAGE);
|
||||||
|
this.responseVersion = LegacyESVersion.V_7_10_2.toString();
|
||||||
|
} else {
|
||||||
|
this.responseVersion = Build.CURRENT.getQualifiedVersion();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -63,6 +90,6 @@ public class TransportMainAction extends HandledTransportAction<MainRequest, Mai
|
||||||
ClusterState clusterState = clusterService.state();
|
ClusterState clusterState = clusterService.state();
|
||||||
listener.onResponse(
|
listener.onResponse(
|
||||||
new MainResponse(nodeName, Version.CURRENT, clusterState.getClusterName(),
|
new MainResponse(nodeName, Version.CURRENT, clusterState.getClusterName(),
|
||||||
clusterState.metadata().clusterUUID(), Build.CURRENT));
|
clusterState.metadata().clusterUUID(), Build.CURRENT, responseVersion));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
package org.opensearch.common.settings;
|
package org.opensearch.common.settings;
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.opensearch.action.main.TransportMainAction;
|
||||||
import org.opensearch.watcher.ResourceWatcherService;
|
import org.opensearch.watcher.ResourceWatcherService;
|
||||||
import org.opensearch.action.admin.cluster.configuration.TransportAddVotingConfigExclusionsAction;
|
import org.opensearch.action.admin.cluster.configuration.TransportAddVotingConfigExclusionsAction;
|
||||||
import org.opensearch.action.admin.indices.close.TransportCloseIndexAction;
|
import org.opensearch.action.admin.indices.close.TransportCloseIndexAction;
|
||||||
|
@ -577,6 +578,7 @@ public final class ClusterSettings extends AbstractScopedSettings {
|
||||||
FsHealthService.ENABLED_SETTING,
|
FsHealthService.ENABLED_SETTING,
|
||||||
FsHealthService.REFRESH_INTERVAL_SETTING,
|
FsHealthService.REFRESH_INTERVAL_SETTING,
|
||||||
FsHealthService.SLOW_PATH_LOGGING_THRESHOLD_SETTING,
|
FsHealthService.SLOW_PATH_LOGGING_THRESHOLD_SETTING,
|
||||||
|
TransportMainAction.OVERRIDE_MAIN_RESPONSE_VERSION,
|
||||||
IndexingPressure.MAX_INDEXING_BYTES)));
|
IndexingPressure.MAX_INDEXING_BYTES)));
|
||||||
|
|
||||||
public static List<SettingUpgrader<?>> BUILT_IN_SETTING_UPGRADERS = Collections.unmodifiableList(Arrays.asList(
|
public static List<SettingUpgrader<?>> BUILT_IN_SETTING_UPGRADERS = Collections.unmodifiableList(Arrays.asList(
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
|
|
||||||
package org.opensearch.action.main;
|
package org.opensearch.action.main;
|
||||||
|
|
||||||
|
import org.opensearch.LegacyESVersion;
|
||||||
import org.opensearch.action.ActionListener;
|
import org.opensearch.action.ActionListener;
|
||||||
import org.opensearch.action.support.ActionFilters;
|
import org.opensearch.action.support.ActionFilters;
|
||||||
import org.opensearch.cluster.ClusterName;
|
import org.opensearch.cluster.ClusterName;
|
||||||
|
@ -40,6 +41,7 @@ import org.opensearch.cluster.block.ClusterBlock;
|
||||||
import org.opensearch.cluster.block.ClusterBlockLevel;
|
import org.opensearch.cluster.block.ClusterBlockLevel;
|
||||||
import org.opensearch.cluster.block.ClusterBlocks;
|
import org.opensearch.cluster.block.ClusterBlocks;
|
||||||
import org.opensearch.cluster.service.ClusterService;
|
import org.opensearch.cluster.service.ClusterService;
|
||||||
|
import org.opensearch.common.settings.ClusterSettings;
|
||||||
import org.opensearch.common.settings.Settings;
|
import org.opensearch.common.settings.Settings;
|
||||||
import org.opensearch.rest.RestStatus;
|
import org.opensearch.rest.RestStatus;
|
||||||
import org.opensearch.tasks.Task;
|
import org.opensearch.tasks.Task;
|
||||||
|
@ -54,6 +56,7 @@ import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
import static org.opensearch.action.main.TransportMainAction.OVERRIDE_MAIN_RESPONSE_VERSION_KEY;
|
||||||
|
|
||||||
public class MainActionTests extends OpenSearchTestCase {
|
public class MainActionTests extends OpenSearchTestCase {
|
||||||
|
|
||||||
|
@ -61,6 +64,8 @@ public class MainActionTests extends OpenSearchTestCase {
|
||||||
final ClusterService clusterService = mock(ClusterService.class);
|
final ClusterService clusterService = mock(ClusterService.class);
|
||||||
final ClusterName clusterName = new ClusterName("opensearch");
|
final ClusterName clusterName = new ClusterName("opensearch");
|
||||||
final Settings settings = Settings.builder().put("node.name", "my-node").build();
|
final Settings settings = Settings.builder().put("node.name", "my-node").build();
|
||||||
|
when(clusterService.getClusterSettings()).thenReturn(new ClusterSettings(Settings.EMPTY,
|
||||||
|
ClusterSettings.BUILT_IN_CLUSTER_SETTINGS));
|
||||||
ClusterBlocks blocks;
|
ClusterBlocks blocks;
|
||||||
if (randomBoolean()) {
|
if (randomBoolean()) {
|
||||||
if (randomBoolean()) {
|
if (randomBoolean()) {
|
||||||
|
@ -99,4 +104,40 @@ public class MainActionTests extends OpenSearchTestCase {
|
||||||
assertNotNull(responseRef.get());
|
assertNotNull(responseRef.get());
|
||||||
verify(clusterService, times(1)).state();
|
verify(clusterService, times(1)).state();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testMainResponseVersionOverrideEnabledByConfigSetting() {
|
||||||
|
final ClusterName clusterName = new ClusterName("opensearch");
|
||||||
|
ClusterState state = ClusterState.builder(clusterName).blocks(mock(ClusterBlocks.class)).build();
|
||||||
|
|
||||||
|
final ClusterService clusterService = mock(ClusterService.class);
|
||||||
|
when(clusterService.state()).thenReturn(state);
|
||||||
|
when(clusterService.getClusterSettings()).thenReturn(new ClusterSettings(Settings.EMPTY,
|
||||||
|
ClusterSettings.BUILT_IN_CLUSTER_SETTINGS));
|
||||||
|
|
||||||
|
TransportService transportService = new TransportService(Settings.EMPTY, mock(Transport.class), null,
|
||||||
|
TransportService.NOOP_TRANSPORT_INTERCEPTOR, x -> null, null, Collections.emptySet());
|
||||||
|
|
||||||
|
final Settings settings = Settings.builder()
|
||||||
|
.put("node.name", "my-node")
|
||||||
|
.put(OVERRIDE_MAIN_RESPONSE_VERSION_KEY, true)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
TransportMainAction action = new TransportMainAction(settings, transportService, mock(ActionFilters.class), clusterService);
|
||||||
|
AtomicReference<MainResponse> responseRef = new AtomicReference<>();
|
||||||
|
action.doExecute(mock(Task.class), new MainRequest(), new ActionListener<MainResponse>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(MainResponse mainResponse) {
|
||||||
|
responseRef.set(mainResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Exception e) {
|
||||||
|
logger.error("unexpected error", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
final MainResponse mainResponse = responseRef.get();
|
||||||
|
assertEquals(LegacyESVersion.V_7_10_2.toString(), mainResponse.getVersionNumber());
|
||||||
|
assertWarnings(TransportMainAction.OVERRIDE_MAIN_RESPONSE_VERSION_DEPRECATION_MESSAGE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,6 +102,15 @@ public class MainResponseTests extends AbstractSerializingTestCase<MainResponse>
|
||||||
+ "}", Strings.toString(builder));
|
+ "}", Strings.toString(builder));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void toXContent_overrideMainResponseVersion() throws IOException {
|
||||||
|
String responseVersion = LegacyESVersion.V_7_10_2.toString();
|
||||||
|
MainResponse response = new MainResponse("nodeName", Version.CURRENT,
|
||||||
|
new ClusterName("clusterName"), randomAlphaOfLengthBetween(10, 20), Build.CURRENT, responseVersion);
|
||||||
|
XContentBuilder builder = XContentFactory.jsonBuilder();
|
||||||
|
response.toXContent(builder, ToXContent.EMPTY_PARAMS);
|
||||||
|
assertTrue(Strings.toString(builder).contains("\"number\":\"" + responseVersion + "\","));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected MainResponse mutateInstance(MainResponse mutateInstance) {
|
protected MainResponse mutateInstance(MainResponse mutateInstance) {
|
||||||
String clusterUuid = mutateInstance.getClusterUuid();
|
String clusterUuid = mutateInstance.getClusterUuid();
|
||||||
|
|
Loading…
Reference in New Issue