Fix HLRC parsing of CancelTasks response (#47017)

Adds support for proper cancel tasks parsing.

Closes #45414
This commit is contained in:
jesinity 2019-11-22 21:35:09 +01:00 committed by Michael Basnight
parent 2ec047db04
commit c9eba17517
19 changed files with 1642 additions and 52 deletions

View File

@ -53,6 +53,7 @@ import org.elasticsearch.client.core.MultiTermVectorsRequest;
import org.elasticsearch.client.core.TermVectorsRequest; import org.elasticsearch.client.core.TermVectorsRequest;
import org.elasticsearch.client.indices.AnalyzeRequest; import org.elasticsearch.client.indices.AnalyzeRequest;
import org.elasticsearch.client.security.RefreshPolicy; import org.elasticsearch.client.security.RefreshPolicy;
import org.elasticsearch.client.tasks.TaskId;
import org.elasticsearch.cluster.health.ClusterHealthStatus; import org.elasticsearch.cluster.health.ClusterHealthStatus;
import org.elasticsearch.common.Nullable; import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.Priority; import org.elasticsearch.common.Priority;
@ -81,13 +82,13 @@ import org.elasticsearch.rest.action.search.RestSearchAction;
import org.elasticsearch.script.mustache.MultiSearchTemplateRequest; import org.elasticsearch.script.mustache.MultiSearchTemplateRequest;
import org.elasticsearch.script.mustache.SearchTemplateRequest; import org.elasticsearch.script.mustache.SearchTemplateRequest;
import org.elasticsearch.search.fetch.subphase.FetchSourceContext; import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
import org.elasticsearch.tasks.TaskId;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
@ -1041,19 +1042,41 @@ final class RequestConverters {
} }
Params withNodes(String[] nodes) { Params withNodes(String[] nodes) {
if (nodes != null && nodes.length > 0) { return withNodes(Arrays.asList(nodes));
}
Params withNodes(List<String> nodes) {
if (nodes != null && nodes.size() > 0) {
return putParam("nodes", String.join(",", nodes)); return putParam("nodes", String.join(",", nodes));
} }
return this; return this;
} }
Params withActions(String[] actions) { Params withActions(String[] actions) {
if (actions != null && actions.length > 0) { return withActions(Arrays.asList(actions));
}
Params withActions(List<String> actions) {
if (actions != null && actions.size() > 0) {
return putParam("actions", String.join(",", actions)); return putParam("actions", String.join(",", actions));
} }
return this; return this;
} }
Params withTaskId(org.elasticsearch.tasks.TaskId taskId) {
if (taskId != null && taskId.isSet()) {
return putParam("task_id", taskId.toString());
}
return this;
}
Params withParentTaskId(org.elasticsearch.tasks.TaskId parentTaskId) {
if (parentTaskId != null && parentTaskId.isSet()) {
return putParam("parent_task_id", parentTaskId.toString());
}
return this;
}
Params withTaskId(TaskId taskId) { Params withTaskId(TaskId taskId) {
if (taskId != null && taskId.isSet()) { if (taskId != null && taskId.isSet()) {
return putParam("task_id", taskId.toString()); return putParam("task_id", taskId.toString());

View File

@ -20,10 +20,10 @@
package org.elasticsearch.client; package org.elasticsearch.client;
import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.admin.cluster.node.tasks.cancel.CancelTasksRequest;
import org.elasticsearch.action.admin.cluster.node.tasks.cancel.CancelTasksResponse;
import org.elasticsearch.action.admin.cluster.node.tasks.list.ListTasksRequest; import org.elasticsearch.action.admin.cluster.node.tasks.list.ListTasksRequest;
import org.elasticsearch.action.admin.cluster.node.tasks.list.ListTasksResponse; import org.elasticsearch.action.admin.cluster.node.tasks.list.ListTasksResponse;
import org.elasticsearch.client.tasks.CancelTasksRequest;
import org.elasticsearch.client.tasks.CancelTasksResponse;
import org.elasticsearch.client.tasks.GetTaskRequest; import org.elasticsearch.client.tasks.GetTaskRequest;
import org.elasticsearch.client.tasks.GetTaskResponse; import org.elasticsearch.client.tasks.GetTaskResponse;

View File

@ -21,23 +21,24 @@ package org.elasticsearch.client;
import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPost;
import org.elasticsearch.action.admin.cluster.node.tasks.cancel.CancelTasksRequest;
import org.elasticsearch.action.admin.cluster.node.tasks.list.ListTasksRequest; import org.elasticsearch.action.admin.cluster.node.tasks.list.ListTasksRequest;
import org.elasticsearch.client.RequestConverters.EndpointBuilder; import org.elasticsearch.client.RequestConverters.EndpointBuilder;
import org.elasticsearch.client.tasks.CancelTasksRequest;
import org.elasticsearch.client.tasks.GetTaskRequest; import org.elasticsearch.client.tasks.GetTaskRequest;
final class TasksRequestConverters { final class TasksRequestConverters {
private TasksRequestConverters() {} private TasksRequestConverters() {}
static Request cancelTasks(CancelTasksRequest cancelTasksRequest) { static Request cancelTasks(CancelTasksRequest req) {
Request request = new Request(HttpPost.METHOD_NAME, "/_tasks/_cancel"); Request request = new Request(HttpPost.METHOD_NAME, "/_tasks/_cancel");
RequestConverters.Params params = new RequestConverters.Params(); RequestConverters.Params params = new RequestConverters.Params();
params.withTimeout(cancelTasksRequest.getTimeout()) req.getTimeout().ifPresent(params::withTimeout);
.withTaskId(cancelTasksRequest.getTaskId()) req.getTaskId().ifPresent(params::withTaskId);
.withNodes(cancelTasksRequest.getNodes()) req.getParentTaskId().ifPresent(params::withParentTaskId);
.withParentTaskId(cancelTasksRequest.getParentTaskId()) params
.withActions(cancelTasksRequest.getActions()); .withNodes(req.getNodes())
.withActions(req.getActions());
request.addParameters(params.asMap()); request.addParameters(params.asMap());
return request; return request;
} }

View File

@ -0,0 +1,151 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.client.tasks;
import org.elasticsearch.client.Validatable;
import org.elasticsearch.common.unit.TimeValue;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
public class CancelTasksRequest implements Validatable {
private final List<String> nodes = new ArrayList<>();
private final List<String> actions = new ArrayList<>();
private Optional<TimeValue> timeout = Optional.empty();
private Optional<TaskId> parentTaskId = Optional.empty();
private Optional<TaskId> taskId = Optional.empty();
CancelTasksRequest(){}
void setNodes(List<String> nodes) {
this.nodes.addAll(nodes);
}
public List<String> getNodes() {
return nodes;
}
void setTimeout(TimeValue timeout) {
this.timeout = Optional.of(timeout);
}
public Optional<TimeValue> getTimeout() {
return timeout;
}
void setActions(List<String> actions) {
this.actions.addAll(actions);
}
public List<String> getActions() {
return actions;
}
void setParentTaskId(TaskId parentTaskId) {
this.parentTaskId = Optional.of(parentTaskId);
}
public Optional<TaskId> getParentTaskId() {
return parentTaskId;
}
void setTaskId(TaskId taskId) {
this.taskId = Optional.of(taskId);
}
public Optional<TaskId> getTaskId() {
return taskId;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof CancelTasksRequest)) return false;
CancelTasksRequest that = (CancelTasksRequest) o;
return Objects.equals(getNodes(), that.getNodes()) &&
Objects.equals(getActions(), that.getActions()) &&
Objects.equals(getTimeout(), that.getTimeout()) &&
Objects.equals(getParentTaskId(), that.getParentTaskId()) &&
Objects.equals(getTaskId(), that.getTaskId()) ;
}
@Override
public int hashCode() {
return Objects.hash(getNodes(), getActions(), getTimeout(), getParentTaskId(), getTaskId());
}
@Override
public String toString() {
return "CancelTasksRequest{" +
"nodes=" + nodes +
", actions=" + actions +
", timeout=" + timeout +
", parentTaskId=" + parentTaskId +
", taskId=" + taskId +
'}';
}
public static class Builder {
private Optional<TimeValue> timeout = Optional.empty();
private Optional<TaskId> taskId = Optional.empty();
private Optional<TaskId> parentTaskId = Optional.empty();
private List<String> actionsFilter = new ArrayList<>();
private List<String> nodesFilter = new ArrayList<>();
public Builder withTimeout(TimeValue timeout){
this.timeout = Optional.of(timeout);
return this;
}
public Builder withTaskId(TaskId taskId){
this.taskId = Optional.of(taskId);
return this;
}
public Builder withParentTaskId(TaskId taskId){
this.parentTaskId = Optional.of(taskId);
return this;
}
public Builder withActionsFiltered(List<String> actions){
this.actionsFilter.clear();
this.actionsFilter.addAll(actions);
return this;
}
public Builder withNodesFiltered(List<String> nodes){
this.nodesFilter.clear();
this.nodesFilter.addAll(nodes);
return this;
}
public CancelTasksRequest build() {
CancelTasksRequest request = new CancelTasksRequest();
timeout.ifPresent(request::setTimeout);
taskId.ifPresent(request::setTaskId);
parentTaskId.ifPresent(request::setParentTaskId);
request.setNodes(nodesFilter);
request.setActions(actionsFilter);
return request;
}
}
}

View File

@ -0,0 +1,91 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.client.tasks;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
import org.elasticsearch.common.xcontent.XContentParser;
import java.io.IOException;
import java.util.List;
import static org.elasticsearch.common.xcontent.ConstructingObjectParser.optionalConstructorArg;
/**
* cancel tasks response that contains
* - task failures
* - node failures
* - tasks
*/
public class CancelTasksResponse extends ListTasksResponse {
CancelTasksResponse(List<NodeData> nodesInfoData,
List<TaskOperationFailure> taskFailures,
List<ElasticsearchException> nodeFailures) {
super(nodesInfoData, taskFailures, nodeFailures);
}
public static CancelTasksResponse fromXContent(final XContentParser parser) throws IOException {
return PARSER.parse(parser, null);
}
private static ConstructingObjectParser<CancelTasksResponse, Void> PARSER;
static {
ConstructingObjectParser<CancelTasksResponse, Void> parser = new ConstructingObjectParser<>("cancel_tasks_response", true,
constructingObjects -> {
int i = 0;
@SuppressWarnings("unchecked")
List<TaskOperationFailure> tasksFailures = (List<TaskOperationFailure>) constructingObjects[i++];
@SuppressWarnings("unchecked")
List<ElasticsearchException> nodeFailures = (List<ElasticsearchException>) constructingObjects[i++];
@SuppressWarnings("unchecked")
List<NodeData> nodesInfoData = (List<NodeData>) constructingObjects[i];
return new CancelTasksResponse(nodesInfoData, tasksFailures, nodeFailures);
});
parser.declareObjectArray(optionalConstructorArg(), (p, c) ->
TaskOperationFailure.fromXContent(p), new ParseField("task_failures"));
parser.declareObjectArray(optionalConstructorArg(), (p, c) ->
ElasticsearchException.fromXContent(p), new ParseField("node_failures"));
parser.declareNamedObjects(optionalConstructorArg(), NodeData.PARSER, new ParseField("nodes"));
PARSER = parser;
}
@Override
public boolean equals(Object o) {
return super.equals(o);
}
@Override
public int hashCode() {
return super.hashCode();
}
@Override
public String toString() {
return "CancelTasksResponse{" +
"taskFailures=" + taskFailures +
", nodeFailures=" + nodeFailures +
", nodesInfoData=" + nodesInfoData +
", tasks=" + tasks +
", taskGroups=" + taskGroups +
'}';
}
}

View File

@ -0,0 +1,225 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.client.tasks;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.xcontent.XContentParser;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import static org.elasticsearch.common.xcontent.XContentParserUtils.ensureExpectedToken;
/**
* client side counterpart of server side
* {@link org.elasticsearch.ElasticsearchException}
* It wraps the same content but it is not throwable.
*/
public class ElasticsearchException {
private static final String TYPE = "type";
private static final String REASON = "reason";
private static final String CAUSED_BY = "caused_by";
private static final ParseField SUPPRESSED = new ParseField("suppressed");
private static final String STACK_TRACE = "stack_trace";
private static final String HEADER = "header";
private static final String ROOT_CAUSE = "root_cause";
private String msg;
private ElasticsearchException cause;
private final Map<String, List<String>> headers = new HashMap<>();
private final List<ElasticsearchException> suppressed = new ArrayList<>();
ElasticsearchException(String msg) {
this.msg = msg;
this.cause = null;
}
ElasticsearchException(String msg, ElasticsearchException cause) {
this.msg = msg;
this.cause = cause;
}
public String getMsg() {
return msg;
}
public ElasticsearchException getCause() {
return cause;
}
public List<ElasticsearchException> getSuppressed() {
return suppressed;
}
void addSuppressed(List<ElasticsearchException> suppressed){
this.suppressed.addAll(suppressed);
}
/**
* Generate a {@link ElasticsearchException} from a {@link XContentParser}. This does not
* return the original exception type (ie NodeClosedException for example) but just wraps
* the type, the reason and the cause of the exception. It also recursively parses the
* tree structure of the cause, returning it as a tree structure of {@link ElasticsearchException}
* instances.
*/
static ElasticsearchException fromXContent(XContentParser parser) throws IOException {
XContentParser.Token token = parser.nextToken();
ensureExpectedToken(XContentParser.Token.FIELD_NAME, token, parser::getTokenLocation);
return innerFromXContent(parser, false);
}
private static ElasticsearchException innerFromXContent(XContentParser parser, boolean parseRootCauses) throws IOException {
XContentParser.Token token = parser.currentToken();
ensureExpectedToken(XContentParser.Token.FIELD_NAME, token, parser::getTokenLocation);
String type = null, reason = null, stack = null;
ElasticsearchException cause = null;
Map<String, List<String>> headers = new HashMap<>();
List<ElasticsearchException> rootCauses = new ArrayList<>();
List<ElasticsearchException> suppressed = new ArrayList<>();
for (; token == XContentParser.Token.FIELD_NAME; token = parser.nextToken()) {
String currentFieldName = parser.currentName();
token = parser.nextToken();
if (token.isValue()) {
if (TYPE.equals(currentFieldName)) {
type = parser.text();
} else if (REASON.equals(currentFieldName)) {
reason = parser.text();
} else if (STACK_TRACE.equals(currentFieldName)) {
stack = parser.text();
}
} else if (token == XContentParser.Token.START_OBJECT) {
if (CAUSED_BY.equals(currentFieldName)) {
cause = fromXContent(parser);
} else if (HEADER.equals(currentFieldName)) {
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) {
currentFieldName = parser.currentName();
} else {
List<String> values = headers.getOrDefault(currentFieldName, new ArrayList<>());
if (token == XContentParser.Token.VALUE_STRING) {
values.add(parser.text());
} else if (token == XContentParser.Token.START_ARRAY) {
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
if (token == XContentParser.Token.VALUE_STRING) {
values.add(parser.text());
} else {
parser.skipChildren();
}
}
} else if (token == XContentParser.Token.START_OBJECT) {
parser.skipChildren();
}
headers.put(currentFieldName, values);
}
}
} else {
// Any additional metadata object added by the metadataToXContent method is ignored
// and skipped, so that the parser does not fail on unknown fields. The parser only
// support metadata key-pairs and metadata arrays of values.
parser.skipChildren();
}
} else if (token == XContentParser.Token.START_ARRAY) {
if (parseRootCauses && ROOT_CAUSE.equals(currentFieldName)) {
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
rootCauses.add(fromXContent(parser));
}
} else if (SUPPRESSED.match(currentFieldName, parser.getDeprecationHandler())) {
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
suppressed.add(fromXContent(parser));
}
} else {
// Parse the array and add each item to the corresponding list of metadata.
// Arrays of objects are not supported yet and just ignored and skipped.
List<String> values = new ArrayList<>();
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
if (token == XContentParser.Token.VALUE_STRING) {
values.add(parser.text());
} else {
parser.skipChildren();
}
}
}
}
}
ElasticsearchException e = new ElasticsearchException(buildMessage(type, reason, stack), cause);
for (Map.Entry<String, List<String>> header : headers.entrySet()) {
e.addHeader(header.getKey(), header.getValue());
}
// Adds root causes as suppressed exception. This way they are not lost
// after parsing and can be retrieved using getSuppressed() method.
e.suppressed.addAll(rootCauses);
e.suppressed.addAll(suppressed);
return e;
}
void addHeader(String key, List<String> value) {
headers.put(key,value);
}
public Map<String, List<String>> getHeaders() {
return headers;
}
static String buildMessage(String type, String reason, String stack) {
StringBuilder message = new StringBuilder("Elasticsearch exception [");
message.append(TYPE).append('=').append(type).append(", ");
message.append(REASON).append('=').append(reason);
if (stack != null) {
message.append(", ").append(STACK_TRACE).append('=').append(stack);
}
message.append(']');
return message.toString();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof ElasticsearchException)) return false;
ElasticsearchException that = (ElasticsearchException) o;
return Objects.equals(getMsg(), that.getMsg()) &&
Objects.equals(getCause(), that.getCause()) &&
Objects.equals(getHeaders(), that.getHeaders()) &&
Objects.equals(getSuppressed(), that.getSuppressed());
}
@Override
public int hashCode() {
return Objects.hash(getMsg(), getCause(), getHeaders(), getSuppressed());
}
@Override
public String toString() {
return "ElasticsearchException{" +
"msg='" + msg + '\'' +
", cause=" + cause +
", headers=" + headers +
", suppressed=" + suppressed +
'}';
}
}

