From 7e28381f0ef27b4036a7ae6aa397d74da4c34618 Mon Sep 17 00:00:00 2001 From: Edwin Kempin Date: Tue, 8 Jul 2014 12:49:03 +0200 Subject: [PATCH] Add REST endpoint to kill a task The kill SSH command was adapted to make use of the new REST endpoint. Change-Id: I7783ded83d4a027fcfeab7573101c9b6f9f69149 Signed-off-by: Edwin Kempin --- Documentation/rest-api-config.txt | 33 ++++++++++ .../acceptance/rest/config/KillTaskIT.java | 64 +++++++++++++++++++ .../gerrit/server/config/DeleteTask.java | 35 ++++++++++ .../google/gerrit/server/config/Module.java | 1 + .../gerrit/sshd/commands/KillCommand.java | 30 ++++----- 5 files changed, 146 insertions(+), 17 deletions(-) create mode 100644 gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/KillTaskIT.java create mode 100644 gerrit-server/src/main/java/com/google/gerrit/server/config/DeleteTask.java diff --git a/Documentation/rest-api-config.txt b/Documentation/rest-api-config.txt index 7d79ae6cb7..d410f5e25f 100644 --- a/Documentation/rest-api-config.txt +++ b/Documentation/rest-api-config.txt @@ -731,6 +731,39 @@ As result a link:#task-info[TaskInfo] entity is returned. } ---- +[[delete-task]] +=== Delete Task +-- +'DELETE /config/server/tasks/link:#task-id[\{task-id\}]' +-- + +Kills a task from the background work queue that the Gerrit daemon +is currently performing, or will perform in the near future. + +The caller must be a member of a group that is granted the +link:access-control.html#capability_kill[Kill Task] capability +or the link:access-control.html#capability_administrateServer[ +Administrate Server] capability. + +End-users may see a task only if they can also see the project the task +is associated with. Tasks operating on other projects, or that do not +have a specific project, are hidden. + +Members of a group that is granted the +link:access-control.html#capability_viewQueue[View Queue] capability or +the link:access-control.html#capability_administrateServer[Administrate +Server] capability can see all tasks. + +.Request +---- + DELETE /config/server/tasks/1e688bea HTTP/1.0 +---- + +.Response +---- + HTTP/1.1 204 No Content +---- + [[get-top-menus]] === Get Top Menus -- diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/KillTaskIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/KillTaskIT.java new file mode 100644 index 0000000000..90cb7ccf09 --- /dev/null +++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/KillTaskIT.java @@ -0,0 +1,64 @@ +// Copyright (C) 2014 The Android Open Source Project +// +// Licensed 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 com.google.gerrit.acceptance.rest.config; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import com.google.gerrit.acceptance.AbstractDaemonTest; +import com.google.gerrit.acceptance.RestResponse; +import com.google.gerrit.server.config.ListTasks.TaskInfo; +import com.google.gson.reflect.TypeToken; + +import org.apache.http.HttpStatus; +import org.junit.Test; + +import java.io.IOException; +import java.util.List; + +public class KillTaskIT extends AbstractDaemonTest { + + @Test + public void killTask() throws IOException { + RestResponse r = adminSession.get("/config/server/tasks/"); + List result = newGson().fromJson(r.getReader(), + new TypeToken>() {}.getType()); + r.consume(); + int taskCount = result.size(); + assertTrue(taskCount > 0); + + r = adminSession.delete("/config/server/tasks/" + result.get(0).id); + assertEquals(HttpStatus.SC_NO_CONTENT, r.getStatusCode()); + r.consume(); + + r = adminSession.get("/config/server/tasks/"); + result = newGson().fromJson(r.getReader(), + new TypeToken>() {}.getType()); + r.consume(); + assertEquals(taskCount - 1, result.size()); + } + + @Test + public void killTask_NotFound() throws IOException { + RestResponse r = adminSession.get("/config/server/tasks/"); + List result = newGson().fromJson(r.getReader(), + new TypeToken>() {}.getType()); + r.consume(); + assertTrue(result.size() > 0); + + r = userSession.delete("/config/server/tasks/" + result.get(0).id); + assertEquals(HttpStatus.SC_NOT_FOUND, r.getStatusCode()); + } +} diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/DeleteTask.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/DeleteTask.java new file mode 100644 index 0000000000..b02906097d --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/DeleteTask.java @@ -0,0 +1,35 @@ +// Copyright (C) 2014 The Android Open Source Project +// +// Licensed 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 com.google.gerrit.server.config; + +import com.google.gerrit.common.data.GlobalCapability; +import com.google.gerrit.extensions.annotations.RequiresCapability; +import com.google.gerrit.extensions.restapi.Response; +import com.google.gerrit.extensions.restapi.RestModifyView; +import com.google.gerrit.server.config.DeleteTask.Input; +import com.google.inject.Singleton; + +@Singleton +@RequiresCapability(GlobalCapability.KILL_TASK) +public class DeleteTask implements RestModifyView { + public static class Input { + } + + @Override + public Response apply(TaskResource rsrc, Input input) { + rsrc.getTask().cancel(true); + return Response.none(); + } +} diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/Module.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/Module.java index 0cf1903e57..64848bae33 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/config/Module.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/Module.java @@ -32,6 +32,7 @@ public class Module extends RestApiModule { child(CONFIG_KIND, "capabilities").to(CapabilitiesCollection.class); child(CONFIG_KIND, "tasks").to(TasksCollection.class); get(TASK_KIND).to(GetTask.class); + delete(TASK_KIND).to(DeleteTask.class); child(CONFIG_KIND, "top-menus").to(TopMenuCollection.class); get(CONFIG_KIND, "version").to(GetVersion.class); get(CONFIG_KIND, "preferences").to(GetPreferences.class); diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/KillCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/KillCommand.java index d8c3403f58..3d3acd5675 100644 --- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/KillCommand.java +++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/KillCommand.java @@ -16,17 +16,18 @@ package com.google.gerrit.sshd.commands; import com.google.gerrit.common.data.GlobalCapability; import com.google.gerrit.extensions.annotations.RequiresCapability; +import com.google.gerrit.server.config.DeleteTask; +import com.google.gerrit.server.config.TaskResource; import com.google.gerrit.server.git.WorkQueue; import com.google.gerrit.server.git.WorkQueue.Task; -import com.google.gerrit.server.util.IdGenerator; import com.google.gerrit.sshd.AdminHighPriorityCommand; import com.google.gerrit.sshd.SshCommand; import com.google.inject.Inject; import org.kohsuke.args4j.Argument; -import java.util.HashSet; -import java.util.Set; +import java.util.ArrayList; +import java.util.List; /** Kill a task in the work queue. */ @AdminHighPriorityCommand @@ -35,25 +36,20 @@ final class KillCommand extends SshCommand { @Inject private WorkQueue workQueue; - private final Set taskIds = new HashSet<>(); + @Inject + private DeleteTask deleteTask; @Argument(index = 0, multiValued = true, required = true, metaVar = "ID") - void addTaskId(final String taskId) { - int p = 0; - while (p < taskId.length() - 1 && taskId.charAt(p) == '0') { - p++; - } - taskIds.add((int) Long.parseLong(taskId.substring(p), 16)); - } + private final List taskIds = new ArrayList<>(); @Override protected void run() { - for (final Integer id : taskIds) { - final Task task = workQueue.getTask(id); - if (task != null) { - task.cancel(true); - } else { - stderr.print("kill: " + IdGenerator.format(id) + ": No such task\n"); + for (String id : taskIds) { + try { + Task task = workQueue.getTask((int) Long.parseLong(id, 16)); + deleteTask.apply(new TaskResource(task), null); + } catch (NumberFormatException e) { + stderr.print("kill: " + id + ": No such task\n"); } } }