Merge changes from topic 'maintain-server'

* changes:
  Add a Maintain Server global capability
  Add @RequiresAnyCapability to require one of a set
This commit is contained in:
Dave Borowitz
2015-06-12 15:20:50 +00:00
committed by Gerrit Code Review
28 changed files with 276 additions and 104 deletions

View File

@@ -1244,6 +1244,22 @@ kill command ends tasks that currently occupy the Gerrit server, usually
a replication task or a user initiated task such as an upload-pack or
receive-pack.
[[capability_maintainServer]]
=== Maintain Server
Allow basic, constrained server maintenance tasks, such as flushing caches and
reindexing changes. Does not grant arbitrary database access, read/write, or
ACL management permissions, as might the
<<capability_administrateServer,administrate server capability>>.
Implies the following capabilities:
* <<capability_flushCaches,Flush Caches>>
* <<capability_kill,Kill Task>>
* <<capability_runGC,Run Garbage Collection>>
* <<capability_viewCaches,View Caches>>
* <<capability_viewQueue,View Queue>>
[[capability_modifyAccount]]
=== Modify Account

View File

@@ -21,9 +21,16 @@ the Gerrit web interface.
If no options are supplied, defaults to `--all`.
== ACCESS
Caller must be a member of the privileged 'Administrators' group,
or in a group that have been granted
link:access-control.html#capability_flushCaches[the 'Flush Caches' global capability].
The caller must be a member of a group that is granted one of the
following capabilities:
* link:access-control.html#capability_flushCaches[Flush Caches] (any cache
except "web_sessions")
* link:access-control.html#capability_maintainServer[Maintain Server] (any cache
including "web_sessions")
* link:access-control.html#capability_administrateServer[Administrate Server]
(any cache including "web_sessions")
== SCRIPTING
This command is intended to be used in scripts.

View File

@@ -30,14 +30,17 @@ Display statistics about the size and hit ratio of in-memory caches.
Width of the output table.
== ACCESS
The caller must be a member of a group that is granted the
link:access-control.html#capability_viewCaches[View Caches] capability
or the link:access-control.html#capability_administrateServer[
Administrate Server] capability.
The caller must be a member of a group that is granted one of the
following capabilities:
* link:access-control.html#capability_viewCaches[View Caches]
* link:access-control.html#capability_maintainServer[Maintain Server]
* link:access-control.html#capability_administrateServer[Administrate Server]
The summary information about SSH, threads, tasks, memory and JVM are
only printed out if the caller is a member of a group that is granted
the link:access-control.html#capability_administrateServer[Administrate
Server] or link:access-control.html#capability_maintainServer[Maintain
Server] capability.
== SCRIPTING

View File

@@ -1324,6 +1324,9 @@ link:access-control.html#capability_flushCaches[Flush Caches]
capability.
|`killTask` |not set if `false`|Whether the user has the
link:access-control.html#capability_kill[Kill Task] capability.
|`maintainServer` |not set if `false`|Whether the user has the
link:access-control.html#capability_maintainServer[Maintain
Server] capability.
|`priority` |not set if `INTERACTIVE`|The name of the thread
pool used by the user, see link:access-control.html#capability_priority[
Priority] capability.

View File

