Skip to content

Commit a42ab49

Browse files
williamrandolphgwbrownelasticmachine
authored
Add API for resetting state of a SystemIndexPlugin (#69469) (#70524)
* Add API for resetting state of a `SystemIndexPlugin` (#69469) When we disable access to system indices, plugins will still need a way to erase their state. The obvious and most pressing use case for this is in tests, which need to be able to clean up the state of a cluster in between groups of tests. * Use a HandledTransportAction for reset action My initial cut used a TransportMasterNodeAction, which requires code that carefully manipulates cluster state. At least for the first cut and testing, it seems like it will be much easier to use a client within a HandledTransportAction, which effectively makes the TransportResetFeatureStateAction a class that dispatches other transport actions to do the real work. * Clean up code by using a GroupedActionListener * ML feature state cleaner * Implement Transform feature state reset * Change _features/reset path to _features/_reset Out of an abundance of caution, I think the "reset" part of this path should have a leading underscore, so that if there's ever a reason to implement "GET _features/<feature_id>" we won't have to worry about distinguishing "reset" from a feature name. Co-authored-by: Gordon Brown <[email protected]> Co-authored-by: Elastic Machine <[email protected]>
1 parent 0675b14 commit a42ab49

File tree

31 files changed

+991
-34
lines changed

31 files changed

+991
-34
lines changed

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

+50-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@
99
package org.elasticsearch.client;
1010

1111
import org.elasticsearch.action.ActionListener;
12-
import org.elasticsearch.client.snapshots.GetFeaturesRequest;
13-
import org.elasticsearch.client.snapshots.GetFeaturesResponse;
12+
import org.elasticsearch.client.feature.GetFeaturesRequest;
13+
import org.elasticsearch.client.feature.GetFeaturesResponse;
14+
import org.elasticsearch.client.feature.ResetFeaturesRequest;
15+
import org.elasticsearch.client.feature.ResetFeaturesResponse;
1416

1517
import java.io.IOException;
1618

@@ -71,4 +73,50 @@ public Cancellable getFeaturesAsync(
7173
emptySet()
7274
);
7375
}
76+
77+
/**
78+
* Reset the state of Elasticsearch features, deleting system indices and performing other
79+
* cleanup operations.
80+
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/reset-features-api.html"> Rest
81+
* Features API on elastic.co</a>
82+
*
83+
* @param resetFeaturesRequest the request
84+
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
85+
* @return the response
86+
* @throws IOException in case there is a problem sending the request or parsing back the response
87+
*/
88+
public ResetFeaturesResponse resetFeatures(ResetFeaturesRequest resetFeaturesRequest, RequestOptions options)
89+
throws IOException {
90+
return restHighLevelClient.performRequestAndParseEntity(
91+
resetFeaturesRequest,
92+
FeaturesRequestConverters::resetFeatures,
93+
options,
94+
ResetFeaturesResponse::parse,
95+
emptySet()
96+
);
97+
}
98+
99+
/**
100+
* Asynchronously reset the state of Elasticsearch features, deleting system indices and performing other
101+
* cleanup operations.
102+
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/get-features-api.html"> Get Snapshottable
103+
* Features API on elastic.co</a>
104+
*
105+
* @param resetFeaturesRequest the request
106+
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
107+
* @param listener the listener to be notified upon request completion
108+
* @return cancellable that may be used to cancel the request
109+
*/
110+
public Cancellable resetFeaturesAsync(
111+
ResetFeaturesRequest resetFeaturesRequest, RequestOptions options,
112+
ActionListener<ResetFeaturesResponse> listener) {
113+
return restHighLevelClient.performRequestAsyncAndParseEntity(
114+
resetFeaturesRequest,
115+
FeaturesRequestConverters::resetFeatures,
116+
options,
117+
ResetFeaturesResponse::parse,
118+
listener,
119+
emptySet()
120+
);
121+
}
74122
}

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

+8-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
package org.elasticsearch.client;
1010