View File

@ -16,7 +16,6 @@
* specific language governing permissions and limitations * specific language governing permissions and limitations
* under the License. * under the License.
*/ */
package org.elasticsearch.client.tasks; package org.elasticsearch.client.tasks;
import org.elasticsearch.common.ParseField; import org.elasticsearch.common.ParseField;

View File

@ -0,0 +1,139 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.client.tasks;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.toList;
public class ListTasksResponse {
protected final List<TaskOperationFailure> taskFailures = new ArrayList<>();
protected final List<ElasticsearchException> nodeFailures = new ArrayList<>();
protected final List<NodeData> nodesInfoData = new ArrayList<>();
protected final List<TaskInfo> tasks = new ArrayList<>();
protected final List<TaskGroup> taskGroups = new ArrayList<>();
ListTasksResponse(List<NodeData> nodesInfoData,
List<TaskOperationFailure> taskFailures,
List<ElasticsearchException> nodeFailures) {
if (taskFailures != null) {
this.taskFailures.addAll(taskFailures);
}
if (nodeFailures != null) {
this.nodeFailures.addAll(nodeFailures);
}
if (nodesInfoData != null) {
this.nodesInfoData.addAll(nodesInfoData);
}
this.tasks.addAll(this
.nodesInfoData
.stream()
.flatMap(nodeData -> nodeData.getTasks().stream())
.collect(toList())
);
this.taskGroups.addAll(buildTaskGroups());
}
private List<TaskGroup> buildTaskGroups() {
Map<TaskId, TaskGroup.Builder> taskGroups = new HashMap<>();
List<TaskGroup.Builder> topLevelTasks = new ArrayList<>();
// First populate all tasks
for (TaskInfo taskInfo : this.tasks) {
taskGroups.put(taskInfo.getTaskId(), TaskGroup.builder(taskInfo));
}
// Now go through all task group builders and add children to their parents
for (TaskGroup.Builder taskGroup : taskGroups.values()) {
TaskId parentTaskId = taskGroup.getTaskInfo().getParentTaskId();
if (parentTaskId != null) {
TaskGroup.Builder parentTask = taskGroups.get(parentTaskId);
if (parentTask != null) {
// we found parent in the list of tasks - add it to the parent list
parentTask.addGroup(taskGroup);
} else {
// we got zombie or the parent was filtered out - add it to the top task list
topLevelTasks.add(taskGroup);
}
} else {
// top level task - add it to the top task list
topLevelTasks.add(taskGroup);
}
}
return Collections.unmodifiableList(topLevelTasks.stream().map(TaskGroup.Builder::build).collect(Collectors.toList()));
}
public List<TaskInfo> getTasks() {
return tasks;
}
public Map<String, List<TaskInfo>> getPerNodeTasks() {
return getTasks()
.stream()
.collect(groupingBy(TaskInfo::getNodeId));
}
public List<TaskOperationFailure> getTaskFailures() {
return taskFailures;
}
public List<ElasticsearchException> getNodeFailures() {
return nodeFailures;
}
public List<TaskGroup> getTaskGroups() {
return taskGroups;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof ListTasksResponse)) return false;
ListTasksResponse response = (ListTasksResponse) o;
return nodesInfoData.equals(response.nodesInfoData) &&
Objects.equals
(getTaskFailures(), response.getTaskFailures()) &&
Objects.equals(getNodeFailures(), response.getNodeFailures()) &&
Objects.equals(getTasks(), response.getTasks()) &&
Objects.equals(getTaskGroups(), response.getTaskGroups());
}
@Override
public int hashCode() {
return Objects.hash(nodesInfoData, getTaskFailures(), getNodeFailures(), getTasks(), getTaskGroups());
}
@Override
public String toString() {
return "CancelTasksResponse{" +
"nodesInfoData=" + nodesInfoData +
", taskFailures=" + taskFailures +
", nodeFailures=" + nodeFailures +
", tasks=" + tasks +
", taskGroups=" + taskGroups +
'}';
}
}

