diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/IndexLifecycleClient.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/IndexLifecycleClient.java index 3f4845a12eb84..b4517574059e8 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/IndexLifecycleClient.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/IndexLifecycleClient.java @@ -29,6 +29,7 @@ import org.elasticsearch.client.indexlifecycle.PutLifecyclePolicyRequest; import org.elasticsearch.client.indexlifecycle.ExplainLifecycleRequest; import org.elasticsearch.client.indexlifecycle.ExplainLifecycleResponse; +import org.elasticsearch.client.indexlifecycle.RetryLifecyclePolicyRequest; import org.elasticsearch.client.indexlifecycle.RemoveIndexLifecyclePolicyRequest; import org.elasticsearch.client.indexlifecycle.RemoveIndexLifecyclePolicyResponse; import org.elasticsearch.client.indexlifecycle.SetIndexLifecyclePolicyRequest; @@ -302,4 +303,32 @@ public void explainLifecycleAsync(ExplainLifecycleRequest request, RequestOption restHighLevelClient.performRequestAsyncAndParseEntity(request, RequestConverters::explainLifecycle, options, ExplainLifecycleResponse::fromXContent, listener, emptySet()); } + + /** + * Retry lifecycle step for given indices + * See + * the docs for more. + * @param request the request + * @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized + * @return the response + * @throws IOException in case there is a problem sending the request or parsing back the response + */ + public AcknowledgedResponse retryLifecycleStep(RetryLifecyclePolicyRequest request, RequestOptions options) throws IOException { + return restHighLevelClient.performRequestAndParseEntity(request, RequestConverters::retryLifecycle, options, + AcknowledgedResponse::fromXContent, emptySet()); + } + + /** + * Asynchronously retry the lifecycle step for given indices + * See + * the docs for more. + * @param request the request + * @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized + * @param listener the listener to be notified upon request completion + */ + public void retryLifecycleStepAsync(RetryLifecyclePolicyRequest request, RequestOptions options, + ActionListener listener) { + restHighLevelClient.performRequestAsyncAndParseEntity(request, RequestConverters::retryLifecycle, options, + AcknowledgedResponse::fromXContent, listener, emptySet()); + } } diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java index acb3e6d02bcb1..eb6f722ba369c 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java @@ -19,6 +19,7 @@ package org.elasticsearch.client; +import java.util.List; import org.apache.http.HttpEntity; import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpGet; @@ -54,6 +55,7 @@ import org.elasticsearch.client.indexlifecycle.GetLifecyclePolicyRequest; import org.elasticsearch.client.indexlifecycle.LifecycleManagementStatusRequest; import org.elasticsearch.client.indexlifecycle.PutLifecyclePolicyRequest; +import org.elasticsearch.client.indexlifecycle.RetryLifecyclePolicyRequest; import org.elasticsearch.client.indexlifecycle.RemoveIndexLifecyclePolicyRequest; import org.elasticsearch.client.indexlifecycle.SetIndexLifecyclePolicyRequest; import org.elasticsearch.client.indexlifecycle.StartILMRequest; @@ -717,6 +719,19 @@ static Request explainLifecycle(ExplainLifecycleRequest explainLifecycleRequest) return request; } + static Request retryLifecycle(RetryLifecyclePolicyRequest retryLifecyclePolicyRequest) { + Request request = new Request(HttpPost.METHOD_NAME, + new EndpointBuilder() + .addCommaSeparatedPathParts(retryLifecyclePolicyRequest.getIndices()) + .addPathPartAsIs("_ilm") + .addPathPartAsIs("retry") + .build()); + Params params = new Params(request); + params.withMasterTimeout(retryLifecyclePolicyRequest.masterNodeTimeout()); + params.withTimeout(retryLifecyclePolicyRequest.timeout()); + return request; + } + static HttpEntity createEntity(ToXContent toXContent, XContentType xContentType) throws IOException { BytesRef source = XContentHelper.toXContent(toXContent, xContentType, false).toBytesRef(); return new ByteArrayEntity(source.bytes, source.offset, source.length, createContentType(xContentType)); @@ -1102,7 +1117,12 @@ EndpointBuilder addCommaSeparatedPathParts(String[] parts) { return this; } - EndpointBuilder addPathPartAsIs(String... parts) { + EndpointBuilder addCommaSeparatedPathParts(List parts) { + addPathPart(String.join(",", parts)); + return this; + } + + EndpointBuilder addPathPartAsIs(String ... parts) { for (String part : parts) { if (Strings.hasLength(part)) { joiner.add(part); diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/indexlifecycle/RetryLifecyclePolicyRequest.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/indexlifecycle/RetryLifecyclePolicyRequest.java new file mode 100644 index 0000000000000..6f3acaf19aaea --- /dev/null +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/indexlifecycle/RetryLifecyclePolicyRequest.java @@ -0,0 +1,58 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.client.indexlifecycle; + +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import org.elasticsearch.client.TimedRequest; + +public class RetryLifecyclePolicyRequest extends TimedRequest { + + private final List indices; + + public RetryLifecyclePolicyRequest(String... indices) { + if (indices.length == 0) { + throw new IllegalArgumentException("Must at least specify one index to retry"); + } + this.indices = Arrays.asList(indices); + } + + public List getIndices() { + return indices; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + RetryLifecyclePolicyRequest that = (RetryLifecyclePolicyRequest) o; + return indices.size() == that.indices.size() && indices.containsAll(that.indices); + } + + @Override + public int hashCode() { + return Objects.hash(indices); + } +} diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/IndexLifecycleIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/IndexLifecycleIT.java index 9d76c19adf74c..8f440539f52e2 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/IndexLifecycleIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/IndexLifecycleIT.java @@ -41,6 +41,7 @@ import org.elasticsearch.client.indexlifecycle.Phase; import org.elasticsearch.client.indexlifecycle.PhaseExecutionInfo; import org.elasticsearch.client.indexlifecycle.PutLifecyclePolicyRequest; +import org.elasticsearch.client.indexlifecycle.RetryLifecyclePolicyRequest; import org.elasticsearch.client.indexlifecycle.RemoveIndexLifecyclePolicyRequest; import org.elasticsearch.client.indexlifecycle.RemoveIndexLifecyclePolicyResponse; import org.elasticsearch.client.indexlifecycle.RolloverAction; @@ -288,4 +289,26 @@ public void testGetMultipleLifecyclePolicies() throws IOException { .map(p -> ((LifecyclePolicyMetadata) p).getPolicy()).collect(Collectors.toList()); assertThat(retrievedPolicies, hasItems(policies)); } + + public void testRetryLifecycleStep() throws IOException { + String policyName = randomAlphaOfLength(10); + LifecyclePolicy policy = createRandomPolicy(policyName); + PutLifecyclePolicyRequest putRequest = new PutLifecyclePolicyRequest(policy); + assertAcked(execute(putRequest, highLevelClient().indexLifecycle()::putLifecyclePolicy, + highLevelClient().indexLifecycle()::putLifecyclePolicyAsync)); + createIndex("retry", Settings.builder().put("index.lifecycle.name", policy.getName()).build()); + RetryLifecyclePolicyRequest retryRequest = new RetryLifecyclePolicyRequest("retry"); + ElasticsearchStatusException ex = expectThrows(ElasticsearchStatusException.class, + () -> execute( + retryRequest, highLevelClient().indexLifecycle()::retryLifecycleStep, + highLevelClient().indexLifecycle()::retryLifecycleStepAsync + ) + ); + assertEquals(400, ex.status().getStatus()); + assertEquals( + "Elasticsearch exception [type=illegal_argument_exception, reason=cannot retry an action for an index [retry]" + + " that has not encountered an error when running a Lifecycle Policy]", + ex.getRootCause().getMessage() + ); + } } diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestConvertersTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestConvertersTests.java index 2f81ced664ba1..eb07c1b4cc160 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestConvertersTests.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestConvertersTests.java @@ -60,6 +60,7 @@ import org.elasticsearch.client.indexlifecycle.LifecyclePolicy; import org.elasticsearch.client.indexlifecycle.PutLifecyclePolicyRequest; import org.elasticsearch.client.indexlifecycle.DeleteLifecyclePolicyRequest; +import org.elasticsearch.client.indexlifecycle.RetryLifecyclePolicyRequest; import org.elasticsearch.client.indexlifecycle.RemoveIndexLifecyclePolicyRequest; import org.elasticsearch.common.CheckedBiConsumer; import org.elasticsearch.common.Strings; @@ -1593,6 +1594,19 @@ public void testExplainLifecycle() throws Exception { assertThat(request.getParameters(), equalTo(expectedParams)); } + public void testRetryLifecycle() throws Exception { + String[] indices = randomIndicesNames(1, 10); + RetryLifecyclePolicyRequest req = new RetryLifecyclePolicyRequest(indices); + Map expectedParams = new HashMap<>(); + setRandomMasterTimeout(req::setMasterTimeout, TimedRequest.DEFAULT_MASTER_NODE_TIMEOUT, expectedParams); + setRandomTimeoutTimeValue(req::setTimeout, TimedRequest.DEFAULT_ACK_TIMEOUT, expectedParams); + Request request = RequestConverters.retryLifecycle(req); + assertThat(request.getMethod(), equalTo(HttpPost.METHOD_NAME)); + String idxString = Strings.arrayToCommaDelimitedString(indices); + assertThat(request.getEndpoint(), equalTo("/" + (idxString.isEmpty() ? "" : (idxString + "/")) + "_ilm/retry")); + assertThat(request.getParameters(), equalTo(expectedParams)); + } + /** * Randomize the {@link FetchSourceContext} request parameters. */