diff --git a/server/src/main/java/org/opensearch/OpenSearchServerException.java b/server/src/main/java/org/opensearch/OpenSearchServerException.java index 89bd50b40a46c..0ee3debb4819a 100644 --- a/server/src/main/java/org/opensearch/OpenSearchServerException.java +++ b/server/src/main/java/org/opensearch/OpenSearchServerException.java @@ -1213,8 +1213,8 @@ public static void registerExceptions() { ); registerExceptionHandle( new OpenSearchExceptionHandle( - org.opensearch.rest.ResponseLimitBreachedException.class, - org.opensearch.rest.ResponseLimitBreachedException::new, + org.opensearch.common.breaker.ResponseLimitBreachedException.class, + org.opensearch.common.breaker.ResponseLimitBreachedException::new, 175, V_2_18_0 ) diff --git a/server/src/main/java/org/opensearch/action/ActionModule.java b/server/src/main/java/org/opensearch/action/ActionModule.java index 68f950f6e3ab9..98bcd6ba9c3f8 100644 --- a/server/src/main/java/org/opensearch/action/ActionModule.java +++ b/server/src/main/java/org/opensearch/action/ActionModule.java @@ -300,6 +300,7 @@ import org.opensearch.cluster.node.DiscoveryNodes; import org.opensearch.common.NamedRegistry; import org.opensearch.common.annotation.PublicApi; +import org.opensearch.common.breaker.ResponseLimitSettings; import org.opensearch.common.inject.AbstractModule; import org.opensearch.common.inject.TypeLiteral; import org.opensearch.common.inject.multibindings.MapBinder; @@ -325,7 +326,6 @@ import org.opensearch.plugins.ActionPlugin; import org.opensearch.plugins.ActionPlugin.ActionHandler; import org.opensearch.rest.NamedRoute; -import org.opensearch.rest.ResponseLimitSettings; import org.opensearch.rest.RestController; import org.opensearch.rest.RestHandler; import org.opensearch.rest.RestHeaderDefinition; @@ -992,7 +992,7 @@ public void initRestHandlers(Supplier nodesInCluster) { registerHandler.accept(new RestTemplatesAction()); // LIST API - registerHandler.accept(new RestIndicesListAction()); + registerHandler.accept(new RestIndicesListAction(responseLimitSettings)); // Point in time API registerHandler.accept(new RestCreatePitAction()); diff --git a/server/src/main/java/org/opensearch/action/admin/cluster/shards/TransportCatShardsAction.java b/server/src/main/java/org/opensearch/action/admin/cluster/shards/TransportCatShardsAction.java index 50ac9a67cddea..c2168177e1070 100644 --- a/server/src/main/java/org/opensearch/action/admin/cluster/shards/TransportCatShardsAction.java +++ b/server/src/main/java/org/opensearch/action/admin/cluster/shards/TransportCatShardsAction.java @@ -16,18 +16,18 @@ import org.opensearch.action.support.HandledTransportAction; import org.opensearch.action.support.TimeoutTaskCancellationUtility; import org.opensearch.client.node.NodeClient; +import org.opensearch.common.breaker.ResponseLimitBreachedException; +import org.opensearch.common.breaker.ResponseLimitSettings; import org.opensearch.common.inject.Inject; import org.opensearch.core.action.ActionListener; import org.opensearch.core.action.NotifyOnceListener; -import org.opensearch.rest.ResponseLimitBreachedException; -import org.opensearch.rest.ResponseLimitSettings; import org.opensearch.tasks.CancellableTask; import org.opensearch.tasks.Task; import org.opensearch.transport.TransportService; import java.util.Objects; -import static org.opensearch.rest.ResponseLimitSettings.LimitEntity.SHARDS; +import static org.opensearch.common.breaker.ResponseLimitSettings.LimitEntity.SHARDS; /** * Perform cat shards action @@ -133,7 +133,11 @@ private void validateRequestLimit( int limit = responseLimitSettings.getCatShardsResponseLimit(); if (ResponseLimitSettings.isResponseLimitBreached(clusterStateResponse.getState().getRoutingTable(), SHARDS, limit)) { listener.onFailure( - new ResponseLimitBreachedException("Too many shards requested. Can not request shards beyond {" + limit + "}") + new ResponseLimitBreachedException( + "Too many shards requested. Can not request shards beyond {" + limit + "}", + limit, + SHARDS + ) ); } } diff --git a/server/src/main/java/org/opensearch/common/breaker/ResponseLimitBreachedException.java b/server/src/main/java/org/opensearch/common/breaker/ResponseLimitBreachedException.java new file mode 100644 index 0000000000000..db6785067edf6 --- /dev/null +++ b/server/src/main/java/org/opensearch/common/breaker/ResponseLimitBreachedException.java @@ -0,0 +1,66 @@ +/* + * 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.common.breaker; + +import org.opensearch.OpenSearchException; +import org.opensearch.core.common.io.stream.StreamInput; +import org.opensearch.core.common.io.stream.StreamOutput; +import org.opensearch.core.rest.RestStatus; +import org.opensearch.core.xcontent.XContentBuilder; + +import java.io.IOException; + +/** + * Thrown when api response breaches threshold limit. + * + * @opensearch.internal + */ +public class ResponseLimitBreachedException extends OpenSearchException { + + private final int responseLimit; + private final ResponseLimitSettings.LimitEntity limitEntity; + + public ResponseLimitBreachedException(StreamInput in) throws IOException { + super(in); + responseLimit = in.readVInt(); + limitEntity = in.readEnum(ResponseLimitSettings.LimitEntity.class); + } + + public ResponseLimitBreachedException(String msg, int responseLimit, ResponseLimitSettings.LimitEntity limitEntity) { + super(msg); + this.responseLimit = responseLimit; + this.limitEntity = limitEntity; + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + super.writeTo(out); + out.writeVInt(responseLimit); + out.writeEnum(limitEntity); + } + + public int getResponseLimit() { + return responseLimit; + } + + public ResponseLimitSettings.LimitEntity getLimitEntity() { + return limitEntity; + } + + @Override + public RestStatus status() { + return RestStatus.TOO_MANY_REQUESTS; + } + + @Override + protected void metadataToXContent(XContentBuilder builder, Params params) throws IOException { + builder.field("response_limit", responseLimit); + builder.field("limit_entity", limitEntity); + } +} diff --git a/server/src/main/java/org/opensearch/rest/ResponseLimitSettings.java b/server/src/main/java/org/opensearch/common/breaker/ResponseLimitSettings.java similarity index 83% rename from server/src/main/java/org/opensearch/rest/ResponseLimitSettings.java rename to server/src/main/java/org/opensearch/common/breaker/ResponseLimitSettings.java index a8a337ac77622..0495cc813bfd0 100644 --- a/server/src/main/java/org/opensearch/rest/ResponseLimitSettings.java +++ b/server/src/main/java/org/opensearch/common/breaker/ResponseLimitSettings.java @@ -6,10 +6,11 @@ * compatible open source license. */ -package org.opensearch.rest; +package org.opensearch.common.breaker; import org.opensearch.cluster.metadata.Metadata; import org.opensearch.cluster.routing.IndexRoutingTable; +import org.opensearch.cluster.routing.IndexShardRoutingTable; import org.opensearch.cluster.routing.RoutingTable; import org.opensearch.common.settings.ClusterSettings; import org.opensearch.common.settings.Setting; @@ -94,8 +95,9 @@ public static boolean isResponseLimitBreached(final Metadata metadata, final Lim if (Objects.requireNonNull(limitEntity) == LimitEntity.INDICES) { int indicesCount = getTotalIndicesFromMetadata.apply(metadata); return indicesCount > limit; + } else { + throw new IllegalArgumentException("Unsupported limit entity [" + limitEntity + "]"); } - return false; } /** @@ -116,17 +118,23 @@ public static boolean isResponseLimitBreached(final RoutingTable routingTable, f if (indicesCount > limit) return true; break; case SHARDS: - final Map indexRoutingTableMap = routingTable.getIndicesRouting(); - int totalShards = 0; - for (final Map.Entry entry : indexRoutingTableMap.entrySet()) { - // In case routing table is corrupted. We will not block actions. - if (Objects.isNull(entry.getValue()) || Objects.isNull(entry.getValue().getShards())) { - return false; - } - totalShards += entry.getValue().getShards().size(); - if (totalShards > limit) return true; - } + if (isShardsLimitBreached(routingTable, limit)) return true; break; + default: + throw new IllegalArgumentException("Unsupported limit entity [" + limitEntity + "]"); + } + return false; + } + + private static boolean isShardsLimitBreached(final RoutingTable routingTable, final int limit) { + final Map indexRoutingTableMap = routingTable.getIndicesRouting(); + int totalShards = 0; + for (final Map.Entry entry : indexRoutingTableMap.entrySet()) { + for (final Map.Entry indexShardRoutingTableEntry : entry.getValue().getShards().entrySet()) { + totalShards += indexShardRoutingTableEntry.getValue().getShards().size(); + // Fail fast if limit value is breached and avoid unnecessary computation. + if (totalShards > limit) return true; + } } return false; } diff --git a/server/src/main/java/org/opensearch/common/settings/ClusterSettings.java b/server/src/main/java/org/opensearch/common/settings/ClusterSettings.java index faa1af2a2fcb6..e18c4dabb29eb 100644 --- a/server/src/main/java/org/opensearch/common/settings/ClusterSettings.java +++ b/server/src/main/java/org/opensearch/common/settings/ClusterSettings.java @@ -84,6 +84,7 @@ import org.opensearch.cluster.service.ClusterManagerTaskThrottler; import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.annotation.PublicApi; +import org.opensearch.common.breaker.ResponseLimitSettings; import org.opensearch.common.cache.CacheType; import org.opensearch.common.cache.settings.CacheSettings; import org.opensearch.common.cache.store.settings.OpenSearchOnHeapCacheSettings; @@ -155,7 +156,6 @@ import org.opensearch.repositories.blobstore.BlobStoreRepository; import org.opensearch.repositories.fs.FsRepository; import org.opensearch.rest.BaseRestHandler; -import org.opensearch.rest.ResponseLimitSettings; import org.opensearch.script.ScriptService; import org.opensearch.search.SearchService; import org.opensearch.search.aggregations.MultiBucketConsumerService; diff --git a/server/src/main/java/org/opensearch/rest/ResponseLimitBreachedException.java b/server/src/main/java/org/opensearch/rest/ResponseLimitBreachedException.java deleted file mode 100644 index d06b7e13d135f..0000000000000 --- a/server/src/main/java/org/opensearch/rest/ResponseLimitBreachedException.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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.rest; - -import org.opensearch.OpenSearchException; -import org.opensearch.core.common.io.stream.StreamInput; -import org.opensearch.core.rest.RestStatus; - -import java.io.IOException; - -/** - * Thrown when api response breaches threshold limit. - * - * @opensearch.internal - */ -public class ResponseLimitBreachedException extends OpenSearchException { - - public ResponseLimitBreachedException(String msg) { - super(msg); - } - - public ResponseLimitBreachedException(StreamInput in) throws IOException { - super(in); - } - - @Override - public RestStatus status() { - return RestStatus.TOO_MANY_REQUESTS; - } -} diff --git a/server/src/main/java/org/opensearch/rest/action/cat/AbstractCatAction.java b/server/src/main/java/org/opensearch/rest/action/cat/AbstractCatAction.java index 654624ca63faa..506f5f1529776 100644 --- a/server/src/main/java/org/opensearch/rest/action/cat/AbstractCatAction.java +++ b/server/src/main/java/org/opensearch/rest/action/cat/AbstractCatAction.java @@ -33,13 +33,13 @@ import org.opensearch.client.node.NodeClient; import org.opensearch.common.Table; +import org.opensearch.common.breaker.ResponseLimitSettings; import org.opensearch.common.io.Streams; import org.opensearch.common.io.UTF8StreamWriter; import org.opensearch.core.common.io.stream.BytesStream; import org.opensearch.core.rest.RestStatus; import org.opensearch.rest.BaseRestHandler; import org.opensearch.rest.BytesRestResponse; -import org.opensearch.rest.ResponseLimitSettings; import org.opensearch.rest.RestRequest; import java.io.IOException; diff --git a/server/src/main/java/org/opensearch/rest/action/cat/RestIndicesAction.java b/server/src/main/java/org/opensearch/rest/action/cat/RestIndicesAction.java index b9910a55d9d85..173fe5aad9744 100644 --- a/server/src/main/java/org/opensearch/rest/action/cat/RestIndicesAction.java +++ b/server/src/main/java/org/opensearch/rest/action/cat/RestIndicesAction.java @@ -50,6 +50,8 @@ import org.opensearch.cluster.health.ClusterIndexHealth; import org.opensearch.cluster.metadata.IndexMetadata; import org.opensearch.common.Table; +import org.opensearch.common.breaker.ResponseLimitBreachedException; +import org.opensearch.common.breaker.ResponseLimitSettings; import org.opensearch.common.collect.Tuple; import org.opensearch.common.logging.DeprecationLogger; import org.opensearch.common.settings.Settings; @@ -59,8 +61,6 @@ import org.opensearch.core.action.ActionResponse; import org.opensearch.core.common.Strings; import org.opensearch.index.IndexSettings; -import org.opensearch.rest.ResponseLimitBreachedException; -import org.opensearch.rest.ResponseLimitSettings; import org.opensearch.rest.RestRequest; import org.opensearch.rest.RestResponse; import org.opensearch.rest.action.RestResponseListener; @@ -88,7 +88,7 @@ import static java.util.Arrays.asList; import static java.util.Collections.unmodifiableList; import static org.opensearch.action.support.clustermanager.ClusterManagerNodeRequest.DEFAULT_CLUSTER_MANAGER_NODE_TIMEOUT; -import static org.opensearch.rest.ResponseLimitSettings.LimitEntity.INDICES; +import static org.opensearch.common.breaker.ResponseLimitSettings.LimitEntity.INDICES; import static org.opensearch.rest.RestRequest.Method.GET; /** @@ -253,7 +253,11 @@ private void validateRequestLimit(final ClusterStateResponse clusterStateRespons int limit = responseLimitSettings.getCatIndicesResponseLimit(); if (ResponseLimitSettings.isResponseLimitBreached(clusterStateResponse.getState().getMetadata(), INDICES, limit)) { listener.onFailure( - new ResponseLimitBreachedException("Too many indices requested. Can not request indices beyond {" + limit + "}") + new ResponseLimitBreachedException( + "Too many indices requested. Can not request indices beyond {" + limit + "}", + limit, + INDICES + ) ); } } diff --git a/server/src/main/java/org/opensearch/rest/action/cat/RestSegmentsAction.java b/server/src/main/java/org/opensearch/rest/action/cat/RestSegmentsAction.java index 8b78897aee3ad..e82b2eff0efc9 100644 --- a/server/src/main/java/org/opensearch/rest/action/cat/RestSegmentsAction.java +++ b/server/src/main/java/org/opensearch/rest/action/cat/RestSegmentsAction.java @@ -42,11 +42,11 @@ import org.opensearch.client.node.NodeClient; import org.opensearch.cluster.node.DiscoveryNodes; import org.opensearch.common.Table; +import org.opensearch.common.breaker.ResponseLimitBreachedException; +import org.opensearch.common.breaker.ResponseLimitSettings; import org.opensearch.common.logging.DeprecationLogger; import org.opensearch.core.common.Strings; import org.opensearch.index.engine.Segment; -import org.opensearch.rest.ResponseLimitBreachedException; -import org.opensearch.rest.ResponseLimitSettings; import org.opensearch.rest.RestRequest; import org.opensearch.rest.RestResponse; import org.opensearch.rest.action.RestActionListener; @@ -58,7 +58,7 @@ import static java.util.Arrays.asList; import static java.util.Collections.unmodifiableList; -import static org.opensearch.rest.ResponseLimitSettings.LimitEntity.INDICES; +import static org.opensearch.common.breaker.ResponseLimitSettings.LimitEntity.INDICES; import static org.opensearch.rest.RestRequest.Method.GET; /** @@ -131,7 +131,9 @@ private void validateRequestLimit(final ClusterStateResponse clusterStateRespons int limit = responseLimitSettings.getCatSegmentsResponseLimit(); if (ResponseLimitSettings.isResponseLimitBreached(clusterStateResponse.getState().getRoutingTable(), INDICES, limit)) { throw new ResponseLimitBreachedException( - "Segments from too many indices requested. Can not request indices beyond {" + limit + "}" + "Segments from too many indices requested. Can not request indices beyond {" + limit + "}", + limit, + INDICES ); } } diff --git a/server/src/main/java/org/opensearch/rest/action/list/RestIndicesListAction.java b/server/src/main/java/org/opensearch/rest/action/list/RestIndicesListAction.java index ad5c58c86ce90..971cab0535be9 100644 --- a/server/src/main/java/org/opensearch/rest/action/list/RestIndicesListAction.java +++ b/server/src/main/java/org/opensearch/rest/action/list/RestIndicesListAction.java @@ -9,6 +9,7 @@ package org.opensearch.rest.action.list; import org.opensearch.action.admin.cluster.state.ClusterStateResponse; +import org.opensearch.common.breaker.ResponseLimitSettings; import org.opensearch.common.collect.Tuple; import org.opensearch.common.settings.Settings; import org.opensearch.rest.RestRequest; @@ -35,6 +36,10 @@ public class RestIndicesListAction extends RestIndicesAction { private static final int MAX_SUPPORTED_LIST_INDICES_PAGE_SIZE = 5000; private static final int DEFAULT_LIST_INDICES_PAGE_SIZE = 500; + public RestIndicesListAction(final ResponseLimitSettings responseLimitSettings) { + super(responseLimitSettings); + } + @Override public List routes() { return unmodifiableList(asList(new Route(GET, "/_list/indices"), new Route(GET, "/_list/indices/{index}"))); @@ -70,6 +75,11 @@ protected PageParams validateAndGetPageParams(RestRequest restRequest) { return pageParams; } + @Override + public boolean isRequestLimitCheckSupported() { + return false; + } + protected int defaultPageSize() { return DEFAULT_LIST_INDICES_PAGE_SIZE; } diff --git a/server/src/test/java/org/opensearch/ExceptionSerializationTests.java b/server/src/test/java/org/opensearch/ExceptionSerializationTests.java index ff68d1718e9b9..c1972daeab6d3 100644 --- a/server/src/test/java/org/opensearch/ExceptionSerializationTests.java +++ b/server/src/test/java/org/opensearch/ExceptionSerializationTests.java @@ -65,6 +65,7 @@ import org.opensearch.cluster.routing.UnsupportedWeightedRoutingStateException; import org.opensearch.cluster.service.ClusterManagerThrottlingException; import org.opensearch.common.UUIDs; +import org.opensearch.common.breaker.ResponseLimitBreachedException; import org.opensearch.common.collect.Tuple; import org.opensearch.common.io.PathUtils; import org.opensearch.common.io.stream.BytesStreamOutput; @@ -106,7 +107,6 @@ import org.opensearch.indices.replication.common.ReplicationFailedException; import org.opensearch.ingest.IngestProcessorException; import org.opensearch.repositories.RepositoryException; -import org.opensearch.rest.ResponseLimitBreachedException; import org.opensearch.rest.action.admin.indices.AliasesNotFoundException; import org.opensearch.search.SearchContextMissingException; import org.opensearch.search.SearchException; diff --git a/server/src/test/java/org/opensearch/action/RenamedTimeoutRequestParameterTests.java b/server/src/test/java/org/opensearch/action/RenamedTimeoutRequestParameterTests.java index d7eaf326939cb..26c4670b4288c 100644 --- a/server/src/test/java/org/opensearch/action/RenamedTimeoutRequestParameterTests.java +++ b/server/src/test/java/org/opensearch/action/RenamedTimeoutRequestParameterTests.java @@ -11,6 +11,7 @@ import org.opensearch.OpenSearchParseException; import org.opensearch.action.support.clustermanager.ClusterManagerNodeRequest; import org.opensearch.client.node.NodeClient; +import org.opensearch.common.breaker.ResponseLimitSettings; import org.opensearch.common.logging.DeprecationLogger; import org.opensearch.common.settings.ClusterSettings; import org.opensearch.common.settings.Settings; @@ -19,7 +20,6 @@ import org.opensearch.core.xcontent.MediaTypeRegistry; import org.opensearch.core.xcontent.NamedXContentRegistry; import org.opensearch.rest.BaseRestHandler; -import org.opensearch.rest.ResponseLimitSettings; import org.opensearch.rest.action.admin.cluster.RestCleanupRepositoryAction; import org.opensearch.rest.action.admin.cluster.RestCloneSnapshotAction; import org.opensearch.rest.action.admin.cluster.RestClusterGetSettingsAction; diff --git a/server/src/test/java/org/opensearch/rest/ResponseLimitSettingsTests.java b/server/src/test/java/org/opensearch/common/breaker/ResponseLimitSettingsTests.java similarity index 55% rename from server/src/test/java/org/opensearch/rest/ResponseLimitSettingsTests.java rename to server/src/test/java/org/opensearch/common/breaker/ResponseLimitSettingsTests.java index 815633a25a31c..a45fee7e58b30 100644 --- a/server/src/test/java/org/opensearch/rest/ResponseLimitSettingsTests.java +++ b/server/src/test/java/org/opensearch/common/breaker/ResponseLimitSettingsTests.java @@ -6,7 +6,7 @@ * compatible open source license. */ -package org.opensearch.rest; +package org.opensearch.common.breaker; import org.opensearch.Version; import org.opensearch.cluster.ClusterState; @@ -27,13 +27,13 @@ import java.util.HashMap; import java.util.Map; -import static org.opensearch.rest.ResponseLimitSettings.CAT_INDICES_RESPONSE_LIMIT_SETTING; -import static org.opensearch.rest.ResponseLimitSettings.CAT_SEGMENTS_RESPONSE_LIMIT_SETTING; -import static org.opensearch.rest.ResponseLimitSettings.CAT_SHARDS_RESPONSE_LIMIT_SETTING; +import static org.opensearch.common.breaker.ResponseLimitSettings.CAT_INDICES_RESPONSE_LIMIT_SETTING; +import static org.opensearch.common.breaker.ResponseLimitSettings.CAT_SEGMENTS_RESPONSE_LIMIT_SETTING; +import static org.opensearch.common.breaker.ResponseLimitSettings.CAT_SHARDS_RESPONSE_LIMIT_SETTING; public class ResponseLimitSettingsTests extends OpenSearchTestCase { - public void testIsResponseLimitBreached_forNullMetadata_expectNotBreached() { + public void testIsResponseLimitBreachedForNullMetadataExpectNotBreached() { final Settings settings = Settings.builder().build(); final ClusterSettings clusterSettings = new ClusterSettings(Settings.EMPTY, ClusterSettings.BUILT_IN_CLUSTER_SETTINGS); final ResponseLimitSettings responseLimitSettings = new ResponseLimitSettings(clusterSettings, settings); @@ -45,7 +45,7 @@ public void testIsResponseLimitBreached_forNullMetadata_expectNotBreached() { assertFalse(breached); } - public void testIsResponseLimitBreached_forNullRoutingTable_expectNotBreached() { + public void testIsResponseLimitBreachedForNullRoutingTableExpectNotBreached() { final Settings settings = Settings.builder().build(); final ClusterSettings clusterSettings = new ClusterSettings(Settings.EMPTY, ClusterSettings.BUILT_IN_CLUSTER_SETTINGS); final ResponseLimitSettings responseLimitSettings = new ResponseLimitSettings(clusterSettings, settings); @@ -57,98 +57,80 @@ public void testIsResponseLimitBreached_forNullRoutingTable_expectNotBreached() assertFalse(breached); } - public void testIsResponseLimitBreached_forCatIndicesWithSettingDisabled_expectNotBreached() { + public void testIsResponseLimitBreachedForCatIndicesWithSettingDisabledExpectNotBreached() { // Don't enable limit final Settings settings = Settings.builder().put(CAT_INDICES_RESPONSE_LIMIT_SETTING.getKey(), -1).build(); - final ClusterSettings clusterSettings = new ClusterSettings(Settings.EMPTY, ClusterSettings.BUILT_IN_CLUSTER_SETTINGS); - final ResponseLimitSettings responseLimitSettings = new ResponseLimitSettings(clusterSettings, settings); - final ClusterState clusterState = buildClusterState("test-index-1", "test-index-2", "test-index-3"); - final boolean breached = ResponseLimitSettings.isResponseLimitBreached( - clusterState.getMetadata(), - ResponseLimitSettings.LimitEntity.INDICES, - responseLimitSettings.getCatIndicesResponseLimit() - ); + final boolean breached = isBreachedForIndices(settings); assertFalse(breached); } - public void testIsResponseLimitBreached_forCatIndicesWithSettingEnabled_expectBreached() { + public void testIsResponseLimitBreachedForCatIndicesWithSettingEnabledExpectBreached() { // Set limit of 1 index final Settings settings = Settings.builder().put(CAT_INDICES_RESPONSE_LIMIT_SETTING.getKey(), 1).build(); - final ClusterSettings clusterSettings = new ClusterSettings(Settings.EMPTY, ClusterSettings.BUILT_IN_CLUSTER_SETTINGS); - final ResponseLimitSettings responseLimitSettings = new ResponseLimitSettings(clusterSettings, settings); - // Pass cluster state with 3 indices - final ClusterState clusterState = buildClusterState("test-index-1", "test-index-2", "test-index-3"); - final boolean breached = ResponseLimitSettings.isResponseLimitBreached( - clusterState.getMetadata(), - ResponseLimitSettings.LimitEntity.INDICES, - responseLimitSettings.getCatIndicesResponseLimit() - ); + final boolean breached = isBreachedForIndices(settings); assertTrue(breached); } - public void testIsResponseLimitBreached_forCatIndicesWithSettingEnabled_expectNotBreached() { + public void testIsResponseLimitBreachedForCatIndicesWithSettingEnabledExpectNotBreached() { // Set limit of 5 indices final Settings settings = Settings.builder().put(CAT_INDICES_RESPONSE_LIMIT_SETTING.getKey(), 5).build(); + final boolean breached = isBreachedForIndices(settings); + assertFalse(breached); + } + + private static boolean isBreachedForIndices(final Settings settings) { final ClusterSettings clusterSettings = new ClusterSettings(Settings.EMPTY, ClusterSettings.BUILT_IN_CLUSTER_SETTINGS); final ResponseLimitSettings responseLimitSettings = new ResponseLimitSettings(clusterSettings, settings); // Pass cluster state with 3 indices final ClusterState clusterState = buildClusterState("test-index-1", "test-index-2", "test-index-3"); - final boolean breached = ResponseLimitSettings.isResponseLimitBreached( + return ResponseLimitSettings.isResponseLimitBreached( clusterState.getMetadata(), ResponseLimitSettings.LimitEntity.INDICES, responseLimitSettings.getCatIndicesResponseLimit() ); - assertFalse(breached); } - public void testIsResponseLimitBreached_forCatShardsWithSettingDisabled_expectNotBreached() { + public void testIsResponseLimitBreachedForCatShardsWithSettingDisabledExpectNotBreached() { // Don't enable limit final Settings settings = Settings.builder().put(CAT_SHARDS_RESPONSE_LIMIT_SETTING.getKey(), -1).build(); + final boolean breached = isBreachedForShards(settings); + assertFalse(breached); + } + + private static boolean isBreachedForShards(Settings settings) { final ClusterSettings clusterSettings = new ClusterSettings(Settings.EMPTY, ClusterSettings.BUILT_IN_CLUSTER_SETTINGS); final ResponseLimitSettings responseLimitSettings = new ResponseLimitSettings(clusterSettings, settings); // Build cluster state with 3 shards final ClusterState clusterState = buildClusterState("test-index-1", "test-index-2", "test-index-3"); - final boolean breached = ResponseLimitSettings.isResponseLimitBreached( + return ResponseLimitSettings.isResponseLimitBreached( clusterState.getRoutingTable(), ResponseLimitSettings.LimitEntity.SHARDS, responseLimitSettings.getCatShardsResponseLimit() ); - assertFalse(breached); } - public void testIsResponseLimitBreached_forCatShardsWithSettingEnabled_expectBreached() { + public void testIsResponseLimitBreachedForCatShardsWithSettingEnabledExpectBreached() { // Set limit of 2 shards final Settings settings = Settings.builder().put(CAT_SHARDS_RESPONSE_LIMIT_SETTING.getKey(), 2).build(); - final ClusterSettings clusterSettings = new ClusterSettings(Settings.EMPTY, ClusterSettings.BUILT_IN_CLUSTER_SETTINGS); - final ResponseLimitSettings responseLimitSettings = new ResponseLimitSettings(clusterSettings, settings); - // Build cluster state with 3 shards - final ClusterState clusterState = buildClusterState("test-index-1", "test-index-2", "test-index-3"); - final boolean breached = ResponseLimitSettings.isResponseLimitBreached( - clusterState.getRoutingTable(), - ResponseLimitSettings.LimitEntity.SHARDS, - responseLimitSettings.getCatShardsResponseLimit() - ); + final boolean breached = isBreachedForShards(settings); assertTrue(breached); } - public void testIsResponseLimitBreached_forCatShardsWithSettingEnabled_expectNotBreached() { - // Set limit of 3 shards - final Settings settings = Settings.builder().put(CAT_SHARDS_RESPONSE_LIMIT_SETTING.getKey(), 3).build(); - final ClusterSettings clusterSettings = new ClusterSettings(Settings.EMPTY, ClusterSettings.BUILT_IN_CLUSTER_SETTINGS); - final ResponseLimitSettings responseLimitSettings = new ResponseLimitSettings(clusterSettings, settings); - // Build cluster state with 3 shards - final ClusterState clusterState = buildClusterState("test-index-1", "test-index-2", "test-index-3"); - final boolean breached = ResponseLimitSettings.isResponseLimitBreached( - clusterState.getRoutingTable(), - ResponseLimitSettings.LimitEntity.SHARDS, - responseLimitSettings.getCatShardsResponseLimit() - ); + public void testIsResponseLimitBreachedForCatShardsWithSettingEnabledExpectNotBreached() { + // Set limit of 9 shards + final Settings settings = Settings.builder().put(CAT_SHARDS_RESPONSE_LIMIT_SETTING.getKey(), 9).build(); + final boolean breached = isBreachedForShards(settings); assertFalse(breached); } - public void testIsResponseLimitBreached_forCatSegmentsWithSettingDisabled_expectNotBreached() { + public void testIsResponseLimitBreachedForCatSegmentsWithSettingDisabledExpectNotBreached() { // Don't enable limit final Settings settings = Settings.builder().put(CAT_SEGMENTS_RESPONSE_LIMIT_SETTING.getKey(), -1).build(); + final boolean breached = isBreachedForSegments(settings); + assertFalse(breached); + } + + private static boolean isBreachedForSegments(Settings settings) { final ClusterSettings clusterSettings = new ClusterSettings(Settings.EMPTY, ClusterSettings.BUILT_IN_CLUSTER_SETTINGS); final ResponseLimitSettings responseLimitSettings = new ResponseLimitSettings(clusterSettings, settings); // Build cluster state with 3 indices @@ -158,36 +140,20 @@ public void testIsResponseLimitBreached_forCatSegmentsWithSettingDisabled_expect ResponseLimitSettings.LimitEntity.INDICES, responseLimitSettings.getCatSegmentsResponseLimit() ); - assertFalse(breached); + return breached; } - public void testIsResponseLimitBreached_forCatSegmentsWithSettingEnabled_expectBreached() { + public void testIsResponseLimitBreachedForCatSegmentsWithSettingEnabledExpectBreached() { // Set limit of 1 index final Settings settings = Settings.builder().put(CAT_SEGMENTS_RESPONSE_LIMIT_SETTING.getKey(), 1).build(); - final ClusterSettings clusterSettings = new ClusterSettings(Settings.EMPTY, ClusterSettings.BUILT_IN_CLUSTER_SETTINGS); - final ResponseLimitSettings responseLimitSettings = new ResponseLimitSettings(clusterSettings, settings); - // Build cluster state with 3 indices - final ClusterState clusterState = buildClusterState("test-index-1", "test-index-2", "test-index-3"); - final boolean breached = ResponseLimitSettings.isResponseLimitBreached( - clusterState.getRoutingTable(), - ResponseLimitSettings.LimitEntity.INDICES, - responseLimitSettings.getCatSegmentsResponseLimit() - ); + final boolean breached = isBreachedForSegments(settings); assertTrue(breached); } - public void testIsResponseLimitBreached_forCatSegmentsWithSettingEnabled_expectNotBreached() { + public void testIsResponseLimitBreachedForCatSegmentsWithSettingEnabledExpectNotBreached() { // Set limit of 3 indices final Settings settings = Settings.builder().put(CAT_SEGMENTS_RESPONSE_LIMIT_SETTING.getKey(), 5).build(); - final ClusterSettings clusterSettings = new ClusterSettings(Settings.EMPTY, ClusterSettings.BUILT_IN_CLUSTER_SETTINGS); - final ResponseLimitSettings responseLimitSettings = new ResponseLimitSettings(clusterSettings, settings); - // Build cluster state with 3 indices - final ClusterState clusterState = buildClusterState("test-index-1", "test-index-2", "test-index-3"); - final boolean breached = ResponseLimitSettings.isResponseLimitBreached( - clusterState.getRoutingTable(), - ResponseLimitSettings.LimitEntity.INDICES, - responseLimitSettings.getCatSegmentsResponseLimit() - ); + final boolean breached = isBreachedForSegments(settings); assertFalse(breached); } @@ -199,12 +165,16 @@ private static ClusterState buildClusterState(String... indices) { final Map indexRoutingTableMap = new HashMap<>(); for (String s : indices) { final Index index = new Index(s, "uuid"); - final ShardId shardId = new ShardId(index, 0); - final ShardRouting primaryShardRouting = createShardRouting(shardId, true); - final IndexShardRoutingTable.Builder indexShardRoutingTableBuilder = new IndexShardRoutingTable.Builder(shardId); + final ShardId primaryShardId = new ShardId(index, 0); + final ShardRouting primaryShardRouting = createShardRouting(primaryShardId, true); + final ShardId replicaShardId = new ShardId(index, 1); + final ShardRouting replicaShardRouting = createShardRouting(replicaShardId, false); + final IndexShardRoutingTable.Builder indexShardRoutingTableBuilder = new IndexShardRoutingTable.Builder(primaryShardId); indexShardRoutingTableBuilder.addShard(primaryShardRouting); + indexShardRoutingTableBuilder.addShard(replicaShardRouting); final IndexRoutingTable.Builder indexRoutingTable = IndexRoutingTable.builder(index) .addShard(primaryShardRouting) + .addShard(replicaShardRouting) .addIndexShard(indexShardRoutingTableBuilder.build()); indexRoutingTableMap.put(index.getName(), indexRoutingTable.build()); } diff --git a/server/src/test/java/org/opensearch/rest/action/cat/RestIndicesActionTests.java b/server/src/test/java/org/opensearch/rest/action/cat/RestIndicesActionTests.java index 6aaa01540c7ae..2debb00a0d14f 100644 --- a/server/src/test/java/org/opensearch/rest/action/cat/RestIndicesActionTests.java +++ b/server/src/test/java/org/opensearch/rest/action/cat/RestIndicesActionTests.java @@ -43,12 +43,12 @@ import org.opensearch.cluster.routing.TestShardRouting; import org.opensearch.common.Table; import org.opensearch.common.UUIDs; +import org.opensearch.common.breaker.ResponseLimitSettings; import org.opensearch.common.settings.ClusterSettings; import org.opensearch.common.settings.Settings; import org.opensearch.core.index.Index; import org.opensearch.core.index.shard.ShardId; import org.opensearch.index.IndexSettings; -import org.opensearch.rest.ResponseLimitSettings; import org.opensearch.rest.action.list.RestIndicesListAction; import org.opensearch.rest.pagination.PageToken; import org.opensearch.test.OpenSearchTestCase; @@ -145,7 +145,6 @@ public void setup() { } } - public void testBuildTable() { final ClusterSettings clusterSettings = new ClusterSettings(Settings.EMPTY, ClusterSettings.BUILT_IN_CLUSTER_SETTINGS); final Settings settings = Settings.builder().build(); @@ -171,8 +170,11 @@ public void testBuildTable() { } public void testBuildPaginatedTable() { - final RestIndicesAction action = new RestIndicesAction(); - final RestIndicesListAction indicesListAction = new RestIndicesListAction(); + final ClusterSettings clusterSettings = new ClusterSettings(Settings.EMPTY, ClusterSettings.BUILT_IN_CLUSTER_SETTINGS); + final Settings settings = Settings.builder().build(); + final ResponseLimitSettings responseLimitSettings = new ResponseLimitSettings(clusterSettings, settings); + final RestIndicesAction action = new RestIndicesAction(responseLimitSettings); + final RestIndicesListAction indicesListAction = new RestIndicesListAction(responseLimitSettings); List indicesList = new ArrayList<>(indicesMetadatas.keySet()); // Using half of the indices from metadata list for a page String[] indicesToBeQueried = indicesList.subList(0, indicesMetadatas.size() / 2).toArray(new String[0]);