diff --git a/Documentation/rest-api-config.txt b/Documentation/rest-api-config.txt index 9ec21ec454..8b5c1210a3 100644 --- a/Documentation/rest-api-config.txt +++ b/Documentation/rest-api-config.txt @@ -691,6 +691,46 @@ command. ] ---- +[[get-task]] +=== Get Task +-- +'GET /config/server/tasks/link:#task-id[\{task-id\}]' +-- + +Retrieves a task from the background work queue that the Gerrit daemon +is currently performing, or will perform in the near future. + +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. + +As result a link:#task-info[TaskInfo] entity is returned. + +.Request +---- + GET /config/server/tasks/1e688bea HTTP/1.0 +---- + +.Response +---- + HTTP/1.1 200 OK + Content-Type: application/json;charset=UTF-8 + + )]}' + { + "id": "1e688bea", + "state": "SLEEPING", + "start_time": "2014-06-11 12:58:51.991000000", + "delay": 3453, + "command": "Reload Submit Queue" + } +---- + [[get-top-menus]] === Get Top Menus -- @@ -741,6 +781,10 @@ plugin name: "-". Gerrit core caches can optionally be prefixed with "gerrit": "gerrit-". +[[task-id]] +=== \{task-id\} +The ID of the task (hex string). + [[json-entities]] == JSON Entities diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/GetTaskIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/GetTaskIT.java new file mode 100644 index 0000000000..2feeab84eb --- /dev/null +++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/GetTaskIT.java @@ -0,0 +1,67 @@ +// 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.assertNotNull; + +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 GetTaskIT extends AbstractDaemonTest { + + @Test + public void getTask() throws IOException { + RestResponse r = + adminSession.get("/config/server/tasks/" + getLogFileCompressorTaskId()); + assertEquals(HttpStatus.SC_OK, r.getStatusCode()); + TaskInfo info = + newGson().fromJson(r.getReader(), + new TypeToken() {}.getType()); + assertNotNull(info.id); + Long.parseLong(info.id, 16); + assertEquals("Log File Compressor", info.command); + assertNotNull(info.startTime); + } + + @Test + public void getTask_NotFound() throws IOException { + RestResponse r = + userSession.get("/config/server/tasks/" + getLogFileCompressorTaskId()); + assertEquals(HttpStatus.SC_NOT_FOUND, r.getStatusCode()); + } + + private String getLogFileCompressorTaskId() throws IOException { + RestResponse r = adminSession.get("/config/server/tasks/"); + List result = + newGson().fromJson(r.getReader(), + new TypeToken>() {}.getType()); + r.consume(); + for (TaskInfo info : result) { + if ("Log File Compressor".equals(info.command)) { + return info.id; + } + } + return null; + } +} diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GetTask.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GetTask.java new file mode 100644 index 0000000000..e4b3320560 --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GetTask.java @@ -0,0 +1,28 @@ +// 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.extensions.restapi.RestReadView; +import com.google.gerrit.server.config.ListTasks.TaskInfo; +import com.google.inject.Singleton; + +@Singleton +public class GetTask implements RestReadView { + + @Override + public TaskInfo apply(TaskResource rsrc) { + return new TaskInfo(rsrc.getTask()); + } +} 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 772ad7fb10..0cf1903e57 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 @@ -31,6 +31,7 @@ public class Module extends RestApiModule { DynamicMap.mapOf(binder(), TOP_MENU_KIND); child(CONFIG_KIND, "capabilities").to(CapabilitiesCollection.class); child(CONFIG_KIND, "tasks").to(TasksCollection.class); + get(TASK_KIND).to(GetTask.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-server/src/main/java/com/google/gerrit/server/config/TaskResource.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/TaskResource.java index 5db163ddcf..7b695335b4 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/config/TaskResource.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/TaskResource.java @@ -15,9 +15,20 @@ package com.google.gerrit.server.config; import com.google.gerrit.extensions.restapi.RestView; +import com.google.gerrit.server.git.WorkQueue.Task; import com.google.inject.TypeLiteral; public class TaskResource extends ConfigResource { public static final TypeLiteral> TASK_KIND = new TypeLiteral>() {}; + + private final Task task; + + public TaskResource(Task task) { + this.task = task; + } + + public Task getTask() { + return task; + } } diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/TasksCollection.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/TasksCollection.java index 98dd92139d..b92cfc20b1 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/config/TasksCollection.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/TasksCollection.java @@ -15,11 +15,20 @@ package com.google.gerrit.server.config; import com.google.gerrit.extensions.registration.DynamicMap; +import com.google.gerrit.extensions.restapi.AuthException; import com.google.gerrit.extensions.restapi.ChildCollection; import com.google.gerrit.extensions.restapi.IdString; import com.google.gerrit.extensions.restapi.ResourceNotFoundException; import com.google.gerrit.extensions.restapi.RestView; +import com.google.gerrit.server.CurrentUser; +import com.google.gerrit.server.IdentifiedUser; +import com.google.gerrit.server.git.WorkQueue; +import com.google.gerrit.server.git.WorkQueue.ProjectTask; +import com.google.gerrit.server.git.WorkQueue.Task; +import com.google.gerrit.server.project.ProjectCache; +import com.google.gerrit.server.project.ProjectState; import com.google.inject.Inject; +import com.google.inject.Provider; import com.google.inject.Singleton; @Singleton @@ -27,12 +36,19 @@ public class TasksCollection implements ChildCollection { private final DynamicMap> views; private final ListTasks list; + private final WorkQueue workQueue; + private final Provider self; + private final ProjectCache projectCache; @Inject - TasksCollection(DynamicMap> views, - ListTasks list) { + TasksCollection(DynamicMap> views, ListTasks list, + WorkQueue workQueue, Provider self, + ProjectCache projectCache) { this.views = views; this.list = list; + this.workQueue = workQueue; + this.self = self; + this.projectCache = projectCache; } @Override @@ -42,8 +58,30 @@ public class TasksCollection implements @Override public TaskResource parse(ConfigResource parent, IdString id) - throws ResourceNotFoundException { - throw new ResourceNotFoundException(id); + throws ResourceNotFoundException, AuthException { + CurrentUser user = self.get(); + if (!user.isIdentifiedUser()) { + throw new AuthException("Authentication required"); + } + + try { + int taskId = (int) Long.parseLong(id.get(), 16); + Task task = workQueue.getTask(taskId); + if (task != null) { + if (self.get().getCapabilities().canViewQueue()) { + return new TaskResource(task); + } else if (task instanceof ProjectTask) { + ProjectTask projectTask = ((ProjectTask) task); + ProjectState e = projectCache.get(projectTask.getProjectNameKey()); + if (e != null && e.controlFor(user).isVisible()) { + return new TaskResource(task); + } + } + } + throw new ResourceNotFoundException(id); + } catch (NumberFormatException e) { + throw new ResourceNotFoundException(id); + } } @Override