diff --git a/docs/reference/snapshot-restore/apis/get-snapshot-api.asciidoc b/docs/reference/snapshot-restore/apis/get-snapshot-api.asciidoc index 12d9793d2e9e2..d55bfe36cd67e 100644 --- a/docs/reference/snapshot-restore/apis/get-snapshot-api.asciidoc +++ b/docs/reference/snapshot-restore/apis/get-snapshot-api.asciidoc @@ -99,6 +99,11 @@ version of Elasticsearch which took the snapshot, the start and end times of the snapshot, and the number of shards snapshotted. Defaults to `true`. If `false`, omits the additional information. +`index_names`:: +(Optional, Boolean) +If `true`, returns the list of snapshot names included in each snapshot in the response. +Defaults to `true`. + `index_details`:: (Optional, Boolean) If `true`, returns additional information about each index in the snapshot diff --git a/qa/smoke-test-http/src/test/java/org/elasticsearch/http/snapshots/RestGetSnapshotsIT.java b/qa/smoke-test-http/src/test/java/org/elasticsearch/http/snapshots/RestGetSnapshotsIT.java index 9114df5d2b2fc..8fa3deed470be 100644 --- a/qa/smoke-test-http/src/test/java/org/elasticsearch/http/snapshots/RestGetSnapshotsIT.java +++ b/qa/smoke-test-http/src/test/java/org/elasticsearch/http/snapshots/RestGetSnapshotsIT.java @@ -41,6 +41,7 @@ import static org.elasticsearch.snapshots.AbstractSnapshotIntegTestCase.assertSnapshotListSorted; import static org.elasticsearch.snapshots.AbstractSnapshotIntegTestCase.matchAllPattern; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; +import static org.hamcrest.Matchers.anEmptyMap; import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.in; import static org.hamcrest.Matchers.is; @@ -90,40 +91,45 @@ public void testSortOrder() throws Exception { } private void doTestSortOrder(String repoName, Collection allSnapshotNames, SortOrder order) throws IOException { - final List defaultSorting = clusterAdmin().prepareGetSnapshots(repoName).setOrder(order).get().getSnapshots(); + final boolean includeIndices = randomBoolean(); + final List defaultSorting = clusterAdmin().prepareGetSnapshots(repoName) + .setOrder(order) + .setIndices(includeIndices) + .get() + .getSnapshots(); assertSnapshotListSorted(defaultSorting, null, order); assertSnapshotListSorted( - allSnapshotsSorted(allSnapshotNames, repoName, GetSnapshotsRequest.SortBy.NAME, order), + allSnapshotsSorted(allSnapshotNames, repoName, GetSnapshotsRequest.SortBy.NAME, order, includeIndices), GetSnapshotsRequest.SortBy.NAME, order ); assertSnapshotListSorted( - allSnapshotsSorted(allSnapshotNames, repoName, GetSnapshotsRequest.SortBy.DURATION, order), + allSnapshotsSorted(allSnapshotNames, repoName, GetSnapshotsRequest.SortBy.DURATION, order, includeIndices), GetSnapshotsRequest.SortBy.DURATION, order ); assertSnapshotListSorted( - allSnapshotsSorted(allSnapshotNames, repoName, GetSnapshotsRequest.SortBy.INDICES, order), + allSnapshotsSorted(allSnapshotNames, repoName, GetSnapshotsRequest.SortBy.INDICES, order, includeIndices), GetSnapshotsRequest.SortBy.INDICES, order ); assertSnapshotListSorted( - allSnapshotsSorted(allSnapshotNames, repoName, GetSnapshotsRequest.SortBy.START_TIME, order), + allSnapshotsSorted(allSnapshotNames, repoName, GetSnapshotsRequest.SortBy.START_TIME, order, includeIndices), GetSnapshotsRequest.SortBy.START_TIME, order ); assertSnapshotListSorted( - allSnapshotsSorted(allSnapshotNames, repoName, GetSnapshotsRequest.SortBy.SHARDS, order), + allSnapshotsSorted(allSnapshotNames, repoName, GetSnapshotsRequest.SortBy.SHARDS, order, includeIndices), GetSnapshotsRequest.SortBy.SHARDS, order ); assertSnapshotListSorted( - allSnapshotsSorted(allSnapshotNames, repoName, GetSnapshotsRequest.SortBy.FAILED_SHARDS, order), + allSnapshotsSorted(allSnapshotNames, repoName, GetSnapshotsRequest.SortBy.FAILED_SHARDS, order, includeIndices), GetSnapshotsRequest.SortBy.FAILED_SHARDS, order ); assertSnapshotListSorted( - allSnapshotsSorted(allSnapshotNames, repoName, GetSnapshotsRequest.SortBy.REPOSITORY, order), + allSnapshotsSorted(allSnapshotNames, repoName, GetSnapshotsRequest.SortBy.REPOSITORY, order, includeIndices), GetSnapshotsRequest.SortBy.REPOSITORY, order ); @@ -143,18 +149,26 @@ public void testResponseSizeLimit() throws Exception { private void doTestPagination(String repoName, List names, GetSnapshotsRequest.SortBy sort, SortOrder order) throws IOException { - final List allSnapshotsSorted = allSnapshotsSorted(names, repoName, sort, order); - final GetSnapshotsResponse batch1 = sortedWithLimit(repoName, sort, null, 2, order); + final boolean includeIndices = randomBoolean(); + final List allSnapshotsSorted = allSnapshotsSorted(names, repoName, sort, order, includeIndices); + final GetSnapshotsResponse batch1 = sortedWithLimit(repoName, sort, null, 2, order, includeIndices); assertEquals(allSnapshotsSorted.subList(0, 2), batch1.getSnapshots()); - final GetSnapshotsResponse batch2 = sortedWithLimit(repoName, sort, batch1.next(), 2, order); + final GetSnapshotsResponse batch2 = sortedWithLimit(repoName, sort, batch1.next(), 2, order, includeIndices); assertEquals(allSnapshotsSorted.subList(2, 4), batch2.getSnapshots()); final int lastBatch = names.size() - batch1.getSnapshots().size() - batch2.getSnapshots().size(); - final GetSnapshotsResponse batch3 = sortedWithLimit(repoName, sort, batch2.next(), lastBatch, order); + final GetSnapshotsResponse batch3 = sortedWithLimit(repoName, sort, batch2.next(), lastBatch, order, includeIndices); assertEquals( batch3.getSnapshots(), allSnapshotsSorted.subList(batch1.getSnapshots().size() + batch2.getSnapshots().size(), names.size()) ); - final GetSnapshotsResponse batch3NoLimit = sortedWithLimit(repoName, sort, batch2.next(), GetSnapshotsRequest.NO_LIMIT, order); + final GetSnapshotsResponse batch3NoLimit = sortedWithLimit( + repoName, + sort, + batch2.next(), + GetSnapshotsRequest.NO_LIMIT, + order, + includeIndices + ); assertNull(batch3NoLimit.next()); assertEquals(batch3.getSnapshots(), batch3NoLimit.getSnapshots()); final GetSnapshotsResponse batch3LargeLimit = sortedWithLimit( @@ -162,7 +176,8 @@ private void doTestPagination(String repoName, List names, GetSnapshotsR sort, batch2.next(), lastBatch + randomIntBetween(1, 100), - order + order, + includeIndices ); assertEquals(batch3.getSnapshots(), batch3LargeLimit.getSnapshots()); assertNull(batch3LargeLimit.next()); @@ -356,10 +371,11 @@ private void createIndexWithContent(String indexName) { private static void assertStablePagination(String repoName, Collection allSnapshotNames, GetSnapshotsRequest.SortBy sort) throws IOException { final SortOrder order = randomFrom(SortOrder.values()); - final List allSorted = allSnapshotsSorted(allSnapshotNames, repoName, sort, order); + final boolean includeIndices = sort == GetSnapshotsRequest.SortBy.INDICES || randomBoolean(); + final List allSorted = allSnapshotsSorted(allSnapshotNames, repoName, sort, order, includeIndices); for (int i = 1; i <= allSnapshotNames.size(); i++) { - final List subsetSorted = sortedWithLimit(repoName, sort, null, i, order).getSnapshots(); + final List subsetSorted = sortedWithLimit(repoName, sort, null, i, order, includeIndices).getSnapshots(); assertEquals(subsetSorted, allSorted.subList(0, i)); } @@ -371,9 +387,10 @@ private static void assertStablePagination(String repoName, Collection a sort, GetSnapshotsRequest.After.from(after, sort).asQueryParam(), i, - order + order, + includeIndices ); - final GetSnapshotsResponse getSnapshotsResponseNumeric = sortedWithLimit(repoName, sort, j + 1, i, order); + final GetSnapshotsResponse getSnapshotsResponseNumeric = sortedWithLimit(repoName, sort, j + 1, i, order, includeIndices); final List subsetSorted = getSnapshotsResponse.getSnapshots(); assertEquals(subsetSorted, getSnapshotsResponseNumeric.getSnapshots()); assertEquals(subsetSorted, allSorted.subList(j + 1, j + i + 1)); @@ -389,15 +406,23 @@ private static List allSnapshotsSorted( Collection allSnapshotNames, String repoName, GetSnapshotsRequest.SortBy sortBy, - SortOrder order + SortOrder order, + boolean includeIndices ) throws IOException { final Request request = baseGetSnapshotsRequest(repoName); request.addParameter("sort", sortBy.toString()); if (order == SortOrder.DESC || randomBoolean()) { request.addParameter("order", order.toString()); } + addIndexNamesParameter(includeIndices, request); final GetSnapshotsResponse getSnapshotsResponse = readSnapshotInfos(getRestClient().performRequest(request)); final List snapshotInfos = getSnapshotsResponse.getSnapshots(); + if (includeIndices == false) { + for (SnapshotInfo snapshotInfo : snapshotInfos) { + assertThat(snapshotInfo.indices(), empty()); + assertThat(snapshotInfo.indexSnapshotDetails(), anEmptyMap()); + } + } assertEquals(snapshotInfos.size(), allSnapshotNames.size()); assertEquals(getSnapshotsResponse.totalCount(), allSnapshotNames.size()); assertEquals(0, getSnapshotsResponse.remaining()); @@ -429,7 +454,8 @@ private static GetSnapshotsResponse sortedWithLimit( GetSnapshotsRequest.SortBy sortBy, String after, int size, - SortOrder order + SortOrder order, + boolean includeIndices ) throws IOException { final Request request = baseGetSnapshotsRequest(repoName); request.addParameter("sort", sortBy.toString()); @@ -442,16 +468,26 @@ private static GetSnapshotsResponse sortedWithLimit( if (order == SortOrder.DESC || randomBoolean()) { request.addParameter("order", order.toString()); } + addIndexNamesParameter(includeIndices, request); final Response response = getRestClient().performRequest(request); return readSnapshotInfos(response); } + private static void addIndexNamesParameter(boolean includeIndices, Request request) { + if (includeIndices == false) { + request.addParameter(SnapshotInfo.INDEX_NAMES_XCONTENT_PARAM, "false"); + } else if (randomBoolean()) { + request.addParameter(SnapshotInfo.INDEX_NAMES_XCONTENT_PARAM, "true"); + } + } + private static GetSnapshotsResponse sortedWithLimit( String repoName, GetSnapshotsRequest.SortBy sortBy, int offset, int size, - SortOrder order + SortOrder order, + boolean includeIndices ) throws IOException { final Request request = baseGetSnapshotsRequest(repoName); request.addParameter("sort", sortBy.toString()); @@ -462,6 +498,7 @@ private static GetSnapshotsResponse sortedWithLimit( if (order == SortOrder.DESC || randomBoolean()) { request.addParameter("order", order.toString()); } + addIndexNamesParameter(includeIndices, request); final Response response = getRestClient().performRequest(request); return readSnapshotInfos(response); } diff --git a/rest-api-spec/src/main/resources/rest-api-spec/api/snapshot.get.json b/rest-api-spec/src/main/resources/rest-api-spec/api/snapshot.get.json index 01387918e5278..927e10f2261bb 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/api/snapshot.get.json +++ b/rest-api-spec/src/main/resources/rest-api-spec/api/snapshot.get.json @@ -38,6 +38,10 @@ "type":"boolean", "description":"Whether to ignore unavailable snapshots, defaults to false which means a SnapshotMissingException is thrown" }, + "index_names":{ + "type":"boolean", + "description":"Whether to include the name of each index in the snapshot. Defaults to true." + }, "index_details":{ "type":"boolean", "description":"Whether to include details of each index in the snapshot, if those details are available. Defaults to false." diff --git a/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/snapshot.get/10_basic.yml b/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/snapshot.get/10_basic.yml index b50ece87e9f88..bec14f0628501 100644 --- a/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/snapshot.get/10_basic.yml +++ b/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/snapshot.get/10_basic.yml @@ -233,6 +233,43 @@ setup: repository: test_repo_get_1 snapshot: test_snapshot_with_index_details +--- +"Get snapshot info without index names": + - skip: + version: " - 8.2.99" + reason: "Introduced in 8.3.0" + + - 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_without_index_names + wait_for_completion: true + + - do: + snapshot.get: + repository: test_repo_get_1 + snapshot: test_snapshot_without_index_names + index_names: false + human: true + + - is_true: snapshots + - match: { snapshots.0.snapshot: test_snapshot_without_index_names } + - match: { snapshots.0.state: SUCCESS } + - is_false: snapshots.0.indices + + - do: + snapshot.delete: + repository: test_repo_get_1 + snapshot: test_snapshot_without_index_names + --- "Get snapshot info without repository names": diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/get/GetSnapshotsRequest.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/get/GetSnapshotsRequest.java index c951fe3267ce4..4cc2c0324b073 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/get/GetSnapshotsRequest.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/get/GetSnapshotsRequest.java @@ -52,6 +52,8 @@ public class GetSnapshotsRequest extends MasterNodeRequest private static final Version SORT_BY_SHARDS_OR_REPO_VERSION = Version.V_7_16_0; + private static final Version INDICES_FLAG_VERSION = Version.V_8_3_0; + public static final int NO_LIMIT = -1; /** @@ -84,6 +86,8 @@ public class GetSnapshotsRequest extends MasterNodeRequest private boolean verbose = DEFAULT_VERBOSE_MODE; + private boolean indices = true; + public GetSnapshotsRequest() {} /** @@ -130,6 +134,9 @@ public GetSnapshotsRequest(StreamInput in) throws IOException { if (in.getVersion().onOrAfter(FROM_SORT_VALUE_VERSION)) { fromSortValue = in.readOptionalString(); } + if (in.getVersion().onOrAfter(INDICES_FLAG_VERSION)) { + indices = in.readBoolean(); + } } } @@ -184,6 +191,9 @@ public void writeTo(StreamOutput out) throws IOException { } else if (fromSortValue != null) { throw new IllegalArgumentException("can't use after-value in snapshot request with node version [" + out.getVersion() + "]"); } + if (out.getVersion().onOrAfter(INDICES_FLAG_VERSION)) { + out.writeBoolean(indices); + } } @Override @@ -324,6 +334,15 @@ public GetSnapshotsRequest verbose(boolean verbose) { return this; } + public GetSnapshotsRequest indices(boolean indices) { + this.indices = indices; + return this; + } + + public boolean indices() { + return indices; + } + public After after() { return after; } diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/get/GetSnapshotsRequestBuilder.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/get/GetSnapshotsRequestBuilder.java index 933506c150ed0..74ce51105db95 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/get/GetSnapshotsRequestBuilder.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/get/GetSnapshotsRequestBuilder.java @@ -142,4 +142,10 @@ public GetSnapshotsRequestBuilder setOrder(SortOrder order) { return this; } + public GetSnapshotsRequestBuilder setIndices(boolean indices) { + request.indices(indices); + return this; + + } + } diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/get/TransportGetSnapshotsAction.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/get/TransportGetSnapshotsAction.java index 231ab29e9a091..d85cf1748629d 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/get/TransportGetSnapshotsAction.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/get/TransportGetSnapshotsAction.java @@ -128,6 +128,7 @@ protected void masterOperation( request.size(), request.order(), SnapshotPredicates.fromRequest(request), + request.indices(), listener ); } @@ -166,6 +167,7 @@ private void getMultipleReposSnapshotInfo( int size, SortOrder order, SnapshotPredicates predicates, + boolean indices, ActionListener listener ) { // short-circuit if there are no repos, because we can not create GroupedActionListener of size 0 @@ -193,7 +195,7 @@ private void getMultipleReposSnapshotInfo( .mapToInt(s -> s.remaining) .sum(); return new GetSnapshotsResponse( - snapshotInfos, + indices ? snapshotInfos : snapshotInfos.stream().map(SnapshotInfo::withoutIndices).toList(), failures, remaining > 0 ? GetSnapshotsRequest.After.from(snapshotInfos.get(snapshotInfos.size() - 1), sortBy).asQueryParam() diff --git a/server/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestGetSnapshotsAction.java b/server/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestGetSnapshotsAction.java index ebc63dc68aef4..0f5f9914c364c 100644 --- a/server/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestGetSnapshotsAction.java +++ b/server/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestGetSnapshotsAction.java @@ -26,6 +26,7 @@ import static org.elasticsearch.rest.RestRequest.Method.GET; import static org.elasticsearch.snapshots.SnapshotInfo.INCLUDE_REPOSITORY_XCONTENT_PARAM; import static org.elasticsearch.snapshots.SnapshotInfo.INDEX_DETAILS_XCONTENT_PARAM; +import static org.elasticsearch.snapshots.SnapshotInfo.INDEX_NAMES_XCONTENT_PARAM; /** * Returns information about snapshot @@ -50,7 +51,7 @@ public String getName() { @Override protected Set responseParams() { - return Set.of(INDEX_DETAILS_XCONTENT_PARAM, INCLUDE_REPOSITORY_XCONTENT_PARAM); + return Set.of(INDEX_DETAILS_XCONTENT_PARAM, INCLUDE_REPOSITORY_XCONTENT_PARAM, INDEX_NAMES_XCONTENT_PARAM); } @Override @@ -80,6 +81,7 @@ public RestChannelConsumer prepareRequest(final RestRequest request, final NodeC final SortOrder order = SortOrder.fromString(request.param("order", getSnapshotsRequest.order().toString())); getSnapshotsRequest.order(order); + getSnapshotsRequest.indices(request.paramAsBoolean(INDEX_NAMES_XCONTENT_PARAM, getSnapshotsRequest.indices())); getSnapshotsRequest.masterNodeTimeout(request.paramAsTime("master_timeout", getSnapshotsRequest.masterNodeTimeout())); return channel -> new RestCancellableNodeClient(client, request.getHttpChannel()).admin() .cluster() diff --git a/server/src/main/java/org/elasticsearch/snapshots/SnapshotInfo.java b/server/src/main/java/org/elasticsearch/snapshots/SnapshotInfo.java index 7fe334235d7c7..d50d04bbb7299 100644 --- a/server/src/main/java/org/elasticsearch/snapshots/SnapshotInfo.java +++ b/server/src/main/java/org/elasticsearch/snapshots/SnapshotInfo.java @@ -48,6 +48,8 @@ public final class SnapshotInfo implements Comparable, ToXContentFragment, Writeable { public static final String INDEX_DETAILS_XCONTENT_PARAM = "index_details"; + + public static final String INDEX_NAMES_XCONTENT_PARAM = "index_names"; public static final String INCLUDE_REPOSITORY_XCONTENT_PARAM = "include_repository"; private static final DateFormatter DATE_TIME_FORMATTER = DateFormatter.forPattern("strict_date_optional_time"); @@ -467,6 +469,29 @@ public SnapshotInfo( this.indexSnapshotDetails = Map.copyOf(indexSnapshotDetails); } + public SnapshotInfo withoutIndices() { + if (indices.isEmpty()) { + return this; + } + return new SnapshotInfo( + snapshot, + List.of(), + dataStreams, + featureStates, + reason, + version, + startTime, + endTime, + totalShards, + successfulShards, + shardFailures, + includeGlobalState, + userMetadata, + state, + indexSnapshotDetails + ); + } + /** * Constructs snapshot information from stream input */ @@ -748,11 +773,10 @@ public XContentBuilder toXContentExternal(final XContentBuilder builder, final T builder.field(VERSION_ID, version.id); builder.field(VERSION, version.toString()); } - builder.startArray(INDICES); - for (String index : indices) { - builder.value(index); + + if (params.paramAsBoolean(INDEX_NAMES_XCONTENT_PARAM, true)) { + builder.stringListField(INDICES, indices); } - builder.endArray(); if (params.paramAsBoolean(INDEX_DETAILS_XCONTENT_PARAM, false) && indexSnapshotDetails.isEmpty() == false) { builder.startObject(INDEX_DETAILS); diff --git a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/slm/SnapshotRetentionTask.java b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/slm/SnapshotRetentionTask.java index 14e99bb6cbe61..6e0e9e6242f5d 100644 --- a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/slm/SnapshotRetentionTask.java +++ b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/slm/SnapshotRetentionTask.java @@ -274,6 +274,7 @@ void getAllRetainableSnapshots( .setMasterNodeTimeout(TimeValue.MAX_VALUE) .setIgnoreUnavailable(true) .setPolicies(policies.toArray(Strings.EMPTY_ARRAY)) + .setIndices(false) .execute(ActionListener.wrap(resp -> { if (logger.isTraceEnabled()) { logger.trace(