-
Notifications
You must be signed in to change notification settings - Fork 25.3k
Add state query param to Get snapshots API #123618
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Documentation preview: |
@elasticsearchmachine test this |
Pinging @elastic/es-distributed-coordination (Team:Distributed Coordination) |
Pinging @elastic/es-distributed-obsolete (Team:Distributed (Obsolete)) |
@@ -571,6 +575,10 @@ private boolean matchesPredicates(SnapshotInfo snapshotInfo) { | |||
return false; | |||
} | |||
|
|||
if (state != null) { | |||
return state.equalsIgnoreCase(snapshotInfo.state().toString()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we also do this as a pre-flight check (in the other matchesPredicates
method)? No need to do the expensive SnapshotInfo
read if we can help it, and most of the time this info is going to be available in RepositoryDetails
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure! Changed this in d9f8faf.
@@ -77,6 +79,8 @@ public class GetSnapshotsRequest extends MasterNodeRequest<GetSnapshotsRequest> | |||
|
|||
private boolean includeIndexNames = true; | |||
|
|||
private String state; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we make this a (nullable) SnapshotState
rather than a string? Also please mark as @Nullable
with a comment saying what the null value means.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also are you sure you only want to pick one state? What about a comma-separated list of values perhaps? For instance SUCCESS,PARTIAL
would give you all the complete snapshots. If so, maybe an EnumSet<SnapshotState>
instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great idea! I think it would be useful to make it an EnumSet<SnapshotState>
so that we can filter by multiple states. Added the change with d9f8faf.
@@ -633,6 +634,57 @@ public void testRetrievingSnapshotsWhenRepositoryIsMissing() throws Exception { | |||
expectThrows(RepositoryMissingException.class, multiRepoFuture::actionGet); | |||
} | |||
|
|||
public void testFilterByState() throws Exception { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we also add this feature to testAllFeatures
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I added some checks there as well. Let me know if I need to add any other tests.
Many thanks for the review @DaveCTurner! I addressed your comments, please let me know if you have any additional suggestions. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 API makes more sense now. I did another pass and left more comments
|
||
final String stateString = request.param("state"); | ||
if (stateString == null || stateString.isEmpty()) { | ||
getSnapshotsRequest.state(EnumSet.noneOf(SnapshotState.class)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggest defaulting to EnumSet.allOf
rather than having a special case for the empty set lower down. We could reasonably reject the empty set in org.elasticsearch.action.admin.cluster.snapshots.get.GetSnapshotsRequest#validate
I suppose since otherwise that'll just filter out everything.
@@ -82,6 +85,14 @@ public RestChannelConsumer prepareRequest(final RestRequest request, final NodeC | |||
final SortOrder order = SortOrder.fromString(request.param("order", getSnapshotsRequest.order().toString())); | |||
getSnapshotsRequest.order(order); | |||
getSnapshotsRequest.includeIndexNames(request.paramAsBoolean(INDEX_NAMES_XCONTENT_PARAM, getSnapshotsRequest.includeIndexNames())); | |||
|
|||
final String stateString = request.param("state"); | |||
if (stateString == null || stateString.isEmpty()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: suggest using org.elasticsearch.common.Strings#hasLength(java.lang.String)
here
@@ -558,11 +564,16 @@ private boolean matchesPredicates(SnapshotId snapshotId, RepositoryData reposito | |||
return false; | |||
} | |||
|
|||
final var details = repositoryData.getSnapshotDetails(snapshotId); | |||
|
|||
if (!state.isEmpty() && !state.contains(details.getSnapshotState())) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The style check will not like the unary !
operators here, you need to say state.contains(details.getSnapshotState()) == false
instead.
@@ -181,6 +184,7 @@ private class GetSnapshotsOperation { | |||
private final SnapshotNamePredicate snapshotNamePredicate; | |||
private final SnapshotPredicates fromSortValuePredicates; | |||
private final Predicate<String> slmPolicyPredicate; | |||
private final EnumSet<SnapshotState> state; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
naming nit
private final EnumSet<SnapshotState> state; | |
private final EnumSet<SnapshotState> states; |
@@ -150,4 +153,8 @@ public GetSnapshotsRequestBuilder setIncludeIndexNames(boolean indices) { | |||
|
|||
} | |||
|
|||
public GetSnapshotsRequestBuilder setState(EnumSet<SnapshotState> state) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
naming nit
public GetSnapshotsRequestBuilder setState(EnumSet<SnapshotState> state) { | |
public GetSnapshotsRequestBuilder setStates(EnumSet<SnapshotState> state) { |
@@ -558,11 +564,16 @@ private boolean matchesPredicates(SnapshotId snapshotId, RepositoryData reposito | |||
return false; | |||
} | |||
|
|||
final var details = repositoryData.getSnapshotDetails(snapshotId); | |||
|
|||
if (!state.isEmpty() && !state.contains(details.getSnapshotState())) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh also we need to handle the cases where details
or details.getSnapshotState()
are null
. In that case, we cannot do the pre-flight check, we will need to retrieve the SnapshotInfo
and then check that in the other matchesPredicates()
method
* @param name the state name | ||
* @return state | ||
*/ | ||
public static SnapshotState of(String name) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Naming nit: maybe fromString
rather than of
? As written here it makes sense if you call the method directly but it's a little awkward to read .map(SnapshotState::of)
, I'd prefer .map(SnapshotState::fromString)
.
Also could we not use the built-in valueOf()
?
@@ -85,6 +85,10 @@ | |||
"verbose":{ | |||
"type":"boolean", | |||
"description":"Whether to show verbose snapshot info or only show the basic info found in the repository index blob" | |||
}, | |||
"state": { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we also add some simple smoke tests to rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/snapshot.get/10_basic.yml
just to check that we are parsing the parameter ok. No need for anything exhaustive, just check that e.g. SUCCESS
and SUCCESS,PARTIAL
both return the expected snapshots.
@@ -912,9 +963,15 @@ public void testAllFeatures() { | |||
// INDICES and by SHARDS. The actual sorting behaviour for these cases is tested elsewhere, here we're just checking that sorting | |||
// interacts correctly with the other parameters to the API. | |||
|
|||
final EnumSet<SnapshotState> state = EnumSet.of(randomFrom(SnapshotState.values())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we test a random nonempty subset rather than just a singleton?
// compute the ordered sequence of snapshots which match the repository/snapshot name filters and SLM policy filter | ||
final var selectedSnapshots = snapshotInfos.stream() | ||
.filter(snapshotInfoPredicate) | ||
.filter(s -> state.contains(s.state())) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should fold the state filter into snapshotInfoPredicate
, since we're really implementing it alongside the SLM policy check etc.
Thanks for the review, @DaveCTurner, and apologies for the delay in addressing the feedback. I've been focused on Kibana-related tasks for my team and, unfortunately, haven’t had a chance to revisit this PR. @JeremyDahlgren reached out and offered to take it over, so he’ll be picking it up from here. I really appreciate your time and input! |
Closing in favor of #128635 |
Closes #97446
This PR introduces a new state query parameter for the Get Snapshots API, allowing users to filter snapshots by state. The parameter accepts comma-separated values for states:
SUCCESS
,IN_PROGRESS
,FAILED
,PARTIAL
,INCOMPATIBLE
(case-insensitive).🎯 Motivation & Use Case
This is my mini-project for the AppEx team’s On-Week, where I aimed to explore contributing to Elasticsearch while addressing several Kibana issues.
In Kibana's Snapshot Restore page, multiple open issues could be resolved by adding this parameter:
1️⃣ Fixing incorrect selection of last successful managed snapshot
2️⃣ Enhancing the Snapshots table:
✅ Summary of Changes
state
as an optional query parameter toGET _snapshot/{repository}/_all
TransportGetSnapshotsAction
GetSnapshotsIT.java