diff --git a/qa/mixed-cluster/src/test/java/org/opensearch/backwards/ExceptionIT.java b/qa/mixed-cluster/src/test/java/org/opensearch/backwards/ExceptionIT.java new file mode 100644 index 00000000000..e0246870181 --- /dev/null +++ b/qa/mixed-cluster/src/test/java/org/opensearch/backwards/ExceptionIT.java @@ -0,0 +1,61 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.backwards; + +import org.apache.http.util.EntityUtils; +import org.opensearch.Version; +import org.opensearch.client.Node; +import org.opensearch.client.Request; +import org.opensearch.client.Response; +import org.opensearch.client.ResponseException; +import org.opensearch.test.rest.OpenSearchRestTestCase; +import org.opensearch.test.rest.yaml.ObjectPath; + +import java.io.IOException; +import java.util.Collections; +import java.util.Map; + +import static org.apache.http.HttpStatus.SC_NOT_FOUND; + +public class ExceptionIT extends OpenSearchRestTestCase { + public void testOpensearchException() throws Exception { + logClusterNodes(); + + Request request = new Request("GET", "/no_such_index"); + + for (Node node : client().getNodes()) { + try { + client().setNodes(Collections.singletonList(node)); + logger.info("node: {}", node.getHost()); + client().performRequest(request); + fail(); + } catch (ResponseException e) { + logger.debug(e.getMessage()); + Response response = e.getResponse(); + assertEquals(SC_NOT_FOUND, response.getStatusLine().getStatusCode()); + assertEquals("no_such_index", ObjectPath.createFromResponse(response).evaluate("error.index")); + } + } + } + + private void logClusterNodes() throws IOException { + ObjectPath objectPath = ObjectPath.createFromResponse(client().performRequest(new Request("GET", "_nodes"))); + Map nodes = objectPath.evaluate("nodes"); + String master = EntityUtils.toString(client().performRequest(new Request("GET", "_cat/master?h=id")).getEntity()).trim(); + logger.info("cluster discovered: master id='{}'", master); + for (String id : nodes.keySet()) { + logger.info("{}: id='{}', name='{}', version={}", + objectPath.evaluate("nodes." + id + ".http.publish_address"), + id, + objectPath.evaluate("nodes." + id + ".name"), + Version.fromString(objectPath.evaluate("nodes." + id + ".version")) + ); + } + } +} diff --git a/server/src/main/java/org/opensearch/OpenSearchException.java b/server/src/main/java/org/opensearch/OpenSearchException.java index b89aebf4b34..8cd06bcdc1d 100644 --- a/server/src/main/java/org/opensearch/OpenSearchException.java +++ b/server/src/main/java/org/opensearch/OpenSearchException.java @@ -61,6 +61,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.regex.Pattern; import java.util.stream.Collectors; import static java.util.Collections.emptyMap; @@ -108,6 +109,10 @@ public class OpenSearchException extends RuntimeException implements ToXContentF private static final Map> ID_TO_SUPPLIER; private static final Map, OpenSearchExceptionHandle> CLASS_TO_OPENSEARCH_EXCEPTION_HANDLE; + + private static final Pattern OS_METADATA = Pattern.compile("^opensearch\\."); + private static final Pattern ES_METADATA = Pattern.compile("^es\\."); + private final Map> metadata = new HashMap<>(); private final Map> headers = new HashMap<>(); @@ -150,7 +155,16 @@ public class OpenSearchException extends RuntimeException implements ToXContentF super(in.readOptionalString(), in.readException()); readStackTrace(this, in); headers.putAll(in.readMapOfLists(StreamInput::readString, StreamInput::readString)); - metadata.putAll(in.readMapOfLists(StreamInput::readString, StreamInput::readString)); + metadata.putAll(in.readMapOfLists(OpenSearchException::readAndReplace, StreamInput::readString)); + } + + private static String readAndReplace(StreamInput in) throws IOException { + String str = in.readString(); + return in.getVersion().onOrBefore(LegacyESVersion.V_7_10_2) ? ES_METADATA.matcher(str).replaceFirst("opensearch.") : str; + } + + private static void replaceAndWrite(StreamOutput out, String str) throws IOException { + out.writeString(out.getVersion().onOrBefore(LegacyESVersion.V_7_10_2) ? OS_METADATA.matcher(str).replaceFirst("es.") : str); } /** @@ -293,7 +307,7 @@ public class OpenSearchException extends RuntimeException implements ToXContentF out.writeException(this.getCause()); writeStackTraces(this, out, StreamOutput::writeException); out.writeMapOfLists(headers, StreamOutput::writeString, StreamOutput::writeString); - out.writeMapOfLists(metadata, StreamOutput::writeString, StreamOutput::writeString); + out.writeMapOfLists(metadata, OpenSearchException::replaceAndWrite, StreamOutput::writeString); } public static OpenSearchException readException(StreamInput input, int id) throws IOException {