-
Notifications
You must be signed in to change notification settings - Fork 25.3k
Add state
query param to GET snapshots API
#128635
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
Hi @JeremyDahlgren, I've created a changelog YAML for you. |
state
query param to Get snapshots APIstate
query param to GET snapshots API
Pinging @elastic/es-distributed-coordination (Team:Distributed Coordination) |
@@ -572,11 +578,19 @@ private boolean matchesPredicates(SnapshotId snapshotId, RepositoryData reposito | |||
return false; | |||
} | |||
|
|||
final var details = repositoryData.getSnapshotDetails(snapshotId); | |||
|
|||
if (states.isEmpty() == false |
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: can omit emptiness check
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.
++ we could reasonably reject a request with an empty states
set in org.elasticsearch.action.admin.cluster.snapshots.get.GetSnapshotsRequest#validate
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.
Removed isEmpty()
check, added a check in GetSnapshotsRequest#validate
, 3ed9350.
server/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestGetSnapshotsAction.java
Show resolved
Hide resolved
@@ -82,6 +128,24 @@ 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 (Strings.hasLength(stateString) == false) { |
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.
State param with empty value seems valid in this condition even if feature is not available ("state="). I think having param keyword should be illegal when feature is off.
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.
Nvm :) I confused myself with another case. If feature is supported but state param is null, will it throw NPE at stateString.split?
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.
Added separate handling for null vs empty, 64d3729.
@@ -572,11 +578,19 @@ private boolean matchesPredicates(SnapshotId snapshotId, RepositoryData reposito | |||
return false; | |||
} | |||
|
|||
final var details = repositoryData.getSnapshotDetails(snapshotId); | |||
|
|||
if (states.isEmpty() == false |
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.
++ we could reasonably reject a request with an empty states
set in org.elasticsearch.action.admin.cluster.snapshots.get.GetSnapshotsRequest#validate
@@ -585,6 +599,10 @@ private boolean matchesPredicates(SnapshotInfo snapshotInfo) { | |||
return false; | |||
} | |||
|
|||
if (states.isEmpty() == false && snapshotInfo.state() != null && states.contains(snapshotInfo.state()) == false) { |
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.
Likewise here, states
should never be empty
server/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestGetSnapshotsAction.java
Show resolved
Hide resolved
server/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestGetSnapshotsAction.java
Outdated
Show resolved
Hide resolved
@@ -82,6 +128,24 @@ 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 (Strings.hasLength(stateString) == false) { |
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 could reasonably reject requests that include ?state=
without a value, in constrast to the parameter being missing (i.e. null
) which should mean "all states" as done here.
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.
Added separate handling for null vs empty, 64d3729.
// Consume these response parameters used in SnapshotInfo now, to avoid assertion errors in BaseRestHandler for requests where they | ||
// may not get used. | ||
if (Assertions.ENABLED) { | ||
for (final var responseParameter : SUPPORTED_RESPONSE_PARAMETERS) { | ||
request.param(responseParameter); | ||
} | ||
} |
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.
Hmm I'm suspicious about this, are you sure it's necessary? If so, it seems like a broader problem than just this one API so maybe we should fix it more fundamentally.
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.
If you comment this if
block out you can get an error running this test:
./gradlew :rest-api-spec:yamlRestTest --tests org.elasticsearch.test.rest.ClientYamlTestSuiteIT -Dtests.method='test {yaml=snapshot.get/10_basic/*}'
This will fail with Connection refused
errors, but if you rerun with --debug
you can see the root cause:
2025-06-12T14:37:37.881-0400 [DEBUG] [TestEventLogger] Caused by: java.lang.AssertionError: get_snapshots_action: consumed params [after, error_trace, filter_path, format, from_sort_value, human, ignore_unavailable, index_names, master_timeout, offset, order, pretty, repository, size, slm_policy_filter, snapshot, sort, state, verbose] while supporting [after, error_trace, filter_path, format, from_sort_value, human, ignore_unavailable, include_repository, index_details, index_names, master_timeout, offset, order, pretty, repository, size, slm_policy_filter, snapshot, sort, state, verbose]
2025-06-12T14:37:37.881-0400 [DEBUG] [TestEventLogger] at org.elasticsearch.server@9.1.0-SNAPSHOT/org.elasticsearch.rest.BaseRestHandler.assertConsumesSupportedParams(BaseRestHandler.java:158)
2025-06-12T14:37:37.881-0400 [DEBUG] [TestEventLogger] at org.elasticsearch.server@9.1.0-SNAPSHOT/org.elasticsearch.rest.BaseRestHandler.handleRequest(BaseRestHandler.java:101)
2025-06-12T14:37:37.881-0400 [DEBUG] [TestEventLogger] at org.elasticsearch.server@9.1.0-SNAPSHOT/org.elasticsearch.rest.RestController$1.onResponse(RestController.java:468)
2025-06-12T14:37:37.881-0400 [DEBUG] [TestEventLogger] at org.elasticsearch.server@9.1.0-SNAPSHOT/org.elasticsearch.rest.RestController$1.onResponse(RestController.java:462)
2025-06-12T14:37:37.881-0400 [DEBUG] [TestEventLogger] at org.elasticsearch.security@9.1.0-SNAPSHOT/org.elasticsearch.xpack.security.rest.SecurityRestFilter.intercept(SecurityRestFilter.java:69)
2025-06-12T14:37:37.881-0400 [DEBUG] [TestEventLogger] at org.elasticsearch.server@9.1.0-SNAPSHOT/org.elasticsearch.rest.RestController.dispatchRequest(RestController.java:462)
I removed this if block and added exclusion support for response parameters in BaseRestHandler.assertConsumesSupportedParams()
, 627c9cc.
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 it's substantial change in our API design - relaxing unconsumed parameters check. Do we need this?
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.
Right yeah this AssertionError
is there to catch discrepancies between the parameters we claim to consume and the ones we actually consume. We definitely shouldn't be working around it like this. But the assertion itself seems buggy:
2025-06-12T14:37:37.881-0400 [DEBUG] [TestEventLogger] Caused by: java.lang.AssertionError: get_snapshots_action: consumed params
[after, error_trace, filter_path, format, from_sort_value, human, ignore_unavailable, index_names, master_timeout, offset, order, pretty, repository, size, slm_policy_filter, snapshot, sort, state, verbose] while supporting
[after, error_trace, filter_path, format, from_sort_value, human, ignore_unavailable, include_repository, index_details, index_names, master_timeout, offset, order, pretty, repository, size, slm_policy_filter, snapshot, sort, state, verbose]
Note that the missing ones are include_repository
and index_details
which are response parameters and therefore aren't expected to be consumed in prepareRequest
. So I think we should fix the assertion.
We must be very careful with code that branches on Assertions.ENABLED
because it means that the tests are not testing the exact production behaviour. Sometimes that's what we want, but not in this case.
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.
@DaveCTurner - In 627c9cc I added the exclusion for the response parameters in BaseRestHandler.assertConsumesSupportedParams()
and removed the if
block. Are you looking for a different approach for fixing the assertion?
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.
Ah sorry I missed that you'd made this change. Let me look again.
…states is not empty in validate()
// Add exclusions for response parameters since they may not always be consumed for every request. | ||
final var unconsumedResponseParams = new HashSet<>(responseParams(request.getRestApiVersion())); | ||
unconsumedResponseParams.removeAll(consumed); | ||
supportedAndCommon.removeAll(unconsumedResponseParams); |
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 this'll permit a case where we declare a response parameter but don't include it in the supported parameters, which would be a bug. Could we instead count the response parameters in consumed
(they're implicitly consumed since they're made available to the response rendering)?
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.
LGTM (one optional nit)
import java.util.Set; | ||
|
||
public class GetSnapshotsFeatures implements FeatureSpecification { | ||
public static final NodeFeature GET_SNAPSHOTS_STATE_PARAMETER = new NodeFeature("get.snapshots.state_parameter"); |
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: we don't really have a formal convention for the names of these features but informally we seem to be converging on hierarchical.with.dot.delimiter
like with setting names. So I think I'd have used snapshots.get.state_parameter
here (also needs adjusting elsewhere in this PR)
public static final NodeFeature GET_SNAPSHOTS_STATE_PARAMETER = new NodeFeature("get.snapshots.state_parameter"); | |
public static final NodeFeature GET_SNAPSHOTS_STATE_PARAMETER = new NodeFeature("snapshots.get.state_parameter"); |
This PR picks up where Elena left off in #123618, addressing the last round of review comments and adding to the tests.
PR description details copied from #123618:
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