/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 org.apache.brooklyn.util.core.internal.ssh; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static org.apache.brooklyn.util.net.Networking.checkPortValid; import java.io.File; import java.util.Map; import java.util.Set; import org.apache.brooklyn.util.exceptions.Exceptions; import org.apache.brooklyn.util.os.Os; import com.google.common.collect.Iterables; import com.google.common.collect.Sets; public abstract class SshAbstractTool extends ShellAbstractTool implements SshTool { protected final String toString; protected final String host; protected final String user; protected final String password; protected final int port; protected String privateKeyPassphrase; protected String privateKeyData; protected File privateKeyFile; protected boolean strictHostKeyChecking; protected boolean allocatePTY; public static interface SshAction<T> { void clear() throws Exception; T create() throws Exception; } public static abstract class AbstractSshToolBuilder<T extends SshTool, B extends AbstractSshToolBuilder<T,B>> { protected String host; protected int port = 22; protected String user = System.getProperty("user.name"); protected String password; protected String privateKeyData; protected String privateKeyPassphrase; protected Set<String> privateKeyFiles = Sets.newLinkedHashSet(); protected boolean strictHostKeyChecking = false; protected boolean allocatePTY = false; protected File localTempDir = null; @SuppressWarnings("unchecked") protected B self() { return (B) this; } public B from(Map<String,?> props) { host = getMandatoryVal(props, PROP_HOST); port = getOptionalVal(props, PROP_PORT); user = getOptionalVal(props, PROP_USER); password = getOptionalVal(props, PROP_PASSWORD); warnOnDeprecated(props, "privateKey", "privateKeyData"); privateKeyData = getOptionalVal(props, PROP_PRIVATE_KEY_DATA); privateKeyPassphrase = getOptionalVal(props, PROP_PRIVATE_KEY_PASSPHRASE); // for backwards compatibility accept keyFiles and privateKey // but sshj accepts only a single privateKeyFile; leave blank to use defaults (i.e. ~/.ssh/id_rsa and id_dsa) warnOnDeprecated(props, "keyFiles", null); String privateKeyFile = getOptionalVal(props, PROP_PRIVATE_KEY_FILE); if (privateKeyFile != null) privateKeyFiles.add(privateKeyFile); strictHostKeyChecking = getOptionalVal(props, PROP_STRICT_HOST_KEY_CHECKING); allocatePTY = getOptionalVal(props, PROP_ALLOCATE_PTY); String localTempDirPath = getOptionalVal(props, PROP_LOCAL_TEMP_DIR); localTempDir = (localTempDirPath == null) ? null : new File(Os.tidyPath(localTempDirPath)); return self(); } public B host(String val) { this.host = val; return self(); } public B user(String val) { this.user = val; return self(); } public B password(String val) { this.password = val; return self(); } public B port(int val) { this.port = val; return self(); } public B privateKeyPassphrase(String val) { this.privateKeyPassphrase = val; return self(); } /** @deprecated 1.4.0, use privateKeyData */ public B privateKey(String val) { this.privateKeyData = val; return self(); } public B privateKeyData(String val) { this.privateKeyData = val; return self(); } public B privateKeyFile(String val) { this.privateKeyFiles.add(val); return self(); } public B localTempDir(File val) { this.localTempDir = val; return self(); } public abstract T build(); } protected SshAbstractTool(AbstractSshToolBuilder<?,?> builder) { super(builder.localTempDir); host = checkNotNull(builder.host, "host"); port = builder.port; user = builder.user; password = builder.password; strictHostKeyChecking = builder.strictHostKeyChecking; allocatePTY = builder.allocatePTY; privateKeyPassphrase = builder.privateKeyPassphrase; privateKeyData = builder.privateKeyData; if (builder.privateKeyFiles.size() > 1) { throw new IllegalArgumentException("sshj supports only a single private key-file; " + "for defaults of ~/.ssh/id_rsa and ~/.ssh/id_dsa leave blank"); } else if (builder.privateKeyFiles.size() == 1) { String privateKeyFileStr = Iterables.get(builder.privateKeyFiles, 0); String amendedKeyFile = privateKeyFileStr.startsWith("~") ? (System.getProperty("user.home")+privateKeyFileStr.substring(1)) : privateKeyFileStr; privateKeyFile = new File(amendedKeyFile); } else { privateKeyFile = null; } checkArgument(host.length() > 0, "host value must not be an empty string"); checkPortValid(port, "ssh port"); toString = String.format("%s@%s:%d", user, host, port); } @Override public String toString() { return toString; } public String getHostAddress() { return this.host; } public String getUsername() { return this.user; } protected SshException propagate(Exception e, String message) throws SshException { Exceptions.propagateIfFatal(e); throw new SshException("(" + toString() + ") " + message + ": " + e.getMessage(), e); } }