View File

@ -0,0 +1,160 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.client.tasks;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.xcontent.ObjectParser;
import org.elasticsearch.common.xcontent.XContentParser;
class NodeData {
private String nodeId;
private String name;
private String transportAddress;
private String host;
private String ip;
private final List<String> roles = new ArrayList<>();
private final Map<String,String> attributes = new HashMap<>();
private final List<TaskInfo> tasks = new ArrayList<>();
NodeData(String nodeId) {
this.nodeId = nodeId;
}
void setName(String name) {
this.name = name;
}
public void setAttributes(Map<String, String> attributes) {
if(attributes!=null){
this.attributes.putAll(attributes);
}
}
void setTransportAddress(String transportAddress) {
this.transportAddress = transportAddress;
}
void setHost(String host) {
this.host = host;
}
void setIp(String ip) {
this.ip = ip;
}
void setRoles(List<String> roles) {
if(roles!=null){
this.roles.addAll(roles);
}
}
public String getNodeId() {
return nodeId;
}
public String getName() {
return name;
}
public String getTransportAddress() {
return transportAddress;
}
public String getHost() {
return host;
}
public String getIp() {
return ip;
}
public List<String> getRoles() {
return roles;
}
public Map<String, String> getAttributes() {
return attributes;
}
public List<TaskInfo> getTasks() {
return tasks;
}
void setTasks(List<TaskInfo> tasks) {
if(tasks!=null){
this.tasks.addAll(tasks);
}
}
@Override
public String toString() {
return "NodeData{" +
"nodeId='" + nodeId + '\'' +
", name='" + name + '\'' +
", transportAddress='" + transportAddress + '\'' +
", host='" + host + '\'' +
", ip='" + ip + '\'' +
", roles=" + roles +
", attributes=" + attributes +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof NodeData)) return false;
NodeData nodeData = (NodeData) o;
return Objects.equals(getNodeId(), nodeData.getNodeId()) &&
Objects.equals(getName(), nodeData.getName()) &&
Objects.equals(getTransportAddress(), nodeData.getTransportAddress()) &&
Objects.equals(getHost(), nodeData.getHost()) &&
Objects.equals(getIp(), nodeData.getIp()) &&
Objects.equals(getRoles(), nodeData.getRoles()) &&
Objects.equals(getAttributes(), nodeData.getAttributes()) &&
Objects.equals(getTasks(), nodeData.getTasks());
}
@Override
public int hashCode() {
return Objects.hash(getNodeId(), getName(), getTransportAddress(), getHost(), getIp(), getRoles(), getAttributes(), getTasks());
}
public static final ObjectParser.NamedObjectParser<NodeData, Void> PARSER;
static {
ObjectParser<NodeData, Void> parser = new ObjectParser<>("nodes");
parser.declareString(NodeData::setName, new ParseField("name"));
parser.declareString(NodeData::setTransportAddress, new ParseField("transport_address"));
parser.declareString(NodeData::setHost, new ParseField("host"));
parser.declareString(NodeData::setIp, new ParseField("ip"));
parser.declareStringArray(NodeData::setRoles, new ParseField("roles"));
parser.declareField(NodeData::setAttributes,
(p, c) -> p.mapStrings(),
new ParseField("attributes"),
ObjectParser.ValueType.OBJECT);
parser.declareNamedObjects(NodeData::setTasks, TaskInfo.PARSER, new ParseField("tasks"));
PARSER = (XContentParser p, Void v, String nodeId) -> parser.parse(p, new NodeData(nodeId), null);
}
}

