Skip to content

Commit 801cde0

Browse files
authored
HLRC: Add ILM Status to HLRC (#33283) (#33448)
Adds support for the Index Lifecycle Management Status to the Java High-Level Rest Client. Relates to #33100
1 parent fb12ea6 commit 801cde0

11 files changed

+293
-19
lines changed

client/rest-high-level/src/main/java/org/elasticsearch/client/IndexLifecycleClient.java

+31
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
import org.elasticsearch.action.ActionListener;
2323
import org.elasticsearch.action.support.master.AcknowledgedResponse;
2424
import org.elasticsearch.client.indexlifecycle.DeleteLifecyclePolicyRequest;
25+
import org.elasticsearch.client.indexlifecycle.LifecycleManagementStatusRequest;
26+
import org.elasticsearch.client.indexlifecycle.LifecycleManagementStatusResponse;
2527
import org.elasticsearch.client.indexlifecycle.PutLifecyclePolicyRequest;
2628
import org.elasticsearch.protocol.xpack.indexlifecycle.ExplainLifecycleRequest;
2729
import org.elasticsearch.protocol.xpack.indexlifecycle.ExplainLifecycleResponse;
@@ -169,6 +171,35 @@ public AcknowledgedResponse stopILM(StopILMRequest request, RequestOptions optio
169171
AcknowledgedResponse::fromXContent, emptySet());
170172
}
171173