@@ -135,10 +135,12 @@ As result a link:#server-info[ServerInfo] entity is returned.
Lists the caches of the server. Caches defined by plugins are included.
The caller must be a member of a group that is granted the
link:access-control.html#capability_viewCaches[View Caches] capability
or the link:access-control.html#capability_administrateServer[
Administrate Server] capability.
The caller must be a member of a group that is granted one of the
following capabilities:
* link:access-control.html#capability_viewCaches[View Caches]
* link:access-control.html#capability_maintainServer[Maintain Server]
* link:access-control.html#capability_administrateServer[Administrate Server]
As result a map of link:#cache-info[CacheInfo] entities is returned.
@@ -493,10 +495,12 @@ link:#cache-operation-input[CacheOperationInput] entity.
Retrieves information about a cache.
The caller must be a member of a group that is granted the
link:access-control.html#capability_viewCaches[View Caches] capability
or the link:access-control.html#capability_administrateServer[
Administrate Server] capability.
The caller must be a member of a group that is granted one of the
following capabilities:
* link:access-control.html#capability_viewCaches[View Caches]
* link:access-control.html#capability_maintainServer[Maintain Server]
* link:access-control.html#capability_administrateServer[Administrate Server]
As result a link:#cache-info[CacheInfo] entity is returned.
@@ -532,15 +536,15 @@ As result a link:#cache-info[CacheInfo] entity is returned.
Flushes a cache.
The caller must be a member of a group that is granted the
link:access-control.html#capability_flushCaches[Flush Caches] capability
or the link:access-control.html#capability_administrateServer[
Administrate Server] capability.
The caller must be a member of a group that is granted one of the
following capabilities:
The "web_sessions" cache can only be flushed if the caller is member of
a group that is granted the
link:access-control.html#capability_administrateServer[Administrate
Server] capability.
* link:access-control.html#capability_flushCaches[Flush Caches] (any cache
except "web_sessions")
* link:access-control.html#capability_maintainServer[Maintain Server] (any cache
including "web_sessions")
* link:access-control.html#capability_administrateServer[Administrate Server]
(any cache including "web_sessions")
.Request
----
@@ -749,10 +753,12 @@ 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.
The caller must be a member of a group that is granted one of the
following capabilities:
* link:access-control.html#capability_viewQueue[View Queue]
* link:access-control.html#capability_maintainServer[Maintain Server]
* link:access-control.html#capability_administrateServer[Administrate Server]
As result a list of link:#task-info[TaskInfo] entities is returned.
@@ -801,10 +807,12 @@ 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.
The caller must be a member of a group that is granted one of the
following capabilities:
* link:access-control.html#capability_viewQueue[View Queue]
* link:access-control.html#capability_maintainServer[Maintain Server]
* link:access-control.html#capability_administrateServer[Administrate Server]
As result a link:#task-info[TaskInfo] entity is returned.
@@ -837,19 +845,23 @@ As result a link:#task-info[TaskInfo] entity is returned.
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.
The caller must be a member of a group that is granted one of the
following capabilities:
* link:access-control.html#capability_kill[Kill Task]
* link:access-control.html#capability_maintainServer[Maintain Server]
* link:access-control.html#capability_administrateServer[Administrate Server]
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.
Members of a group granted one of the following capabilities may view
all tasks:
* link:access-control.html#capability_viewQueue[View Queue]
* link:access-control.html#capability_maintainServer[Maintain Server]
* link:access-control.html#capability_administrateServer[Administrate Server]
.Request
----

View File

