Adds ignoreUnavailable option to the snapshot status API (#20066)

Adds ignoreUnavailable to the snapshot status API to be consistent
with the get snapshots API which has a similar parameter. If
ignoreUnavailable is set to true, then the snapshot status request
will ignore any snapshots that were not found in the repository,
instead of throwing a SnapshotMissingException.

Closes #18522
This commit is contained in:
Ali Beyad 2016-08-19 16:19:56 -04:00 committed by GitHub
parent cf32f8de34
commit 1c9b64e09a
10 changed files with 201 additions and 15 deletions

View File

@ -38,6 +38,8 @@ public class SnapshotsStatusRequest extends MasterNodeRequest<SnapshotsStatusReq
private String[] snapshots = Strings.EMPTY_ARRAY;
private boolean ignoreUnavailable;
public SnapshotsStatusRequest() {
}
@ -112,11 +114,33 @@ public class SnapshotsStatusRequest extends MasterNodeRequest<SnapshotsStatusReq
return this;
}
/**
* Set to <code>true</code> to ignore unavailable snapshots, instead of throwing an exception.
* Defaults to <code>false</code>, which means unavailable snapshots cause an exception to be thrown.
*
* @param ignoreUnavailable whether to ignore unavailable snapshots
* @return this request
*/
public SnapshotsStatusRequest ignoreUnavailable(boolean ignoreUnavailable) {
this.ignoreUnavailable = ignoreUnavailable;
return this;
}
/**
* Returns whether the request permits unavailable snapshots to be ignored.
*
* @return true if the request will ignore unavailable snapshots, false if it will throw an exception on unavailable snapshots
*/
public boolean ignoreUnavailable() {
return ignoreUnavailable;
}
@Override
public void readFrom(StreamInput in) throws IOException {
super.readFrom(in);
repository = in.readString();
snapshots = in.readStringArray();
ignoreUnavailable = in.readBoolean();
}
@Override
@ -124,5 +148,6 @@ public class SnapshotsStatusRequest extends MasterNodeRequest<SnapshotsStatusReq
super.writeTo(out);
out.writeString(repository);
out.writeStringArray(snapshots);
out.writeBoolean(ignoreUnavailable);
}
}

View File

@ -74,4 +74,16 @@ public class SnapshotsStatusRequestBuilder extends MasterNodeOperationRequestBui
request.snapshots(ArrayUtils.concat(request.snapshots(), snapshots));
return this;
}
/**
* Set to <code>true</code> to ignore unavailable snapshots, instead of throwing an exception.
* Defaults to <code>false</code>, which means unavailable snapshots cause an exception to be thrown.
*
* @param ignoreUnavailable whether to ignore unavailable snapshots.
* @return this builder
*/
public SnapshotsStatusRequestBuilder setIgnoreUnavailable(boolean ignoreUnavailable) {
request.ignoreUnavailable(ignoreUnavailable);
return this;
}
}

View File

@ -214,7 +214,14 @@ public class TransportSnapshotsStatusAction extends TransportMasterNodeAction<Sn
SnapshotId snapshotId = matchedSnapshotIds.get(snapshotName);
if (snapshotId == null) {
// neither in the current snapshot entries nor found in the repository
throw new SnapshotMissingException(repositoryName, snapshotName);
if (request.ignoreUnavailable()) {
// ignoring unavailable snapshots, so skip over
logger.debug("snapshot status request ignoring snapshot [{}], not found in repository [{}]",
snapshotName, repositoryName);
continue;
} else {
throw new SnapshotMissingException(repositoryName, snapshotName);
}
}
SnapshotInfo snapshotInfo = snapshotsService.snapshot(repositoryName, snapshotId);
List<SnapshotIndexShardStatus> shardStatusBuilder = new ArrayList<>();

View File

@ -20,7 +20,6 @@
package org.elasticsearch.rest.action.admin.cluster;
import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotsStatusRequest;
import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotsStatusResponse;
import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.inject.Inject;
@ -54,9 +53,10 @@ public class RestSnapshotsStatusAction extends BaseRestHandler {
if (snapshots.length == 1 && "_all".equalsIgnoreCase(snapshots[0])) {
snapshots = Strings.EMPTY_ARRAY;
}
SnapshotsStatusRequest snapshotsStatusResponse = snapshotsStatusRequest(repository).snapshots(snapshots);
SnapshotsStatusRequest snapshotsStatusRequest = snapshotsStatusRequest(repository).snapshots(snapshots);
snapshotsStatusRequest.ignoreUnavailable(request.paramAsBoolean("ignore_unavailable", snapshotsStatusRequest.ignoreUnavailable()));
snapshotsStatusResponse.masterNodeTimeout(request.paramAsTime("master_timeout", snapshotsStatusResponse.masterNodeTimeout()));
client.admin().cluster().snapshotsStatus(snapshotsStatusResponse, new RestToXContentListener<SnapshotsStatusResponse>(channel));
snapshotsStatusRequest.masterNodeTimeout(request.paramAsTime("master_timeout", snapshotsStatusRequest.masterNodeTimeout()));
client.admin().cluster().snapshotsStatus(snapshotsStatusRequest, new RestToXContentListener<>(channel));
}
}

View File