View File

@ -0,0 +1,101 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.client.tasks;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* Client side counterpart of server side version.
*
* {@link org.elasticsearch.action.admin.cluster.node.tasks.list.TaskGroup}
*/
public class TaskGroup {
private final TaskInfo task;
@Override
public String toString() {
return "TaskGroup{" +
"task=" + task +
", childTasks=" + childTasks +
'}';
}
private final List<TaskGroup> childTasks = new ArrayList<>();
public TaskGroup(TaskInfo task, List<TaskGroup> childTasks) {
this.task = task;
this.childTasks.addAll(childTasks);
}
public static TaskGroup.Builder builder(TaskInfo taskInfo) {
return new TaskGroup.Builder(taskInfo);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof TaskGroup)) return false;
TaskGroup taskGroup = (TaskGroup) o;
return Objects.equals(task, taskGroup.task) &&
Objects.equals(getChildTasks(), taskGroup.getChildTasks());
}
@Override
public int hashCode() {
return Objects.hash(task, getChildTasks());
}
public static class Builder {
private TaskInfo taskInfo;
private List<TaskGroup.Builder> childTasks;
private Builder(TaskInfo taskInfo) {
this.taskInfo = taskInfo;
childTasks = new ArrayList<>();
}
public void addGroup(TaskGroup.Builder builder) {
childTasks.add(builder);
}
public TaskInfo getTaskInfo() {
return taskInfo;
}
public TaskGroup build() {
return new TaskGroup(
taskInfo,
childTasks.stream().map(TaskGroup.Builder::build).collect(Collectors.toList())
);
}
}
public TaskInfo getTaskInfo() {
return task;
}
public List<TaskGroup> getChildTasks() {
return childTasks;
}
}

View File

@ -0,0 +1,91 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.client.tasks;
import java.util.Objects;
/**
* client side version of a {@link org.elasticsearch.tasks.TaskId}
*/
public class TaskId {
protected final String nodeId;
protected final long id;
public TaskId(String nodeId, long id) {
this.nodeId = nodeId;
this.id = id;
}
/**
* accepts a raw format task id
* @param taskId expected to be nodeid:taskId
*/
public TaskId(String taskId) {
if (taskId == null) {
throw new IllegalArgumentException("null task id");
}
String[] s = taskId.split(":");
if (s.length != 2) {
throw new IllegalArgumentException("malformed task id " + taskId);
}
this.nodeId = s[0];
try {
this.id = Long.parseLong(s[1]);
} catch (NumberFormatException ex) {
throw new IllegalArgumentException("malformed task id " + taskId, ex);
}
}
public String getNodeId() {
return nodeId;
}
public long getId() {
return id;
}
public boolean isSet() {
return id != -1L;
}
@Override
public String toString() {
if (isSet()) {
return nodeId + ":" + id;
} else {
return "unset";
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof TaskId)) return false;
TaskId taskId = (TaskId) o;
return getId() == taskId.getId() &&
Objects.equals(getNodeId(), taskId.getNodeId());
}
@Override
public int hashCode() {
return Objects.hash(getNodeId(), getId());
}
}

View File