1111
import org.apache.http.client.methods.HttpGet;
12-
import org.elasticsearch.client.snapshots.GetFeaturesRequest;
12+
import org.apache.http.client.methods.HttpPost;
13+
import org.elasticsearch.client.feature.GetFeaturesRequest;
14+
import org.elasticsearch.client.feature.ResetFeaturesRequest;
1315

1416
public class FeaturesRequestConverters {
1517

@@ -23,4 +25,9 @@ static Request getFeatures(GetFeaturesRequest getFeaturesRequest) {
2325
request.addParameters(parameters.asMap());
2426
return request;
2527
}
28+
29+
static Request resetFeatures(ResetFeaturesRequest resetFeaturesRequest) {
30+
String endpoint = "/_features/_reset";
31+
return new Request(HttpPost.METHOD_NAME, endpoint);
32+
}
2633
}

client/rest-high-level/src/main/java/org/elasticsearch/client/snapshots/GetFeaturesRequest.java renamed to client/rest-high-level/src/main/java/org/elasticsearch/client/feature/GetFeaturesRequest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* Side Public License, v 1.
77
*/
88

9-
package org.elasticsearch.client.snapshots;
9+
package org.elasticsearch.client.feature;
1010

1111
import org.elasticsearch.client.TimedRequest;
1212

client/rest-high-level/src/main/java/org/elasticsearch/client/snapshots/GetFeaturesResponse.java renamed to client/rest-high-level/src/main/java/org/elasticsearch/client/feature/GetFeaturesResponse.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* Side Public License, v 1.
77
*/
88

9-
package org.elasticsearch.client.snapshots;
9+
package org.elasticsearch.client.feature;
1010

