Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions docs/reference/snapshot-restore/apis/get-snapshot-api.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -148,12 +148,20 @@ Offset identifier to start pagination from as returned by the `next` field in th
Numeric offset to start pagination from based on the snapshots matching this request. Using a non-zero value for this parameter is mutually
exclusive with using the `after` parameter. Defaults to `0`.

`slm_policy_filter`::
(Optional, string)
Filter snapshots by a comma-separated list of SLM policy names that snapshots belong to. Also accepts wildcards (`\*`) and combinations
of wildcards followed by exclude patterns starting in `-`. For example, the pattern `*,-policy-a-\*` will return all snapshots except
for those that were created by an SLM policy with a name starting in `policy-a-`. Note that the wildcard pattern `*` matches all snapshots
created by an SLM policy but not those snapshots that were not created by an SLM policy. To include snapshots not created by an SLM
policy you can use the special pattern `_none` that will match all snapshots without an SLM policy.

NOTE: The `after` parameter and `next` field allow for iterating through snapshots with some consistency guarantees regarding concurrent
creation or deletion of snapshots. It is guaranteed that any snapshot that exists at the beginning of the iteration and not concurrently
deleted will be seen during the iteration. Snapshots concurrently created may be seen during an iteration.

NOTE: The pagination parameters `size`, `order`, `after`, `offset` and `sort` are not supported when using `verbose=false` and the sort
order for requests with `verbose=false` is undefined.
NOTE: The parameters `size`, `order`, `after`, `offset`, `slm_policy_filter` and `sort` are not supported when using `verbose=false` and
the sort order for requests with `verbose=false` is undefined.

[role="child_attributes"]
[[get-snapshot-api-response-body]]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import org.elasticsearch.action.admin.cluster.snapshots.get.GetSnapshotsResponse;
import org.elasticsearch.client.Request;
import org.elasticsearch.client.Response;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.xcontent.DeprecationHandler;
import org.elasticsearch.xcontent.NamedXContentRegistry;
Expand All @@ -23,6 +24,7 @@
import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.snapshots.AbstractSnapshotIntegTestCase;
import org.elasticsearch.snapshots.SnapshotInfo;
import org.elasticsearch.snapshots.SnapshotsService;
import org.elasticsearch.threadpool.ThreadPool;

import java.io.IOException;
Expand All @@ -33,6 +35,7 @@
import java.util.List;

import static org.elasticsearch.snapshots.AbstractSnapshotIntegTestCase.assertSnapshotListSorted;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.in;
import static org.hamcrest.Matchers.is;

Expand Down Expand Up @@ -183,6 +186,69 @@ public void testSortAndPaginateWithInProgress() throws Exception {
assertStablePagination(repoName, allSnapshotNames, GetSnapshotsRequest.SortBy.INDICES);
}

public void testFilterBySLMPolicy() throws Exception {
final String repoName = "test-repo";
AbstractSnapshotIntegTestCase.createRepository(logger, repoName, "fs");
AbstractSnapshotIntegTestCase.createNSnapshots(logger, repoName, randomIntBetween(1, 5));
final List<SnapshotInfo> snapshotsWithoutPolicy = clusterAdmin().prepareGetSnapshots("*").setSnapshots("*")
.setSort(GetSnapshotsRequest.SortBy.NAME).get().getSnapshots();
final String snapshotWithPolicy = "snapshot-with-policy";
final String policyName = "some-policy";
final SnapshotInfo withPolicy = AbstractSnapshotIntegTestCase.assertSuccessful(
logger,
clusterAdmin().prepareCreateSnapshot(repoName, snapshotWithPolicy)
.setUserMetadata(org.elasticsearch.core.Map.of(SnapshotsService.POLICY_ID_METADATA_FIELD, policyName))
.setWaitForCompletion(true)
.execute()
);

assertThat(getAllSnapshotsForPolicies(policyName), is(org.elasticsearch.core.List.of(withPolicy)));
assertThat(getAllSnapshotsForPolicies("some-*"), is(org.elasticsearch.core.List.of(withPolicy)));
assertThat(getAllSnapshotsForPolicies("*", "-" + policyName), empty());
assertThat(getAllSnapshotsForPolicies(GetSnapshotsRequest.NO_POLICY_PATTERN), is(snapshotsWithoutPolicy));
assertThat(
getAllSnapshotsForPolicies(GetSnapshotsRequest.NO_POLICY_PATTERN, "-" + policyName), is(snapshotsWithoutPolicy));
assertThat(getAllSnapshotsForPolicies(GetSnapshotsRequest.NO_POLICY_PATTERN), is(snapshotsWithoutPolicy));
assertThat(getAllSnapshotsForPolicies(GetSnapshotsRequest.NO_POLICY_PATTERN, "-*"), is(snapshotsWithoutPolicy));
assertThat(getAllSnapshotsForPolicies("no-such-policy"), empty());
assertThat(getAllSnapshotsForPolicies("no-such-policy*"), empty());

final String snapshotWithOtherPolicy = "snapshot-with-other-policy";
final String otherPolicyName = "other-policy";
final SnapshotInfo withOtherPolicy = AbstractSnapshotIntegTestCase.assertSuccessful(
logger,
clusterAdmin().prepareCreateSnapshot(repoName, snapshotWithOtherPolicy)
.setUserMetadata(org.elasticsearch.core.Map.of(SnapshotsService.POLICY_ID_METADATA_FIELD, otherPolicyName))
.setWaitForCompletion(true)
.execute()
);
assertThat(getAllSnapshotsForPolicies("*"), is(org.elasticsearch.core.List.of(withOtherPolicy, withPolicy)));
assertThat(getAllSnapshotsForPolicies(policyName, otherPolicyName),
is(org.elasticsearch.core.List.of(withOtherPolicy, withPolicy)));
assertThat(getAllSnapshotsForPolicies(policyName, otherPolicyName, "no-such-policy*"),
is(org.elasticsearch.core.List.of(withOtherPolicy, withPolicy)));
final List<SnapshotInfo> allSnapshots = clusterAdmin().prepareGetSnapshots("*")
.setSnapshots("*")
.setSort(GetSnapshotsRequest.SortBy.NAME)
.get()
.getSnapshots();
assertThat(
getAllSnapshotsForPolicies(GetSnapshotsRequest.NO_POLICY_PATTERN, policyName, otherPolicyName),
is(allSnapshots)
);
assertThat(
getAllSnapshotsForPolicies(GetSnapshotsRequest.NO_POLICY_PATTERN, "*"),
is(allSnapshots)
);
}