@@ -24,6 +24,7 @@ class CapabilityInfo {
public boolean emailReviewers;
public boolean flushCaches;
public boolean killTask;
public boolean maintainServer;
public boolean modifyAccount;
public boolean priority;
public QueryLimit queryLimit;

View File

@@ -26,7 +26,7 @@ public class IndexChangeIT extends AbstractDaemonTest {
@Test
public void indexChange() throws Exception {
String changeId = createChange().getChangeId();
RestResponse r = userSession.post("/changes/" + changeId + "/index/");
RestResponse r = adminSession.post("/changes/" + changeId + "/index/");
assertThat(r.getStatusCode()).isEqualTo(HttpStatus.SC_NO_CONTENT);
}

View File

@@ -82,7 +82,8 @@ public class GarbageCollectionIT extends AbstractDaemonTest {
public void testGcWithoutCapability_Error() throws Exception {
SshSession s = new SshSession(server, user);
s.exec("gerrit gc --all");
assertError("Capability runGC is required to access this resource", s.getError());
assertError("One of the following capabilities is required to access this"
+ " resource: [runGC, maintainServer]", s.getError());
s.close();
}

View File

@@ -71,6 +71,16 @@ public class GlobalCapability {
/** Can terminate any task using the kill command. */
public static final String KILL_TASK = "killTask";
/**
* Can perform limited server maintenance.
* <p>
* Includes tasks such as reindexing changes and flushing caches that may need
* to be performed regularly. Does <strong>not</strong> grant arbitrary
* read/write/ACL management permissions as does {@link
* #ADMINISTRATE_SERVER}.
*/
public static final String MAINTAIN_SERVER = "maintainServer";
/** Can modify any account on the server. */
public static final String MODIFY_ACCOUNT = "modifyAccount";
@@ -121,6 +131,7 @@ public class GlobalCapability {
NAMES_ALL.add(EMAIL_REVIEWERS);
NAMES_ALL.add(FLUSH_CACHES);
NAMES_ALL.add(KILL_TASK);
NAMES_ALL.add(MAINTAIN_SERVER);
NAMES_ALL.add(MODIFY_ACCOUNT);
NAMES_ALL.add(PRIORITY);
NAMES_ALL.add(QUERY_LIMIT);

View File

@@ -0,0 +1,36 @@
// Copyright (C) 2015 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.extensions.annotations;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
/**
* Annotation on {@code com.google.gerrit.sshd.SshCommand} or
* {@code com.google.gerrit.httpd.restapi.RestApiServlet} declaring a set of
* capabilities of which at least one must be granted.
*/
@Target({ElementType.TYPE})
@Retention(RUNTIME)
public @interface RequiresAnyCapability {
/** Capabilities at least one of which is required to invoke this action. */
String[] value();
/** Scope of the named capabilities. */
CapabilityScope scope() default CapabilityScope.CONTEXT;
}

View File

@@ -28,7 +28,7 @@ import java.lang.annotation.Target;
@Target({ElementType.TYPE})
@Retention(RUNTIME)
public @interface RequiresCapability {
/** Name of the capability required to invoke this action. */
/** Name of the capability required to invoke this action. */
String value();
/** Scope of the named capability. */

View File

@@ -107,7 +107,7 @@ public class CapabilityControl {
/** @return true if the user can kill any running task. */
public boolean canKillTask() {
return canPerform(GlobalCapability.KILL_TASK)
|| canAdministrateServer();
|| canMaintainServer();
}
/** @return true if the user can modify an account for another user. */
@@ -125,12 +125,18 @@ public class CapabilityControl {
/** @return true if the user can view the server caches. */
public boolean canViewCaches() {
return canPerform(GlobalCapability.VIEW_CACHES)
|| canAdministrateServer();
|| canMaintainServer();
}
/** @return true if the user can flush the server's caches. */
public boolean canFlushCaches() {
return canPerform(GlobalCapability.FLUSH_CACHES)
|| canMaintainServer();
}
/** @return true if the user can perform basic server maintenance. */
public boolean canMaintainServer() {
return canPerform(GlobalCapability.MAINTAIN_SERVER)
|| canAdministrateServer();
}
@@ -149,7 +155,7 @@ public class CapabilityControl {
/** @return true if the user can view the entire queue. */
public boolean canViewQueue() {
return canPerform(GlobalCapability.VIEW_QUEUE)
|| canAdministrateServer();
|| canMaintainServer();
}
/** @return true if the user can access the database (with gsql). */
@@ -166,7 +172,7 @@ public class CapabilityControl {
/** @return true if the user can run the Git garbage collection. */
public boolean canRunGC() {
return canPerform(GlobalCapability.RUN_GC)
|| canAdministrateServer();
|| canMaintainServer();
}
/** @return true if the user can impersonate another user. */

View File

@@ -15,6 +15,7 @@
package com.google.gerrit.server.account;
import com.google.gerrit.extensions.annotations.CapabilityScope;
import com.google.gerrit.extensions.annotations.RequiresAnyCapability;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.server.CurrentUser;
@@ -24,6 +25,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.annotation.Annotation;
import java.util.Arrays;
public class CapabilityUtils {
private static final Logger log = LoggerFactory
@@ -33,33 +35,80 @@ public class CapabilityUtils {
String pluginName, Class<?> clazz)
throws AuthException {
RequiresCapability rc = getClassAnnotation(clazz, RequiresCapability.class);
if (rc != null) {
CurrentUser user = userProvider.get();
CapabilityControl ctl = user.getCapabilities();
if (ctl.canAdministrateServer()) {
RequiresAnyCapability rac =
getClassAnnotation(clazz, RequiresAnyCapability.class);
if (rc != null && rac != null) {
log.error(String.format(
"Class %s uses both @%s and @%s",
clazz.getName(),
RequiresCapability.class.getSimpleName(),
RequiresAnyCapability.class.getSimpleName()));
throw new AuthException("cannot check capability");
}
CurrentUser user = userProvider.get();
CapabilityControl ctl = user.getCapabilities();
if (ctl.canAdministrateServer()) {
return;
}
checkRequiresCapability(ctl, pluginName, clazz, rc);
checkRequiresAnyCapability(ctl, pluginName, clazz, rac);
}
private static void checkRequiresCapability(CapabilityControl ctl,
String pluginName, Class<?> clazz, RequiresCapability rc)
throws AuthException {
if (rc == null) {
return;
}
String capability =
resolveCapability(pluginName, rc.value(), rc.scope(), clazz);
if (!ctl.canPerform(capability)) {
throw new AuthException(String.format(
"Capability %s is required to access this resource",
capability));
}
}
private static void checkRequiresAnyCapability(CapabilityControl ctl,
String pluginName, Class<?> clazz, RequiresAnyCapability rac)
throws AuthException {
if (rac == null) {
return;
}
if (rac.value().length == 0) {
log.error(String.format(
"Class %s uses @%s with no capabilities listed",
clazz.getName(),
RequiresAnyCapability.class.getSimpleName()));
throw new AuthException("cannot check capability");
}
for (String capability : rac.value()) {
capability =
resolveCapability(pluginName, capability, rac.scope(), clazz);
if (ctl.canPerform(capability)) {
return;
}
String capability = rc.value();
if (pluginName != null && !"gerrit".equals(pluginName)
&& (rc.scope() == CapabilityScope.PLUGIN
|| rc.scope() == CapabilityScope.CONTEXT)) {
capability = String.format("%s-%s", pluginName, rc.value());
} else if (rc.scope() == CapabilityScope.PLUGIN) {
log.error(String.format(
"Class %s uses @%s(scope=%s), but is not within a plugin",
clazz.getName(),
RequiresCapability.class.getSimpleName(),
CapabilityScope.PLUGIN.name()));
throw new AuthException("cannot check capability");
}
if (!ctl.canPerform(capability)) {
throw new AuthException(String.format(
"Capability %s is required to access this resource",
capability));
}
}
throw new AuthException(
"One of the following capabilities is required to access this"
+ " resource: " + Arrays.asList(rac.value()));
}
private static String resolveCapability(String pluginName, String capability,
CapabilityScope scope, Class<?> clazz) throws AuthException {
if (pluginName != null && !"gerrit".equals(pluginName)
&& (scope == CapabilityScope.PLUGIN
|| scope == CapabilityScope.CONTEXT)) {
capability = String.format("%s-%s", pluginName, capability);
} else if (scope == CapabilityScope.PLUGIN) {
log.error(String.format(
"Class %s uses @%s(scope=%s), but is not within a plugin",
clazz.getName(),
RequiresCapability.class.getSimpleName(),
CapabilityScope.PLUGIN.name()));
throw new AuthException("cannot check capability");
}
return capability;
}
/**

View File

@@ -21,6 +21,7 @@ import static com.google.gerrit.common.data.GlobalCapability.CREATE_PROJECT;
import static com.google.gerrit.common.data.GlobalCapability.EMAIL_REVIEWERS;
import static com.google.gerrit.common.data.GlobalCapability.FLUSH_CACHES;
import static com.google.gerrit.common.data.GlobalCapability.KILL_TASK;
import static com.google.gerrit.common.data.GlobalCapability.MAINTAIN_SERVER;
import static com.google.gerrit.common.data.GlobalCapability.MODIFY_ACCOUNT;
import static com.google.gerrit.common.data.GlobalCapability.PRIORITY;
import static com.google.gerrit.common.data.GlobalCapability.RUN_GC;
@@ -115,6 +116,7 @@ class GetCapabilities implements RestReadView<AccountResource> {
have.put(EMAIL_REVIEWERS, cc.canEmailReviewers());
have.put(FLUSH_CACHES, cc.canFlushCaches());
have.put(KILL_TASK, cc.canKillTask());
have.put(MAINTAIN_SERVER, cc.canMaintainServer());
have.put(MODIFY_ACCOUNT, cc.canModifyAccount());
have.put(RUN_GC, cc.canRunGC());
have.put(STREAM_EVENTS, cc.canStreamEvents());

View File

@@ -46,8 +46,8 @@ public class Check implements RestReadView<ChangeResource>,
ChangeControl ctl = rsrc.getControl();
if (!ctl.isOwner()
&& !ctl.getProjectControl().isOwner()
&& !ctl.getCurrentUser().getCapabilities().canAdministrateServer()) {
throw new AuthException("Not owner");
&& !ctl.getCurrentUser().getCapabilities().canMaintainServer()) {
throw new AuthException("Cannot fix change");
}
return Response.withMustRevalidate(json.fix(input).format(rsrc));
}

View File

@@ -14,11 +14,13 @@
package com.google.gerrit.server.change;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestModifyView;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.change.Index.Input;
import com.google.gerrit.server.index.ChangeIndexer;
import com.google.gerrit.server.project.ChangeControl;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
@@ -41,7 +43,14 @@ public class Index implements RestModifyView<ChangeResource, Input> {
}
@Override
public Response<?> apply(ChangeResource rsrc, Input input) throws IOException {
public Response<?> apply(ChangeResource rsrc, Input input)
throws IOException, AuthException {
ChangeControl ctl = rsrc.getControl();
if (!ctl.isOwner()
&& !ctl.getCurrentUser().getCapabilities().canMaintainServer()) {
throw new AuthException(
"Only change owner or server maintainer can reindex");
}
indexer.index(db.get(), rsrc.getChange());
return Response.none();
}

View File

@@ -14,9 +14,11 @@
package com.google.gerrit.server.config;
import static com.google.gerrit.common.data.GlobalCapability.MAINTAIN_SERVER;
import static com.google.gerrit.common.data.GlobalCapability.VIEW_CACHES;
import com.google.common.cache.Cache;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.extensions.annotations.RequiresAnyCapability;
import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.restapi.AcceptsPost;
import com.google.gerrit.extensions.restapi.AuthException;
@@ -31,7 +33,7 @@ import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
@RequiresCapability(GlobalCapability.VIEW_CACHES)
@RequiresAnyCapability({VIEW_CACHES, MAINTAIN_SERVER})
@Singleton
public class CachesCollection implements
ChildCollection<ConfigResource, CacheResource>, AcceptsPost<ConfigResource> {

View File

@@ -31,6 +31,7 @@ public class CapabilityConstants extends TranslationBundle {
public String emailReviewers;
public String flushCaches;
public String killTask;
public String maintainServer;
public String modifyAccount;
public String priority;
public String queryLimit;

View File

@@ -14,15 +14,17 @@
package com.google.gerrit.server.config;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import static com.google.gerrit.common.data.GlobalCapability.KILL_TASK;
import static com.google.gerrit.common.data.GlobalCapability.MAINTAIN_SERVER;
import com.google.gerrit.extensions.annotations.RequiresAnyCapability;
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)
@RequiresAnyCapability({KILL_TASK, MAINTAIN_SERVER})
public class DeleteTask implements RestModifyView<TaskResource, Input> {
public static class Input {
}

View File

@@ -14,8 +14,10 @@
package com.google.gerrit.server.config;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import static com.google.gerrit.common.data.GlobalCapability.FLUSH_CACHES;
import static com.google.gerrit.common.data.GlobalCapability.MAINTAIN_SERVER;
import com.google.gerrit.extensions.annotations.RequiresAnyCapability;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestModifyView;
@@ -25,7 +27,7 @@ import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
@RequiresCapability(GlobalCapability.FLUSH_CACHES)
@RequiresAnyCapability({FLUSH_CACHES, MAINTAIN_SERVER})
@Singleton
public class FlushCache implements RestModifyView<CacheResource, Input> {
public static class Input {
@@ -44,9 +46,9 @@ public class FlushCache implements RestModifyView<CacheResource, Input> {
public Response<String> apply(CacheResource rsrc, Input input)
throws AuthException {
if (WEB_SESSIONS.equals(rsrc.getName())
&& !self.get().getCapabilities().canAdministrateServer()) {
&& !self.get().getCapabilities().canMaintainServer()) {
throw new AuthException(String.format(
"only site administrators can flush %s", WEB_SESSIONS));
"only site maintainers can flush %s", WEB_SESSIONS));
}
rsrc.getCache().invalidateAll();

View File

@@ -40,7 +40,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
@RequiresCapability(GlobalCapability.MAINTAIN_SERVER)
public class GetSummary implements RestReadView<ConfigResource> {
private final WorkQueue workQueue;

View File

@@ -14,14 +14,15 @@
package com.google.gerrit.server.config;
import static com.google.gerrit.common.data.GlobalCapability.MAINTAIN_SERVER;
import static com.google.gerrit.common.data.GlobalCapability.VIEW_CACHES;
import static com.google.gerrit.server.config.CacheResource.cacheNameOf;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.common.base.Joiner;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheStats;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.extensions.annotations.RequiresAnyCapability;
import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.restapi.BinaryResult;
import com.google.gerrit.extensions.restapi.RestReadView;
@@ -36,7 +37,7 @@ import java.util.List;
import java.util.Map;
import java.util.TreeMap;
@RequiresCapability(GlobalCapability.VIEW_CACHES)
@RequiresAnyCapability({VIEW_CACHES, MAINTAIN_SERVER})
public class ListCaches implements RestReadView<ConfigResource> {
private final DynamicMap<Cache<?, ?>> cacheMap;

View File

@@ -14,9 +14,11 @@
package com.google.gerrit.server.config;
import static com.google.gerrit.common.data.GlobalCapability.FLUSH_CACHES;
import static com.google.gerrit.common.data.GlobalCapability.MAINTAIN_SERVER;
import com.google.common.cache.Cache;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.extensions.annotations.RequiresAnyCapability;
import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.BadRequestException;
@@ -31,7 +33,7 @@ import com.google.inject.Singleton;
import java.util.ArrayList;
import java.util.List;
@RequiresCapability(GlobalCapability.FLUSH_CACHES)
@RequiresAnyCapability({FLUSH_CACHES, MAINTAIN_SERVER})
@Singleton
public class PostCaches implements RestModifyView<ConfigResource, Input> {
public static class Input {

View File

@@ -7,6 +7,7 @@ createProject = Create Project
emailReviewers = Email Reviewers
flushCaches = Flush Caches
killTask = Kill Task
maintainServer = Maintain Server
modifyAccount = Modify Account
priority = Priority
queryLimit = Query Limit

View File

@@ -14,12 +14,13 @@
package com.google.gerrit.sshd.commands;
import static com.google.gerrit.common.data.GlobalCapability.FLUSH_CACHES;
import static com.google.gerrit.common.data.GlobalCapability.MAINTAIN_SERVER;
import static com.google.gerrit.server.config.PostCaches.Operation.FLUSH;
import static com.google.gerrit.server.config.PostCaches.Operation.FLUSH_ALL;
import static com.google.gerrit.sshd.CommandMetaData.Mode.MASTER_OR_SLAVE;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.extensions.annotations.RequiresAnyCapability;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.server.config.ConfigResource;
import com.google.gerrit.server.config.ListCaches;
@@ -36,7 +37,7 @@ import java.util.ArrayList;
import java.util.List;
/** Causes the caches to purge all entries and reload. */
@RequiresCapability(GlobalCapability.FLUSH_CACHES)
@RequiresAnyCapability({FLUSH_CACHES, MAINTAIN_SERVER})
@CommandMetaData(name = "flush-caches", description = "Flush some/all server caches from memory",
runsAt = MASTER_OR_SLAVE)
final class FlushCaches extends SshCommand {

View File

@@ -14,12 +14,13 @@
package com.google.gerrit.sshd.commands;
import static com.google.gerrit.common.data.GlobalCapability.MAINTAIN_SERVER;
import static com.google.gerrit.common.data.GlobalCapability.RUN_GC;
import static com.google.gerrit.sshd.CommandMetaData.Mode.MASTER_OR_SLAVE;
import com.google.common.collect.Lists;
import com.google.gerrit.common.data.GarbageCollectionResult;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.extensions.annotations.RequiresAnyCapability;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.git.GarbageCollection;
import com.google.gerrit.server.project.ProjectCache;
@@ -35,7 +36,7 @@ import java.util.ArrayList;
import java.util.List;
/** Runs the Git garbage collection. */
@RequiresCapability(GlobalCapability.RUN_GC)
@RequiresAnyCapability({RUN_GC, MAINTAIN_SERVER})
@CommandMetaData(name = "gc", description = "Run Git garbage collection",
runsAt = MASTER_OR_SLAVE)
public class GarbageCollectionCommand extends SshCommand {

View File

@@ -14,8 +14,10 @@
package com.google.gerrit.sshd.commands;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import static com.google.gerrit.common.data.GlobalCapability.KILL_TASK;
import static com.google.gerrit.common.data.GlobalCapability.MAINTAIN_SERVER;
import com.google.gerrit.extensions.annotations.RequiresAnyCapability;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.IdString;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
@@ -34,7 +36,7 @@ import java.util.List;
/** Kill a task in the work queue. */
@AdminHighPriorityCommand
@RequiresCapability(GlobalCapability.KILL_TASK)
@RequiresAnyCapability({KILL_TASK, MAINTAIN_SERVER})
final class KillCommand extends SshCommand {
@Inject
private TasksCollection tasksCollection;

View File

@@ -14,13 +14,14 @@
package com.google.gerrit.sshd.commands;
import static com.google.gerrit.common.data.GlobalCapability.MAINTAIN_SERVER;
import static com.google.gerrit.common.data.GlobalCapability.VIEW_CACHES;
import static com.google.gerrit.sshd.CommandMetaData.Mode.MASTER_OR_SLAVE;
import com.google.common.base.Strings;
import com.google.gerrit.common.TimeUtil;
import com.google.gerrit.common.Version;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.extensions.annotations.RequiresCapability;
import com.google.gerrit.extensions.annotations.RequiresAnyCapability;
import com.google.gerrit.extensions.events.LifecycleListener;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.config.ConfigResource;
@@ -53,7 +54,7 @@ import java.util.Map;
import java.util.Map.Entry;
/** Show the current cache states. */
@RequiresCapability(GlobalCapability.VIEW_CACHES)
@RequiresAnyCapability({VIEW_CACHES, MAINTAIN_SERVER})
@CommandMetaData(name = "show-caches", description = "Display current cache statistics",
runsAt = MASTER_OR_SLAVE)
final class ShowCaches extends SshCommand {
@@ -154,7 +155,7 @@ final class ShowCaches extends SshCommand {
printDiskCaches(caches);
stdout.print('\n');
if (self.get().getCapabilities().canAdministrateServer()) {
if (self.get().getCapabilities().canMaintainServer()) {
sshSummary();
SummaryInfo summary =