Skip to content

Commit 6c9e0ae

Browse files
authored
Adds API to assign or change the policy for an index (#31277)
* Adds API to assign or change the policy for an index This api will change `index.lifecycle.name` for all indexes in the provided pattern as long as they are not currently in the shrink action. Later changes will loosen this restriction so an index is only reject if it is currently in the shrink action AND the diff between the old and new policy includes changes to the shrink action. Also later changes will detect if the current step is not present in the new policy and move the index onto the next available step * Changes name to SetPolicyForIndexAction Also changes all related Classes and api endpoints * fixes tests
1 parent 6785391 commit 6c9e0ae

File tree

14 files changed

+153274
-15
lines changed

14 files changed

+153274
-15
lines changed

consoleFull

Lines changed: 152309 additions & 0 deletions
Large diffs are not rendered by default.

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackClientPlugin.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
import org.elasticsearch.xpack.core.indexlifecycle.RolloverAction;
5252
import org.elasticsearch.xpack.core.indexlifecycle.ShrinkAction;
5353
import org.elasticsearch.xpack.core.indexlifecycle.TimeseriesLifecycleType;
54+
import org.elasticsearch.xpack.core.indexlifecycle.action.SetPolicyForIndexAction;
5455
import org.elasticsearch.xpack.core.indexlifecycle.action.DeleteLifecycleAction;
5556
import org.elasticsearch.xpack.core.indexlifecycle.action.ExplainLifecycleAction;
5657
import org.elasticsearch.xpack.core.indexlifecycle.action.GetLifecycleAction;
@@ -330,6 +331,7 @@ public List<GenericAction> getClientActions() {
330331
GetLifecycleAction.INSTANCE,
331332
PutLifecycleAction.INSTANCE,
332333
ExplainLifecycleAction.INSTANCE,
334+
SetPolicyForIndexAction.INSTANCE,
333335
MoveToStepAction.INSTANCE,
334336
RetryAction.INSTANCE
335337
);
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
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+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
package org.elasticsearch.xpack.core.indexlifecycle.action;
8+
9+
import org.elasticsearch.action.Action;
10+
import org.elasticsearch.action.ActionRequestValidationException;
11+
import org.elasticsearch.action.ActionResponse;
12+
import org.elasticsearch.action.IndicesRequest;
13+
import org.elasticsearch.action.support.IndicesOptions;
14+
import org.elasticsearch.action.support.master.AcknowledgedRequest;
15+
import org.elasticsearch.common.ParseField;
16+
import org.elasticsearch.common.io.stream.StreamInput;
17+
import org.elasticsearch.common.io.stream.StreamOutput;
18+
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
19+
import org.elasticsearch.common.xcontent.ToXContentObject;
20+
import org.elasticsearch.common.xcontent.XContentBuilder;
21+
22+
import java.io.IOException;
23+
import java.util.Arrays;
24+
import java.util.List;
25+
import java.util.Objects;
26+
27+
public class SetPolicyForIndexAction extends Action<SetPolicyForIndexAction.Request, SetPolicyForIndexAction.Response> {
28+
public static final SetPolicyForIndexAction INSTANCE = new SetPolicyForIndexAction();
29+
public static final String NAME = "indices:admin/xpack/index_lifecycle/set_policy";
30+
31+
protected SetPolicyForIndexAction() {
32+
super(NAME);
33+
}
34+
35+
@Override
36+
public SetPolicyForIndexAction.Response newResponse() {
37+
return new Response();
38+
}
39+
40+
public static class Response extends ActionResponse implements ToXContentObject {
41+
42+
public static final ParseField HAS_FAILURES_FIELD = new ParseField("has_failures");
43+
public static final ParseField FAILED_INDEXES_FIELD = new ParseField("failed_indexes");
44+
@SuppressWarnings("unchecked")
45+
public static final ConstructingObjectParser<Response, Void> PARSER = new ConstructingObjectParser<>(
46+
"change_policy_for_index_response", a -> new Response((List<String>) a[0]));
47+
static {
48+
PARSER.declareStringArray(ConstructingObjectParser.constructorArg(), FAILED_INDEXES_FIELD);
49+
// Needs to be declared but not used in constructing the response object
50+
PARSER.declareBoolean(ConstructingObjectParser.constructorArg(), HAS_FAILURES_FIELD);
51+
}
52+
53+
private List<String> failedIndexes;
54+
55+
public Response() {
56+
}
57+
58+
public Response(List<String> failedIndexes) {
59+
if (failedIndexes == null) {
60+
throw new IllegalArgumentException(FAILED_INDEXES_FIELD.getPreferredName() + " cannot be null");
61+
}
62+
this.failedIndexes = failedIndexes;
63+
}
64+
65+
public List<String> getFailedIndexes() {
66+
return failedIndexes;
67+
}
68+
69+
public boolean hasFailures() {
70+
return failedIndexes.isEmpty() == false;
71+
}
72+
73+
@Override
74+
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
75+
builder.startObject();
76+
builder.field(HAS_FAILURES_FIELD.getPreferredName(), hasFailures());
77+
builder.field(FAILED_INDEXES_FIELD.getPreferredName(), failedIndexes);
78+
builder.endObject();
79+
return builder;
80+
}
81+
82+
@Override
83+
public void readFrom(StreamInput in) throws IOException {
84+
super.readFrom(in);
85+
failedIndexes = in.readList(StreamInput::readString);
86+
}
87+
88+
@Override
89+
public void writeTo(StreamOutput out) throws IOException {
90+
super.writeTo(out);
91+
out.writeStringList(failedIndexes);
92+
}
93+
94+
@Override
95+
public int hashCode() {
96+
return Objects.hash(failedIndexes);
97+
}
98+
99+
@Override
100+
public boolean equals(Object obj) {
101+
if (obj == null) {
102+
return false;
103+
}
104+
if (getClass() != obj.getClass()) {
105+
return false;
106+
}
107+
Response other = (Response) obj;
108+
return Objects.equals(failedIndexes, other.failedIndexes);
109+
}
110+
111+
}
112+
113+
public static class Request extends AcknowledgedRequest<Request> implements IndicesRequest.Replaceable {
114+
115+
private String[] indices;
116+
private IndicesOptions indicesOptions = IndicesOptions.strictExpandOpen();
117+
private String policy;
118+
119+
public Request() {
120+
}
121+
122+
public Request(String policy, String... indices) {
123+
if (indices == null) {
124+
throw new IllegalArgumentException("indices cannot be null");
125+
}
126+
if (policy == null) {
127+
throw new IllegalArgumentException("policy cannot be null");
128+
}
129+
this.indices = indices;
130+
this.policy = policy;
131+
}
132+
133+
@Override
134+
public Request indices(String... indices) {
135+
this.indices = indices;
136+
return this;
137+
}
138+
139+
@Override
140+
public String[] indices() {
141+
return indices;
142+
}
143+
144+
public String policy() {
145+
return policy;
146+
}
147+
148+
public void indicesOptions(IndicesOptions indicesOptions) {
149+
this.indicesOptions = indicesOptions;
150+
}
151+
152+
public IndicesOptions indicesOptions() {
153+
return indicesOptions;
154+
}
155+
156+
@Override
157+
public ActionRequestValidationException validate() {
158+
return null;
159+
}
160+
161+
@Override
162+
public void readFrom(StreamInput in) throws IOException {
163+
super.readFrom(in);
164+
indices = in.readStringArray();
165+
indicesOptions = IndicesOptions.readIndicesOptions(in);
166+
policy = in.readString();
167+
}
168+
169+
@Override
170+
public void writeTo(StreamOutput out) throws IOException {
171+
super.writeTo(out);
172+
out.writeStringArray(indices);
173+
indicesOptions.writeIndicesOptions(out);
174+
out.writeString(policy);
175+
}
176+
177+
@Override
178+
public int hashCode() {
179+
return Objects.hash(Arrays.hashCode(indices), indicesOptions, policy);
180+
}
181+
182+
@Override
183+
public boolean equals(Object obj) {
184+
if (obj == null) {
185+
return false;
186+
}
187+
if (getClass() != obj.getClass()) {
188+
return false;
189+
}
190+
Request other = (Request) obj;
191+
return Objects.deepEquals(indices, other.indices) &&
192+
Objects.equals(indicesOptions, other.indicesOptions) &&
193+
Objects.equals(policy, other.policy);
194+
}
195+
196+
}
197+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
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+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
package org.elasticsearch.xpack.core.indexlifecycle.action;
8+
9+
import org.elasticsearch.action.support.IndicesOptions;
10+
import org.elasticsearch.test.AbstractStreamableTestCase;
11+
import org.elasticsearch.xpack.core.indexlifecycle.action.SetPolicyForIndexAction.Request;
12+
13+
import java.io.IOException;
14+
import java.util.Arrays;
15+
16+
public class SetPolicyForIndexRequestTests extends AbstractStreamableTestCase<SetPolicyForIndexAction.Request> {
17+
18+
@Override
19+
protected Request createTestInstance() {
20+
Request request = new Request(randomAlphaOfLength(20), generateRandomStringArray(20, 20, false));
21+
if (randomBoolean()) {
22+
IndicesOptions indicesOptions = IndicesOptions.fromOptions(randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean(),
23+
randomBoolean(), randomBoolean(), randomBoolean());
24+
request.indicesOptions(indicesOptions);
25+
}
26+
return request;
27+
}
28+
29+
@Override
30+
protected Request createBlankInstance() {
31+
return new Request();
32+
}
33+
34+
@Override
35+
protected Request mutateInstance(Request instance) throws IOException {
36+
String[] indices = instance.indices();
37+
IndicesOptions indicesOptions = instance.indicesOptions();
38+
String policy = instance.policy();
39+
switch (between(0, 2)) {
40+
case 0:
41+
indices = randomValueOtherThanMany(i -> Arrays.equals(i, instance.indices()),
42+
() -> generateRandomStringArray(20, 20, false));
43+
break;
44+
case 1:
45+
indicesOptions = randomValueOtherThan(indicesOptions, () -> IndicesOptions.fromOptions(randomBoolean(), randomBoolean(),
46+
randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean()));
47+
break;
48+
case 2:
49+
policy = randomValueOtherThan(policy, () -> randomAlphaOfLength(20));
50+
break;
51+
default:
52+
throw new AssertionError("Illegal randomisation branch");
53+
}
54+
Request newRequest = new Request(policy, indices);
55+
newRequest.indicesOptions(indicesOptions);
56+
return newRequest;
57+
}
58+
59+
public void testNullIndices() {
60+
IllegalArgumentException exception = expectThrows(IllegalArgumentException.class,
61+
() -> new Request(randomAlphaOfLength(20), (String[]) null));
62+
assertEquals("indices cannot be null", exception.getMessage());
63+
}
64+
65+
public void testNullPolicy() {
66+
IllegalArgumentException exception = expectThrows(IllegalArgumentException.class,
67+
() -> new Request(null, generateRandomStringArray(20, 20, false)));
68+
assertEquals("policy cannot be null", exception.getMessage());
69+
}
70+
71+
public void testValidate() {
72+
Request request = createTestInstance();
73+
assertNull(request.validate());
74+
}
75+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
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+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
package org.elasticsearch.xpack.core.indexlifecycle.action;
8+
9+
import org.elasticsearch.common.xcontent.XContentParser;
10+
import org.elasticsearch.test.AbstractStreamableXContentTestCase;
11+
import org.elasticsearch.xpack.core.indexlifecycle.action.SetPolicyForIndexAction.Response;
12+
13+
import java.io.IOException;
14+
import java.util.ArrayList;
15+
import java.util.Arrays;
16+
import java.util.Collections;
17+
import java.util.List;
18+
19+
public class SetPolicyForIndexResponseTests extends AbstractStreamableXContentTestCase<SetPolicyForIndexAction.Response> {
20+
21+
@Override
22+
protected Response createBlankInstance() {
23+
return new Response();
24+
}
25+
26+
@Override
27+
protected Response createTestInstance() {
28+
List<String> failedIndexes = Arrays.asList(generateRandomStringArray(20, 20, false));
29+
return new Response(failedIndexes);
30+
}
31+
32+
@Override
33+
protected Response mutateInstance(Response instance) throws IOException {
34+
List<String> failedIndices = randomValueOtherThan(instance.getFailedIndexes(),
35+
() -> Arrays.asList(generateRandomStringArray(20, 20, false)));
36+
return new Response(failedIndices);
37+
}
38+
39+
@Override
40+
protected Response doParseInstance(XContentParser parser) throws IOException {
41+
return Response.PARSER.apply(parser, null);
42+
}
43+
44+
@Override
45+
protected boolean supportsUnknownFields() {
46+
return false;
47+
}
48+
49+
public void testNullFailedIndices() {
50+
IllegalArgumentException exception = expectThrows(IllegalArgumentException.class, () -> new Response((List<String>) null));
51+
assertEquals("failed_indexes cannot be null", exception.getMessage());
52+
}
53+
54+
public void testHasFailures() {
55+
Response response = new Response(new ArrayList<>());
56+
assertFalse(response.hasFailures());
57+
assertEquals(Collections.emptyList(), response.getFailedIndexes());
58+
59+
int size = randomIntBetween(1, 10);
60+
List<String> failedIndexes = new ArrayList<>(size);
61+
for (int i = 0; i < size; i++) {
62+
failedIndexes.add(randomAlphaOfLength(20));
63+
}
64+
response = new Response(failedIndexes);
65+
assertTrue(response.hasFailures());
66+
assertEquals(failedIndexes, response.getFailedIndexes());
67+
}
68+
69+
}

x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycle.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,18 +34,21 @@
3434
import org.elasticsearch.xpack.core.XPackSettings;
3535
import org.elasticsearch.xpack.core.indexlifecycle.LifecycleSettings;
3636
import org.elasticsearch.xpack.core.indexlifecycle.RolloverAction;
37+
import org.elasticsearch.xpack.core.indexlifecycle.action.SetPolicyForIndexAction;
3738
import org.elasticsearch.xpack.core.indexlifecycle.action.DeleteLifecycleAction;
3839
import org.elasticsearch.xpack.core.indexlifecycle.action.ExplainLifecycleAction;
3940
import org.elasticsearch.xpack.core.indexlifecycle.action.GetLifecycleAction;
4041
import org.elasticsearch.xpack.core.indexlifecycle.action.MoveToStepAction;
4142
import org.elasticsearch.xpack.core.indexlifecycle.action.PutLifecycleAction;
4243
import org.elasticsearch.xpack.core.indexlifecycle.action.RetryAction;
44+
import org.elasticsearch.xpack.indexlifecycle.action.RestSetPolicyForIndexAction;
4345
import org.elasticsearch.xpack.indexlifecycle.action.RestDeleteLifecycleAction;
4446
import org.elasticsearch.xpack.indexlifecycle.action.RestExplainLifecycleAction;
4547
import org.elasticsearch.xpack.indexlifecycle.action.RestGetLifecycleAction;
4648
import org.elasticsearch.xpack.indexlifecycle.action.RestMoveToStepAction;
4749
import org.elasticsearch.xpack.indexlifecycle.action.RestPutLifecycleAction;
4850
import org.elasticsearch.xpack.indexlifecycle.action.RestRetryAction;
51+
import org.elasticsearch.xpack.indexlifecycle.action.TransportSetPolicyForIndexAction;
4952
import org.elasticsearch.xpack.indexlifecycle.action.TransportDeleteLifcycleAction;
5053
import org.elasticsearch.xpack.indexlifecycle.action.TransportExplainLifecycleAction;
5154
import org.elasticsearch.xpack.indexlifecycle.action.TransportGetLifecycleAction;
@@ -147,6 +150,7 @@ public List<RestHandler> getRestHandlers(Settings settings, RestController restC
147150
new RestGetLifecycleAction(settings, restController),
148151
new RestDeleteLifecycleAction(settings, restController),
149152
new RestExplainLifecycleAction(settings, restController),
153+
new RestSetPolicyForIndexAction(settings, restController),
150154
new RestMoveToStepAction(settings, restController),
151155
new RestRetryAction(settings, restController)
152156
);
@@ -162,6 +166,7 @@ public List<RestHandler> getRestHandlers(Settings settings, RestController restC
162166
new ActionHandler<>(GetLifecycleAction.INSTANCE, TransportGetLifecycleAction.class),
163167
new ActionHandler<>(DeleteLifecycleAction.INSTANCE, TransportDeleteLifcycleAction.class),
164168
new ActionHandler<>(ExplainLifecycleAction.INSTANCE, TransportExplainLifecycleAction.class),
169+
new ActionHandler<>(SetPolicyForIndexAction.INSTANCE, TransportSetPolicyForIndexAction.class),
165170
new ActionHandler<>(MoveToStepAction.INSTANCE, TransportMoveToStepAction.class),
166171
new ActionHandler<>(RetryAction.INSTANCE, TransportRetryAction.class));
167172
}

0 commit comments

Comments
 (0)