Merge branch 'stable-3.0' into stable-3.1
* stable-3.0: Bump Bazel version to 3.5.1 Upgrade jackson-core to 2.11.3 Register graceful shutdown for version command Register graceful shutdown for show queue command Register graceful shutdown for show connections command Register graceful shutdown for show caches command Register graceful shutdown for set reviewers command Register graceful shutdown for set project command Register graceful shutdown for set parent command Register graceful shutdown for set members command Register graceful shutdown for set logging level command Register graceful shutdown for set head command Register graceful shutdown for set account command Register graceful shutdown for review command Register graceful shutdown for rename group command Register graceful shutdown for reload config command Register graceful shutdown for query command Register graceful shutdown for list plugins command Register graceful shutdown for plugin admin commands Register graceful shutdown for list user refs command Register graceful shutdown for list projects command Register graceful shutdown for list members command Register graceful shutdown for list logging level command Register graceful shutdown for list groups command Register graceful shutdown for kill command Register graceful shutdown for index start command Register graceful shutdown for index changes in project command Register graceful shutdown for index changes command Register graceful shutdown for index activate command Register graceful shutdown for gc command Register graceful shutdown for flush caches command Register graceful shutdown for create project command Register graceful shutdown for create group command Register graceful shutdown for create branch command Register graceful shutdown for create account command Register graceful shutdown for close connection command Register graceful shutdown for prolog test commands Register graceful shutdown for ban commit command Register graceful shutdown for apropos command Limit graceful shutdown to SSH sessions serving git requests Update git submodules Change-Id: I519ba25b10209f8856ecf289915c65e5eb8ee09a
This commit is contained in:
@@ -1 +1 @@
|
||||
3.5.0
|
||||
3.5.1
|
||||
|
||||
@@ -377,6 +377,15 @@ public abstract class AbstractDaemonTest {
|
||||
initSsh();
|
||||
}
|
||||
|
||||
protected void restart() throws Exception {
|
||||
server = GerritServer.restart(server, createModule(), createSshModule());
|
||||
server.getTestInjector().injectMembers(this);
|
||||
if (resetter != null) {
|
||||
server.getTestInjector().injectMembers(resetter);
|
||||
}
|
||||
initSsh();
|
||||
}
|
||||
|
||||
protected void evictAndReindexAccount(Account.Id accountId) {
|
||||
accountCache.evict(accountId);
|
||||
accountIndexer.index(accountId);
|
||||
@@ -419,13 +428,16 @@ public abstract class AbstractDaemonTest {
|
||||
|
||||
baseConfig.setInt("receive", null, "changeUpdateThreads", 4);
|
||||
Module module = createModule();
|
||||
Module sshModule = createSshModule();
|
||||
if (classDesc.equals(methodDesc) && !classDesc.sandboxed() && !methodDesc.sandboxed()) {
|
||||
if (commonServer == null) {
|
||||
commonServer = GerritServer.initAndStart(temporaryFolder, classDesc, baseConfig, module);
|
||||
commonServer =
|
||||
GerritServer.initAndStart(temporaryFolder, classDesc, baseConfig, module, sshModule);
|
||||
}
|
||||
server = commonServer;
|
||||
} else {
|
||||
server = GerritServer.initAndStart(temporaryFolder, methodDesc, baseConfig, module);
|
||||
server =
|
||||
GerritServer.initAndStart(temporaryFolder, methodDesc, baseConfig, module, sshModule);
|
||||
}
|
||||
|
||||
server.getTestInjector().injectMembers(this);
|
||||
@@ -518,6 +530,11 @@ public abstract class AbstractDaemonTest {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Override to bind an additional Guice module for SSH injector */
|
||||
public Module createSshModule() {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void initSsh() throws Exception {
|
||||
if (testRequiresSsh
|
||||
&& SshMode.useSsh()
|
||||
|
||||
@@ -312,6 +312,7 @@ public class GerritServer implements AutoCloseable {
|
||||
* @param desc server description.
|
||||
* @param baseConfig default config values; merged with config from {@code desc}.
|
||||
* @param testSysModule additional Guice module to use.
|
||||
* @param testSshModule additional Guice module to use.
|
||||
* @return started server.
|
||||
* @throws Exception
|
||||
*/
|
||||
@@ -319,14 +320,15 @@ public class GerritServer implements AutoCloseable {
|
||||
TemporaryFolder temporaryFolder,
|
||||
Description desc,
|
||||
Config baseConfig,
|
||||
@Nullable Module testSysModule)
|
||||
@Nullable Module testSysModule,
|
||||
@Nullable Module testSshModule)
|
||||
throws Exception {
|
||||
Path site = temporaryFolder.newFolder().toPath();
|
||||
try {
|
||||
if (!desc.memory()) {
|
||||
init(desc, baseConfig, site);
|
||||
}
|
||||
return start(desc, baseConfig, site, testSysModule, null);
|
||||
return start(desc, baseConfig, site, testSysModule, testSshModule, null);
|
||||
} catch (Exception e) {
|
||||
throw e;
|
||||
}
|
||||
@@ -342,6 +344,7 @@ public class GerritServer implements AutoCloseable {
|
||||
* initialize this directory. Can be retrieved from the returned instance via {@link
|
||||
* #getSitePath()}.
|
||||
* @param testSysModule optional additional module to add to the system injector.
|
||||
* @param testSshModule optional additional module to add to the ssh injector.
|
||||
* @param inMemoryRepoManager {@link InMemoryRepositoryManager} that should be used if the site is
|
||||
* started in memory
|
||||
* @param additionalArgs additional command-line arguments for the daemon program; only allowed if
|
||||
@@ -354,6 +357,7 @@ public class GerritServer implements AutoCloseable {
|
||||
Config baseConfig,
|
||||
Path site,
|
||||
@Nullable Module testSysModule,
|
||||
@Nullable Module testSshModule,
|
||||
@Nullable InMemoryRepositoryManager inMemoryRepoManager,
|
||||
String... additionalArgs)
|
||||
throws Exception {
|
||||
@@ -376,6 +380,9 @@ public class GerritServer implements AutoCloseable {
|
||||
if (testSysModule != null) {
|
||||
daemon.addAdditionalSysModuleForTesting(testSysModule);
|
||||
}
|
||||
if (testSshModule != null) {
|
||||
daemon.addAdditionalSshModuleForTesting(testSshModule);
|
||||
}
|
||||
daemon.setEnableSshd(desc.useSsh());
|
||||
|
||||
if (desc.memory()) {
|
||||
@@ -596,7 +603,24 @@ public class GerritServer implements AutoCloseable {
|
||||
|
||||
server.close();
|
||||
server.daemon.stop();
|
||||
return start(server.desc, cfg, site, null, inMemoryRepoManager);
|
||||
return start(server.desc, cfg, site, null, null, inMemoryRepoManager);
|
||||
}
|
||||
|
||||
public static GerritServer restart(
|
||||
GerritServer server, @Nullable Module testSysModule, @Nullable Module testSshModule)
|
||||
throws Exception {
|
||||
checkState(server.desc.sandboxed(), "restarting as slave requires @Sandboxed");
|
||||
Config cfg = server.testInjector.getInstance(Key.get(Config.class, GerritServerConfig.class));
|
||||
Path site = server.testInjector.getInstance(Key.get(Path.class, SitePath.class));
|
||||
|
||||
InMemoryRepositoryManager inMemoryRepoManager = null;
|
||||
if (hasBinding(server.testInjector, InMemoryRepositoryManager.class)) {
|
||||
inMemoryRepoManager = server.testInjector.getInstance(InMemoryRepositoryManager.class);
|
||||
}
|
||||
|
||||
server.close();
|
||||
server.daemon.stop();
|
||||
return start(server.desc, cfg, site, testSysModule, testSshModule, inMemoryRepoManager);
|
||||
}
|
||||
|
||||
private static boolean hasBinding(Injector injector, Class<?> clazz) {
|
||||
|
||||
@@ -66,6 +66,22 @@ public class SshSession {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("resource")
|
||||
public int execAndReturnStatus(String command) throws Exception {
|
||||
ChannelExec channel = (ChannelExec) getSession().openChannel("exec");
|
||||
try {
|
||||
channel.setCommand(command);
|
||||
InputStream err = channel.getErrStream();
|
||||
channel.connect();
|
||||
|
||||
Scanner s = new Scanner(err, UTF_8.name()).useDelimiter("\\A");
|
||||
error = s.hasNext() ? s.next() : null;
|
||||
return channel.getExitStatus();
|
||||
} finally {
|
||||
channel.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
public InputStream exec2(String command, InputStream opt) throws Exception {
|
||||
ChannelExec channel = (ChannelExec) getSession().openChannel("exec");
|
||||
channel.setCommand(command);
|
||||
|
||||
@@ -187,7 +187,7 @@ public abstract class StandaloneSiteTest {
|
||||
private GerritServer startImpl(@Nullable Module testSysModule, String... additionalArgs)
|
||||
throws Exception {
|
||||
return GerritServer.start(
|
||||
serverDesc, baseConfig, sitePaths.site_path, testSysModule, null, additionalArgs);
|
||||
serverDesc, baseConfig, sitePaths.site_path, testSysModule, null, null, additionalArgs);
|
||||
}
|
||||
|
||||
protected static void runGerrit(String... args) throws Exception {
|
||||
|
||||
31
java/com/google/gerrit/acceptance/ssh/GracefulCommand.java
Normal file
31
java/com/google/gerrit/acceptance/ssh/GracefulCommand.java
Normal file
@@ -0,0 +1,31 @@
|
||||
// Copyright (C) 2020 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.ssh;
|
||||
|
||||
import static com.google.gerrit.sshd.CommandMetaData.Mode.MASTER_OR_SLAVE;
|
||||
|
||||
import com.google.gerrit.sshd.CommandMetaData;
|
||||
|
||||
@CommandMetaData(
|
||||
name = "graceful",
|
||||
description = "Test command for graceful shutdown",
|
||||
runsAt = MASTER_OR_SLAVE)
|
||||
public class GracefulCommand extends TestCommand {
|
||||
|
||||
@Override
|
||||
boolean isGraceful() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright (C) 2020 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.ssh;
|
||||
|
||||
import static com.google.gerrit.sshd.CommandMetaData.Mode.MASTER_OR_SLAVE;
|
||||
|
||||
import com.google.gerrit.sshd.CommandMetaData;
|
||||
|
||||
@CommandMetaData(
|
||||
name = "non-graceful",
|
||||
description = "Test command for immediate shutdown",
|
||||
runsAt = MASTER_OR_SLAVE)
|
||||
public class NonGracefulCommand extends TestCommand {
|
||||
|
||||
@Override
|
||||
boolean isGraceful() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
49
java/com/google/gerrit/acceptance/ssh/TestCommand.java
Normal file
49
java/com/google/gerrit/acceptance/ssh/TestCommand.java
Normal file
@@ -0,0 +1,49 @@
|
||||
// Copyright (C) 2020 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.ssh;
|
||||
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import com.google.gerrit.sshd.SshCommand;
|
||||
import java.util.concurrent.CyclicBarrier;
|
||||
import org.kohsuke.args4j.Option;
|
||||
|
||||
public abstract class TestCommand extends SshCommand {
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
public static final CyclicBarrier syncPoint = new CyclicBarrier(2);
|
||||
|
||||
@Option(
|
||||
name = "--duration",
|
||||
aliases = {"-d"},
|
||||
required = true,
|
||||
usage = "Duration of the command execution in seconds")
|
||||
private int duration;
|
||||
|
||||
@Override
|
||||
protected void run() throws UnloggedFailure, Failure, Exception {
|
||||
logger.atFine().log("Starting command.");
|
||||
if (isGraceful()) {
|
||||
enableGracefulStop();
|
||||
}
|
||||
try {
|
||||
syncPoint.await();
|
||||
Thread.sleep(duration * 1000);
|
||||
logger.atFine().log("Stopping command.");
|
||||
} catch (Exception e) {
|
||||
throw die("Command ended prematurely.", e);
|
||||
}
|
||||
}
|
||||
|
||||
abstract boolean isGraceful();
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// Copyright (C) 2020 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.ssh;
|
||||
|
||||
import com.google.gerrit.sshd.CommandModule;
|
||||
|
||||
public class TestSshCommandModule extends CommandModule {
|
||||
@Override
|
||||
protected void configure() {
|
||||
command("graceful").to(GracefulCommand.class);
|
||||
command("non-graceful").to(NonGracefulCommand.class);
|
||||
}
|
||||
}
|
||||
@@ -192,6 +192,7 @@ public class Daemon extends SiteProgram {
|
||||
private AbstractModule luceneModule;
|
||||
private Module emailModule;
|
||||
private List<Module> testSysModules = new ArrayList<>();
|
||||
private List<Module> testSshModules = new ArrayList<>();
|
||||
private Module auditEventModule;
|
||||
|
||||
private Runnable serverStarted;
|
||||
@@ -322,6 +323,11 @@ public class Daemon extends SiteProgram {
|
||||
testSysModules.addAll(Arrays.asList(modules));
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public void addAdditionalSshModuleForTesting(@Nullable Module... modules) {
|
||||
testSshModules.addAll(Arrays.asList(modules));
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public void start() throws IOException {
|
||||
if (dbInjector == null) {
|
||||
@@ -515,6 +521,8 @@ public class Daemon extends SiteProgram {
|
||||
replica,
|
||||
sysInjector.getInstance(DownloadConfig.class),
|
||||
sysInjector.getInstance(LfsPluginAuthCommand.Module.class)));
|
||||
|
||||
modules.addAll(testSshModules);
|
||||
if (!replica) {
|
||||
modules.add(new IndexCommandsModule(sysInjector));
|
||||
}
|
||||
|
||||
@@ -52,6 +52,7 @@ public abstract class AbstractGitCommand extends BaseCommand {
|
||||
|
||||
@Override
|
||||
public void start(ChannelSession channel, Environment env) {
|
||||
enableGracefulStop();
|
||||
String gitProtocol = env.getEnv().get(GIT_PROTOCOL);
|
||||
if (gitProtocol != null) {
|
||||
extraParameters = gitProtocol.split(":");
|
||||
|
||||
@@ -403,6 +403,10 @@ public abstract class BaseCommand implements Command {
|
||||
}
|
||||
}
|
||||
|
||||
protected void enableGracefulStop() {
|
||||
context.getSession().setGracefulStop(true);
|
||||
}
|
||||
|
||||
protected String getTaskDescription() {
|
||||
String[] ta = getTrimmedArguments();
|
||||
if (ta != null) {
|
||||
|
||||
@@ -89,6 +89,7 @@ import org.apache.sshd.common.mac.Mac;
|
||||
import org.apache.sshd.common.random.Random;
|
||||
import org.apache.sshd.common.random.SingletonRandomFactory;
|
||||
import org.apache.sshd.common.session.Session;
|
||||
import org.apache.sshd.common.session.helpers.AbstractSession;
|
||||
import org.apache.sshd.common.session.helpers.DefaultUnknownChannelReferenceHandler;
|
||||
import org.apache.sshd.common.util.buffer.Buffer;
|
||||
import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
|
||||
@@ -368,14 +369,24 @@ public class SshDaemon extends SshServer implements SshInfo, LifecycleListener {
|
||||
Collection<IoSession> ioSessions = daemonAcceptor.getManagedSessions().values();
|
||||
CountDownLatch allSessionsClosed = new CountDownLatch(ioSessions.size());
|
||||
for (IoSession io : ioSessions) {
|
||||
logger.atFine().log("Waiting for session %s to stop.", io.getId());
|
||||
io.addCloseFutureListener(
|
||||
new SshFutureListener<CloseFuture>() {
|
||||
@Override
|
||||
public void operationComplete(CloseFuture future) {
|
||||
allSessionsClosed.countDown();
|
||||
}
|
||||
});
|
||||
AbstractSession serverSession = AbstractSession.getSession(io, true);
|
||||
SshSession sshSession =
|
||||
serverSession != null ? serverSession.getAttribute(SshSession.KEY) : null;
|
||||
if (sshSession != null && sshSession.requiresGracefulStop()) {
|
||||
logger.atFine().log("Waiting for session %s to stop.", io.getId());
|
||||
io.addCloseFutureListener(
|
||||
new SshFutureListener<CloseFuture>() {
|
||||
@Override
|
||||
public void operationComplete(CloseFuture future) {
|
||||
logger.atFine().log("Session %s was stopped.", io.getId());
|
||||
allSessionsClosed.countDown();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
logger.atFine().log("Stopping session %s immediately.", io.getId());
|
||||
io.close(true);
|
||||
allSessionsClosed.countDown();
|
||||
}
|
||||
}
|
||||
try {
|
||||
if (!allSessionsClosed.await(gracefulStopTimeout, TimeUnit.SECONDS)) {
|
||||
|
||||
@@ -35,6 +35,8 @@ public class SshSession {
|
||||
private volatile String authError;
|
||||
private volatile String peerAgent;
|
||||
|
||||
private volatile boolean gracefulStop = false;
|
||||
|
||||
SshSession(int sessionId, SocketAddress peer) {
|
||||
this.sessionId = sessionId;
|
||||
this.remoteAddress = peer;
|
||||
@@ -58,6 +60,14 @@ public class SshSession {
|
||||
return sessionId;
|
||||
}
|
||||
|
||||
public boolean requiresGracefulStop() {
|
||||
return gracefulStop;
|
||||
}
|
||||
|
||||
public void setGracefulStop(boolean gracefulStop) {
|
||||
this.gracefulStop = gracefulStop;
|
||||
}
|
||||
|
||||
/** Identity of the authenticated user account on the socket. */
|
||||
public CurrentUser getUser() {
|
||||
return identity;
|
||||
|
||||
@@ -39,6 +39,7 @@ final class AproposCommand extends SshCommand {
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
enableGracefulStop();
|
||||
try {
|
||||
List<QueryDocumentationExecutor.DocResult> res = searcher.doQuery(q);
|
||||
for (DocResult docResult : res) {
|
||||
|
||||
@@ -63,6 +63,7 @@ public class BanCommitCommand extends SshCommand {
|
||||
|
||||
@Override
|
||||
protected void run() throws Failure {
|
||||
enableGracefulStop();
|
||||
try {
|
||||
BanCommitInput input =
|
||||
BanCommitInput.fromCommits(Lists.transform(commitsToBan, ObjectId::getName));
|
||||
|
||||
@@ -59,6 +59,7 @@ abstract class BaseTestPrologCommand extends SshCommand {
|
||||
|
||||
@Override
|
||||
protected final void run() throws UnloggedFailure {
|
||||
enableGracefulStop();
|
||||
try {
|
||||
RevisionResource revision =
|
||||
revisions.parse(
|
||||
|
||||
@@ -57,6 +57,7 @@ final class CloseConnection extends SshCommand {
|
||||
|
||||
@Override
|
||||
protected void run() throws Failure {
|
||||
enableGracefulStop();
|
||||
SshUtil.forEachSshSession(
|
||||
sshDaemon,
|
||||
(k, sshSession, abstractSession, ioSession) -> {
|
||||
|
||||
@@ -72,6 +72,7 @@ final class CreateAccountCommand extends SshCommand {
|
||||
@Override
|
||||
protected void run()
|
||||
throws IOException, ConfigInvalidException, UnloggedFailure, PermissionBackendException {
|
||||
enableGracefulStop();
|
||||
AccountInput input = new AccountInput();
|
||||
input.username = username;
|
||||
input.email = email;
|
||||
|
||||
@@ -44,6 +44,7 @@ public final class CreateBranchCommand extends SshCommand {
|
||||
|
||||
@Override
|
||||
protected void run() throws UnloggedFailure {
|
||||
enableGracefulStop();
|
||||
try {
|
||||
BranchInput in = new BranchInput();
|
||||
in.revision = revision;
|
||||
|
||||
@@ -102,6 +102,7 @@ final class CreateGroupCommand extends SshCommand {
|
||||
@Override
|
||||
protected void run()
|
||||
throws Failure, IOException, ConfigInvalidException, PermissionBackendException {
|
||||
enableGracefulStop();
|
||||
try {
|
||||
GroupResource rsrc = createGroup();
|
||||
|
||||
|
||||
@@ -166,6 +166,7 @@ final class CreateProjectCommand extends SshCommand {
|
||||
|
||||
@Override
|
||||
protected void run() throws Failure {
|
||||
enableGracefulStop();
|
||||
try {
|
||||
if (!suggestParent) {
|
||||
if (projectName == null) {
|
||||
|
||||
@@ -55,6 +55,7 @@ final class FlushCaches extends SshCommand {
|
||||
|
||||
@Override
|
||||
protected void run() throws Failure {
|
||||
enableGracefulStop();
|
||||
try {
|
||||
if (list) {
|
||||
if (all || !caches.isEmpty()) {
|
||||
|
||||
@@ -62,6 +62,7 @@ public class GarbageCollectionCommand extends SshCommand {
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
enableGracefulStop();
|
||||
verifyCommandLine();
|
||||
runGC();
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ public class IndexActivateCommand extends SshCommand {
|
||||
|
||||
@Override
|
||||
protected void run() throws UnloggedFailure {
|
||||
enableGracefulStop();
|
||||
try {
|
||||
if (versionManager.isKnownIndex(name)) {
|
||||
if (versionManager.activateLatestIndex(name)) {
|
||||
|
||||
@@ -53,6 +53,7 @@ final class IndexChangesCommand extends SshCommand {
|
||||
|
||||
@Override
|
||||
protected void run() throws UnloggedFailure {
|
||||
enableGracefulStop();
|
||||
boolean ok = true;
|
||||
for (ChangeResource rsrc : changes.values()) {
|
||||
try {
|
||||
|
||||
@@ -43,6 +43,7 @@ final class IndexChangesInProjectCommand extends SshCommand {
|
||||
|
||||
@Override
|
||||
protected void run() throws UnloggedFailure, Failure, Exception {
|
||||
enableGracefulStop();
|
||||
if (projects.isEmpty()) {
|
||||
throw die("needs at least one project as command arguments");
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ public class IndexStartCommand extends SshCommand {
|
||||
|
||||
@Override
|
||||
protected void run() throws UnloggedFailure {
|
||||
enableGracefulStop();
|
||||
try {
|
||||
if (versionManager.isKnownIndex(name)) {
|
||||
if (versionManager.startReindexer(name, force)) {
|
||||
|
||||
@@ -47,6 +47,7 @@ final class KillCommand extends SshCommand {
|
||||
|
||||
@Override
|
||||
protected void run() {
|
||||
enableGracefulStop();
|
||||
ConfigResource cfgRsrc = new ConfigResource();
|
||||
for (String id : taskIds) {
|
||||
try {
|
||||
|
||||
@@ -52,6 +52,7 @@ public class ListGroupsCommand extends SshCommand {
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
enableGracefulStop();
|
||||
if (listGroups.getUser() != null && !listGroups.getProjects().isEmpty()) {
|
||||
throw die("--user and --project options are not compatible.");
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ public class ListLoggingLevelCommand extends SshCommand {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected void run() {
|
||||
enableGracefulStop();
|
||||
Map<String, String> logs = new TreeMap<>();
|
||||
for (Enumeration<Logger> logger = LogManager.getCurrentLoggers(); logger.hasMoreElements(); ) {
|
||||
Logger log = logger.nextElement();
|
||||
|
||||
@@ -45,6 +45,7 @@ public class ListMembersCommand extends SshCommand {
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
enableGracefulStop();
|
||||
impl.display(stdout);
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ public class ListProjectsCommand extends SshCommand {
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
enableGracefulStop();
|
||||
if (!impl.getFormat().isJson()) {
|
||||
List<String> showBranch = impl.getShowBranch();
|
||||
if (impl.isShowTree() && (showBranch != null) && !showBranch.isEmpty()) {
|
||||
|
||||
@@ -74,6 +74,7 @@ public class LsUserRefs extends SshCommand {
|
||||
|
||||
@Override
|
||||
protected void run() throws Failure {
|
||||
enableGracefulStop();
|
||||
Account.Id userAccountId;
|
||||
try {
|
||||
userAccountId = accountResolver.resolve(userName).asUnique().account().id();
|
||||
|
||||
@@ -28,6 +28,7 @@ public abstract class PluginAdminSshCommand extends SshCommand {
|
||||
|
||||
@Override
|
||||
protected final void run() throws UnloggedFailure {
|
||||
enableGracefulStop();
|
||||
if (!loader.isRemoteAdminEnabled()) {
|
||||
throw die("remote plugin administration is disabled");
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ public class PluginLsCommand extends SshCommand {
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
enableGracefulStop();
|
||||
Map<String, PluginInfo> output = list.apply(TopLevelResource.INSTANCE).value();
|
||||
|
||||
if (format.isJson()) {
|
||||
|
||||
@@ -106,6 +106,7 @@ public class Query extends SshCommand implements DynamicOptions.BeanReceiver {
|
||||
|
||||
@Override
|
||||
protected void run() throws Exception {
|
||||
enableGracefulStop();
|
||||
processor.query(join(query, " "));
|
||||
}
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ public class ReloadConfig extends SshCommand {
|
||||
|
||||
@Override
|
||||
protected void run() throws Failure {
|
||||
enableGracefulStop();
|
||||
Multimap<UpdateResult, ConfigUpdateEntry> updates = gerritServerConfigReloader.reloadConfig();
|
||||
if (updates.isEmpty()) {
|
||||
stdout.println("No config entries updated!");
|
||||
|
||||
@@ -46,6 +46,7 @@ public class RenameGroupCommand extends SshCommand {
|
||||
|
||||
@Override
|
||||
protected void run() throws Failure {
|
||||
enableGracefulStop();
|
||||
try {
|
||||
GroupResource rsrc = groups.parse(TopLevelResource.INSTANCE, IdString.fromDecoded(groupName));
|
||||
NameInput input = new NameInput();
|
||||
|
||||
@@ -167,6 +167,7 @@ public class ReviewCommand extends SshCommand {
|
||||
|
||||
@Override
|
||||
protected void run() throws UnloggedFailure {
|
||||
enableGracefulStop();
|
||||
if (abandonChange) {
|
||||
if (restoreChange) {
|
||||
throw die("abandon and restore actions are mutually exclusive");
|
||||
|
||||
@@ -154,6 +154,7 @@ final class SetAccountCommand extends SshCommand {
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
enableGracefulStop();
|
||||
user = genericUserFactory.create(id);
|
||||
|
||||
validate();
|
||||
|
||||
@@ -43,6 +43,7 @@ public class SetHeadCommand extends SshCommand {
|
||||
|
||||
@Override
|
||||
protected void run() throws Exception {
|
||||
enableGracefulStop();
|
||||
HeadInput input = new HeadInput();
|
||||
input.ref = newHead;
|
||||
try {
|
||||
|
||||
@@ -61,6 +61,7 @@ public class SetLoggingLevelCommand extends SshCommand {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected void run() throws MalformedURLException {
|
||||
enableGracefulStop();
|
||||
if (level == LevelOption.RESET) {
|
||||
reset();
|
||||
} else {
|
||||
|
||||
@@ -102,6 +102,7 @@ public class SetMembersCommand extends SshCommand {
|
||||
|
||||
@Override
|
||||
protected void run() throws UnloggedFailure, Failure, Exception {
|
||||
enableGracefulStop();
|
||||
try {
|
||||
for (AccountGroup.UUID groupUuid : groups) {
|
||||
GroupResource resource =
|
||||
|
||||
@@ -88,6 +88,7 @@ final class SetParentCommand extends SshCommand {
|
||||
|
||||
@Override
|
||||
protected void run() throws Failure {
|
||||
enableGracefulStop();
|
||||
if (oldParent == null && children.isEmpty()) {
|
||||
throw die(
|
||||
"child projects have to be specified as "
|
||||
|
||||
@@ -132,6 +132,7 @@ final class SetProjectCommand extends SshCommand {
|
||||
|
||||
@Override
|
||||
protected void run() throws Failure {
|
||||
enableGracefulStop();
|
||||
ConfigInput configInput = new ConfigInput();
|
||||
configInput.requireChangeId = requireChangeID;
|
||||
configInput.submitType = submitType;
|
||||
|
||||
@@ -96,6 +96,7 @@ public class SetReviewersCommand extends SshCommand {
|
||||
|
||||
@Override
|
||||
protected void run() throws UnloggedFailure {
|
||||
enableGracefulStop();
|
||||
boolean ok = true;
|
||||
for (ChangeResource rsrc : changes.values()) {
|
||||
try {
|
||||
|
||||
@@ -112,6 +112,7 @@ final class ShowCaches extends SshCommand {
|
||||
|
||||
@Override
|
||||
protected void run() throws Failure {
|
||||
enableGracefulStop();
|
||||
nw = columns - 50;
|
||||
Date now = new Date();
|
||||
stdout.format(
|
||||
|
||||
@@ -86,6 +86,7 @@ final class ShowConnections extends SshCommand {
|
||||
|
||||
@Override
|
||||
protected void run() throws Failure {
|
||||
enableGracefulStop();
|
||||
final IoAcceptor acceptor = daemon.getIoAcceptor();
|
||||
if (acceptor == null) {
|
||||
throw new Failure(1, "fatal: sshd no longer running");
|
||||
|
||||
@@ -85,6 +85,7 @@ final class ShowQueue extends SshCommand {
|
||||
|
||||
@Override
|
||||
protected void run() throws Failure {
|
||||
enableGracefulStop();
|
||||
maxCommandWidth = wide ? Integer.MAX_VALUE : columns - 8 - 12 - 12 - 4 - 4;
|
||||
stdout.print(
|
||||
String.format(
|
||||
|
||||
@@ -25,6 +25,7 @@ final class VersionCommand extends SshCommand {
|
||||
|
||||
@Override
|
||||
protected void run() throws Failure {
|
||||
enableGracefulStop();
|
||||
String v = Version.getVersion();
|
||||
if (v == null) {
|
||||
throw new Failure(1, "fatal: version unavailable");
|
||||
|
||||
100
javatests/com/google/gerrit/acceptance/ssh/SshDaemonIT.java
Normal file
100
javatests/com/google/gerrit/acceptance/ssh/SshDaemonIT.java
Normal file
@@ -0,0 +1,100 @@
|
||||
// Copyright (C) 2020 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.ssh;
|
||||
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import com.google.gerrit.acceptance.AbstractDaemonTest;
|
||||
import com.google.gerrit.acceptance.NoHttpd;
|
||||
import com.google.gerrit.acceptance.Sandboxed;
|
||||
import com.google.gerrit.acceptance.UseSsh;
|
||||
import com.google.gerrit.server.config.SitePaths;
|
||||
import com.google.gerrit.server.restapi.config.ListTasks;
|
||||
import com.google.gerrit.testing.ConfigSuite;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Module;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.eclipse.jgit.lib.Config;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@NoHttpd
|
||||
@UseSsh
|
||||
@Sandboxed
|
||||
@RunWith(ConfigSuite.class)
|
||||
@SuppressWarnings("unused")
|
||||
public class SshDaemonIT extends AbstractDaemonTest {
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
@Inject private ListTasks listTasks;
|
||||
@Inject private SitePaths gerritSitePath;
|
||||
|
||||
@ConfigSuite.Parameter protected Config config;
|
||||
|
||||
@ConfigSuite.Config
|
||||
public static Config gracefulConfig() {
|
||||
Config config = new Config();
|
||||
config.setString("sshd", null, "gracefulStopTimeout", "10s");
|
||||
return config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Module createSshModule() {
|
||||
return new TestSshCommandModule();
|
||||
}
|
||||
|
||||
public Future<Integer> startCommand(String command) throws Exception {
|
||||
Callable<Integer> gracefulSession =
|
||||
() -> {
|
||||
int returnCode = -1;
|
||||
logger.atFine().log("Before Command");
|
||||
returnCode = userSshSession.execAndReturnStatus(command);
|
||||
logger.atFine().log("After Command");
|
||||
return returnCode;
|
||||
};
|
||||
|
||||
ExecutorService executor = Executors.newFixedThreadPool(1);
|
||||
Future<Integer> future = executor.submit(gracefulSession);
|
||||
|
||||
LocalDateTime timeout = LocalDateTime.now().plusSeconds(10);
|
||||
|
||||
TestCommand.syncPoint.await();
|
||||
|
||||
return future;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void NonGracefulCommandIsStoppedImmediately() throws Exception {
|
||||
Future<Integer> future = startCommand("non-graceful -d 5");
|
||||
restart();
|
||||
Assert.assertTrue(future.get() == -1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void GracefulCommandIsStoppedGracefully() throws Exception {
|
||||
Future<Integer> future = startCommand("graceful -d 5");
|
||||
restart();
|
||||
if (cfg.getTimeUnit("sshd", null, "gracefulStopTimeout", 0, TimeUnit.SECONDS) == 0) {
|
||||
Assert.assertTrue(future.get() == -1);
|
||||
} else {
|
||||
Assert.assertTrue(future.get() == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -108,8 +108,8 @@ def declare_nongoogle_deps():
|
||||
|
||||
maven_jar(
|
||||
name = "jackson-core",
|
||||
artifact = "com.fasterxml.jackson.core:jackson-core:2.11.2",
|
||||
sha1 = "bc022ab0f0c83c07f9c52c5ab9a6a4932b15cc35",
|
||||
artifact = "com.fasterxml.jackson.core:jackson-core:2.11.3",
|
||||
sha1 = "c2351800432bdbdd8284c3f5a7f0782a352aa84a",
|
||||
)
|
||||
|
||||
# Google internal dependencies: these are developed at Google, so there is
|
||||
|
||||
Reference in New Issue
Block a user