blob: d195aa3cf2a4d28d8949cf133217552730fb8580 [file] [log] [blame]
// Copyright (C) 2017 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.googlesource.gerrit.plugins.replication;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.entities.Project;
import com.google.gerrit.server.ssh.SshAddressesModule;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URISyntaxException;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.jgit.transport.URIish;
public class GerritSshApi implements AdminApi {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
static final int SSH_COMMAND_FAILED = -1;
static final String GERRIT_ADMIN_PROTOCOL_PREFIX = "gerrit+";
protected final SshHelper sshHelper;
protected final URIish uri;
private final Set<URIish> withoutDeleteProjectPlugin = new HashSet<>();
protected GerritSshApi(SshHelper sshHelper, URIish uri) {
this.sshHelper = sshHelper;
this.uri = uri;
}
@Override
public boolean createProject(Project.NameKey projectName, String head) {
OutputStream errStream = sshHelper.newErrorBufferStream();
String cmd = "gerrit create-project --branch " + head + " " + projectName.get();
try {
execute(uri, cmd, errStream);
} catch (IOException e) {
logError("creating", uri, errStream, cmd, e);
return false;
}
return true;
}
@Override
public boolean deleteProject(Project.NameKey projectName) {
if (!withoutDeleteProjectPlugin.contains(uri)) {
OutputStream errStream = sshHelper.newErrorBufferStream();
String cmd = "deleteproject delete --yes-really-delete --force " + projectName.get();
int exitCode = -1;
try {
exitCode = execute(uri, cmd, errStream);
} catch (IOException e) {
logError("deleting", uri, errStream, cmd, e);
return false;
}
if (exitCode == 1) {
logger.atInfo().log(
"DeleteProject plugin is not installed on %s;"
+ " will not try to forward this operation to that host");
withoutDeleteProjectPlugin.add(uri);
}
}
return true;
}
@Override
public boolean updateHead(Project.NameKey projectName, String newHead) {
OutputStream errStream = sshHelper.newErrorBufferStream();
String cmd = "gerrit set-head " + projectName.get() + " --new-head " + newHead;
try {
execute(uri, cmd, errStream);
} catch (IOException e) {
logError("updating HEAD of", uri, errStream, cmd, e);
return false;
}
return true;
}
private URIish toSshUri(URIish uri) throws URISyntaxException {
String uriStr = uri.toString();
if (uri.getHost() != null && uriStr.startsWith(GERRIT_ADMIN_PROTOCOL_PREFIX)) {
return new URIish(uriStr.substring(GERRIT_ADMIN_PROTOCOL_PREFIX.length()));
}
String rawPath = uri.getRawPath();
if (!rawPath.endsWith("/")) {
rawPath = rawPath + "/";
}
URIish sshUri = new URIish("ssh://" + rawPath);
if (sshUri.getPort() < 0) {
sshUri = sshUri.setPort(SshAddressesModule.DEFAULT_PORT);
}
return sshUri;
}
private int execute(URIish uri, String cmd, OutputStream errStream) throws IOException {
try {
URIish sshUri = toSshUri(uri);
return sshHelper.executeRemoteSsh(sshUri, cmd, errStream);
} catch (URISyntaxException e) {
logger.atSevere().withCause(e).log("Cannot convert %s to SSH uri", uri);
}
return SSH_COMMAND_FAILED;
}
public void logError(String msg, URIish uri, OutputStream errStream, String cmd, IOException e) {
logger.atSevere().withCause(e).log(
"Error %s remote repository at %s:\n Exception: %s\n Command: %s\n Output: %s",
msg, uri, e, cmd, errStream);
}
}