private static List<SnapshotInfo> getAllSnapshotsForPolicies(String... policies) throws IOException {
final Request requestWithPolicy = new Request(HttpGet.METHOD_NAME, "/_snapshot/*/*");
requestWithPolicy.addParameter("slm_policy_filter", Strings.arrayToCommaDelimitedString(policies));
requestWithPolicy.addParameter("sort", GetSnapshotsRequest.SortBy.NAME.toString());
return readSnapshotInfos(getRestClient().performRequest(requestWithPolicy)).getSnapshots();
}

private void createIndexWithContent(String indexName) {
logger.info("--> creating index [{}]", indexName);
createIndex(indexName, AbstractSnapshotIntegTestCase.SINGLE_SHARD_NO_REPLICA);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import java.util.HashSet;
import java.util.List;

import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.in;
import static org.hamcrest.Matchers.is;

Expand Down Expand Up @@ -209,6 +210,70 @@ public void testPaginationRequiresVerboseListing() throws Exception {
);
}

public void testFilterBySLMPolicy() throws Exception {
final String repoName = "test-repo";
createRepository(repoName, "fs");
createNSnapshots(repoName, randomIntBetween(1, 5));
final List<SnapshotInfo> snapshotsWithoutPolicy = clusterAdmin().prepareGetSnapshots("*")
.setSnapshots("*")
.setSort(GetSnapshotsRequest.SortBy.NAME)
.get()
.getSnapshots();
final String snapshotWithPolicy = "snapshot-with-policy";
final String policyName = "some-policy";
final SnapshotInfo withPolicy = assertSuccessful(
clusterAdmin().prepareCreateSnapshot(repoName, snapshotWithPolicy)
.setUserMetadata(org.elasticsearch.core.Map.of(SnapshotsService.POLICY_ID_METADATA_FIELD, policyName))
.setWaitForCompletion(true)
.execute()
);

assertThat(getAllSnapshotsForPolicies(policyName), is(org.elasticsearch.core.List.of(withPolicy)));
assertThat(getAllSnapshotsForPolicies("some-*"), is(org.elasticsearch.core.List.of(withPolicy)));
assertThat(getAllSnapshotsForPolicies("*", "-" + policyName), empty());
assertThat(getAllSnapshotsForPolicies(GetSnapshotsRequest.NO_POLICY_PATTERN), is(snapshotsWithoutPolicy));
assertThat(getAllSnapshotsForPolicies(GetSnapshotsRequest.NO_POLICY_PATTERN, "-" + policyName), is(snapshotsWithoutPolicy));
assertThat(getAllSnapshotsForPolicies(GetSnapshotsRequest.NO_POLICY_PATTERN), is(snapshotsWithoutPolicy));
assertThat(getAllSnapshotsForPolicies(GetSnapshotsRequest.NO_POLICY_PATTERN, "-*"), is(snapshotsWithoutPolicy));
assertThat(getAllSnapshotsForPolicies("no-such-policy"), empty());
assertThat(getAllSnapshotsForPolicies("no-such-policy*"), empty());

final String snapshotWithOtherPolicy = "snapshot-with-other-policy";
final String otherPolicyName = "other-policy";
final SnapshotInfo withOtherPolicy = assertSuccessful(
clusterAdmin().prepareCreateSnapshot(repoName, snapshotWithOtherPolicy)
.setUserMetadata(org.elasticsearch.core.Map.of(SnapshotsService.POLICY_ID_METADATA_FIELD, otherPolicyName))
.setWaitForCompletion(true)
.execute()
);
assertThat(getAllSnapshotsForPolicies("*"), is(org.elasticsearch.core.List.of(withOtherPolicy, withPolicy)));
assertThat(
getAllSnapshotsForPolicies(policyName, otherPolicyName),
is(org.elasticsearch.core.List.of(withOtherPolicy, withPolicy))
);
assertThat(
getAllSnapshotsForPolicies(policyName, otherPolicyName, "no-such-policy*"),
is(org.elasticsearch.core.List.of(withOtherPolicy, withPolicy))
);

final List<SnapshotInfo> allSnapshots = clusterAdmin().prepareGetSnapshots("*")
.setSnapshots("*")
.setSort(GetSnapshotsRequest.SortBy.NAME)
.get()
.getSnapshots();
assertThat(getAllSnapshotsForPolicies(GetSnapshotsRequest.NO_POLICY_PATTERN, policyName, otherPolicyName), is(allSnapshots));
assertThat(getAllSnapshotsForPolicies(GetSnapshotsRequest.NO_POLICY_PATTERN, "*"), is(allSnapshots));
}

