Add a Maintain Server global capability

This capability allows for general maintenance tasks like flushing
caches and reindexing changes, without requiring either Administrate
Server (which is too broad) or a handful of other minor capabilities
(which we don't want to grow out of control).

Change-Id: I3dd75d14e7b0303b23bad24dffb9bfdfb515efc8
This commit is contained in:
Dave Borowitz
2015-06-11 15:35:48 -04:00
parent 4b61a78478
commit 664d040c79
25 changed files with 166 additions and 79 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 a replication task or a user initiated task such as an upload-pack or
receive-pack. 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]] [[capability_modifyAccount]]
=== Modify Account === Modify Account

View File

@@ -21,9 +21,16 @@ the Gerrit web interface.
If no options are supplied, defaults to `--all`. If no options are supplied, defaults to `--all`.
== ACCESS == ACCESS
Caller must be a member of the privileged 'Administrators' group,
or in a group that have been granted The caller must be a member of a group that is granted one of the
link:access-control.html#capability_flushCaches[the 'Flush Caches' global capability]. 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 == SCRIPTING
This command is intended to be used in scripts. 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. Width of the output table.
== ACCESS == ACCESS
The caller must be a member of a group that is granted the The caller must be a member of a group that is granted one of the
link:access-control.html#capability_viewCaches[View Caches] capability following capabilities:
or the link:access-control.html#capability_administrateServer[
Administrate Server] capability. * 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 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 only printed out if the caller is a member of a group that is granted
the link:access-control.html#capability_administrateServer[Administrate the link:access-control.html#capability_administrateServer[Administrate
Server] or link:access-control.html#capability_maintainServer[Maintain
Server] capability. Server] capability.
== SCRIPTING == SCRIPTING

View File

@@ -1324,6 +1324,9 @@ link:access-control.html#capability_flushCaches[Flush Caches]
capability. capability.
|`killTask` |not set if `false`|Whether the user has the |`killTask` |not set if `false`|Whether the user has the
link:access-control.html#capability_kill[Kill Task] capability. 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 |`priority` |not set if `INTERACTIVE`|The name of the thread
pool used by the user, see link:access-control.html#capability_priority[ pool used by the user, see link:access-control.html#capability_priority[
Priority] capability. 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. 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 The caller must be a member of a group that is granted one of the
link:access-control.html#capability_viewCaches[View Caches] capability following capabilities:
or the link:access-control.html#capability_administrateServer[
Administrate Server] capability. * 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. 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. Retrieves information about a cache.
The caller must be a member of a group that is granted the The caller must be a member of a group that is granted one of the
link:access-control.html#capability_viewCaches[View Caches] capability following capabilities:
or the link:access-control.html#capability_administrateServer[
Administrate Server] capability. * 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. 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. Flushes a cache.
The caller must be a member of a group that is granted the The caller must be a member of a group that is granted one of the
link:access-control.html#capability_flushCaches[Flush Caches] capability following capabilities:
or the link:access-control.html#capability_administrateServer[
Administrate Server] capability.
The "web_sessions" cache can only be flushed if the caller is member of * link:access-control.html#capability_flushCaches[Flush Caches] (any cache
a group that is granted the except "web_sessions")
link:access-control.html#capability_administrateServer[Administrate * link:access-control.html#capability_maintainServer[Maintain Server] (any cache
Server] capability. including "web_sessions")
* link:access-control.html#capability_administrateServer[Administrate Server]
(any cache including "web_sessions")
.Request .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 is associated with. Tasks operating on other projects, or that do not
have a specific project, are hidden. have a specific project, are hidden.
Members of a group that is granted the The caller must be a member of a group that is granted one of the
link:access-control.html#capability_viewQueue[View Queue] capability or following capabilities:
the link:access-control.html#capability_administrateServer[Administrate
Server] capability can see 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]
As result a list of link:#task-info[TaskInfo] entities is returned. 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 is associated with. Tasks operating on other projects, or that do not
have a specific project, are hidden. have a specific project, are hidden.
Members of a group that is granted the The caller must be a member of a group that is granted one of the
link:access-control.html#capability_viewQueue[View Queue] capability or following capabilities:
the link:access-control.html#capability_administrateServer[Administrate
Server] capability can see 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]
As result a link:#task-info[TaskInfo] entity is returned. 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 Kills a task from the background work queue that the Gerrit daemon
is currently performing, or will perform in the near future. is currently performing, or will perform in the near future.
The caller must be a member of a group that is granted the The caller must be a member of a group that is granted one of the
link:access-control.html#capability_kill[Kill Task] capability following capabilities:
or the link:access-control.html#capability_administrateServer[
Administrate Server] capability. * 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 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 is associated with. Tasks operating on other projects, or that do not
have a specific project, are hidden. have a specific project, are hidden.
Members of a group that is granted the Members of a group granted one of the following capabilities may view
link:access-control.html#capability_viewQueue[View Queue] capability or all tasks:
the link:access-control.html#capability_administrateServer[Administrate
Server] capability can see 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 .Request
---- ----

