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:
Marco Miller
2020-10-06 08:28:15 -04:00
53 changed files with 381 additions and 17 deletions

View File

@@ -1 +1 @@
3.5.0
3.5.1

View File

@@ -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()

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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 {

View 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;
}
}

View 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 = "non-graceful",
description = "Test command for immediate shutdown",
runsAt = MASTER_OR_SLAVE)
public class NonGracefulCommand extends TestCommand {
@Override
boolean isGraceful() {
return false;
}
}

View 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();
}

View File

@@ -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);
}
}

View File

@@ -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));
}

View File

@@ -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(":");

View File

@@ -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) {

View File

@@ -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)) {

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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));

View File

@@ -59,6 +59,7 @@ abstract class BaseTestPrologCommand extends SshCommand {
@Override
protected final void run() throws UnloggedFailure {
enableGracefulStop();
try {
RevisionResource revision =
revisions.parse(

View File

@@ -57,6 +57,7 @@ final class CloseConnection extends SshCommand {
@Override
protected void run() throws Failure {
enableGracefulStop();
SshUtil.forEachSshSession(
sshDaemon,
(k, sshSession, abstractSession, ioSession) -> {

View File

@@ -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;

View File

@@ -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;

View File

@@ -102,6 +102,7 @@ final class CreateGroupCommand extends SshCommand {
@Override
protected void run()
throws Failure, IOException, ConfigInvalidException, PermissionBackendException {
enableGracefulStop();
try {
GroupResource rsrc = createGroup();

View File

@@ -166,6 +166,7 @@ final class CreateProjectCommand extends SshCommand {
@Override
protected void run() throws Failure {
enableGracefulStop();
try {
if (!suggestParent) {
if (projectName == null) {

View File

@@ -55,6 +55,7 @@ final class FlushCaches extends SshCommand {
@Override
protected void run() throws Failure {
enableGracefulStop();
try {
if (list) {
if (all || !caches.isEmpty()) {

View File

@@ -62,6 +62,7 @@ public class GarbageCollectionCommand extends SshCommand {
@Override
public void run() throws Exception {
enableGracefulStop();
verifyCommandLine();
runGC();
}

View File

@@ -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)) {

View File

@@ -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 {

View File

@@ -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");
}

View File

@@ -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)) {

View File

@@ -47,6 +47,7 @@ final class KillCommand extends SshCommand {
@Override
protected void run() {
enableGracefulStop();
ConfigResource cfgRsrc = new ConfigResource();
for (String id : taskIds) {
try {

View File

@@ -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.");
}

View File

@@ -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();

View File

@@ -45,6 +45,7 @@ public class ListMembersCommand extends SshCommand {
@Override
public void run() throws Exception {
enableGracefulStop();
impl.display(stdout);
}

View File

@@ -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()) {

View File

@@ -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();

View File

@@ -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");
}

View File

@@ -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()) {

View File

@@ -106,6 +106,7 @@ public class Query extends SshCommand implements DynamicOptions.BeanReceiver {
@Override
protected void run() throws Exception {
enableGracefulStop();
processor.query(join(query, " "));
}

View File

@@ -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!");

View File

@@ -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();

View File

@@ -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");

View File

@@ -154,6 +154,7 @@ final class SetAccountCommand extends SshCommand {
@Override
public void run() throws Exception {
enableGracefulStop();
user = genericUserFactory.create(id);
validate();

View File

@@ -43,6 +43,7 @@ public class SetHeadCommand extends SshCommand {
@Override
protected void run() throws Exception {
enableGracefulStop();
HeadInput input = new HeadInput();
input.ref = newHead;
try {

View File

@@ -61,6 +61,7 @@ public class SetLoggingLevelCommand extends SshCommand {
@SuppressWarnings("unchecked")
@Override
protected void run() throws MalformedURLException {
enableGracefulStop();
if (level == LevelOption.RESET) {
reset();
} else {

View File

@@ -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 =

View File

@@ -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 "

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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(

View File

@@ -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");

View File

@@ -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(

View File

@@ -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");

View 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);
}
}
}

View File

@@ -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