@ -0,0 +1,194 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.client.tasks;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.xcontent.ObjectParser;
import org.elasticsearch.common.xcontent.XContentParser;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
/**
* client side counterpart of server side
* <p>
* {@link org.elasticsearch.tasks.TaskInfo}
*/
public class TaskInfo {
private TaskId taskId;
private String type;
private String action;
private String description;
private long startTime;
private long runningTimeNanos;
private boolean cancellable;
private TaskId parentTaskId;
private final Map<String, Object> status = new HashMap<>();
private final Map<String, String> headers = new HashMap<>();
public TaskInfo(TaskId taskId) {
this.taskId = taskId;
}
public TaskId getTaskId() {
return taskId;
}
public String getNodeId() {
return taskId.nodeId;
}
public String getType() {
return type;
}
void setType(String type) {
this.type = type;
}
public String getAction() {
return action;
}
void setAction(String action) {
this.action = action;
}
public String getDescription() {
return description;
}
void setDescription(String description) {
this.description = description;
}
public long getStartTime() {
return startTime;
}
void setStartTime(long startTime) {
this.startTime = startTime;
}
public long getRunningTimeNanos() {
return runningTimeNanos;
}
void setRunningTimeNanos(long runningTimeNanos) {
this.runningTimeNanos = runningTimeNanos;
}
public boolean isCancellable() {
return cancellable;
}
void setCancellable(boolean cancellable) {
this.cancellable = cancellable;
}
public TaskId getParentTaskId() {
return parentTaskId;
}
void setParentTaskId(String parentTaskId) {
this.parentTaskId = new TaskId(parentTaskId);
}
public Map<String, String> getHeaders() {
return headers;
}
void setHeaders(Map<String, String> headers) {
this.headers.putAll(headers);
}
void setStatus(Map<String, Object> status) {
this.status.putAll(status);
}
public Map<String, Object> getStatus() {
return status;
}
private void noOpParse(Object s) {}
public static final ObjectParser.NamedObjectParser<TaskInfo, Void> PARSER;
static {
ObjectParser<TaskInfo, Void> parser = new ObjectParser<>("tasks", true, null);
// already provided in constructor: triggering a no-op
parser.declareString(TaskInfo::noOpParse, new ParseField("node"));
// already provided in constructor: triggering a no-op
parser.declareLong(TaskInfo::noOpParse, new ParseField("id"));
parser.declareString(TaskInfo::setType, new ParseField("type"));
parser.declareString(TaskInfo::setAction, new ParseField("action"));
parser.declareObject(TaskInfo::setStatus, (p, c) -> p.map(), new ParseField("status"));
parser.declareString(TaskInfo::setDescription, new ParseField("description"));
parser.declareLong(TaskInfo::setStartTime, new ParseField("start_time_in_millis"));
parser.declareLong(TaskInfo::setRunningTimeNanos, new ParseField("running_time_in_nanos"));
parser.declareBoolean(TaskInfo::setCancellable, new ParseField("cancellable"));
parser.declareString(TaskInfo::setParentTaskId, new ParseField("parent_task_id"));
parser.declareObject(TaskInfo::setHeaders, (p, c) -> p.mapStrings(), new ParseField("headers"));
PARSER = (XContentParser p, Void v, String name) -> parser.parse(p, new TaskInfo(new TaskId(name)), null);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof TaskInfo)) return false;
TaskInfo taskInfo = (TaskInfo) o;
return getStartTime() == taskInfo.getStartTime() &&
getRunningTimeNanos() == taskInfo.getRunningTimeNanos() &&
isCancellable() == taskInfo.isCancellable() &&
Objects.equals(getTaskId(), taskInfo.getTaskId()) &&
Objects.equals(getType(), taskInfo.getType()) &&
Objects.equals(getAction(), taskInfo.getAction()) &&
Objects.equals(getDescription(), taskInfo.getDescription()) &&
Objects.equals(getParentTaskId(), taskInfo.getParentTaskId()) &&
Objects.equals(status, taskInfo.status) &&
Objects.equals(getHeaders(), taskInfo.getHeaders());
}
@Override
public int hashCode() {
return Objects.hash(
getTaskId(), getType(), getAction(), getDescription(), getStartTime(),
getRunningTimeNanos(), isCancellable(), getParentTaskId(), status, getHeaders()
);
}
@Override
public String toString() {
return "TaskInfo{" +
"taskId=" + taskId +
", type='" + type + '\'' +
", action='" + action + '\'' +
", description='" + description + '\'' +
", startTime=" + startTime +
", runningTimeNanos=" + runningTimeNanos +
", cancellable=" + cancellable +
", parentTaskId=" + parentTaskId +
", status=" + status +
", headers=" + headers +
'}';
}
}

View File

@ -0,0 +1,107 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.client.tasks;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
import org.elasticsearch.common.xcontent.XContentParser;
import java.util.Objects;
import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg;
/**
* client side counterpart of server side
* {@link org.elasticsearch.action.TaskOperationFailure}
*/
public class TaskOperationFailure {
private final String nodeId;
private final long taskId;
private final ElasticsearchException reason;
private final String status;
public TaskOperationFailure(String nodeId, long taskId,String status, ElasticsearchException reason) {
this.nodeId = nodeId;
this.taskId = taskId;
this.status = status;
this.reason = reason;
}
public String getNodeId() {
return nodeId;
}
public long getTaskId() {
return taskId;
}
public ElasticsearchException getReason() {
return reason;
}
public String getStatus() {
return status;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof TaskOperationFailure)) return false;
TaskOperationFailure that = (TaskOperationFailure) o;
return getTaskId() == that.getTaskId() &&
Objects.equals(getNodeId(), that.getNodeId()) &&
Objects.equals(getReason(), that.getReason()) &&
Objects.equals(getStatus(), that.getStatus());
}
@Override
public int hashCode() {
return Objects.hash(getNodeId(), getTaskId(), getReason(), getStatus());
}
@Override
public String toString() {
return "TaskOperationFailure{" +
"nodeId='" + nodeId + '\'' +
", taskId=" + taskId +
", reason=" + reason +
", status='" + status + '\'' +
'}';
}
public static TaskOperationFailure fromXContent(XContentParser parser) {
return PARSER.apply(parser, null);
}
private static final ConstructingObjectParser<TaskOperationFailure, Void> PARSER =
new ConstructingObjectParser<>("task_info", true, constructorObjects -> {
int i = 0;
String nodeId = (String) constructorObjects[i++];
long taskId = (long) constructorObjects[i++];
String status = (String) constructorObjects[i++];
ElasticsearchException reason = (ElasticsearchException) constructorObjects[i];
return new TaskOperationFailure(nodeId, taskId, status, reason);
});
static {
PARSER.declareString(constructorArg(), new ParseField("node_id"));
PARSER.declareLong(constructorArg(), new ParseField("task_id"));
PARSER.declareString(constructorArg(), new ParseField("status"));
PARSER.declareObject(constructorArg(), (parser, c) -> ElasticsearchException.fromXContent(parser), new ParseField("reason"));
}
}

View File

