Skip to content

Commit

Permalink
Register and use custom exception
Browse files Browse the repository at this point in the history
Signed-off-by: Lakshya Taragi <lakshya.taragi@gmail.com>
  • Loading branch information
ltaragi committed Aug 29, 2024
1 parent 7bda010 commit b5cab5b
Show file tree
Hide file tree
Showing 8 changed files with 146 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,26 @@
"description":"A comma-separated list of snapshot names"
}
}
},
{
"path":"/_snapshot/{repository}/{snapshot}/{index}/_status",
"methods":[
"GET"
],
"parts":{
"repository":{
"type":"string",
"description":"A repository name"
},
"snapshot":{
"type":"string",
"description":"A snapshot name"
},
"index":{
"type": "list",
"description":"A comma-separated list of index names"
}
}
}
]
},
Expand All @@ -58,7 +78,7 @@
},
"ignore_unavailable":{
"type":"boolean",
"description":"Whether to ignore unavailable snapshots, defaults to false which means a SnapshotMissingException is thrown"
"description":"Whether to ignore unavailable snapshots and indices, defaults to false which means a SnapshotMissingException or IndexNotFoundException is thrown"
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import org.opensearch.cluster.SnapshotsInProgress;
import org.opensearch.common.action.ActionFuture;
import org.opensearch.common.settings.Settings;
import org.opensearch.indices.RemoteStoreSettings;
import org.opensearch.repositories.blobstore.BlobStoreRepository;
import org.opensearch.test.OpenSearchIntegTestCase;
import org.opensearch.threadpool.ThreadPool;
Expand Down Expand Up @@ -201,20 +202,25 @@ public void testStatusAPICallInProgressShallowSnapshot() throws Exception {

public void testStatusAPICallForShallowV2Snapshot() throws Exception {
disableRepoConsistencyCheck("Remote store repository is being used for the test");
internalCluster().startClusterManagerOnlyNode();
internalCluster().startDataOnlyNodes(2);
Settings pinnedTimestampSettings = Settings.builder()
.put(RemoteStoreSettings.CLUSTER_REMOTE_STORE_PINNED_TIMESTAMP_ENABLED.getKey(), true)
.build();
internalCluster().startClusterManagerOnlyNode(pinnedTimestampSettings);
internalCluster().startDataOnlyNodes(2, pinnedTimestampSettings);

logger.info("Create repository for shallow V2 snapshots");
final String index1 = "remote-index-1";
final String index2 = "remote-index-2";
final String index3 = "remote-index-3";
final String snapshotRepoName = "snapshot-repo-name";
final String snapshot = "snapshot";

logger.info("Create repository for shallow V2 snapshots");
Settings.Builder snapshotV2RepoSettings = snapshotRepoSettingsForShallowCopy().put(
BlobStoreRepository.SHALLOW_SNAPSHOT_V2.getKey(),
Boolean.TRUE
);
createRepository(snapshotRepoName, "fs", snapshotV2RepoSettings);

final String index1 = "remote-index-1";
final String index2 = "remote-index-2";
final String index3 = "remote-index-3";
final Settings remoteStoreEnabledIndexSettings = getRemoteStoreBackedIndexSettings();
createIndex(index1, remoteStoreEnabledIndexSettings);
createIndex(index2, remoteStoreEnabledIndexSettings);
Expand All @@ -229,7 +235,6 @@ public void testStatusAPICallForShallowV2Snapshot() throws Exception {
}
refresh();

final String snapshot = "snapshot";
SnapshotInfo snapshotInfo = createFullSnapshot(snapshotRepoName, snapshot);
assertTrue(snapshotInfo.getPinnedTimestamp() > 0); // to assert creation of a shallow v2 snapshot

Expand All @@ -238,8 +243,8 @@ public void testStatusAPICallForShallowV2Snapshot() throws Exception {
updateSettingsRequest.persistentSettings(Settings.builder().put(MAX_SHARDS_ALLOWED_IN_STATUS_API.getKey(), 2));
assertAcked(client().admin().cluster().updateSettings(updateSettingsRequest).actionGet());

// without index filter
assertBusy(() -> {
// without index filter
// although no. of shards in snapshot (3) is greater than the max value allowed in a status api call, the request does not fail
SnapshotStatus snapshotStatusWithoutIndexFilter = client().admin()
.cluster()
Expand All @@ -252,6 +257,7 @@ public void testStatusAPICallForShallowV2Snapshot() throws Exception {

assertShallowV2SnapshotStatus(snapshotStatusWithoutIndexFilter, false);

// with index filter
SnapshotStatus snapshotStatusWithIndexFilter = client().admin()
.cluster()
.prepareSnapshotStatus(snapshotRepoName)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
import org.opensearch.core.common.Strings;
import org.opensearch.core.common.unit.ByteSizeUnit;
import org.opensearch.core.rest.RestStatus;
import org.opensearch.index.IndexNotFoundException;
import org.opensearch.repositories.blobstore.BlobStoreRepository;
import org.opensearch.threadpool.ThreadPool;

Expand Down Expand Up @@ -601,32 +602,30 @@ public void testSnapshotStatusApiFailureForTooManyShardsAcrossSnapshots() throws

// across a single snapshot
assertBusy(() -> {
SnapshotException snapshotException = expectThrows(
SnapshotException.class,
TooManyShardsInSnapshotsStatusException exception = expectThrows(
TooManyShardsInSnapshotsStatusException.class,
() -> client().admin().cluster().prepareSnapshotStatus(repositoryName).setSnapshots(snapshot1).execute().actionGet()
);
assertEquals(snapshotException.status(), RestStatus.REQUEST_ENTITY_TOO_LARGE);
assertEquals(exception.status(), RestStatus.REQUEST_ENTITY_TOO_LARGE);
assertTrue(
snapshotException.getMessage()
.endsWith(" is more than the maximum allowed value of shard count [2] for snapshot status request")
exception.getMessage().endsWith(" is more than the maximum allowed value of shard count [2] for snapshot status request")
);
}, 1, TimeUnit.MINUTES);

// across multiple snapshots
assertBusy(() -> {
SnapshotException snapshotException = expectThrows(
SnapshotException.class,
TooManyShardsInSnapshotsStatusException exception = expectThrows(
TooManyShardsInSnapshotsStatusException.class,
() -> client().admin()
.cluster()
.prepareSnapshotStatus(repositoryName)
.setSnapshots(snapshot1, snapshot2)
.execute()
.actionGet()
);
assertEquals(snapshotException.status(), RestStatus.REQUEST_ENTITY_TOO_LARGE);
assertEquals(exception.status(), RestStatus.REQUEST_ENTITY_TOO_LARGE);
assertTrue(
snapshotException.getMessage()
.endsWith(" is more than the maximum allowed value of shard count [2] for snapshot status request")
exception.getMessage().endsWith(" is more than the maximum allowed value of shard count [2] for snapshot status request")
);
}, 1, TimeUnit.MINUTES);

Expand Down Expand Up @@ -713,8 +712,8 @@ public void testSnapshotStatusFailuresWithIndexFilter() throws Exception {

assertBusy(() -> {
// failure due to index not found in snapshot
SnapshotException ex = expectThrows(
SnapshotException.class,
IndexNotFoundException ex = expectThrows(
IndexNotFoundException.class,
() -> client().admin()
.cluster()
.prepareSnapshotStatus(repositoryName)
Expand All @@ -726,13 +725,12 @@ public void testSnapshotStatusFailuresWithIndexFilter() throws Exception {
assertEquals(ex.status(), RestStatus.NOT_FOUND);
String cause = String.format(
Locale.ROOT,
"[%s:%s] indices [%s] missing in snapshot [%s]",
repositoryName,
snapshot2,
"indices [%s] missing in snapshot [%s] of repository [%s]",
String.join(", ", List.of(index2, index3)),
snapshot2
snapshot2,
repositoryName
);
assertEquals(cause, ex.getMessage());
assertEquals(cause, ex.getCause().getMessage());

}, 1, TimeUnit.MINUTES);

Expand All @@ -743,8 +741,8 @@ public void testSnapshotStatusFailuresWithIndexFilter() throws Exception {
updateSettingsRequest.persistentSettings(Settings.builder().put(MAX_SHARDS_ALLOWED_IN_STATUS_API.getKey(), 2));
assertAcked(client().admin().cluster().updateSettings(updateSettingsRequest).actionGet());

SnapshotException ex3 = expectThrows(
SnapshotException.class,
TooManyShardsInSnapshotsStatusException ex = expectThrows(
TooManyShardsInSnapshotsStatusException.class,
() -> client().admin()
.cluster()
.prepareSnapshotStatus(repositoryName)
Expand All @@ -753,8 +751,8 @@ public void testSnapshotStatusFailuresWithIndexFilter() throws Exception {
.execute()
.actionGet()
);
assertEquals(ex3.status(), RestStatus.REQUEST_ENTITY_TOO_LARGE);
assertTrue(ex3.getMessage().endsWith(" is more than the maximum allowed value of shard count [2] for snapshot status request"));
assertEquals(ex.status(), RestStatus.REQUEST_ENTITY_TOO_LARGE);
assertTrue(ex.getMessage().endsWith(" is more than the maximum allowed value of shard count [2] for snapshot status request"));

logger.info("Reset MAX_SHARDS_ALLOWED_IN_STATUS_API to default value");
updateSettingsRequest.persistentSettings(Settings.builder().putNull(MAX_SHARDS_ALLOWED_IN_STATUS_API.getKey()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import static org.opensearch.OpenSearchException.OpenSearchExceptionHandle;
import static org.opensearch.OpenSearchException.OpenSearchExceptionHandleRegistry.registerExceptionHandle;
import static org.opensearch.OpenSearchException.UNKNOWN_VERSION_ADDED;
import static org.opensearch.Version.CURRENT;
import static org.opensearch.Version.V_2_10_0;
import static org.opensearch.Version.V_2_13_0;
import static org.opensearch.Version.V_2_1_0;
Expand Down Expand Up @@ -1201,6 +1202,14 @@ public static void registerExceptions() {
V_2_13_0
)
);
registerExceptionHandle(
new OpenSearchExceptionHandle(
org.opensearch.snapshots.TooManyShardsInSnapshotsStatusException.class,
org.opensearch.snapshots.TooManyShardsInSnapshotsStatusException::new,
174,
CURRENT
)
);
registerExceptionHandle(
new OpenSearchExceptionHandle(
org.opensearch.cluster.block.IndexCreateBlockException.class,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public SnapshotsStatusRequest(StreamInput in) throws IOException {
repository = in.readString();
snapshots = in.readStringArray();
ignoreUnavailable = in.readBoolean();
if (in.getVersion().onOrAfter(Version.V_2_17_0)) {
if (in.getVersion().onOrAfter(Version.CURRENT)) {
indices = in.readOptionalStringArray();
}
}
Expand All @@ -89,7 +89,7 @@ public void writeTo(StreamOutput out) throws IOException {
out.writeString(repository);
out.writeStringArray(snapshots);
out.writeBoolean(ignoreUnavailable);
if (out.getVersion().onOrAfter(Version.V_2_17_0)) {
if (out.getVersion().onOrAfter(Version.CURRENT)) {
out.writeOptionalStringArray(indices);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,21 +52,21 @@
import org.opensearch.core.common.io.stream.StreamInput;
import org.opensearch.core.common.util.CollectionUtils;
import org.opensearch.core.index.shard.ShardId;
import org.opensearch.core.rest.RestStatus;
import org.opensearch.index.IndexNotFoundException;
import org.opensearch.index.snapshots.IndexShardSnapshotStatus;
import org.opensearch.repositories.IndexId;
import org.opensearch.repositories.RepositoriesService;
import org.opensearch.repositories.Repository;
import org.opensearch.repositories.RepositoryData;
import org.opensearch.snapshots.Snapshot;
import org.opensearch.snapshots.SnapshotException;
import org.opensearch.snapshots.SnapshotId;
import org.opensearch.snapshots.SnapshotInfo;
import org.opensearch.snapshots.SnapshotMissingException;
import org.opensearch.snapshots.SnapshotShardFailure;
import org.opensearch.snapshots.SnapshotShardsService;
import org.opensearch.snapshots.SnapshotState;
import org.opensearch.snapshots.SnapshotsService;
import org.opensearch.snapshots.TooManyShardsInSnapshotsStatusException;
import org.opensearch.threadpool.ThreadPool;
import org.opensearch.transport.TransportService;

Expand Down Expand Up @@ -458,17 +458,13 @@ private Map<SnapshotId, SnapshotInfo> snapshotsInfo(
snapshotsInfoMap.put(snapshotId, snapshotInfo);
}
if (totalShardsAcrossSnapshots > maximumAllowedShardCount && request.indices().length == 0) {
String cause = "Total shard count ["
String message = "Total shard count ["
+ totalShardsAcrossSnapshots
+ "] is more than the maximum allowed value of shard count ["
+ maximumAllowedShardCount
+ "] for snapshot status request";
throw new SnapshotException(repositoryName, String.join(", ", requestedSnapshotNames), cause) {
@Override
public RestStatus status() {
return RestStatus.REQUEST_ENTITY_TOO_LARGE;
}
};

throw new TooManyShardsInSnapshotsStatusException(repositoryName, message, request.snapshots());
}
return unmodifiableMap(snapshotsInfoMap);
}
Expand Down Expand Up @@ -524,19 +520,15 @@ private Map<ShardId, IndexShardSnapshotStatus> snapshotShards(
}

if (totalShardsAcrossIndices > maximumAllowedShardCount && requestedIndexNames.isEmpty() == false && isV2Snapshot == false) {
String cause = "Total shard count ["
String message = "Total shard count ["
+ totalShardsAcrossIndices
+ "] across the requested indices ["
+ requestedIndexNames.stream().collect(Collectors.joining(", "))
+ "] is more than the maximum allowed value of shard count ["
+ maximumAllowedShardCount
+ "] for snapshot status request";
throw new SnapshotException(repositoryName, snapshotName, cause) {
@Override
public RestStatus status() {
return RestStatus.REQUEST_ENTITY_TOO_LARGE;
}
};

throw new TooManyShardsInSnapshotsStatusException(repositoryName, message, snapshotName);
}

final Map<ShardId, IndexShardSnapshotStatus> shardStatus = new HashMap<>();
Expand Down Expand Up @@ -587,13 +579,8 @@ private void handleIndexNotFound(String index, SnapshotsStatusRequest request, S
repositoryName
);
} else {
String cause = "indices [" + index + "] missing in snapshot [" + snapshotName + "]";
throw new SnapshotException(repositoryName, snapshotName, cause) {
@Override
public RestStatus status() {
return RestStatus.NOT_FOUND;
}
};
String cause = "indices [" + index + "] missing in snapshot [" + snapshotName + "] of repository [" + repositoryName + "]";
throw new IndexNotFoundException(index, new IllegalArgumentException(cause));
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* 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.
*/

/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

/*
* Modifications Copyright OpenSearch Contributors. See
* GitHub history for details.
*/

package org.opensearch.snapshots;

import org.opensearch.core.common.io.stream.StreamInput;
import org.opensearch.core.rest.RestStatus;

import java.io.IOException;

/**
* Thrown if the number of shards across the requested resources (snapshot(s) or the index/indices of a particular snapshot)
* breaches the limit of snapshot.max_shards_allowed_in_status_api cluster setting
*
* @opensearch.internal
*/
public class TooManyShardsInSnapshotsStatusException extends SnapshotException {

public TooManyShardsInSnapshotsStatusException(
final String repositoryName,
final SnapshotId snapshotId,
final String message,
final Throwable cause
) {
super(repositoryName, snapshotId, message, cause);
}

public TooManyShardsInSnapshotsStatusException(final String repositoryName, final String message, String... snapshotName) {
super(repositoryName, String.join(", ", snapshotName), message);
}

public TooManyShardsInSnapshotsStatusException(StreamInput in) throws IOException {
super(in);
}

@Override
public RestStatus status() {
return RestStatus.REQUEST_ENTITY_TOO_LARGE;
}
}
Loading

0 comments on commit b5cab5b

Please sign in to comment.