View File

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

View File

@@ -26,7 +26,7 @@ public class IndexChangeIT extends AbstractDaemonTest {
@Test @Test
public void indexChange() throws Exception { public void indexChange() throws Exception {
String changeId = createChange().getChangeId(); 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); 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 { public void testGcWithoutCapability_Error() throws Exception {
SshSession s = new SshSession(server, user); SshSession s = new SshSession(server, user);
s.exec("gerrit gc --all"); 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(); s.close();
} }

View File

@@ -71,6 +71,16 @@ public class GlobalCapability {
/** Can terminate any task using the kill command. */ /** Can terminate any task using the kill command. */
public static final String KILL_TASK = "killTask"; 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. */ /** Can modify any account on the server. */
public static final String MODIFY_ACCOUNT = "modifyAccount"; public static final String MODIFY_ACCOUNT = "modifyAccount";
@@ -121,6 +131,7 @@ public class GlobalCapability {
NAMES_ALL.add(EMAIL_REVIEWERS); NAMES_ALL.add(EMAIL_REVIEWERS);
NAMES_ALL.add(FLUSH_CACHES); NAMES_ALL.add(FLUSH_CACHES);
NAMES_ALL.add(KILL_TASK); NAMES_ALL.add(KILL_TASK);
NAMES_ALL.add(MAINTAIN_SERVER);
NAMES_ALL.add(MODIFY_ACCOUNT); NAMES_ALL.add(MODIFY_ACCOUNT);
NAMES_ALL.add(PRIORITY); NAMES_ALL.add(PRIORITY);
NAMES_ALL.add(QUERY_LIMIT); NAMES_ALL.add(QUERY_LIMIT);

View File

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

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.EMAIL_REVIEWERS;
import static com.google.gerrit.common.data.GlobalCapability.FLUSH_CACHES; 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.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.MODIFY_ACCOUNT;
import static com.google.gerrit.common.data.GlobalCapability.PRIORITY; import static com.google.gerrit.common.data.GlobalCapability.PRIORITY;
import static com.google.gerrit.common.data.GlobalCapability.RUN_GC; 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(EMAIL_REVIEWERS, cc.canEmailReviewers());
have.put(FLUSH_CACHES, cc.canFlushCaches()); have.put(FLUSH_CACHES, cc.canFlushCaches());
have.put(KILL_TASK, cc.canKillTask()); have.put(KILL_TASK, cc.canKillTask());
have.put(MAINTAIN_SERVER, cc.canMaintainServer());
have.put(MODIFY_ACCOUNT, cc.canModifyAccount()); have.put(MODIFY_ACCOUNT, cc.canModifyAccount());
have.put(RUN_GC, cc.canRunGC()); have.put(RUN_GC, cc.canRunGC());
have.put(STREAM_EVENTS, cc.canStreamEvents()); have.put(STREAM_EVENTS, cc.canStreamEvents());

View File

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

View File

@@ -14,11 +14,13 @@
package com.google.gerrit.server.change; 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.Response;
import com.google.gerrit.extensions.restapi.RestModifyView; import com.google.gerrit.extensions.restapi.RestModifyView;
import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.change.Index.Input; import com.google.gerrit.server.change.Index.Input;
import com.google.gerrit.server.index.ChangeIndexer; import com.google.gerrit.server.index.ChangeIndexer;
import com.google.gerrit.server.project.ChangeControl;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Provider; import com.google.inject.Provider;
import com.google.inject.Singleton; import com.google.inject.Singleton;
@@ -41,7 +43,14 @@ public class Index implements RestModifyView<ChangeResource, Input> {
} }
@Override @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()); indexer.index(db.get(), rsrc.getChange());
return Response.none(); return Response.none();
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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