Skip to content

Add option to filter ILM explain response #44777

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jul 25, 2019
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
9 changes: 9 additions & 0 deletions docs/reference/ilm/apis/explain.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,15 @@ about any failures.

==== Request Parameters

`only_managed`::
(boolean) Filters the returned indices to only indices that are managed by
ILM.

`only_errors`::
(boolean) Filters the returned indices to only indices that are managed by
ILM and are in an error state, either due to an encountering an error while
executing the policy, or attempting to use a policy that does not exist.

include::{docdir}/rest-api/timeoutparms.asciidoc[]

==== Authorization
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@

package org.elasticsearch.xpack.core.indexlifecycle;

import org.elasticsearch.Version;
import org.elasticsearch.action.ActionRequestValidationException;
import org.elasticsearch.action.support.master.info.ClusterInfoRequest;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;

import java.io.IOException;
import java.util.Arrays;
Expand All @@ -21,13 +23,48 @@
* {@link #indices(String...)} method
*/
public class ExplainLifecycleRequest extends ClusterInfoRequest<ExplainLifecycleRequest> {
private static final Version FILTERS_INTRODUCED_VERSION = Version.V_8_0_0;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: Update this in the backport and in master after merging the backport.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the serialization version in a76242d now that the backport has been merged.


private boolean onlyErrors = false;
private boolean onlyManaged = false;

public ExplainLifecycleRequest() {
super();
}

public ExplainLifecycleRequest(StreamInput in) throws IOException {
super(in);
if (in.getVersion().onOrAfter(FILTERS_INTRODUCED_VERSION)) {
onlyErrors = in.readBoolean();
onlyManaged = in.readBoolean();
}
}

@Override
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
if (out.getVersion().onOrAfter(FILTERS_INTRODUCED_VERSION)) {
out.writeBoolean(onlyErrors);
out.writeBoolean(onlyManaged);
}
}

public boolean onlyErrors() {
return onlyErrors;
}

public ExplainLifecycleRequest onlyErrors(boolean onlyErrors) {
this.onlyErrors = onlyErrors;
return this;
}

public boolean onlyManaged() {
return onlyManaged;
}

public ExplainLifecycleRequest onlyManaged(boolean onlyManaged) {
this.onlyManaged = onlyManaged;
return this;
}

@Override
Expand All @@ -37,7 +74,7 @@ public ActionRequestValidationException validate() {

@Override
public int hashCode() {
return Objects.hash(Arrays.hashCode(indices()), indicesOptions());
return Objects.hash(Arrays.hashCode(indices()), indicesOptions(), onlyErrors, onlyManaged);
}

@Override
Expand All @@ -50,12 +87,15 @@ public boolean equals(Object obj) {
}
ExplainLifecycleRequest other = (ExplainLifecycleRequest) obj;
return Objects.deepEquals(indices(), other.indices()) &&
Objects.equals(indicesOptions(), other.indicesOptions());
Objects.equals(indicesOptions(), other.indicesOptions()) &&
Objects.equals(onlyErrors(), other.onlyErrors()) &&
Objects.equals(onlyManaged(), other.onlyManaged());
}

@Override
public String toString() {
return "ExplainLifecycleRequest [indices()=" + Arrays.toString(indices()) + ", indicesOptions()=" + indicesOptions() + "]";
return "ExplainLifecycleRequest [indices()=" + Arrays.toString(indices()) + ", indicesOptions()=" + indicesOptions() +
", onlyErrors()=" + onlyErrors() + ", onlyManaged()=" + onlyManaged() + "]";
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -26,28 +26,44 @@ protected ExplainLifecycleRequest createTestInstance() {
randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean());
request.indicesOptions(indicesOptions);
}
if (randomBoolean()) {
request.onlyErrors(randomBoolean());
}
if (randomBoolean()) {
request.onlyManaged(randomBoolean());
}
return request;
}