@ -30,15 +30,15 @@ import java.io.IOException;
public class SnapshotMissingException extends SnapshotException {
public SnapshotMissingException(final String repositoryName, final SnapshotId snapshotId, final Throwable cause) {
super(repositoryName, snapshotId, "is missing", cause);
super(repositoryName, snapshotId, " is missing", cause);
}
public SnapshotMissingException(final String repositoryName, final SnapshotId snapshotId) {
super(repositoryName, snapshotId, "is missing");
super(repositoryName, snapshotId, " is missing");
}
public SnapshotMissingException(final String repositoryName, final String snapshotName) {
super(repositoryName, snapshotName, "is missing");
super(repositoryName, snapshotName, " is missing");
}
public SnapshotMissingException(StreamInput in) throws IOException {

View File

@ -1504,12 +1504,24 @@ public class SharedClusterSnapshotRestoreIT extends AbstractSnapshotIntegTestCas
logger.info("--> checking that _current no longer returns the snapshot");
assertThat(client.admin().cluster().prepareGetSnapshots("test-repo").addSnapshots("_current").execute().actionGet().getSnapshots().isEmpty(), equalTo(true));
try {
client.admin().cluster().prepareSnapshotStatus("test-repo").addSnapshots("test-snap-doesnt-exist").execute().actionGet();
fail();
} catch (SnapshotMissingException ex) {
// Expected
}
// test that getting an unavailable snapshot status throws an exception if ignoreUnavailable is false on the request
SnapshotMissingException ex = expectThrows(SnapshotMissingException.class, () ->
client.admin().cluster().prepareSnapshotStatus("test-repo").addSnapshots("test-snap-doesnt-exist").get());
assertEquals("[test-repo:test-snap-doesnt-exist] is missing", ex.getMessage());
// test that getting an unavailable snapshot status does not throw an exception if ignoreUnavailable is true on the request
response = client.admin().cluster().prepareSnapshotStatus("test-repo")
.addSnapshots("test-snap-doesnt-exist")
.setIgnoreUnavailable(true)
.get();
assertTrue(response.getSnapshots().isEmpty());
// test getting snapshot status for available and unavailable snapshots where ignoreUnavailable is true
// (available one should be returned)
response = client.admin().cluster().prepareSnapshotStatus("test-repo")
.addSnapshots("test-snap", "test-snap-doesnt-exist")
.setIgnoreUnavailable(true)
.get();
assertEquals(1, response.getSnapshots().size());
assertEquals("test-snap", response.getSnapshots().get(0).getSnapshot().getSnapshotId().getName());
}
public void testSnapshotRelocatingPrimary() throws Exception {

View File

@ -21,6 +21,10 @@
"master_timeout": {
"type" : "time",
"description" : "Explicit operation timeout for connection to master node"
},
"ignore_unavailable": {
"type": "boolean",
"description": "Whether to ignore unavailable snapshots, defaults to false which means a SnapshotMissingException is thrown"
}
}
},

View File

@ -19,6 +19,10 @@
"master_timeout": {
"type" : "time",
"description" : "Explicit operation timeout for connection to master node"
},
"ignore_unavailable": {
"type": "boolean",
"description": "Whether to ignore unavailable snapshots, defaults to false which means a SnapshotMissingException is thrown"
}
}
},

View File

@ -0,0 +1,61 @@
---
setup:
- do:
snapshot.create_repository:
repository: test_repo_get_1
body:
type: fs
settings:
location: "test_repo_get_1_loc"
---
teardown:
- do:
snapshot.delete_repository:
repository: test_repo_get_1
---
"Get snapshot info":
- do:
indices.create:
index: test_index
body:
settings:
number_of_shards: 1
number_of_replicas: 0
- do:
snapshot.create:
repository: test_repo_get_1
snapshot: test_snapshot
wait_for_completion: true
- do:
snapshot.get:
repository: test_repo_get_1
snapshot: test_snapshot
- is_true: snapshots
---
"Get missing snapshot info throws an exception":
- do:
catch: /snapshot_missing_exception.+ is missing/
snapshot.get:
repository: test_repo_get_1
snapshot: test_nonexistent_snapshot
---
"Get missing snapshot info succeeds when ignoreUnavailable is true":
- do:
snapshot.get:
repository: test_repo_get_1
snapshot: test_nonexistent_snapshot
ignore_unavailable: true
- is_true: snapshots

View File

@ -0,0 +1,61 @@
---
setup:
- do:
snapshot.create_repository:
repository: test_repo_status_1
body:
type: fs
settings:
location: "test_repo_status_1_loc"
---
teardown:
- do:
snapshot.delete_repository:
repository: test_repo_status_1
---
"Get snapshot status":
- do:
indices.create:
index: test_index
body:
settings:
number_of_shards: 1
number_of_replicas: 0
- do:
snapshot.create:
repository: test_repo_status_1
snapshot: test_snapshot
wait_for_completion: true
- do:
snapshot.status:
repository: test_repo_status_1
snapshot: test_snapshot
- is_true: snapshots
---
"Get missing snapshot status throws an exception":
- do:
catch: /snapshot_missing_exception.+ is missing/
snapshot.status:
repository: test_repo_status_1
snapshot: test_nonexistent_snapshot
---
"Get missing snapshot status succeeds when ignoreUnavailable is true":
- do:
snapshot.status:
repository: test_repo_status_1
snapshot: test_nonexistent_snapshot
ignore_unavailable: true
- is_true: snapshots