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