private static List<SnapshotInfo> getAllSnapshotsForPolicies(String... policies) {
return clusterAdmin().prepareGetSnapshots("*")
.setSnapshots("*")
.setPolicies(policies)
.setSort(GetSnapshotsRequest.SortBy.NAME)
.get()
.getSnapshots();
}

private static void assertStablePagination(String repoName, Collection<String> allSnapshotNames, GetSnapshotsRequest.SortBy sort) {
final SortOrder order = randomFrom(SortOrder.values());
final List<SnapshotInfo> allSorted = allSnapshotsSorted(allSnapshotNames, repoName, sort, order);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,11 @@ public class GetSnapshotsRequest extends MasterNodeRequest<GetSnapshotsRequest>

public static final String ALL_SNAPSHOTS = "_all";
public static final String CURRENT_SNAPSHOT = "_current";
public static final String NO_POLICY_PATTERN = "_none";
public static final boolean DEFAULT_VERBOSE_MODE = true;

public static final Version SLM_POLICY_FILTERING_VERSION = Version.V_7_16_0;

public static final Version MULTIPLE_REPOSITORIES_SUPPORT_ADDED = Version.V_7_14_0;

public static final Version PAGINATED_GET_SNAPSHOTS_VERSION = Version.V_7_14_0;
Expand Down Expand Up @@ -71,6 +74,8 @@ public class GetSnapshotsRequest extends MasterNodeRequest<GetSnapshotsRequest>

private String[] snapshots = Strings.EMPTY_ARRAY;

private String[] policies = Strings.EMPTY_ARRAY;

private boolean ignoreUnavailable;

private boolean verbose = DEFAULT_VERBOSE_MODE;
Expand Down Expand Up @@ -126,6 +131,9 @@ public GetSnapshotsRequest(StreamInput in) throws IOException {
if (in.getVersion().onOrAfter(NUMERIC_PAGINATION_VERSION)) {
offset = in.readVInt();
}
if (in.getVersion().onOrAfter(SLM_POLICY_FILTERING_VERSION)) {
policies = in.readStringArray();
}
}
}

Expand Down Expand Up @@ -168,6 +176,13 @@ public void writeTo(StreamOutput out) throws IOException {
} else if (sort != SortBy.START_TIME || size != NO_LIMIT || after != null || order != SortOrder.ASC) {
throw new IllegalArgumentException("can't use paginated get snapshots request with node version [" + out.getVersion() + "]");
}
if (out.getVersion().onOrAfter(SLM_POLICY_FILTERING_VERSION)) {
out.writeStringArray(policies);
} else if (policies.length > 0) {
throw new IllegalArgumentException(
"can't use slm policy filter in snapshots request with node version [" + out.getVersion() + "]"
);
}
}

@Override
Expand Down Expand Up @@ -195,6 +210,9 @@ public ActionRequestValidationException validate() {
if (order != SortOrder.ASC) {
validationException = addValidationError("can't use non-default sort order with verbose=false", validationException);
}
if (policies.length != 0) {
validationException = addValidationError("can't use slm policy filter with verbose=false", validationException);
}
} else if (after != null && offset > 0) {
validationException = addValidationError("can't use after and offset simultaneously", validationException);
}
Expand All @@ -221,6 +239,26 @@ public String[] repositories() {
return this.repositories;
}

/**
* Sets slm policy patterns
*
* @param policies policy patterns
* @return this request
*/
public GetSnapshotsRequest policies(String... policies) {
this.policies = policies;
return this;
}

/**
* Returns policy patterns
*
* @return policy patterns
*/
public String[] policies() {
return policies;
}

public boolean isSingleRepositoryRequest() {
return repositories.length == 1
&& repositories[0] != null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,17 @@ public GetSnapshotsRequestBuilder setRepositories(String... repositories) {
return this;
}

/**
* Sets slm policy patterns
*
* @param policies slm policy patterns
* @return this builder
*/
public GetSnapshotsRequestBuilder setPolicies(String... policies) {
request.policies(policies);
return this;
}

/**
* Sets list of snapshots to return
*
Expand Down
Loading