Skip to content

Commit 36f2705

Browse files
authored
[7.x] Add descriptions parameter for listing tasks (#70759) (#70982)
* Add descriptions parameter for listing tasks (#70759) This commit adds a new `descriptions` parameter for listing tasks in the transport layer. This allows tasks to be filtered by `actions` and `descriptions` so that matching specific tasks within a particular action is possible. related to: #70008
1 parent 4afbf45 commit 36f2705

File tree

4 files changed

+172
-0
lines changed

4 files changed

+172
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
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.action.admin.cluster.tasks;
10+
11+
import org.elasticsearch.action.ActionRequestValidationException;
12+
import org.elasticsearch.test.ESIntegTestCase;
13+
14+
import static org.hamcrest.Matchers.containsString;
15+
import static org.hamcrest.Matchers.empty;
16+
import static org.hamcrest.Matchers.is;
17+
import static org.hamcrest.Matchers.not;
18+
19+
public class ListTasksIT extends ESIntegTestCase {
20+
21+
public void testListTasksFilteredByDescription() {
22+
23+
// The list tasks action itself is filtered out via this description filter
24+
assertThat(
25+
client().admin().cluster().prepareListTasks().setDetailed(true).setDescriptions("match_nothing*").get().getTasks(),
26+
is(empty())
27+
);
28+
29+
// The list tasks action itself is kept via this description filter which matches everything
30+
assertThat(
31+
client().admin().cluster().prepareListTasks().setDetailed(true).setDescriptions("*").get().getTasks(),
32+
is(not(empty()))
33+
);
34+
35+
}
36+
37+
public void testListTasksValidation() {
38+
39+
ActionRequestValidationException ex = expectThrows(
40+
ActionRequestValidationException.class,
41+
() -> client().admin().cluster().prepareListTasks().setDescriptions("*").get()
42+
);
43+
assertThat(ex.getMessage(), containsString("matching on descriptions is not available when [detailed] is false"));
44+
45+
}
46+
}

server/src/main/java/org/elasticsearch/action/admin/cluster/node/tasks/list/ListTasksRequest.java

+51
Original file line numberDiff line numberDiff line change
@@ -8,34 +8,68 @@
88

99
package org.elasticsearch.action.admin.cluster.node.tasks.list;
1010

11+
import org.elasticsearch.Version;
12+
import org.elasticsearch.action.ActionRequestValidationException;
1113
import org.elasticsearch.action.support.tasks.BaseTasksRequest;
14+
import org.elasticsearch.common.Strings;
1215
import org.elasticsearch.common.io.stream.StreamInput;
1316
import org.elasticsearch.common.io.stream.StreamOutput;
17+
import org.elasticsearch.tasks.Task;
1418

1519
import java.io.IOException;
1620

21+
import static org.elasticsearch.common.regex.Regex.simpleMatch;
22+
import static org.elasticsearch.action.ValidateActions.addValidationError;
23+
import static org.elasticsearch.common.util.CollectionUtils.isEmpty;
24+
1725
/**
1826
* A request to get node tasks
1927
*/
2028
public class ListTasksRequest extends BaseTasksRequest<ListTasksRequest> {
2129

30+
public static final String[] ANY_DESCRIPTION = Strings.EMPTY_ARRAY;
31+
2232
private boolean detailed = false;
2333
private boolean waitForCompletion = false;
2434

35+
private String[] descriptions = ANY_DESCRIPTION;
36+
2537
public ListTasksRequest() {
2638
}
2739

2840
public ListTasksRequest(StreamInput in) throws IOException {
2941
super(in);
3042
detailed = in.readBoolean();
3143
waitForCompletion = in.readBoolean();
44+
if (in.getVersion().onOrAfter(Version.V_7_13_0)) {
45+
descriptions = in.readStringArray();
46+
}
3247
}
3348

3449
@Override
3550
public void writeTo(StreamOutput out) throws IOException {
3651
super.writeTo(out);
3752
out.writeBoolean(detailed);
3853
out.writeBoolean(waitForCompletion);
54+
if (out.getVersion().onOrAfter(Version.V_7_13_0)) {
55+
out.writeStringArray(descriptions);
56+
}
57+
}
58+
59+
@Override
60+
public ActionRequestValidationException validate() {
61+
ActionRequestValidationException validationException = super.validate();
62+
if (descriptions.length > 0 && detailed == false) {
63+
validationException = addValidationError("matching on descriptions is not available when [detailed] is false",
64+
validationException);
65+
}
66+
return validationException;
67+
}
68+
69+
@Override
70+
public boolean match(Task task) {
71+
return super.match(task)
72+
&& (isEmpty(getDescriptions()) || simpleMatch(getDescriptions(), task.getDescription()));
3973
}
4074

4175
/**
@@ -68,4 +102,21 @@ public ListTasksRequest setWaitForCompletion(boolean waitForCompletion) {
68102
return this;
69103
}
70104

105+
/**
106+
* Description patters on which to match.
107+
*
108+
* If other matching criteria are set, descriptions are matched last once other criteria are satisfied
109+
*
110+
* Matching on descriptions is only available if `detailed` is `true`.
111+
* @return array of absolute or simple wildcard matching strings
112+
*/
113+
public String[] getDescriptions() {
114+
return descriptions;
115+
}
116+
117+
public ListTasksRequest setDescriptions(String... descriptions) {
118+
this.descriptions = descriptions;
119+
return this;
120+
}
121+
71122
}

server/src/main/java/org/elasticsearch/action/admin/cluster/node/tasks/list/ListTasksRequestBuilder.java

+12
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,16 @@ public final ListTasksRequestBuilder setWaitForCompletion(boolean waitForComplet
3535
request.setWaitForCompletion(waitForCompletion);
3636
return this;
3737
}
38+
39+
/**
40+
* Should the task match specific descriptions.
41+
*
42+
* Cannot be used unless {@link ListTasksRequestBuilder#setDetailed(boolean)} is `true`
43+
* @param descriptions string array containing simple regex or absolute description matching
44+
* @return the builder with descriptions set
45+
*/
46+
public final ListTasksRequestBuilder setDescriptions(String... descriptions) {
47+
request.setDescriptions(descriptions);
48+
return this;
49+
}
3850
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
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.action.admin.cluster.node.tasks.list;
10+
11+
import org.elasticsearch.action.ActionRequestValidationException;
12+
import org.elasticsearch.tasks.Task;
13+
import org.elasticsearch.tasks.TaskId;
14+
import org.elasticsearch.test.ESTestCase;
15+
16+
import java.util.Collections;
17+
18+
import static org.hamcrest.Matchers.is;
19+
import static org.hamcrest.Matchers.not;
20+
import static org.hamcrest.Matchers.nullValue;
21+
22+
public class ListTasksRequestTests extends ESTestCase {
23+
24+
public void testValidation() {
25+
ActionRequestValidationException ex = new ListTasksRequest().setDescriptions("foo*").validate();
26+
assertThat(ex, is(not(nullValue())));
27+
28+
ex = new ListTasksRequest().setDescriptions("foo*").setDetailed(true).validate();
29+
assertThat(ex, is(nullValue()));
30+
}
31+
32+
public void testMatch() {
33+
ListTasksRequest filterOnDescription = new ListTasksRequest().setDescriptions("foo*", "*bar", "absolute").setActions("my_action*");
34+
35+
assertTrue(filterOnDescription.match(taskWithActionDescription("my_action_foo", "foo_action")));
36+
assertTrue(filterOnDescription.match(taskWithActionDescription("my_action_bar", "absolute")));
37+
assertTrue(filterOnDescription.match(taskWithActionDescription("my_action_baz", "action_bar")));
38+
39+
assertFalse(filterOnDescription.match(taskWithActionDescription("my_action_foo", "not_wanted")));
40+
assertFalse(filterOnDescription.match(taskWithActionDescription("not_wanted_action", "foo_action")));
41+
42+
43+
ListTasksRequest notFilterOnDescription = new ListTasksRequest().setActions("my_action*");
44+
assertTrue(notFilterOnDescription.match(taskWithActionDescription("my_action_foo", "foo_action")));
45+
assertTrue(notFilterOnDescription.match(taskWithActionDescription("my_action_bar", "absolute")));
46+
assertTrue(notFilterOnDescription.match(taskWithActionDescription("my_action_baz", "action_bar")));
47+
assertTrue(notFilterOnDescription.match(taskWithActionDescription("my_action_baz", randomAlphaOfLength(10))));
48+
49+
assertFalse(notFilterOnDescription.match(taskWithActionDescription("not_wanted_action", randomAlphaOfLength(10))));
50+
}
51+
52+
private static Task taskWithActionDescription(String action, String description) {
53+
return new Task(
54+
randomNonNegativeLong(),
55+
randomAlphaOfLength(10),
56+
action,
57+
description,
58+
new TaskId("test_node", randomNonNegativeLong()),
59+
Collections.emptyMap()
60+
);
61+
}
62+
63+
}

0 commit comments

Comments
 (0)