@ -19,21 +19,20 @@
package org.elasticsearch.client; package org.elasticsearch.client;
import org.elasticsearch.action.admin.cluster.node.tasks.cancel.CancelTasksRequest;
import org.elasticsearch.action.admin.cluster.node.tasks.cancel.CancelTasksResponse;
import org.elasticsearch.action.admin.cluster.node.tasks.list.ListTasksRequest; import org.elasticsearch.action.admin.cluster.node.tasks.list.ListTasksRequest;
import org.elasticsearch.action.admin.cluster.node.tasks.list.ListTasksResponse; import org.elasticsearch.action.admin.cluster.node.tasks.list.ListTasksResponse;
import org.elasticsearch.action.admin.cluster.node.tasks.list.TaskGroup; import org.elasticsearch.action.admin.cluster.node.tasks.list.TaskGroup;
import org.elasticsearch.action.bulk.BulkRequest; import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.support.WriteRequest.RefreshPolicy; import org.elasticsearch.action.support.WriteRequest.RefreshPolicy;
import org.elasticsearch.client.tasks.CancelTasksRequest;
import org.elasticsearch.client.tasks.CancelTasksResponse;
import org.elasticsearch.client.tasks.GetTaskRequest; import org.elasticsearch.client.tasks.GetTaskRequest;
import org.elasticsearch.client.tasks.GetTaskResponse; import org.elasticsearch.client.tasks.GetTaskResponse;
import org.elasticsearch.client.tasks.TaskId;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.rest.RestStatus; import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.tasks.TaskId;
import org.elasticsearch.tasks.TaskInfo;
import java.io.IOException; import java.io.IOException;
import java.util.Collections; import java.util.Collections;
@ -58,12 +57,12 @@ public class TasksIT extends ESRestHighLevelClientTestCase {
assertThat(response.getTasks().size(), greaterThanOrEqualTo(2)); assertThat(response.getTasks().size(), greaterThanOrEqualTo(2));
boolean listTasksFound = false; boolean listTasksFound = false;
for (TaskGroup taskGroup : response.getTaskGroups()) { for (TaskGroup taskGroup : response.getTaskGroups()) {
TaskInfo parent = taskGroup.getTaskInfo(); org.elasticsearch.tasks.TaskInfo parent = taskGroup.getTaskInfo();
if ("cluster:monitor/tasks/lists".equals(parent.getAction())) { if ("cluster:monitor/tasks/lists".equals(parent.getAction())) {
assertThat(taskGroup.getChildTasks().size(), equalTo(1)); assertThat(taskGroup.getChildTasks().size(), equalTo(1));
TaskGroup childGroup = taskGroup.getChildTasks().iterator().next(); TaskGroup childGroup = taskGroup.getChildTasks().iterator().next();
assertThat(childGroup.getChildTasks().isEmpty(), equalTo(true)); assertThat(childGroup.getChildTasks().isEmpty(), equalTo(true));
TaskInfo child = childGroup.getTaskInfo(); org.elasticsearch.tasks.TaskInfo child = childGroup.getTaskInfo();
assertThat(child.getAction(), equalTo("cluster:monitor/tasks/lists[n]")); assertThat(child.getAction(), equalTo("cluster:monitor/tasks/lists[n]"));
assertThat(child.getParentTaskId(), equalTo(parent.getTaskId())); assertThat(child.getParentTaskId(), equalTo(parent.getTaskId()));
listTasksFound = true; listTasksFound = true;
@ -117,7 +116,7 @@ public class TasksIT extends ESRestHighLevelClientTestCase {
if (gtr.getWaitForCompletion()) { if (gtr.getWaitForCompletion()) {
assertTrue(taskResponse.isCompleted()); assertTrue(taskResponse.isCompleted());
} }
TaskInfo info = taskResponse.getTaskInfo(); org.elasticsearch.tasks.TaskInfo info = taskResponse.getTaskInfo();
assertTrue(info.isCancellable()); assertTrue(info.isCancellable());
assertEquals("reindex from [source1] to [dest][_doc]", info.getDescription()); assertEquals("reindex from [source1] to [dest][_doc]", info.getDescription());
assertEquals("indices:data/write/reindex", info.getAction()); assertEquals("indices:data/write/reindex", info.getAction());
@ -142,12 +141,12 @@ public class TasksIT extends ESRestHighLevelClientTestCase {
); );
// in this case, probably no task will actually be cancelled. // in this case, probably no task will actually be cancelled.
// this is ok, that case is covered in TasksIT.testTasksCancellation // this is ok, that case is covered in TasksIT.testTasksCancellation
TaskInfo firstTask = listResponse.getTasks().get(0); org.elasticsearch.tasks.TaskInfo firstTask = listResponse.getTasks().get(0);
String node = listResponse.getPerNodeTasks().keySet().iterator().next(); String node = listResponse.getPerNodeTasks().keySet().iterator().next();
CancelTasksRequest cancelTasksRequest = new CancelTasksRequest(); CancelTasksRequest cancelTasksRequest = new CancelTasksRequest.Builder().withTaskId(
cancelTasksRequest.setTaskId(new TaskId(node, firstTask.getId())); new TaskId(node, firstTask.getId())
cancelTasksRequest.setReason("testreason"); ).build();
CancelTasksResponse response = execute(cancelTasksRequest, CancelTasksResponse response = execute(cancelTasksRequest,
highLevelClient().tasks()::cancel, highLevelClient().tasks()::cancel,
highLevelClient().tasks()::cancelAsync); highLevelClient().tasks()::cancelAsync);

View File

@ -21,7 +21,6 @@ package org.elasticsearch.client;
import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPost;
import org.elasticsearch.action.admin.cluster.node.tasks.cancel.CancelTasksRequest;
import org.elasticsearch.action.admin.cluster.node.tasks.list.ListTasksRequest; import org.elasticsearch.action.admin.cluster.node.tasks.list.ListTasksRequest;
import org.elasticsearch.tasks.TaskId; import org.elasticsearch.tasks.TaskId;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
@ -36,12 +35,16 @@ import static org.hamcrest.Matchers.nullValue;
public class TasksRequestConvertersTests extends ESTestCase { public class TasksRequestConvertersTests extends ESTestCase {
public void testCancelTasks() { public void testCancelTasks() {
CancelTasksRequest request = new CancelTasksRequest();
Map<String, String> expectedParams = new HashMap<>(); Map<String, String> expectedParams = new HashMap<>();
TaskId taskId = new TaskId(randomAlphaOfLength(5), randomNonNegativeLong()); org.elasticsearch.client.tasks.TaskId taskId =
TaskId parentTaskId = new TaskId(randomAlphaOfLength(5), randomNonNegativeLong()); new org.elasticsearch.client.tasks.TaskId(randomAlphaOfLength(5), randomNonNegativeLong());
request.setTaskId(taskId); org.elasticsearch.client.tasks.TaskId parentTaskId =
request.setParentTaskId(parentTaskId); new org.elasticsearch.client.tasks.TaskId(randomAlphaOfLength(5), randomNonNegativeLong());
org.elasticsearch.client.tasks.CancelTasksRequest request =
new org.elasticsearch.client.tasks.CancelTasksRequest.Builder()
.withTaskId(taskId)
.withParentTaskId(parentTaskId)
.build();
expectedParams.put("task_id", taskId.toString()); expectedParams.put("task_id", taskId.toString());
expectedParams.put("parent_task_id", parentTaskId.toString()); expectedParams.put("parent_task_id", parentTaskId.toString());
Request httpRequest = TasksRequestConverters.cancelTasks(request); Request httpRequest = TasksRequestConverters.cancelTasks(request);

View File

@ -23,19 +23,21 @@ import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.LatchedActionListener; import org.elasticsearch.action.LatchedActionListener;
import org.elasticsearch.action.TaskOperationFailure; import org.elasticsearch.action.TaskOperationFailure;
import org.elasticsearch.action.admin.cluster.node.tasks.cancel.CancelTasksRequest;
import org.elasticsearch.action.admin.cluster.node.tasks.cancel.CancelTasksResponse;
import org.elasticsearch.action.admin.cluster.node.tasks.list.ListTasksRequest; import org.elasticsearch.action.admin.cluster.node.tasks.list.ListTasksRequest;
import org.elasticsearch.action.admin.cluster.node.tasks.list.ListTasksResponse; import org.elasticsearch.action.admin.cluster.node.tasks.list.ListTasksResponse;
import org.elasticsearch.action.admin.cluster.node.tasks.list.TaskGroup; import org.elasticsearch.action.admin.cluster.node.tasks.list.TaskGroup;
import org.elasticsearch.client.ESRestHighLevelClientTestCase; import org.elasticsearch.client.ESRestHighLevelClientTestCase;
import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.tasks.CancelTasksRequest;
import org.elasticsearch.client.tasks.CancelTasksResponse;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.tasks.TaskId; import org.elasticsearch.tasks.TaskId;
import org.elasticsearch.tasks.TaskInfo; import org.elasticsearch.tasks.TaskInfo;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
@ -155,19 +157,21 @@ public class TasksClientDocumentationIT extends ESRestHighLevelClientTestCase {
RestHighLevelClient client = highLevelClient(); RestHighLevelClient client = highLevelClient();
{ {
// tag::cancel-tasks-request // tag::cancel-tasks-request
CancelTasksRequest request = new CancelTasksRequest(); CancelTasksRequest request = new org.elasticsearch.client.tasks.CancelTasksRequest.Builder()
.withNodesFiltered(Arrays.asList("nodeId1", "nodeId2"))
.withActionsFiltered(Collections.singletonList("cluster:*"))
.build();
// end::cancel-tasks-request // end::cancel-tasks-request
// tag::cancel-tasks-request-filter // tag::cancel-tasks-request-filter
request.setTaskId(new TaskId("nodeId1", 42)); //<1> CancelTasksRequest byTaskIdRequest = new org.elasticsearch.client.tasks.CancelTasksRequest.Builder() // <1>
request.setActions("cluster:*"); // <2> .withTaskId(new org.elasticsearch.client.tasks.TaskId("myNode",44L)) // <2>
request.setNodes("nodeId1", "nodeId2"); // <3> .build(); // <3>
// end::cancel-tasks-request-filter // end::cancel-tasks-request-filter
} }
CancelTasksRequest request = new CancelTasksRequest(); CancelTasksRequest request = new org.elasticsearch.client.tasks.CancelTasksRequest.Builder().build();
request.setTaskId(TaskId.EMPTY_TASK_ID);
// tag::cancel-tasks-execute // tag::cancel-tasks-execute
CancelTasksResponse response = client.tasks().cancel(request, RequestOptions.DEFAULT); CancelTasksResponse response = client.tasks().cancel(request, RequestOptions.DEFAULT);
@ -176,18 +180,18 @@ public class TasksClientDocumentationIT extends ESRestHighLevelClientTestCase {
assertThat(response, notNullValue()); assertThat(response, notNullValue());
// tag::cancel-tasks-response-tasks // tag::cancel-tasks-response-tasks
List<TaskInfo> tasks = response.getTasks(); // <1> List<org.elasticsearch.client.tasks.TaskInfo> tasks = response.getTasks(); // <1>
// end::cancel-tasks-response-tasks // end::cancel-tasks-response-tasks
// tag::cancel-tasks-response-calc // tag::cancel-tasks-response-calc
Map<String, List<TaskInfo>> perNodeTasks = response.getPerNodeTasks(); // <1> Map<String, List<org.elasticsearch.client.tasks.TaskInfo>> perNodeTasks = response.getPerNodeTasks(); // <1>
List<TaskGroup> groups = response.getTaskGroups(); // <2> List<org.elasticsearch.client.tasks.TaskGroup> groups = response.getTaskGroups(); // <2>
// end::cancel-tasks-response-calc // end::cancel-tasks-response-calc
// tag::cancel-tasks-response-failures // tag::cancel-tasks-response-failures
List<ElasticsearchException> nodeFailures = response.getNodeFailures(); // <1> List<org.elasticsearch.client.tasks.ElasticsearchException> nodeFailures = response.getNodeFailures(); // <1>
List<TaskOperationFailure> taskFailures = response.getTaskFailures(); // <2> List<org.elasticsearch.client.tasks.TaskOperationFailure> taskFailures = response.getTaskFailures(); // <2>
// end::cancel-tasks-response-failures // end::cancel-tasks-response-failures
assertThat(response.getNodeFailures(), equalTo(emptyList())); assertThat(response.getNodeFailures(), equalTo(emptyList()));
@ -198,7 +202,7 @@ public class TasksClientDocumentationIT extends ESRestHighLevelClientTestCase {
RestHighLevelClient client = highLevelClient(); RestHighLevelClient client = highLevelClient();
{ {
CancelTasksRequest request = new CancelTasksRequest(); CancelTasksRequest request = new org.elasticsearch.client.tasks.CancelTasksRequest.Builder().build();
// tag::cancel-tasks-execute-listener // tag::cancel-tasks-execute-listener
ActionListener<CancelTasksResponse> listener = ActionListener<CancelTasksResponse> listener =

View File

@ -0,0 +1,219 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.client.tasks;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.Version;
import org.elasticsearch.action.TaskOperationFailure;
import org.elasticsearch.action.admin.cluster.node.tasks.cancel.CancelTasksResponse;
import org.elasticsearch.client.AbstractResponseTestCase;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.cluster.node.DiscoveryNodes;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.tasks.Task;
import org.elasticsearch.tasks.TaskId;
import org.elasticsearch.tasks.TaskInfo;
import java.io.IOException;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import static java.util.Collections.emptyMap;
import static java.util.Collections.emptySet;
public class CancelTasksResponseTests extends AbstractResponseTestCase<CancelTasksResponseTests.ByNodeCancelTasksResponse,
org.elasticsearch.client.tasks.CancelTasksResponse> {
private static String NODE_ID = "node_id";
@Override
protected CancelTasksResponseTests.ByNodeCancelTasksResponse createServerTestInstance(XContentType xContentType) {
List<org.elasticsearch.tasks.TaskInfo> tasks = new ArrayList<>();
List<TaskOperationFailure> taskFailures = new ArrayList<>();
List<ElasticsearchException> nodeFailures = new ArrayList<>();
for (int i = 0; i < randomIntBetween(1, 4); i++) {
taskFailures.add(new TaskOperationFailure(randomAlphaOfLength(4), (long) i,
new RuntimeException(randomAlphaOfLength(4))));
}
for (int i = 0; i < randomIntBetween(1, 4); i++) {
nodeFailures.add(new ElasticsearchException(new RuntimeException(randomAlphaOfLength(10))));
}
for (int i = 0; i < 4; i++) {
tasks.add(new org.elasticsearch.tasks.TaskInfo(
new TaskId(NODE_ID, (long) i),
randomAlphaOfLength(4),
randomAlphaOfLength(4),
randomAlphaOfLength(10),
new FakeTaskStatus(randomAlphaOfLength(4), randomInt()),
randomLongBetween(1, 3),
randomIntBetween(5, 10),
false,
new TaskId("node1", randomLong()),
Collections.singletonMap("x-header-of", "some-value")));
}
return new ByNodeCancelTasksResponse(tasks, taskFailures, nodeFailures);
}
@Override
protected org.elasticsearch.client.tasks.CancelTasksResponse doParseToClientInstance(XContentParser parser) throws IOException {
return org.elasticsearch.client.tasks.CancelTasksResponse.fromXContent(parser);
}
@Override
protected void assertInstances(ByNodeCancelTasksResponse serverTestInstance,
org.elasticsearch.client.tasks.CancelTasksResponse clientInstance) {
// checking tasks
List<TaskInfo> sTasks = serverTestInstance.getTasks();
List<org.elasticsearch.client.tasks.TaskInfo> cTasks = clientInstance.getTasks();
Map<org.elasticsearch.client.tasks.TaskId, org.elasticsearch.client.tasks.TaskInfo> cTasksMap =
cTasks.stream().collect(Collectors.toMap(org.elasticsearch.client.tasks.TaskInfo::getTaskId,
Function.identity()));
for (TaskInfo ti : sTasks) {
org.elasticsearch.client.tasks.TaskInfo taskInfo = cTasksMap.get(
new org.elasticsearch.client.tasks.TaskId(ti.getTaskId().getNodeId(), ti.getTaskId().getId())
);
assertEquals(ti.getAction(), taskInfo.getAction());
assertEquals(ti.getDescription(), taskInfo.getDescription());
assertEquals(new HashMap<>(ti.getHeaders()), new HashMap<>(taskInfo.getHeaders()));
assertEquals(ti.getType(), taskInfo.getType());
assertEquals(ti.getStartTime(), taskInfo.getStartTime());
assertEquals(ti.getRunningTimeNanos(), taskInfo.getRunningTimeNanos());
assertEquals(ti.isCancellable(), taskInfo.isCancellable());
assertEquals(ti.getParentTaskId().getNodeId(), taskInfo.getParentTaskId().getNodeId());
assertEquals(ti.getParentTaskId().getId(), taskInfo.getParentTaskId().getId());
FakeTaskStatus status = (FakeTaskStatus) ti.getStatus();
assertEquals(status.code, taskInfo.getStatus().get("code"));
assertEquals(status.status, taskInfo.getStatus().get("status"));
}
//checking failures
List<ElasticsearchException> serverNodeFailures = serverTestInstance.getNodeFailures();
List<org.elasticsearch.client.tasks.ElasticsearchException> cNodeFailures = clientInstance.getNodeFailures();
List<String> sExceptionsMessages = serverNodeFailures.stream().map(x ->
org.elasticsearch.client.tasks.ElasticsearchException.buildMessage(
"exception", x.getMessage(), null)
).collect(Collectors.toList()
);
List<String> cExceptionsMessages = cNodeFailures.stream().map(
org.elasticsearch.client.tasks.ElasticsearchException::getMsg
).collect(Collectors.toList());
assertEquals(new HashSet<>(sExceptionsMessages), new HashSet<>(cExceptionsMessages));
List<TaskOperationFailure> sTaskFailures = serverTestInstance.getTaskFailures();
List<org.elasticsearch.client.tasks.TaskOperationFailure> cTaskFailures = clientInstance.getTaskFailures();
Map<Long, org.elasticsearch.client.tasks.TaskOperationFailure> cTasksFailuresMap =
cTaskFailures.stream().collect(Collectors.toMap(
org.elasticsearch.client.tasks.TaskOperationFailure::getTaskId,
Function.identity()));
for (TaskOperationFailure tof : sTaskFailures) {
org.elasticsearch.client.tasks.TaskOperationFailure failure = cTasksFailuresMap.get(tof.getTaskId());
assertEquals(tof.getNodeId(), failure.getNodeId());
assertTrue(failure.getReason().getMsg().contains("runtime_exception"));
assertTrue(failure.getStatus().contains("" + tof.getStatus().name()));
}
}
public static class FakeTaskStatus implements Task.Status {
final String status;
final int code;
public FakeTaskStatus(String status, int code) {
this.status = status;
this.code = code;
}
@Override
public String getWriteableName() {
return "faker";
}
@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeString(status);
out.writeInt(code);
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
builder.field("status", status);
builder.field("code", code);
return builder.endObject();
}
}
/**
* tasks are grouped under nodes, and in order to create DiscoveryNodes we need different
* IP addresses.
* So in this test we assume all tasks are issued by a single node whose name and IP address is hardcoded.
*/
static class ByNodeCancelTasksResponse extends CancelTasksResponse {
ByNodeCancelTasksResponse(StreamInput in) throws IOException {
super(in);
}
ByNodeCancelTasksResponse(
List<TaskInfo> tasks,
List<TaskOperationFailure> taskFailures,
List<? extends ElasticsearchException> nodeFailures) {
super(tasks, taskFailures, nodeFailures);
}
// it knows the hardcoded address space.
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
DiscoveryNodes.Builder dnBuilder = new DiscoveryNodes.Builder();
InetAddress inetAddress = InetAddress.getByAddress(new byte[]{(byte) 192, (byte) 168, (byte) 0, (byte) 1});
TransportAddress transportAddress = new TransportAddress(inetAddress, randomIntBetween(0, 65535));
dnBuilder.add(new DiscoveryNode(NODE_ID, NODE_ID, transportAddress, emptyMap(), emptySet(), Version.CURRENT));
DiscoveryNodes build = dnBuilder.build();
builder.startObject();
super.toXContentGroupedByNode(builder, params, build);
builder.endObject();
return builder;
}
}
}

View File

@ -0,0 +1,83 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.client.tasks;
import org.elasticsearch.client.AbstractResponseTestCase;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType;
import java.io.IOException;
import java.util.Collections;
public class ElasticsearchExceptionTests extends AbstractResponseTestCase<org.elasticsearch.ElasticsearchException,
org.elasticsearch.client.tasks.ElasticsearchException> {
@Override
protected org.elasticsearch.ElasticsearchException createServerTestInstance(XContentType xContentType) {
IllegalStateException ies = new IllegalStateException("illegal_state");
IllegalArgumentException iae = new IllegalArgumentException("argument", ies);
org.elasticsearch.ElasticsearchException exception = new org.elasticsearch.ElasticsearchException("elastic_exception", iae);
exception.addHeader("key","value");
exception.addMetadata("es.meta","data");
exception.addSuppressed(new NumberFormatException("3/0"));
return exception;
}
@Override
protected ElasticsearchException doParseToClientInstance(XContentParser parser) throws IOException {
parser.nextToken();
return ElasticsearchException.fromXContent(parser);
}
@Override
protected void assertInstances(org.elasticsearch.ElasticsearchException serverTestInstance, ElasticsearchException clientInstance) {
IllegalArgumentException sCauseLevel1 = (IllegalArgumentException) serverTestInstance.getCause();
ElasticsearchException cCauseLevel1 = clientInstance.getCause();
assertTrue(sCauseLevel1 !=null);
assertTrue(cCauseLevel1 !=null);
IllegalStateException causeLevel2 = (IllegalStateException) serverTestInstance.getCause().getCause();
ElasticsearchException cCauseLevel2 = clientInstance.getCause().getCause();
assertTrue(causeLevel2 !=null);
assertTrue(cCauseLevel2 !=null);
ElasticsearchException cause = new ElasticsearchException(
"Elasticsearch exception [type=illegal_state_exception, reason=illegal_state]"
);
ElasticsearchException caused1 = new ElasticsearchException(
"Elasticsearch exception [type=illegal_argument_exception, reason=argument]",cause
);
ElasticsearchException caused2 = new ElasticsearchException(
"Elasticsearch exception [type=exception, reason=elastic_exception]",caused1
);
caused2.addHeader("key", Collections.singletonList("value"));
ElasticsearchException supp = new ElasticsearchException(
"Elasticsearch exception [type=number_format_exception, reason=3/0]"
);
caused2.addSuppressed(Collections.singletonList(supp));
assertEquals(caused2,clientInstance);
}
}