1111
import org.elasticsearch.common.ParseField;
1212
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0 and the Server Side Public License, v 1; you may not use this file except
5+
* in compliance with, at your election, the Elastic License 2.0 or the Server
6+
* Side Public License, v 1.
7+
*/
8+
9+
package org.elasticsearch.client.feature;
10+
11+
import org.elasticsearch.client.TimedRequest;
12+
13+
public class ResetFeaturesRequest extends TimedRequest {
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0 and the Server Side Public License, v 1; you may not use this file except
5+
* in compliance with, at your election, the Elastic License 2.0 or the Server
6+
* Side Public License, v 1.
7+
*/
8+
9+
package org.elasticsearch.client.feature;
10+
11+
import org.elasticsearch.common.ParseField;
12+
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
13+
import org.elasticsearch.common.xcontent.ObjectParser;
14+
import org.elasticsearch.common.xcontent.XContentParser;
15+
16+
import java.util.List;
17+
18+
public class ResetFeaturesResponse {
19+
private final List<ResetFeatureStateStatus> features;
20+
21+
private static final ParseField FEATURES = new ParseField("features");
22+
23+
@SuppressWarnings("unchecked")
24+
private static final ConstructingObjectParser<ResetFeaturesResponse, Void> PARSER = new ConstructingObjectParser<>(
25+
"snapshottable_features_response", true,
26+
(a, ctx) -> new ResetFeaturesResponse((List<ResetFeatureStateStatus>) a[0])
27+
);
28+
29+
static {
30+
PARSER.declareObjectArray(
31+
ConstructingObjectParser.constructorArg(),
32+
ResetFeaturesResponse.ResetFeatureStateStatus::parse, FEATURES);
33+
}
34+
35+
public ResetFeaturesResponse(List<ResetFeatureStateStatus> features) {
36+
this.features = features;
37+
}
38+
39+
public List<ResetFeatureStateStatus> getFeatures() {
40+
return features;
41+
}
42+
43+
public static ResetFeaturesResponse parse(XContentParser parser) {
44+
return PARSER.apply(parser, null);
45+
}
46+
47+
public static class ResetFeatureStateStatus {
48+
private final String featureName;
49+
private final String status;
50+
51+
private static final ParseField FEATURE_NAME = new ParseField("feature_name");
52+
private static final ParseField STATUS = new ParseField("status");
53+
54+
private static final ConstructingObjectParser<ResetFeatureStateStatus, Void> PARSER = new ConstructingObjectParser<>(
55+
"features", true, (a, ctx) -> new ResetFeatureStateStatus((String) a[0], (String) a[1])
56+
);
57+
58+
static {
59+
PARSER.declareField(ConstructingObjectParser.constructorArg(),
60+
(p, c) -> p.text(), FEATURE_NAME, ObjectParser.ValueType.STRING);
61+
PARSER.declareField(ConstructingObjectParser.constructorArg(),
62+
(p, c) -> p.text(), STATUS, ObjectParser.ValueType.STRING);
63+
}
64+
65+
ResetFeatureStateStatus(String featureName, String status) {
66+
this.featureName = featureName;
67+
this.status = status;
68+
}
69+
70+
public static ResetFeatureStateStatus parse(XContentParser parser, Void ctx) {
71+
return PARSER.apply(parser, ctx);
72+
}
73+
74+
public String getFeatureName() {
75+
return featureName;
76+
}
77+
78+
public String getStatus() {
79+
return status;
80+
}
81+
}
82+
}

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

+17-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@
88

99
package org.elasticsearch.client;
1010

11-
import org.elasticsearch.client.snapshots.GetFeaturesRequest;
12-
import org.elasticsearch.client.snapshots.GetFeaturesResponse;
11+
import org.elasticsearch.client.feature.GetFeaturesRequest;
12+
import org.elasticsearch.client.feature.GetFeaturesResponse;
13+
import org.elasticsearch.client.feature.ResetFeaturesRequest;
14+
import org.elasticsearch.client.feature.ResetFeaturesResponse;
1315

1416
import java.io.IOException;
1517

@@ -28,4 +30,17 @@ public void testGetFeatures() throws IOException {
2830
assertThat(response.getFeatures().size(), greaterThan(1));
2931
assertTrue(response.getFeatures().stream().anyMatch(feature -> "tasks".equals(feature.getFeatureName())));
3032
}
33+
34+
public void testResetFeatures() throws IOException {
35+
ResetFeaturesRequest request = new ResetFeaturesRequest();
36+
37+
ResetFeaturesResponse response = execute(request,
38+
highLevelClient().features()::resetFeatures, highLevelClient().features()::resetFeaturesAsync);
39+
40+
assertThat(response, notNullValue());
41+
assertThat(response.getFeatures(), notNullValue());
42+
assertThat(response.getFeatures().size(), greaterThan(1));
43+
assertTrue(response.getFeatures().stream().anyMatch(
44+
feature -> "tasks".equals(feature.getFeatureName()) && "SUCCESS".equals(feature.getStatus())));
45+
}
3146
}

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

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
package org.elasticsearch.client.snapshots;
1010

1111
import org.elasticsearch.client.AbstractResponseTestCase;
12+
import org.elasticsearch.client.feature.GetFeaturesResponse;
1213
import org.elasticsearch.common.xcontent.XContentParser;
1314
import org.elasticsearch.common.xcontent.XContentType;
1415

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"features.reset_features":{
3+
"documentation":{
4+
"url":"https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-snapshots.html",
5+
"description":"Resets the internal state of features, usually by deleting system indices"
6+
},
7+
"stability":"experimental",
8+
"visibility":"public",
9+
"headers":{
10+
"accept": [ "application/json"]
11+
},
12+
"url":{
13+
"paths":[
14+
{
15+
"path":"/_features/_reset",
16+
"methods":[
17+
"POST"
18+
]
19+
}
20+
]
21+
}
22+
}
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
"Get Features":
3+
- skip:
4+
features: contains
5+
version: " - 7.99.99" # Adjust this after backport
6+
reason: "This API was added in 7.13.0"
7+
- do: { features.get_features: {}}
8+
- contains: {'features': {'name': 'tasks'}}

0 commit comments

Comments
 (0)