@Override
protected ExplainLifecycleRequest mutateInstance(ExplainLifecycleRequest instance) throws IOException {
String[] indices = instance.indices();
IndicesOptions indicesOptions = instance.indicesOptions();
switch (between(0, 1)) {
case 0:
indices = randomValueOtherThanMany(i -> Arrays.equals(i, instance.indices()),
boolean onlyErrors = instance.onlyErrors();
boolean onlyManaged = instance.onlyManaged();
switch (between(0, 3)) {
case 0:
indices = randomValueOtherThanMany(i -> Arrays.equals(i, instance.indices()),
() -> generateRandomStringArray(20, 10, false, false));
break;
case 1:
indicesOptions = randomValueOtherThan(indicesOptions, () -> IndicesOptions.fromOptions(randomBoolean(), randomBoolean(),
break;
case 1:
indicesOptions = randomValueOtherThan(indicesOptions, () -> IndicesOptions.fromOptions(randomBoolean(), randomBoolean(),
randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean()));
break;
default:
throw new AssertionError("Illegal randomisation branch");
break;
case 2:
onlyErrors = !onlyErrors;
break;
case 3:
onlyManaged = !onlyManaged;
break;
default:
throw new AssertionError("Illegal randomisation branch");
}
ExplainLifecycleRequest newRequest = new ExplainLifecycleRequest();
newRequest.indices(indices);
newRequest.indicesOptions(indicesOptions);
newRequest.onlyErrors(onlyErrors);
newRequest.onlyManaged(onlyManaged);
return newRequest;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,11 @@

import static java.util.Collections.singletonMap;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.hasKey;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue;

Expand Down Expand Up @@ -829,6 +831,45 @@ public void testCanStopILMWithPolicyUsingNonexistentPolicy() throws Exception {
assertOK(client().performRequest(startILMReqest));
}

public void testExplainFilters() throws Exception {
String goodIndex = index + "-good-000001";
String errorIndex = index + "-error";
String nonexistantPolicyIndex = index + "-nonexistant-policy";
String unmanagedIndex = index + "-unmanaged";

createFullPolicy(TimeValue.ZERO);

createIndexWithSettings(goodIndex, Settings.builder()
.put(RolloverAction.LIFECYCLE_ROLLOVER_ALIAS, "alias")
.put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, 0)
.put(LifecycleSettings.LIFECYCLE_NAME, policy));
createIndexWithSettingsNoAlias(errorIndex, Settings.builder()
.put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, 0)
.put(LifecycleSettings.LIFECYCLE_NAME, policy));
createIndexWithSettingsNoAlias(nonexistantPolicyIndex, Settings.builder()
.put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, 0)
.put(LifecycleSettings.LIFECYCLE_NAME, randomValueOtherThan(policy, () -> randomAlphaOfLengthBetween(3,10))));
createIndexWithSettingsNoAlias(unmanagedIndex, Settings.builder()
.put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, 0));

assertBusy(() -> {
Map<String, Map<String, Object>> explainResponse = explain(index + "*", false, false);
assertNotNull(explainResponse);
assertThat(explainResponse,
allOf(hasKey(goodIndex), hasKey(errorIndex), hasKey(nonexistantPolicyIndex), hasKey(unmanagedIndex)));

Map<String, Map<String, Object>> onlyManagedResponse = explain(index + "*", false, true);
assertNotNull(onlyManagedResponse);
assertThat(onlyManagedResponse, allOf(hasKey(goodIndex), hasKey(errorIndex), hasKey(nonexistantPolicyIndex)));
assertThat(onlyManagedResponse, not(hasKey(unmanagedIndex)));

Map<String, Map<String, Object>> onlyErrorsResponse = explain(index + "*", true, randomBoolean());
assertNotNull(onlyErrorsResponse);
assertThat(onlyErrorsResponse, allOf(hasKey(errorIndex), hasKey(nonexistantPolicyIndex)));
assertThat(onlyErrorsResponse, allOf(not(hasKey(goodIndex)), not(hasKey(unmanagedIndex))));
});
}

private void createFullPolicy(TimeValue hotTime) throws IOException {
Map<String, LifecycleAction> hotActions = new HashMap<>();
hotActions.put(SetPriorityAction.NAME, new SetPriorityAction(100));
Expand Down Expand Up @@ -948,15 +989,21 @@ private String getReasonForIndex(String indexName) throws IOException {
}

private Map<String, Object> explainIndex(String indexName) throws IOException {
Request explainRequest = new Request("GET", indexName + "/_ilm/explain");
return explain(indexName, false, false).get(indexName);
}

private Map<String, Map<String, Object>> explain(String indexPattern, boolean onlyErrors, boolean onlyManaged) throws IOException {
Request explainRequest = new Request("GET", indexPattern + "/_ilm/explain");
explainRequest.addParameter("only_errors", Boolean.toString(onlyErrors));
explainRequest.addParameter("only_managed", Boolean.toString(onlyManaged));
Response response = client().performRequest(explainRequest);
Map<String, Object> responseMap;
try (InputStream is = response.getEntity().getContent()) {
responseMap = XContentHelper.convertToMap(XContentType.JSON.xContent(), is, true);
}

@SuppressWarnings("unchecked") Map<String, Object> indexResponse = ((Map<String, Map<String, Object>>) responseMap.get("indices"))
.get(indexName);
@SuppressWarnings("unchecked") Map<String, Map<String, Object>> indexResponse =
((Map<String, Map<String, Object>>) responseMap.get("indices"));
return indexResponse;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ setup:
- do:
indices.create:
index: my_index_no_policy
- do:
indices.create:
index: index_with_policy_that_doesnt_exist
body:
settings:
index.lifecycle.name: "a_policy_that_doesnt_exist"

---
teardown:
Expand All @@ -81,6 +87,10 @@ teardown:
indices.delete:
index: my_index_no_policy

- do:
indices.delete:
index: index_with_policy_that_doesnt_exist

- do:
ilm.delete_lifecycle:
policy: "my_moveable_timeseries_lifecycle"
Expand Down Expand Up @@ -112,6 +122,7 @@ teardown:
- is_false: indices.my_index2
- is_false: indices.another_index
- is_false: indices.unmanaged_index
- is_false: indices.index_with_policy_that_doesnt_exist

---
"Test Wildcard Index Lifecycle Explain":
Expand Down Expand Up @@ -146,6 +157,7 @@ teardown:

- is_false: indices.another_index
- is_false: indices.unmanaged_index
- is_false: indices.index_with_policy_that_doesnt_exist


---
Expand Down Expand Up @@ -201,6 +213,16 @@ teardown:
- is_false: indices.another_index.failed_step
- is_false: indices.another_index.step_info

- match: { indices.index_with_policy_that_doesnt_exist.index: "index_with_policy_that_doesnt_exist" }
- match: { indices.index_with_policy_that_doesnt_exist.policy: "a_policy_that_doesnt_exist" }
- match: { indices.index_with_policy_that_doesnt_exist.step_info.reason: "policy [a_policy_that_doesnt_exist] does not exist" }
- is_true: indices.index_with_policy_that_doesnt_exist.managed
- is_false: indices.index_with_policy_that_doesnt_exist.phase
- is_false: indices.index_with_policy_that_doesnt_exist.action
- is_false: indices.index_with_policy_that_doesnt_exist.step
- is_false: indices.index_with_policy_that_doesnt_exist.age
- is_false: indices.index_with_policy_that_doesnt_exist.failed_step

---
"Test Unmanaged Index Lifecycle Explain":

Expand All @@ -221,3 +243,34 @@ teardown:
- is_false: indices.my_index
- is_false: indices.my_index2
- is_false: indices.another_index
- is_false: indices.index_with_policy_that_doesnt_exist

---
"Test filter for only managed indices":

- do:
ilm.explain_lifecycle:
index: "*"
only_managed: true

- match: { indices.my_index.index: "my_index" }
- match: { indices.my_index2.index: "my_index2" }
- match: { indices.another_index.index: "another_index" }
- match: { indices.index_with_policy_that_doesnt_exist.index: "index_with_policy_that_doesnt_exist" }
- is_false: indices.unmanaged_index
- is_false: indices.my_index_no_policy

---
"Test filter for only error indices":

- do:
ilm.explain_lifecycle:
index: "*"
only_errors: true

- match: { indices.index_with_policy_that_doesnt_exist.index: "index_with_policy_that_doesnt_exist" }
- is_false: indices.unmanaged_index
- is_false: indices.my_index_no_policy
- is_false: indices.my_index
- is_false: indices.my_index2
- is_false: indices.another_index
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,10 @@ public void triggered(SchedulerEngine.Event event) {
}
}

public boolean policyExists(String policyId) {
return policyRegistry.policyExists(policyId);
}

/**
* executes the policy execution on the appropriate indices by running cluster-state tasks per index.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@
import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.xpack.core.indexlifecycle.ExplainLifecycleRequest;
import org.elasticsearch.rest.BaseRestHandler;
import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.rest.action.RestToXContentListener;
import org.elasticsearch.xpack.core.indexlifecycle.ExplainLifecycleRequest;
import org.elasticsearch.xpack.core.indexlifecycle.action.ExplainLifecycleAction;

import java.io.IOException;
Expand All @@ -37,6 +37,8 @@ protected RestChannelConsumer prepareRequest(RestRequest restRequest, NodeClient
ExplainLifecycleRequest explainLifecycleRequest = new ExplainLifecycleRequest();
explainLifecycleRequest.indices(indexes);
explainLifecycleRequest.indicesOptions(IndicesOptions.fromRequest(restRequest, IndicesOptions.strictExpandOpen()));
explainLifecycleRequest.onlyManaged(restRequest.paramAsBoolean("only_managed", false));
explainLifecycleRequest.onlyErrors(restRequest.paramAsBoolean("only_errors", false));
String masterNodeTimeout = restRequest.param("master_timeout");
if (masterNodeTimeout != null) {
explainLifecycleRequest.masterNodeTimeout(masterNodeTimeout);
Expand Down
Loading