174+
/**
175+
* Get the status of index lifecycle management
176+
* See <a href="https://fix-me-when-we-have-docs.com">
177+
* the docs</a> for more.
178+
*
179+
* @param request the request
180+
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
181+
*/
182+
public LifecycleManagementStatusResponse lifecycleManagementStatus(LifecycleManagementStatusRequest request, RequestOptions options)
183+
throws IOException {
184+
return restHighLevelClient.performRequestAndParseEntity(request, RequestConverters::lifecycleManagementStatus, options,
185+
LifecycleManagementStatusResponse::fromXContent, emptySet());
186+
}
187+
188+
/**
189+
* Asynchronously get the status of index lifecycle management
190+
* See <a href="https://fix-me-when-we-have-docs.com">
191+
* the docs</a> for more.
192+
*
193+
* @param request the request
194+
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
195+
* @param listener the listener to be notified upon request completion
196+
*/
197+
public void lifecycleManagementStatusAsync(LifecycleManagementStatusRequest request, RequestOptions options,
198+
ActionListener<LifecycleManagementStatusResponse> listener) {
199+
restHighLevelClient.performRequestAsyncAndParseEntity(request, RequestConverters::lifecycleManagementStatus, options,
200+
LifecycleManagementStatusResponse::fromXContent, listener, emptySet());
201+
}
202+
172203
/**
173204
* Asynchronously stop the Index Lifecycle Management feature.
174205
* See <a href="https://fix-me-when-we-have-docs.com">

client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java

+13
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@
8989
import org.elasticsearch.client.security.RefreshPolicy;
9090
import org.elasticsearch.client.indexlifecycle.PutLifecyclePolicyRequest;
9191
import org.elasticsearch.client.indexlifecycle.DeleteLifecyclePolicyRequest;
92+
import org.elasticsearch.client.indexlifecycle.LifecycleManagementStatusRequest;
9293
import org.elasticsearch.cluster.health.ClusterHealthStatus;
9394
import org.elasticsearch.common.Nullable;
9495
import org.elasticsearch.common.Priority;
@@ -1277,6 +1278,18 @@ static Request stopILM(StopILMRequest stopILMRequest) {
12771278
return request;
12781279
}
12791280

1281+
static Request lifecycleManagementStatus(LifecycleManagementStatusRequest lifecycleManagementStatusRequest){
1282+
Request request = new Request(HttpGet.METHOD_NAME,
1283+
new EndpointBuilder()
1284+
.addPathPartAsIs("_ilm")
1285+
.addPathPartAsIs("status")
1286+
.build());
1287+
Params params = new Params(request);
1288+
params.withMasterTimeout(lifecycleManagementStatusRequest.masterNodeTimeout());
1289+
params.withTimeout(lifecycleManagementStatusRequest.timeout());
1290+
return request;
1291+
}
1292+
12801293
static Request explainLifecycle(ExplainLifecycleRequest explainLifecycleRequest) {
12811294
String[] indices = explainLifecycleRequest.indices() == null ? Strings.EMPTY_ARRAY : explainLifecycleRequest.indices();
12821295
Request request = new Request(HttpGet.METHOD_NAME,

client/rest-high-level/src/main/java/org/elasticsearch/client/TimedRequest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
* Please note, any requests that use a ackTimeout should set timeout as they
2727
* represent the same backing field on the server.
2828
*/
29-
public class TimedRequest implements Validatable {
29+
public abstract class TimedRequest implements Validatable {
3030

3131
public static final TimeValue DEFAULT_TIMEOUT = TimeValue.timeValueSeconds(30);
3232
public static final TimeValue DEFAULT_MASTER_TIMEOUT = TimeValue.timeValueSeconds(30);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.elasticsearch.client.indexlifecycle;
21+
22+
import org.elasticsearch.client.TimedRequest;
23+
24+
/**
25+
* A {@link TimedRequest} to get the current status of index lifecycle management.
26+
*/
27+
public class LifecycleManagementStatusRequest extends TimedRequest {
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.elasticsearch.client.indexlifecycle;
21+
22+
import org.elasticsearch.common.ParseField;
23+
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
24+
import org.elasticsearch.common.xcontent.XContentParser;
25+
26+
import java.util.Objects;
27+
28+
/**
29+
* The current status of index lifecycle management. See {@link OperationMode} for available statuses.
30+
*/
31+
public class LifecycleManagementStatusResponse {
32+
33+
private final OperationMode operationMode;
34+
private static final String OPERATION_MODE = "operation_mode";
35+
@SuppressWarnings("unchecked")
36+
private static final ConstructingObjectParser<LifecycleManagementStatusResponse, Void> PARSER = new ConstructingObjectParser<>(
37+
OPERATION_MODE, a -> new LifecycleManagementStatusResponse((String) a[0]));
38+
39+
static {
40+
PARSER.declareString(ConstructingObjectParser.constructorArg(), new ParseField(OPERATION_MODE));
41+
}
42+
43+
//package private for testing
44+
LifecycleManagementStatusResponse(String operationMode) {
45+
this.operationMode = OperationMode.fromString(operationMode);
46+
}
47+
48+
public OperationMode getOperationMode() {
49+
return operationMode;
50+
}
51+
52+
public static LifecycleManagementStatusResponse fromXContent(XContentParser parser) {
53+
return PARSER.apply(parser, null);
54+
}
55+
56+
@Override
57+
public boolean equals(Object o) {
58+
if (this == o) return true;
59+
if (o == null || getClass() != o.getClass()) return false;
60+
LifecycleManagementStatusResponse that = (LifecycleManagementStatusResponse) o;
61+
return operationMode == that.operationMode;
62+
}
63+
64+
@Override
65+
public int hashCode() {
66+
return Objects.hash(operationMode);
67+
}
68+
}

client/rest-high-level/src/main/java/org/elasticsearch/client/indexlifecycle/OperationMode.java

+9
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020

2121
import org.elasticsearch.action.admin.indices.shrink.ShrinkAction;
2222

23+
import java.util.EnumSet;
24+
import java.util.Locale;
25+
2326
/**
2427
* Enum representing the different modes that Index Lifecycle Service can operate in.
2528
*/
@@ -56,4 +59,10 @@ public boolean isValidChange(OperationMode nextMode) {
5659
};
5760

5861
public abstract boolean isValidChange(OperationMode nextMode);
62+
63+
static OperationMode fromString(String string) {
64+
return EnumSet.allOf(OperationMode.class).stream()
65+
.filter(e -> string.equalsIgnoreCase(e.name())).findFirst()
66+
.orElseThrow(() -> new IllegalArgumentException(String.format(Locale.ROOT, "%s is not a valid operation_mode", string)));
67+
}
5968
}

client/rest-high-level/src/test/java/org/elasticsearch/client/IndexLifecycleIT.java

+18-18
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,17 @@
1919

2020
package org.elasticsearch.client;
2121

22-
import org.apache.http.util.EntityUtils;
2322
import org.elasticsearch.action.admin.indices.settings.get.GetSettingsRequest;
2423
import org.elasticsearch.action.admin.indices.settings.get.GetSettingsResponse;
2524
import org.elasticsearch.action.support.master.AcknowledgedResponse;
2625
import org.elasticsearch.client.indexlifecycle.AllocateAction;
2726
import org.elasticsearch.client.indexlifecycle.DeleteAction;
2827
import org.elasticsearch.client.indexlifecycle.ForceMergeAction;
2928
import org.elasticsearch.client.indexlifecycle.LifecycleAction;
29+
import org.elasticsearch.client.indexlifecycle.LifecycleManagementStatusRequest;
30+
import org.elasticsearch.client.indexlifecycle.LifecycleManagementStatusResponse;
3031
import org.elasticsearch.client.indexlifecycle.LifecyclePolicy;
32+
import org.elasticsearch.client.indexlifecycle.OperationMode;
3133
import org.elasticsearch.client.indexlifecycle.Phase;
3234
import org.elasticsearch.client.indexlifecycle.PutLifecyclePolicyRequest;
3335
import org.elasticsearch.client.indexlifecycle.RolloverAction;
@@ -88,35 +90,33 @@ public void testStartStopILM() throws Exception {
8890
createIndex("baz", Settings.builder().put("index.lifecycle.name", "eggplant").build());
8991
createIndex("squash", Settings.EMPTY);
9092

91-
// TODO: NORELEASE convert this to using the high level client once
92-
// there are APIs for it
93-
Request statusReq = new Request("GET", "/_ilm/status");
94-
Response statusResponse = client().performRequest(statusReq);
95-
String statusResponseString = EntityUtils.toString(statusResponse.getEntity());
96-
assertEquals("{\"operation_mode\":\"RUNNING\"}", statusResponseString);
93+
LifecycleManagementStatusRequest statusRequest = new LifecycleManagementStatusRequest();
94+
LifecycleManagementStatusResponse statusResponse = execute(
95+
statusRequest,
96+
highLevelClient().indexLifecycle()::lifecycleManagementStatus,
97+
highLevelClient().indexLifecycle()::lifecycleManagementStatusAsync);
98+
assertEquals(statusResponse.getOperationMode(), OperationMode.RUNNING);
9799

98100
StopILMRequest stopReq = new StopILMRequest();
99101
AcknowledgedResponse stopResponse = execute(stopReq, highLevelClient().indexLifecycle()::stopILM,
100102
highLevelClient().indexLifecycle()::stopILMAsync);
101103
assertTrue(stopResponse.isAcknowledged());
102104

103-
// TODO: NORELEASE convert this to using the high level client once there are APIs for it
104-
statusReq = new Request("GET", "/_ilm/status");
105-
statusResponse = client().performRequest(statusReq);
106-
statusResponseString = EntityUtils.toString(statusResponse.getEntity());
107-
assertThat(statusResponseString,
108-
Matchers.anyOf(equalTo("{\"operation_mode\":\"STOPPING\"}"), equalTo("{\"operation_mode\":\"STOPPED\"}")));
105+
106+
statusResponse = execute(statusRequest, highLevelClient().indexLifecycle()::lifecycleManagementStatus,
107+
highLevelClient().indexLifecycle()::lifecycleManagementStatusAsync);
108+
assertThat(statusResponse.getOperationMode(),
109+
Matchers.anyOf(equalTo(OperationMode.STOPPING),
110+
equalTo(OperationMode.STOPPED)));
109111

110112
StartILMRequest startReq = new StartILMRequest();
111113
AcknowledgedResponse startResponse = execute(startReq, highLevelClient().indexLifecycle()::startILM,
112114
highLevelClient().indexLifecycle()::startILMAsync);
113115
assertTrue(startResponse.isAcknowledged());
114116

115-
// TODO: NORELEASE convert this to using the high level client once there are APIs for it
116-
statusReq = new Request("GET", "/_ilm/status");
117-
statusResponse = client().performRequest(statusReq);
118-
statusResponseString = EntityUtils.toString(statusResponse.getEntity());
119-
assertEquals("{\"operation_mode\":\"RUNNING\"}", statusResponseString);
117+
statusResponse = execute(statusRequest, highLevelClient().indexLifecycle()::lifecycleManagementStatus,
118+
highLevelClient().indexLifecycle()::lifecycleManagementStatusAsync);
119+
assertEquals(statusResponse.getOperationMode(), OperationMode.RUNNING);
120120
}
121121

122122
public void testExplainLifecycle() throws Exception {

client/rest-high-level/src/test/java/org/elasticsearch/client/RequestConvertersTests.java

+13
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@
9494
import org.elasticsearch.action.support.replication.ReplicationRequest;
9595
import org.elasticsearch.action.update.UpdateRequest;
9696
import org.elasticsearch.client.RequestConverters.EndpointBuilder;
97+
import org.elasticsearch.client.indexlifecycle.LifecycleManagementStatusRequest;
9798
import org.elasticsearch.client.indexlifecycle.LifecyclePolicy;
9899
import org.elasticsearch.client.indexlifecycle.PutLifecyclePolicyRequest;
99100
import org.elasticsearch.client.indexlifecycle.DeleteLifecyclePolicyRequest;
@@ -2808,6 +2809,18 @@ public void testStopILM() throws Exception {
28082809
assertThat(request.getParameters(), equalTo(expectedParams));
28092810
}
28102811

2812+
public void testLifecycleManagementStatus() throws Exception {
2813+
LifecycleManagementStatusRequest req = new LifecycleManagementStatusRequest();
2814+
Map<String, String> expectedParams = new HashMap<>();
2815+
setRandomMasterTimeout(req::setMasterTimeout, TimedRequest.DEFAULT_TIMEOUT, expectedParams);
2816+
setRandomTimeoutTimeValue(req::setTimeout, TimedRequest.DEFAULT_MASTER_TIMEOUT, expectedParams);
2817+
2818+
Request request = RequestConverters.lifecycleManagementStatus(req);
2819+
assertThat(request.getMethod(), equalTo(HttpGet.METHOD_NAME));
2820+
assertThat(request.getEndpoint(), equalTo("/_ilm/status"));
2821+
assertThat(request.getParameters(), equalTo(expectedParams));
2822+
}
2823+
28112824
public void testExplainLifecycle() throws Exception {
28122825
ExplainLifecycleRequest req = new ExplainLifecycleRequest();
28132826
String[] indices = rarely() ? null : randomIndicesNames(0, 10);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.elasticsearch.client;
21+
22+
import org.elasticsearch.common.unit.TimeValue;
23+
import org.elasticsearch.test.ESTestCase;
24+
25+
public class TimedRequestTests extends ESTestCase {
26+
27+
public void testDefaults() {
28+
TimedRequest timedRequest = new TimedRequest(){};
29+
assertEquals(timedRequest.timeout(), TimedRequest.DEFAULT_TIMEOUT);
30+
assertEquals(timedRequest.masterNodeTimeout(), TimedRequest.DEFAULT_MASTER_TIMEOUT);
31+
}
32+
33+
public void testNonDefaults() {
34+
TimedRequest timedRequest = new TimedRequest(){};
35+
TimeValue timeout = TimeValue.timeValueSeconds(randomIntBetween(0, 1000));
36+
TimeValue masterTimeout = TimeValue.timeValueSeconds(randomIntBetween(0,1000));
37+
timedRequest.setTimeout(timeout);
38+
timedRequest.setMasterTimeout(masterTimeout);
39+
assertEquals(timedRequest.timeout(), timeout);
40+
assertEquals(timedRequest.masterNodeTimeout(), masterTimeout);
41+
}
42+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.elasticsearch.client.indexlifecycle;
21+
22+
import org.elasticsearch.common.xcontent.DeprecationHandler;
23+
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
24+
import org.elasticsearch.common.xcontent.XContentParser;
25+
import org.elasticsearch.common.xcontent.XContentType;
26+
import org.elasticsearch.test.ESTestCase;
27+
import org.hamcrest.CoreMatchers;
28+
29+
import java.io.IOException;
30+
import java.util.EnumSet;
31+
import java.util.stream.Collectors;
32+
33+
public class LifecycleManagementStatusResponseTests extends ESTestCase {
34+
35+
public void testAllValidStatuses() {
36+
EnumSet.allOf(OperationMode.class)
37+
.forEach(e -> assertEquals(new LifecycleManagementStatusResponse(e.name()).getOperationMode(), e));
38+
}
39+
40+
public void testXContent() throws IOException {
41+
XContentType xContentType = XContentType.JSON;
42+
String mode = randomFrom(EnumSet.allOf(OperationMode.class)
43+
.stream().map(Enum::name).collect(Collectors.toList()));
44+
XContentParser parser = xContentType.xContent().createParser(NamedXContentRegistry.EMPTY,
45+
DeprecationHandler.THROW_UNSUPPORTED_OPERATION, "{\"operation_mode\" : \"" + mode + "\"}");
46+
assertEquals(LifecycleManagementStatusResponse.fromXContent(parser).getOperationMode(), OperationMode.fromString(mode));
47+
}
48+
49+
public void testXContentInvalid() throws IOException {
50+
XContentType xContentType = XContentType.JSON;
51+
String mode = randomAlphaOfLength(10);
52+
XContentParser parser = xContentType.xContent().createParser(NamedXContentRegistry.EMPTY,
53+
DeprecationHandler.THROW_UNSUPPORTED_OPERATION, "{\"operation_mode\" : \"" + mode + "\"}");
54+
Exception e = expectThrows(IllegalArgumentException.class, () -> LifecycleManagementStatusResponse.fromXContent(parser));
55+
assertThat(e.getMessage(), CoreMatchers.containsString("failed to parse field [operation_mode]"));
56+
}
57+
}

0 commit comments

Comments
 (0)