Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Mike Arnold 2012-03-11 09:27:11 -05:00
commit 982022be3e
39 changed files with 1099 additions and 283 deletions

View File

@ -123,7 +123,7 @@ public class ServerToNodeMetadata implements Function<Server, NodeMetadata> {
try { try {
return Iterables.find(hardwares.get(), new FindHardwareForServer(from)); return Iterables.find(hardwares.get(), new FindHardwareForServer(from));
} catch (NoSuchElementException e) { } catch (NoSuchElementException e) {
logger.warn("could not find a matching hardware for server %s", from); logger.debug("could not find a matching hardware for server %s", from);
} }
return null; return null;
} }
@ -132,7 +132,7 @@ public class ServerToNodeMetadata implements Function<Server, NodeMetadata> {
try { try {
return Iterables.find(images.get(), new FindImageForServer(from)).getOperatingSystem(); return Iterables.find(images.get(), new FindImageForServer(from)).getOperatingSystem();
} catch (NoSuchElementException e) { } catch (NoSuchElementException e) {
logger.warn("could not find a matching image for server %s in location %s", from, location.get()); logger.debug("could not find a matching image for server %s in location %s", from, location.get());
} }
return null; return null;
} }

View File

@ -98,7 +98,7 @@ public class InstanceToNodeMetadata implements Function<Instance, NodeMetadata>
try { try {
return Iterables.find(hardwares.get(), new FindHardwareForInstance(from)); return Iterables.find(hardwares.get(), new FindHardwareForInstance(from));
} catch (NoSuchElementException e) { } catch (NoSuchElementException e) {
logger.warn("could not find a matching hardware for instance %s", from); logger.debug("could not find a matching hardware for instance %s", from);
} }
return null; return null;
} }
@ -107,7 +107,7 @@ public class InstanceToNodeMetadata implements Function<Instance, NodeMetadata>
try { try {
return Iterables.find(images.get(), new FindImageForInstance(from)).getOperatingSystem(); return Iterables.find(images.get(), new FindImageForInstance(from)).getOperatingSystem();
} catch (NoSuchElementException e) { } catch (NoSuchElementException e) {
logger.warn("could not find a matching image for instance %s", from); logger.debug("could not find a matching image for instance %s", from);
} }
return null; return null;
} }
@ -129,7 +129,7 @@ public class InstanceToNodeMetadata implements Function<Instance, NodeMetadata>
try { try {
return Iterables.find(locations.get(), new FindLocationForInstance(from)); return Iterables.find(locations.get(), new FindLocationForInstance(from));
} catch (NoSuchElementException e) { } catch (NoSuchElementException e) {
logger.warn("could not find a matching realm for instance %s", from); logger.debug("could not find a matching realm for instance %s", from);
} }
return null; return null;
} }

View File

@ -126,7 +126,7 @@ public class ServerToNodeMetadata implements Function<Server, NodeMetadata> {
try { try {
return Iterables.find(hardwares.get(), new FindHardwareForServer(from)); return Iterables.find(hardwares.get(), new FindHardwareForServer(from));
} catch (NoSuchElementException e) { } catch (NoSuchElementException e) {
logger.warn("could not find a matching hardware for server %s", from); logger.debug("could not find a matching hardware for server %s", from);
} }
return null; return null;
} }
@ -135,7 +135,7 @@ public class ServerToNodeMetadata implements Function<Server, NodeMetadata> {
try { try {
return Iterables.find(images.get(), new FindImageForServer(from)); return Iterables.find(images.get(), new FindImageForServer(from));
} catch (NoSuchElementException e) { } catch (NoSuchElementException e) {
logger.warn("could not find a matching image for server %s in location %s", from, location.get()); logger.debug("could not find a matching image for server %s in location %s", from, location.get());
} }
return null; return null;
} }

View File

@ -39,7 +39,7 @@ public interface SshClient {
*/ */
@Deprecated @Deprecated
SshClient create(IPSocket socket, Credentials credentials); SshClient create(IPSocket socket, Credentials credentials);
SshClient create(IPSocket socket, LoginCredentials credentials); SshClient create(IPSocket socket, LoginCredentials credentials);
} }
@ -51,19 +51,23 @@ public interface SshClient {
void put(String path, Payload contents); void put(String path, Payload contents);
Payload get(String path); Payload get(String path);
/** /**
* Execute a process and block until it is complete * Execute a process and block until it is complete
* *
* @param command command line to invoke * @param command
* command line to invoke
* @return output of the command * @return output of the command
*/ */
ExecResponse exec(String command); ExecResponse exec(String command);
/** /**
* Execute a process and allow the user to interact with it * Execute a process and allow the user to interact with it. Note that this will allow the
* session to exist indefinitely, and its connection is not closed when {@link #disconnect()} is
* called.
* *
* @param command command line to invoke * @param command
* command line to invoke
* @return reference to the running process * @return reference to the running process
* @since 1.5.0 * @since 1.5.0
*/ */

View File

@ -34,7 +34,6 @@ import java.io.Closeable;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.ConnectException; import java.net.ConnectException;
import java.util.Arrays;
import javax.annotation.PreDestroy; import javax.annotation.PreDestroy;
import javax.annotation.Resource; import javax.annotation.Resource;
@ -44,6 +43,7 @@ import org.apache.commons.io.input.ProxyInputStream;
import org.apache.commons.io.output.ByteArrayOutputStream; import org.apache.commons.io.output.ByteArrayOutputStream;
import org.jclouds.compute.domain.ExecChannel; import org.jclouds.compute.domain.ExecChannel;
import org.jclouds.compute.domain.ExecResponse; import org.jclouds.compute.domain.ExecResponse;
import org.jclouds.domain.LoginCredentials;
import org.jclouds.http.handlers.BackoffLimitedRetryHandler; import org.jclouds.http.handlers.BackoffLimitedRetryHandler;
import org.jclouds.io.Payload; import org.jclouds.io.Payload;
import org.jclouds.io.Payloads; import org.jclouds.io.Payloads;
@ -52,7 +52,6 @@ import org.jclouds.net.IPSocket;
import org.jclouds.rest.AuthorizationException; import org.jclouds.rest.AuthorizationException;
import org.jclouds.ssh.SshClient; import org.jclouds.ssh.SshClient;
import org.jclouds.ssh.SshException; import org.jclouds.ssh.SshException;
import org.jclouds.util.CredentialUtils;
import org.jclouds.util.Strings2; import org.jclouds.util.Strings2;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
@ -61,10 +60,10 @@ import com.google.common.base.Predicates;
import com.google.common.base.Splitter; import com.google.common.base.Splitter;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.io.Closeables; import com.google.common.io.Closeables;
import com.google.common.net.HostAndPort;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.jcraft.jsch.ChannelExec; import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.ChannelSftp; import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException; import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session; import com.jcraft.jsch.Session;
@ -91,11 +90,7 @@ public class JschSshClient implements SshClient {
sftp.disconnect(); sftp.disconnect();
} }
} }
private final String host;
private final int port;
private final String username;
private final String password;
private final String toString; private final String toString;
@Inject(optional = true) @Inject(optional = true)
@ -121,31 +116,31 @@ public class JschSshClient implements SshClient {
@Named("jclouds.ssh") @Named("jclouds.ssh")
protected Logger logger = Logger.NULL; protected Logger logger = Logger.NULL;
private Session session;
private final byte[] privateKey;
final byte[] emptyPassPhrase = new byte[0];
private final int timeout;
private final BackoffLimitedRetryHandler backoffLimitedRetryHandler; private final BackoffLimitedRetryHandler backoffLimitedRetryHandler;
public JschSshClient(BackoffLimitedRetryHandler backoffLimitedRetryHandler, IPSocket socket, int timeout, final SessionConnection sessionConnection;
String username, String password, byte[] privateKey) { final String user;
final String host;
public JschSshClient(BackoffLimitedRetryHandler backoffLimitedRetryHandler, IPSocket socket,
LoginCredentials loginCredentials, int timeout) {
this.user = checkNotNull(loginCredentials, "loginCredentials").getUser();
this.host = checkNotNull(socket, "socket").getAddress(); this.host = checkNotNull(socket, "socket").getAddress();
checkArgument(socket.getPort() > 0, "ssh port must be greater then zero" + socket.getPort()); checkArgument(socket.getPort() > 0, "ssh port must be greater then zero" + socket.getPort());
checkArgument(password != null || privateKey != null, "you must specify a password or a key"); checkArgument(loginCredentials.getPassword() != null || loginCredentials.getPrivateKey() != null,
this.port = socket.getPort(); "you must specify a password or a key");
this.username = checkNotNull(username, "username");
this.backoffLimitedRetryHandler = checkNotNull(backoffLimitedRetryHandler, "backoffLimitedRetryHandler"); this.backoffLimitedRetryHandler = checkNotNull(backoffLimitedRetryHandler, "backoffLimitedRetryHandler");
this.timeout = timeout; if (loginCredentials.getPrivateKey() == null) {
this.password = password; this.toString = String.format("%s:pw[%s]@%s:%d", loginCredentials.getUser(), hex(md5(loginCredentials
this.privateKey = privateKey; .getPassword().getBytes())), host, socket.getPort());
if (privateKey == null) {
this.toString = String.format("%s:pw[%s]@%s:%d", username, hex(md5(password.getBytes())), host, port);
} else { } else {
String fingerPrint = fingerprintPrivateKey(new String(privateKey)); String fingerPrint = fingerprintPrivateKey(loginCredentials.getPrivateKey());
String sha1 = sha1PrivateKey(new String(privateKey)); String sha1 = sha1PrivateKey(loginCredentials.getPrivateKey());
this.toString = String.format("%s:rsa[fingerprint(%s),sha1(%s)]@%s:%d", username, fingerPrint, sha1, host, this.toString = String.format("%s:rsa[fingerprint(%s),sha1(%s)]@%s:%d", loginCredentials.getUser(),
port); fingerPrint, sha1, host, socket.getPort());
} }
sessionConnection = SessionConnection.builder().hostAndPort(HostAndPort.fromParts(host, socket.getPort())).loginCredentials(
loginCredentials).connectTimeout(timeout).sessionTimeout(timeout).build();
} }
@Override @Override
@ -154,7 +149,8 @@ public class JschSshClient implements SshClient {
} }
private void checkConnected() { private void checkConnected() {
checkState(session != null && session.isConnected(), String.format("(%s) Session not connected!", toString())); checkState(sessionConnection.getSession() != null && sessionConnection.getSession().isConnected(), String.format(
"(%s) Session not connected!", toString()));
} }
public static interface Connection<T> { public static interface Connection<T> {
@ -163,45 +159,6 @@ public class JschSshClient implements SshClient {
T create() throws Exception; T create() throws Exception;
} }
Connection<Session> sessionConnection = new Connection<Session>() {
@Override
public void clear() {
if (session != null && session.isConnected()) {
session.disconnect();
session = null;
}
}
@Override
public Session create() throws Exception {
JSch jsch = new JSch();
session = jsch.getSession(username, host, port);
if (timeout != 0)
session.setTimeout(timeout);
if (password != null) {
session.setPassword(password);
} else {
// jsch wipes out your private key
if (CredentialUtils.isPrivateKeyEncrypted(privateKey)) {
throw new IllegalArgumentException(
"JschSshClientModule does not support private keys that require a passphrase");
}
jsch.addIdentity(username, Arrays.copyOf(privateKey, privateKey.length), null, emptyPassPhrase);
}
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect(timeout);
return session;
}
@Override
public String toString() {
return String.format("Session(timeout=%d)", timeout);
}
};
protected <T, C extends Connection<T>> T acquire(C connection) { protected <T, C extends Connection<T>> T acquire(C connection) {
connection.clear(); connection.clear();
String errorMessage = String.format("(%s) error acquiring %s", toString(), connection); String errorMessage = String.format("(%s) error acquiring %s", toString(), connection);
@ -245,7 +202,7 @@ public class JschSshClient implements SshClient {
public ChannelSftp create() throws JSchException { public ChannelSftp create() throws JSchException {
checkConnected(); checkConnected();
String channel = "sftp"; String channel = "sftp";
sftp = (ChannelSftp) session.openChannel(channel); sftp = (ChannelSftp) sessionConnection.getSession().openChannel(channel);
sftp.connect(); sftp.connect();
return sftp; return sftp;
} }
@ -394,7 +351,7 @@ public class JschSshClient implements SshClient {
public ChannelExec create() throws Exception { public ChannelExec create() throws Exception {
checkConnected(); checkConnected();
String channel = "exec"; String channel = "exec";
executor = (ChannelExec) session.openChannel(channel); executor = (ChannelExec) sessionConnection.getSession().openChannel(channel);
executor.setPty(true); executor.setPty(true);
executor.setCommand(command); executor.setCommand(command);
ByteArrayOutputStream error = new ByteArrayOutputStream(); ByteArrayOutputStream error = new ByteArrayOutputStream();
@ -468,13 +425,13 @@ public class JschSshClient implements SshClient {
@Override @Override
public String getUsername() { public String getUsername() {
return this.username; return this.user;
} }
class ExecChannelConnection implements Connection<ExecChannel> { class ExecChannelConnection implements Connection<ExecChannel> {
private final String command; private final String command;
private ChannelExec executor = null; private ChannelExec executor = null;
private Session sessionConnection;
ExecChannelConnection(String command) { ExecChannelConnection(String command) {
this.command = checkNotNull(command, "command"); this.command = checkNotNull(command, "command");
@ -484,14 +441,16 @@ public class JschSshClient implements SshClient {
public void clear() { public void clear() {
if (executor != null) if (executor != null)
executor.disconnect(); executor.disconnect();
if (sessionConnection != null)
sessionConnection.disconnect();
} }
@Override @Override
public ExecChannel create() throws Exception { public ExecChannel create() throws Exception {
checkConnected(); this.sessionConnection = acquire(SessionConnection.builder().fromSessionConnection(
JschSshClient.this.sessionConnection).sessionTimeout(0).build());
String channel = "exec"; String channel = "exec";
executor = (ChannelExec) session.openChannel(channel); executor = (ChannelExec) sessionConnection.openChannel(channel);
executor.setPty(true);
executor.setCommand(command); executor.setCommand(command);
ByteArrayOutputStream error = new ByteArrayOutputStream(); ByteArrayOutputStream error = new ByteArrayOutputStream();
executor.setErrStream(error); executor.setErrStream(error);
@ -521,7 +480,6 @@ public class JschSshClient implements SshClient {
} }
}; };
@Override @Override
public ExecChannel execChannel(String command) { public ExecChannel execChannel(String command) {
return acquire(new ExecChannelConnection(command)); return acquire(new ExecChannelConnection(command));

View File

@ -0,0 +1,201 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.jclouds.ssh.jsch;
import static com.google.common.base.Objects.equal;
import java.util.Arrays;
import org.jclouds.domain.LoginCredentials;
import org.jclouds.ssh.jsch.JschSshClient.Connection;
import org.jclouds.util.CredentialUtils;
import com.google.common.base.Objects;
import com.google.common.net.HostAndPort;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
public class SessionConnection implements Connection<Session> {
public static Builder builder() {
return new Builder();
}
public static class Builder {
protected HostAndPort hostAndPort;
protected LoginCredentials loginCredentials;
protected int connectTimeout;
protected int sessionTimeout;
/**
* @see SessionConnection#getHostAndPort()
*/
public Builder hostAndPort(HostAndPort hostAndPort) {
this.hostAndPort = hostAndPort;
return this;
}
/**
* @see SessionConnection#getLoginCredentials()
*/
public Builder loginCredentials(LoginCredentials loginCredentials) {
this.loginCredentials = loginCredentials;
return this;
}
/**
* @see SessionConnection#getConnectTimeout()
*/
public Builder connectTimeout(int connectTimeout) {
this.connectTimeout = connectTimeout;
return this;
}
/**
* @see SessionConnection#getConnectTimeout()
*/
public Builder sessionTimeout(int sessionTimeout) {
this.sessionTimeout = sessionTimeout;
return this;
}
public SessionConnection build() {
return new SessionConnection(hostAndPort, loginCredentials, connectTimeout, sessionTimeout);
}
protected Builder fromSessionConnection(SessionConnection in) {
return hostAndPort(in.getHostAndPort()).connectTimeout(in.getConnectTimeout()).loginCredentials(
in.getLoginCredentials());
}
}
private SessionConnection(HostAndPort hostAndPort, LoginCredentials loginCredentials, int connectTimeout,
int sessionTimeout) {
this.hostAndPort = hostAndPort;
this.loginCredentials = loginCredentials;
this.connectTimeout = connectTimeout;
this.sessionTimeout = sessionTimeout;
}
private static final byte[] emptyPassPhrase = new byte[0];
private final HostAndPort hostAndPort;
private final LoginCredentials loginCredentials;
private final int connectTimeout;
private final int sessionTimeout;
private transient Session session;
@Override
public void clear() {
if (session != null && session.isConnected()) {
session.disconnect();
session = null;
}
}
@Override
public Session create() throws Exception {
JSch jsch = new JSch();
session = jsch
.getSession(loginCredentials.getUser(), hostAndPort.getHostText(), hostAndPort.getPortOrDefault(22));
if (sessionTimeout != 0)
session.setTimeout(sessionTimeout);
if (loginCredentials.getPrivateKey() == null) {
session.setPassword(loginCredentials.getPassword());
} else {
byte[] privateKey = loginCredentials.getPrivateKey().getBytes();
if (CredentialUtils.isPrivateKeyEncrypted(privateKey)) {
throw new IllegalArgumentException(
"JschSshClientModule does not support private keys that require a passphrase");
}
jsch.addIdentity(loginCredentials.getUser(), Arrays.copyOf(privateKey, privateKey.length), null,
emptyPassPhrase);
}
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect(connectTimeout);
return session;
}
/**
* @return host and port, where port if not present defaults to {@code 22}
*/
public HostAndPort getHostAndPort() {
return hostAndPort;
}
/**
*
* @return login used in this session
*/
public LoginCredentials getLoginCredentials() {
return loginCredentials;
}
/**
*
* @return how long to wait for the initial connection to be made
*/
public int getConnectTimeout() {
return connectTimeout;
}
/**
*
* @return how long to keep the session open, or {@code 0} for indefinitely
*/
public int getSessionTimeout() {
return sessionTimeout;
}
/**
*
* @return the current session or {@code null} if not connected
*/
public Session getSession() {
return session;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
SessionConnection that = SessionConnection.class.cast(o);
return equal(this.hostAndPort, that.hostAndPort) && equal(this.loginCredentials, that.loginCredentials)
&& equal(this.session, that.session);
}
@Override
public int hashCode() {
return Objects.hashCode(hostAndPort, loginCredentials, session);
}
@Override
public String toString() {
return Objects.toStringHelper("").add("hostAndPort", hostAndPort).add("loginUser", loginCredentials.getUser())
.add("session", session != null ? session.hashCode() : null).add("connectTimeout", connectTimeout).add(
"sessionTimeout", sessionTimeout).toString();
}
}

View File

@ -65,9 +65,7 @@ public class JschSshClientModule extends AbstractModule {
@Override @Override
public SshClient create(IPSocket socket, LoginCredentials credentials) { public SshClient create(IPSocket socket, LoginCredentials credentials) {
SshClient client = new JschSshClient(backoffLimitedRetryHandler, socket, timeout, credentials.getUser(), SshClient client = new JschSshClient(backoffLimitedRetryHandler, socket, credentials, timeout);
(credentials.getPrivateKey() == null) ? credentials.getPassword() : null,
credentials.getPrivateKey() != null ? credentials.getPrivateKey().getBytes() : null);
injector.injectMembers(client);// add logger injector.injectMembers(client);// add logger
return client; return client;
} }

View File

@ -170,8 +170,10 @@ public class JschSshClientLiveTest {
: sshHost); : sshHost);
} }
public void testExecChannelTakesStdinAndEchosBack() throws IOException { public void testExecChannelTakesStdinAndNoEchoOfCharsInOuputAndOutlivesClient() throws IOException {
ExecChannel response = setupClient().execChannel("cat <<EOF"); SshClient client = setupClient();
ExecChannel response = client.execChannel("cat <<EOF");
client.disconnect();
assertEquals(response.getExitStatus().get(), null); assertEquals(response.getExitStatus().get(), null);
try { try {
PrintStream printStream = new PrintStream(response.getInput()); PrintStream printStream = new PrintStream(response.getInput());
@ -179,12 +181,10 @@ public class JschSshClientLiveTest {
printStream.append("EOF\n"); printStream.append("EOF\n");
printStream.close(); printStream.close();
assertEquals(Strings2.toStringAndClose(response.getError()), ""); assertEquals(Strings2.toStringAndClose(response.getError()), "");
// local echo assertEquals(Strings2.toStringAndClose(response.getOutput()), "");
assertEquals(Strings2.toStringAndClose(response.getOutput()), "foo\r\nEOF\r\n");
} finally { } finally {
Closeables.closeQuietly(response); Closeables.closeQuietly(response);
} }
assertEquals(response.getExitStatus().get(), new Integer(0)); assertEquals(response.getExitStatus().get(), new Integer(0));
} }
} }

View File

@ -0,0 +1,209 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.jclouds.sshj;
import static com.google.common.base.Objects.equal;
import java.io.IOException;
import javax.annotation.Resource;
import javax.inject.Named;
import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.transport.verification.PromiscuousVerifier;
import net.schmizz.sshj.userauth.keyprovider.OpenSSHKeyFile;
import org.jclouds.domain.LoginCredentials;
import org.jclouds.logging.Logger;
import org.jclouds.sshj.SshjSshClient.Connection;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Objects;
import com.google.common.net.HostAndPort;
public class SSHClientConnection implements Connection<SSHClient> {
public static Builder builder() {
return new Builder();
}
public static class Builder {
protected HostAndPort hostAndPort;
protected LoginCredentials loginCredentials;
protected int connectTimeout;
protected int sessionTimeout;
/**
* @see SSHClientConnection#getHostAndPort()
*/
public Builder hostAndPort(HostAndPort hostAndPort) {
this.hostAndPort = hostAndPort;
return this;
}
/**
* @see SSHClientConnection#getLoginCredentials()
*/
public Builder loginCredentials(LoginCredentials loginCredentials) {
this.loginCredentials = loginCredentials;
return this;
}
/**
* @see SSHClientConnection#getConnectTimeout()
*/
public Builder connectTimeout(int connectTimeout) {
this.connectTimeout = connectTimeout;
return this;
}
/**
* @see SSHClientConnection#getConnectTimeout()
*/
public Builder sessionTimeout(int sessionTimeout) {
this.sessionTimeout = sessionTimeout;
return this;
}
public SSHClientConnection build() {
return new SSHClientConnection(hostAndPort, loginCredentials, connectTimeout, sessionTimeout);
}
protected Builder fromSSHClientConnection(SSHClientConnection in) {
return hostAndPort(in.getHostAndPort()).connectTimeout(in.getConnectTimeout()).loginCredentials(
in.getLoginCredentials());
}
}
private SSHClientConnection(HostAndPort hostAndPort, LoginCredentials loginCredentials, int connectTimeout,
int sessionTimeout) {
this.hostAndPort = hostAndPort;
this.loginCredentials = loginCredentials;
this.connectTimeout = connectTimeout;
this.sessionTimeout = sessionTimeout;
}
@Resource
@Named("jclouds.ssh")
protected Logger logger = Logger.NULL;
private final HostAndPort hostAndPort;
private final LoginCredentials loginCredentials;
private final int connectTimeout;
private final int sessionTimeout;
@VisibleForTesting
transient SSHClient ssh;
@Override
public void clear() {
if (ssh != null && ssh.isConnected()) {
try {
ssh.disconnect();
} catch (IOException e) {
logger.debug("<< exception disconnecting from %s: %s", e, e.getMessage());
}
ssh = null;
}
}
@Override
public SSHClient create() throws Exception {
ssh = new net.schmizz.sshj.SSHClient();
ssh.addHostKeyVerifier(new PromiscuousVerifier());
if (connectTimeout != 0) {
ssh.setConnectTimeout(connectTimeout);
}
if (sessionTimeout != 0) {
ssh.setTimeout(sessionTimeout);
}
ssh.connect(hostAndPort.getHostText(), hostAndPort.getPortOrDefault(22));
if (loginCredentials.getPassword() != null) {
ssh.authPassword(loginCredentials.getUser(), loginCredentials.getPassword());
} else {
OpenSSHKeyFile key = new OpenSSHKeyFile();
key.init(loginCredentials.getPrivateKey(), null);
ssh.authPublickey(loginCredentials.getUser(), key);
}
return ssh;
}
/**
* @return host and port, where port if not present defaults to {@code 22}
*/
public HostAndPort getHostAndPort() {
return hostAndPort;
}
/**
*
* @return login used in this ssh
*/
public LoginCredentials getLoginCredentials() {
return loginCredentials;
}
/**
*
* @return how long to wait for the initial connection to be made
*/
public int getConnectTimeout() {
return connectTimeout;
}
/**
*
* @return how long to keep the ssh open, or {@code 0} for indefinitely
*/
public int getSessionTimeout() {
return sessionTimeout;
}
/**
*
* @return the current ssh or {@code null} if not connected
*/
public SSHClient getSSHClient() {
return ssh;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
SSHClientConnection that = SSHClientConnection.class.cast(o);
return equal(this.hostAndPort, that.hostAndPort) && equal(this.loginCredentials, that.loginCredentials)
&& equal(this.ssh, that.ssh);
}
@Override
public int hashCode() {
return Objects.hashCode(hostAndPort, loginCredentials, ssh);
}
@Override
public String toString() {
return Objects.toStringHelper("").add("hostAndPort", hostAndPort).add("loginUser", loginCredentials.getUser())
.add("ssh", ssh != null ? ssh.hashCode() : null).add("connectTimeout", connectTimeout).add(
"sessionTimeout", sessionTimeout).toString();
}
}

View File

@ -52,14 +52,13 @@ import net.schmizz.sshj.connection.channel.direct.Session.Command;
import net.schmizz.sshj.sftp.SFTPClient; import net.schmizz.sshj.sftp.SFTPClient;
import net.schmizz.sshj.sftp.SFTPException; import net.schmizz.sshj.sftp.SFTPException;
import net.schmizz.sshj.transport.TransportException; import net.schmizz.sshj.transport.TransportException;
import net.schmizz.sshj.transport.verification.PromiscuousVerifier;
import net.schmizz.sshj.userauth.UserAuthException; import net.schmizz.sshj.userauth.UserAuthException;
import net.schmizz.sshj.userauth.keyprovider.OpenSSHKeyFile;
import net.schmizz.sshj.xfer.InMemorySourceFile; import net.schmizz.sshj.xfer.InMemorySourceFile;
import org.apache.commons.io.input.ProxyInputStream; import org.apache.commons.io.input.ProxyInputStream;
import org.jclouds.compute.domain.ExecChannel; import org.jclouds.compute.domain.ExecChannel;
import org.jclouds.compute.domain.ExecResponse; import org.jclouds.compute.domain.ExecResponse;
import org.jclouds.domain.LoginCredentials;
import org.jclouds.http.handlers.BackoffLimitedRetryHandler; import org.jclouds.http.handlers.BackoffLimitedRetryHandler;
import org.jclouds.io.Payload; import org.jclouds.io.Payload;
import org.jclouds.io.Payloads; import org.jclouds.io.Payloads;
@ -77,6 +76,7 @@ import com.google.common.base.Splitter;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.base.Throwables; import com.google.common.base.Throwables;
import com.google.common.io.Closeables; import com.google.common.io.Closeables;
import com.google.common.net.HostAndPort;
import com.google.inject.Inject; import com.google.inject.Inject;
/** /**
@ -104,10 +104,6 @@ public class SshjSshClient implements SshClient {
} }
} }
private final String host;
private final int port;
private final String username;
private final String password;
private final String toString; private final String toString;
@Inject(optional = true) @Inject(optional = true)
@ -129,41 +125,42 @@ public class SshjSshClient implements SshClient {
@Named("jclouds.ssh.retry-predicate") @Named("jclouds.ssh.retry-predicate")
// NOTE cannot retry io exceptions, as SSHException is a part of the chain // NOTE cannot retry io exceptions, as SSHException is a part of the chain
private Predicate<Throwable> retryPredicate = or(instanceOf(ConnectionException.class), private Predicate<Throwable> retryPredicate = or(instanceOf(ConnectionException.class),
instanceOf(ConnectException.class), instanceOf(SocketTimeoutException.class), instanceOf(ConnectException.class), instanceOf(SocketTimeoutException.class),
instanceOf(TransportException.class), instanceOf(TransportException.class),
// safe to retry sftp exceptions as they are idempotent // safe to retry sftp exceptions as they are idempotent
instanceOf(SFTPException.class)); instanceOf(SFTPException.class));
@Resource @Resource
@Named("jclouds.ssh") @Named("jclouds.ssh")
protected Logger logger = Logger.NULL; protected Logger logger = Logger.NULL;
@VisibleForTesting @VisibleForTesting
SSHClient ssh; SSHClientConnection sshClientConnection;
private final byte[] privateKey;
final byte[] emptyPassPhrase = new byte[0]; final String user;
private final int timeoutMillis; final String host;
private final BackoffLimitedRetryHandler backoffLimitedRetryHandler; private final BackoffLimitedRetryHandler backoffLimitedRetryHandler;
public SshjSshClient(BackoffLimitedRetryHandler backoffLimitedRetryHandler, IPSocket socket, int timeout, public SshjSshClient(BackoffLimitedRetryHandler backoffLimitedRetryHandler, IPSocket socket,
String username, String password, byte[] privateKey) { LoginCredentials loginCredentials, int timeout) {
this.user = checkNotNull(loginCredentials, "loginCredentials").getUser();
this.host = checkNotNull(socket, "socket").getAddress(); this.host = checkNotNull(socket, "socket").getAddress();
checkArgument(socket.getPort() > 0, "ssh port must be greater then zero" + socket.getPort()); checkArgument(socket.getPort() > 0, "ssh port must be greater then zero" + socket.getPort());
checkArgument(password != null || privateKey != null, "you must specify a password or a key"); checkArgument(loginCredentials.getPassword() != null || loginCredentials.getPrivateKey() != null,
this.port = socket.getPort(); "you must specify a password or a key");
this.username = checkNotNull(username, "username");
this.backoffLimitedRetryHandler = checkNotNull(backoffLimitedRetryHandler, "backoffLimitedRetryHandler"); this.backoffLimitedRetryHandler = checkNotNull(backoffLimitedRetryHandler, "backoffLimitedRetryHandler");
this.timeoutMillis = timeout; if (loginCredentials.getPrivateKey() == null) {
this.password = password; this.toString = String.format("%s:pw[%s]@%s:%d", loginCredentials.getUser(), hex(md5(loginCredentials
this.privateKey = privateKey; .getPassword().getBytes())), host, socket.getPort());
if (privateKey == null) {
this.toString = String.format("%s:pw[%s]@%s:%d", username, hex(md5(password.getBytes())), host, port);
} else { } else {
String fingerPrint = fingerprintPrivateKey(new String(privateKey)); String fingerPrint = fingerprintPrivateKey(loginCredentials.getPrivateKey());
String sha1 = sha1PrivateKey(new String(privateKey)); String sha1 = sha1PrivateKey(loginCredentials.getPrivateKey());
this.toString = String.format("%s:rsa[fingerprint(%s),sha1(%s)]@%s:%d", username, fingerPrint, sha1, host, this.toString = String.format("%s:rsa[fingerprint(%s),sha1(%s)]@%s:%d", loginCredentials.getUser(),
port); fingerPrint, sha1, host, socket.getPort());
} }
sshClientConnection = SSHClientConnection.builder().hostAndPort(HostAndPort.fromParts(host, socket.getPort()))
.loginCredentials(loginCredentials).connectTimeout(timeout).sessionTimeout(timeout).build();
} }
@Override @Override
@ -172,7 +169,8 @@ public class SshjSshClient implements SshClient {
} }
private void checkConnected() { private void checkConnected() {
checkState(ssh != null && ssh.isConnected(), String.format("(%s) ssh not connected!", toString())); checkState(sshClientConnection.ssh != null && sshClientConnection.ssh.isConnected(), String
.format("(%s) ssh not connected!", toString()));
} }
public static interface Connection<T> { public static interface Connection<T> {
@ -181,45 +179,6 @@ public class SshjSshClient implements SshClient {
T create() throws Exception; T create() throws Exception;
} }
Connection<net.schmizz.sshj.SSHClient> sshConnection = new Connection<net.schmizz.sshj.SSHClient>() {
@Override
public void clear() {
if (ssh != null && ssh.isConnected()) {
try {
ssh.disconnect();
} catch (IOException e) {
logger.warn(e, "<< exception disconnecting from %s: %s", e, e.getMessage());
}
ssh = null;
}
}
@Override
public net.schmizz.sshj.SSHClient create() throws Exception {
net.schmizz.sshj.SSHClient ssh = new net.schmizz.sshj.SSHClient();
ssh.addHostKeyVerifier(new PromiscuousVerifier());
if (timeoutMillis != 0) {
ssh.setTimeout(timeoutMillis);
ssh.setConnectTimeout(timeoutMillis);
}
ssh.connect(host, port);
if (password != null) {
ssh.authPassword(username, password);
} else {
OpenSSHKeyFile key = new OpenSSHKeyFile();
key.init(new String(privateKey), null);
ssh.authPublickey(username, key);
}
return ssh;
}
@Override
public String toString() {
return String.format("SSHClient(timeout=%d)", timeoutMillis);
}
};
private void backoffForAttempt(int retryAttempt, String message) { private void backoffForAttempt(int retryAttempt, String message) {
backoffLimitedRetryHandler.imposeBackoffExponentialDelay(200L, 2, retryAttempt, sshRetries, message); backoffLimitedRetryHandler.imposeBackoffExponentialDelay(200L, 2, retryAttempt, sshRetries, message);
} }
@ -240,16 +199,17 @@ public class SshjSshClient implements SshClient {
logger.warn(from, "<< (%s) error closing connection", toString()); logger.warn(from, "<< (%s) error closing connection", toString());
} }
if (i + 1 == sshRetries) { if (i + 1 == sshRetries) {
throw propagate(from, errorMessage+" (out of retries - max "+sshRetries+")"); throw propagate(from, errorMessage + " (out of retries - max " + sshRetries + ")");
} else if (shouldRetry(from) || } else if (shouldRetry(from)
(Throwables2.getFirstThrowableOfType(from, IllegalStateException.class) != null)) { || (Throwables2.getFirstThrowableOfType(from, IllegalStateException.class) != null)) {
logger.info("<< " + errorMessage + " (attempt " + (i + 1) + " of " + sshRetries + "): " + from.getMessage()); logger.info("<< " + errorMessage + " (attempt " + (i + 1) + " of " + sshRetries + "): "
+ from.getMessage());
backoffForAttempt(i + 1, errorMessage + ": " + from.getMessage()); backoffForAttempt(i + 1, errorMessage + ": " + from.getMessage());
if (connection != sshConnection) if (connection != sshClientConnection)
connect(); connect();
continue; continue;
} else { } else {
throw propagate(from, errorMessage+" (not retryable)"); throw propagate(from, errorMessage + " (not retryable)");
} }
} }
} }
@ -259,7 +219,7 @@ public class SshjSshClient implements SshClient {
public void connect() { public void connect() {
try { try {
ssh = acquire(sshConnection); acquire(sshClientConnection);
} catch (Exception e) { } catch (Exception e) {
Throwables.propagate(e); Throwables.propagate(e);
} }
@ -282,7 +242,7 @@ public class SshjSshClient implements SshClient {
@Override @Override
public SFTPClient create() throws IOException { public SFTPClient create() throws IOException {
checkConnected(); checkConnected();
sftp = ssh.newSFTPClient(); sftp = sshClientConnection.ssh.newSFTPClient();
return sftp; return sftp;
} }
@ -310,7 +270,7 @@ public class SshjSshClient implements SshClient {
public Payload create() throws Exception { public Payload create() throws Exception {
sftp = acquire(sftpConnection); sftp = acquire(sftpConnection);
return Payloads.newInputStreamPayload(new CloseFtpChannelOnCloseInputStream(sftp.getSFTPEngine().open(path) return Payloads.newInputStreamPayload(new CloseFtpChannelOnCloseInputStream(sftp.getSFTPEngine().open(path)
.getInputStream(), sftp)); .getInputStream(), sftp));
} }
@Override @Override
@ -385,7 +345,7 @@ public class SshjSshClient implements SshClient {
@VisibleForTesting @VisibleForTesting
boolean shouldRetry(Exception from) { boolean shouldRetry(Exception from) {
Predicate<Throwable> predicate = retryAuth ? Predicates.<Throwable> or(retryPredicate, Predicate<Throwable> predicate = retryAuth ? Predicates.<Throwable> or(retryPredicate,
instanceOf(AuthorizationException.class), instanceOf(UserAuthException.class)) : retryPredicate; instanceOf(AuthorizationException.class), instanceOf(UserAuthException.class)) : retryPredicate;
if (any(getCausalChain(from), predicate)) if (any(getCausalChain(from), predicate))
return true; return true;
if (!retryableMessages.equals("")) if (!retryableMessages.equals(""))
@ -404,7 +364,7 @@ public class SshjSshClient implements SshClient {
@Override @Override
public boolean apply(Throwable arg0) { public boolean apply(Throwable arg0) {
return (arg0.toString().indexOf(input) != -1) return (arg0.toString().indexOf(input) != -1)
|| (arg0.getMessage() != null && arg0.getMessage().indexOf(input) != -1); || (arg0.getMessage() != null && arg0.getMessage().indexOf(input) != -1);
} }
}); });
@ -420,7 +380,7 @@ public class SshjSshClient implements SshClient {
if (e instanceof UserAuthException) if (e instanceof UserAuthException)
throw new AuthorizationException("(" + toString() + ") " + message, e); throw new AuthorizationException("(" + toString() + ") " + message, e);
throw e instanceof SshException ? SshException.class.cast(e) : new SshException( throw e instanceof SshException ? SshException.class.cast(e) : new SshException(
"(" + toString() + ") " + message, e); "(" + toString() + ") " + message, e);
} }
@Override @Override
@ -431,7 +391,7 @@ public class SshjSshClient implements SshClient {
@PreDestroy @PreDestroy
public void disconnect() { public void disconnect() {
try { try {
sshConnection.clear(); sshClientConnection.clear();
} catch (Exception e) { } catch (Exception e) {
Throwables.propagate(e); Throwables.propagate(e);
} }
@ -452,8 +412,8 @@ public class SshjSshClient implements SshClient {
@Override @Override
public Session create() throws Exception { public Session create() throws Exception {
checkConnected(); checkConnected();
session = ssh.startSession(); session = sshClientConnection.ssh.startSession();
session.allocatePTY("vt100", 80, 24, 0, 0, Collections.<PTYMode, Integer>emptyMap()); session.allocatePTY("vt100", 80, 24, 0, 0, Collections.<PTYMode, Integer> emptyMap());
return session; return session;
} }
@ -485,7 +445,7 @@ public class SshjSshClient implements SshClient {
session = acquire(execConnection()); session = acquire(execConnection());
Command output = session.exec(checkNotNull(command, "command")); Command output = session.exec(checkNotNull(command, "command"));
String outputString = IOUtils.readFully(output.getInputStream()).toString(); String outputString = IOUtils.readFully(output.getInputStream()).toString();
output.join(timeoutMillis, TimeUnit.SECONDS); output.join(sshClientConnection.getSessionTimeout(), TimeUnit.MILLISECONDS);
int errorStatus = output.getExitStatus(); int errorStatus = output.getExitStatus();
String errorString = IOUtils.readFully(output.getErrorStream()).toString(); String errorString = IOUtils.readFully(output.getErrorStream()).toString();
return new ExecResponse(outputString, errorString, errorStatus); return new ExecResponse(outputString, errorString, errorStatus);
@ -504,6 +464,37 @@ public class SshjSshClient implements SshClient {
return acquire(new ExecConnection(command)); return acquire(new ExecConnection(command));
} }
protected Connection<Session> noPTYConnection() {
return new Connection<Session>() {
private Session session = null;
private SSHClient sshClientConnection;
@Override
public void clear() throws TransportException, ConnectionException {
if (session != null)
session.close();
if (sshClientConnection != null)
Closeables.closeQuietly(sshClientConnection);
}
@Override
public Session create() throws Exception {
this.sshClientConnection = acquire(SSHClientConnection.builder().fromSSHClientConnection(
SshjSshClient.this.sshClientConnection).sessionTimeout(0).build());
session = sshClientConnection.startSession();
return session;
}
@Override
public String toString() {
return "Session()";
}
};
}
class ExecChannelConnection implements Connection<ExecChannel> { class ExecChannelConnection implements Connection<ExecChannel> {
private final String command; private final String command;
private SessionChannel session; private SessionChannel session;
@ -521,7 +512,7 @@ public class SshjSshClient implements SshClient {
@Override @Override
public ExecChannel create() throws Exception { public ExecChannel create() throws Exception {
session = SessionChannel.class.cast(acquire(execConnection())); session = SessionChannel.class.cast(acquire(noPTYConnection()));
output = session.exec(command); output = session.exec(command);
return new ExecChannel(output.getOutputStream(), output.getInputStream(), output.getErrorStream(), return new ExecChannel(output.getOutputStream(), output.getInputStream(), output.getErrorStream(),
new Supplier<Integer>() { new Supplier<Integer>() {
@ -552,7 +543,7 @@ public class SshjSshClient implements SshClient {
public ExecChannel execChannel(String command) { public ExecChannel execChannel(String command) {
return acquire(new ExecChannelConnection(command)); return acquire(new ExecChannelConnection(command));
} }
@Override @Override
public String getHostAddress() { public String getHostAddress() {
return this.host; return this.host;
@ -560,7 +551,7 @@ public class SshjSshClient implements SshClient {
@Override @Override
public String getUsername() { public String getUsername() {
return this.username; return this.user;
} }
} }

View File

@ -65,9 +65,7 @@ public class SshjSshClientModule extends AbstractModule {
@Override @Override
public SshClient create(IPSocket socket, LoginCredentials credentials) { public SshClient create(IPSocket socket, LoginCredentials credentials) {
SshClient client = new SshjSshClient(backoffLimitedRetryHandler, socket, timeout, credentials.getUser(), SshClient client = new SshjSshClient(backoffLimitedRetryHandler, socket, credentials, timeout);
(credentials.getPrivateKey() == null) ? credentials.getPassword() : null,
credentials.getPrivateKey() != null ? credentials.getPrivateKey().getBytes() : null);
injector.injectMembers(client);// add logger injector.injectMembers(client);// add logger
return client; return client;
} }

View File

@ -169,9 +169,11 @@ public class SshjSshClientLiveTest {
assertEquals(response.getOutput().trim(), "localhost".equals(sshHost) ? InetAddress.getLocalHost().getHostName() assertEquals(response.getOutput().trim(), "localhost".equals(sshHost) ? InetAddress.getLocalHost().getHostName()
: sshHost); : sshHost);
} }
public void testExecChannelTakesStdinAndEchosBack() throws IOException { public void testExecChannelTakesStdinAndNoEchoOfCharsInOuputAndOutlivesClient() throws IOException {
ExecChannel response = setupClient().execChannel("cat <<EOF"); SshClient client = setupClient();
ExecChannel response = client.execChannel("cat <<EOF");
client.disconnect();
assertEquals(response.getExitStatus().get(), null); assertEquals(response.getExitStatus().get(), null);
try { try {
PrintStream printStream = new PrintStream(response.getInput()); PrintStream printStream = new PrintStream(response.getInput());
@ -179,8 +181,7 @@ public class SshjSshClientLiveTest {
printStream.append("EOF\n"); printStream.append("EOF\n");
printStream.close(); printStream.close();
assertEquals(Strings2.toStringAndClose(response.getError()), ""); assertEquals(Strings2.toStringAndClose(response.getError()), "");
// local echo assertEquals(Strings2.toStringAndClose(response.getOutput()), "");
assertEquals(Strings2.toStringAndClose(response.getOutput()), "foo\r\nEOF\r\n");
} finally { } finally {
Closeables.closeQuietly(response); Closeables.closeQuietly(response);
} }

View File

@ -172,8 +172,8 @@ public class SshjSshClientTest {
ssh.disconnect(); ssh.disconnect();
expectLastCall().andThrow(new ConnectionException("disconnected")); expectLastCall().andThrow(new ConnectionException("disconnected"));
replay(ssh); replay(ssh);
ssh1.ssh = ssh; ssh1.sshClientConnection.ssh = ssh;
ssh1.sshConnection.clear(); ssh1.sshClientConnection.clear();
verify(ssh); verify(ssh);
} }
@ -186,10 +186,9 @@ public class SshjSshClientTest {
} }
public void testRetriesLoggedAtInfoWithCount() throws Exception { public void testRetriesLoggedAtInfoWithCount() throws Exception {
@SuppressWarnings("unchecked") SSHClientConnection mockConnection = createMock(SSHClientConnection.class);
SshjSshClient.Connection<net.schmizz.sshj.SSHClient> mockConnection = createMock(SshjSshClient.Connection.class);
net.schmizz.sshj.SSHClient mockClient = createMock(net.schmizz.sshj.SSHClient.class); net.schmizz.sshj.SSHClient mockClient = createMock(net.schmizz.sshj.SSHClient.class);
mockConnection.clear(); expectLastCall(); mockConnection.clear(); expectLastCall();
mockConnection.create(); expectLastCall().andThrow(new ConnectionException("test1")); mockConnection.create(); expectLastCall().andThrow(new ConnectionException("test1"));
mockConnection.clear(); expectLastCall(); mockConnection.clear(); expectLastCall();
@ -199,14 +198,14 @@ public class SshjSshClientTest {
replay(mockConnection); replay(mockConnection);
replay(mockClient); replay(mockClient);
ssh.sshConnection = mockConnection; ssh.sshClientConnection = mockConnection;
BufferLogger logcheck = new BufferLogger(ssh.getClass().getCanonicalName()); BufferLogger logcheck = new BufferLogger(ssh.getClass().getCanonicalName());
ssh.logger = logcheck; ssh.logger = logcheck;
logcheck.setLevel(Level.INFO); logcheck.setLevel(Level.INFO);
ssh.connect(); ssh.connect();
Assert.assertEquals(ssh.ssh, mockClient); Assert.assertEquals(ssh.sshClientConnection, mockConnection);
verify(mockConnection); verify(mockConnection);
verify(mockClient); verify(mockClient);
Record r = logcheck.assertLogContains("attempt 1 of 5"); Record r = logcheck.assertLogContains("attempt 1 of 5");

View File

@ -127,7 +127,7 @@ public class ServerDetailsToNodeMetadata implements Function<ServerDetails, Node
try { try {
return Iterables.find(images.get(), new FindImageForServer(from)).getOperatingSystem(); return Iterables.find(images.get(), new FindImageForServer(from)).getOperatingSystem();
} catch (NoSuchElementException e) { } catch (NoSuchElementException e) {
logger.warn("could not find a matching image for server %s", from); logger.debug("could not find a matching image for server %s", from);
} }
return null; return null;
} }

View File

@ -19,13 +19,22 @@
package org.jclouds.virtualbox; package org.jclouds.virtualbox;
import java.net.URI;
import java.util.List; import java.util.List;
import java.util.Properties; import java.util.Properties;
import org.jclouds.byon.Node;
import org.jclouds.byon.config.CacheNodeStoreModule;
import org.jclouds.compute.StandaloneComputeServiceContextBuilder; import org.jclouds.compute.StandaloneComputeServiceContextBuilder;
import org.jclouds.compute.domain.OsFamily;
import org.jclouds.concurrent.MoreExecutors;
import org.jclouds.concurrent.config.ExecutorServiceModule;
import org.jclouds.virtualbox.config.VirtualBoxComputeServiceContextModule; import org.jclouds.virtualbox.config.VirtualBoxComputeServiceContextModule;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.inject.Module; import com.google.inject.Module;
/** /**
@ -37,12 +46,31 @@ import com.google.inject.Module;
public class VirtualBoxContextBuilder extends StandaloneComputeServiceContextBuilder<Supplier> { public class VirtualBoxContextBuilder extends StandaloneComputeServiceContextBuilder<Supplier> {
public VirtualBoxContextBuilder(Properties properties) { public VirtualBoxContextBuilder(Properties properties) {
super(Supplier.class, properties); super(Supplier.class, new VirtualBoxPropertiesBuilder(properties).defaultProperties());
} }
@Override @Override
protected void addContextModule(List<Module> modules) { protected void addContextModule(List<Module> modules) {
modules.add(new VirtualBoxComputeServiceContextModule()); modules.add(new VirtualBoxComputeServiceContextModule());
addHostModuleIfNotPresent(modules);
}
protected void addHostModuleIfNotPresent(List<Module> modules) {
if (!Iterables.any(modules, new Predicate<Module>() {
public boolean apply(Module input) {
return input instanceof CacheNodeStoreModule;
}
})) {
CacheNodeStoreModule hostModule = new CacheNodeStoreModule(ImmutableMap.of(
"host",
Node.builder().id("host").name("host installing virtualbox").hostname("localhost")
.osFamily(OsFamily.LINUX.toString()).osDescription(System.getProperty("os.name"))
.osVersion(System.getProperty("os.version")).group("ssh")
.username(System.getProperty("user.name"))
.credentialUrl(URI.create("file://" + System.getProperty("user.home") + "/.ssh/id_rsa"))
.build()));
modules.add(hostModule);
}
} }
} }

View File

@ -20,27 +20,34 @@
package org.jclouds.virtualbox.compute; package org.jclouds.virtualbox.compute;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.Iterables.filter; import static com.google.common.collect.Iterables.filter;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX; import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_NODE_PREFIX; import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_NODE_PREFIX;
import java.util.Map; import java.util.Map;
import javax.annotation.Resource;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named;
import org.jclouds.compute.ComputeServiceAdapter; import org.jclouds.compute.ComputeServiceAdapter;
import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.Template; import org.jclouds.compute.domain.Template;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
import org.jclouds.javax.annotation.Nullable; import org.jclouds.javax.annotation.Nullable;
import org.jclouds.logging.Logger;
import org.jclouds.virtualbox.domain.Master; import org.jclouds.virtualbox.domain.Master;
import org.jclouds.virtualbox.domain.NodeSpec; import org.jclouds.virtualbox.domain.NodeSpec;
import org.jclouds.virtualbox.domain.YamlImage; import org.jclouds.virtualbox.domain.YamlImage;
import org.virtualbox_4_1.CleanupMode; import org.jclouds.virtualbox.functions.admin.UnregisterMachineIfExistsAndForceDeleteItsMedia;
import org.virtualbox_4_1.IMachine; import org.virtualbox_4_1.IMachine;
import org.virtualbox_4_1.IProgress; import org.virtualbox_4_1.IProgress;
import org.virtualbox_4_1.ISession; import org.virtualbox_4_1.ISession;
import org.virtualbox_4_1.MachineState;
import org.virtualbox_4_1.SessionState; import org.virtualbox_4_1.SessionState;
import org.virtualbox_4_1.VBoxException;
import org.virtualbox_4_1.VirtualBoxManager; import org.virtualbox_4_1.VirtualBoxManager;
import com.google.common.base.Function; import com.google.common.base.Function;
@ -61,6 +68,10 @@ import com.google.inject.Singleton;
@Singleton @Singleton
public class VirtualBoxComputeServiceAdapter implements ComputeServiceAdapter<IMachine, IMachine, Image, Location> { public class VirtualBoxComputeServiceAdapter implements ComputeServiceAdapter<IMachine, IMachine, Image, Location> {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
private final Supplier<VirtualBoxManager> manager; private final Supplier<VirtualBoxManager> manager;
private final Map<Image, YamlImage> images; private final Map<Image, YamlImage> images;
private final LoadingCache<Image, Master> mastersLoader; private final LoadingCache<Image, Master> mastersLoader;
@ -81,6 +92,7 @@ public class VirtualBoxComputeServiceAdapter implements ComputeServiceAdapter<IM
Template template) { Template template) {
try { try {
Master master = mastersLoader.get(template.getImage()); Master master = mastersLoader.get(template.getImage());
checkState(master != null, "could not find a master for image: "+template.getClass());
NodeSpec nodeSpec = NodeSpec.builder().master(master).name(name).tag(tag).template(template).build(); NodeSpec nodeSpec = NodeSpec.builder().master(master).name(name).tag(tag).template(template).build();
return cloneCreator.apply(nodeSpec); return cloneCreator.apply(nodeSpec);
} catch (Exception e) { } catch (Exception e) {
@ -93,7 +105,7 @@ public class VirtualBoxComputeServiceAdapter implements ComputeServiceAdapter<IM
return Iterables.filter(manager.get().getVBox().getMachines(), new Predicate<IMachine>() { return Iterables.filter(manager.get().getVBox().getMachines(), new Predicate<IMachine>() {
@Override @Override
public boolean apply(IMachine arg0) { public boolean apply(IMachine arg0) {
return !arg0.getName().startsWith(VIRTUALBOX_NODE_PREFIX); return arg0.getName().startsWith(VIRTUALBOX_NODE_PREFIX);
} }
}); });
} }
@ -127,14 +139,21 @@ public class VirtualBoxComputeServiceAdapter implements ComputeServiceAdapter<IM
@Override @Override
public IMachine getNode(String vmName) { public IMachine getNode(String vmName) {
return manager.get().getVBox().findMachine(vmName); try {
return manager.get().getVBox().findMachine(vmName);
} catch (VBoxException e) {
if (e.getMessage().contains("Could not find a registered machine named")){
return null;
}
throw Throwables.propagate(e);
}
} }
@Override @Override
public void destroyNode(String vmName) { public void destroyNode(String vmName) {
IMachine machine = manager.get().getVBox().findMachine(vmName); IMachine machine = manager.get().getVBox().findMachine(vmName);
powerDownMachine(machine); powerDownMachine(machine);
machine.unregister(CleanupMode.Full); new UnregisterMachineIfExistsAndForceDeleteItsMedia().apply(machine);
} }
@Override @Override
@ -178,6 +197,11 @@ public class VirtualBoxComputeServiceAdapter implements ComputeServiceAdapter<IM
private void powerDownMachine(IMachine machine) { private void powerDownMachine(IMachine machine) {
try { try {
if (machine.getState() == MachineState.PoweredOff){
logger.debug("vm was already powered down: ", machine.getName());
return;
}
logger.debug("powering down vm: ", machine.getName());
ISession machineSession = manager.get().openMachineSession(machine); ISession machineSession = manager.get().openMachineSession(machine);
IProgress progress = machineSession.getConsole().powerDown(); IProgress progress = machineSession.getConsole().powerDown();
progress.waitForCompletion(-1); progress.waitForCompletion(-1);
@ -185,7 +209,7 @@ public class VirtualBoxComputeServiceAdapter implements ComputeServiceAdapter<IM
while (!machine.getSessionState().equals(SessionState.Unlocked)) { while (!machine.getSessionState().equals(SessionState.Unlocked)) {
try { try {
System.out.println("waiting for unlocking session - session state: " + machine.getSessionState()); logger.info("waiting for unlocking session - session state: " + machine.getSessionState());
Thread.sleep(1000); Thread.sleep(1000);
} catch (InterruptedException e) { } catch (InterruptedException e) {
} }

View File

@ -49,6 +49,7 @@ import org.jclouds.compute.domain.NodeState;
import org.jclouds.compute.domain.OsFamily; import org.jclouds.compute.domain.OsFamily;
import org.jclouds.compute.domain.TemplateBuilder; import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts; import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts;
import org.jclouds.concurrent.SingleThreaded;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
import org.jclouds.functions.IdentityFunction; import org.jclouds.functions.IdentityFunction;
import org.jclouds.logging.slf4j.config.SLF4JLoggingModule; import org.jclouds.logging.slf4j.config.SLF4JLoggingModule;
@ -104,6 +105,7 @@ import com.google.inject.TypeLiteral;
* @author Mattias Holmqvist, Andrea Turli * @author Mattias Holmqvist, Andrea Turli
*/ */
@SuppressWarnings({ "unchecked", "rawtypes" }) @SuppressWarnings({ "unchecked", "rawtypes" })
@SingleThreaded
public class VirtualBoxComputeServiceContextModule extends public class VirtualBoxComputeServiceContextModule extends
ComputeServiceAdapterContextModule<Supplier, Supplier, IMachine, IMachine, Image, Location> { ComputeServiceAdapterContextModule<Supplier, Supplier, IMachine, IMachine, Image, Location> {
@ -176,16 +178,8 @@ public class VirtualBoxComputeServiceContextModule extends
String provider = "byon"; String provider = "byon";
String identity = ""; String identity = "";
String credential = ""; String credential = "";
CacheNodeStoreModule hostModule = new CacheNodeStoreModule(ImmutableMap.of(
"host",
Node.builder().id("host").name("host installing virtualbox").hostname("localhost")
.osFamily(OsFamily.LINUX.toString()).osDescription(System.getProperty("os.name"))
.osVersion(System.getProperty("os.version")).group("ssh")
.username(System.getProperty("user.name"))
.credentialUrl(URI.create("file://" + System.getProperty("user.home") + "/.ssh/id_rsa"))
.build()));
return new ComputeServiceContextFactory().createContext(provider, identity, credential, return new ComputeServiceContextFactory().createContext(provider, identity, credential,
ImmutableSet.<Module> of(new SLF4JLoggingModule(), new SshjSshClientModule(), hostModule)); ImmutableSet.<Module> of(new SLF4JLoggingModule(), new SshjSshClientModule()));
} }
@Provides @Provides

View File

@ -24,6 +24,8 @@ import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Collections; import java.util.Collections;
import java.util.Set; import java.util.Set;
import javax.annotation.Nullable;
import org.virtualbox_4_1.NATProtocol; import org.virtualbox_4_1.NATProtocol;
import org.virtualbox_4_1.NetworkAttachmentType; import org.virtualbox_4_1.NetworkAttachmentType;
@ -41,13 +43,16 @@ public class NetworkAdapter {
private final NetworkAttachmentType networkAttachmentType; private final NetworkAttachmentType networkAttachmentType;
private final String macAddress; private final String macAddress;
private final Set<RedirectRule> redirectRules; private final Set<RedirectRule> redirectRules;
private final String staticIp;
public NetworkAdapter(NetworkAttachmentType networkAttachmentType, public NetworkAdapter(NetworkAttachmentType networkAttachmentType,
String macAddress, Set<RedirectRule> redirectRules) { String macAddress, Set<RedirectRule> redirectRules,
String staticIp) {
this.networkAttachmentType = checkNotNull(networkAttachmentType, this.networkAttachmentType = checkNotNull(networkAttachmentType,
"networkAttachmentType"); "networkAttachmentType");
this.macAddress = macAddress; this.macAddress = macAddress;
this.redirectRules = ImmutableSet.<RedirectRule>copyOf(redirectRules); this.redirectRules = ImmutableSet.<RedirectRule>copyOf(redirectRules);
this.staticIp = staticIp;
} }
public static Builder builder() { public static Builder builder() {
@ -59,6 +64,7 @@ public class NetworkAdapter {
private NetworkAttachmentType networkAttachmentType; private NetworkAttachmentType networkAttachmentType;
private String macAddress; private String macAddress;
private Set<RedirectRule> redirectRules = Sets.newLinkedHashSet(); private Set<RedirectRule> redirectRules = Sets.newLinkedHashSet();
private String staticIp;
/** /**
* *
@ -112,10 +118,15 @@ public class NetworkAdapter {
guest, guestPort)); guest, guestPort));
return this; return this;
} }
public Builder staticIp(@Nullable String staticIp) {
this.staticIp = staticIp;
return this;
}
public NetworkAdapter build() { public NetworkAdapter build() {
return new NetworkAdapter(networkAttachmentType, macAddress, return new NetworkAdapter(networkAttachmentType, macAddress,
redirectRules); redirectRules,staticIp);
} }
} }
@ -130,6 +141,10 @@ public class NetworkAdapter {
public String getMacAddress() { public String getMacAddress() {
return macAddress; return macAddress;
} }
public String getStaticIp() {
return staticIp;
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {

View File

@ -18,6 +18,7 @@
*/ */
package org.jclouds.virtualbox.domain; package org.jclouds.virtualbox.domain;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.base.Objects; import com.google.common.base.Objects;
@ -41,11 +42,12 @@ public class NetworkInterfaceCard {
public static class Builder { public static class Builder {
private long slot; private long slot = 0L;
private NetworkAdapter networkAdapter; private NetworkAdapter networkAdapter;
private String hostInterfaceName; private String hostInterfaceName;
public Builder slot(long slot) { public Builder slot(long slot) {
checkArgument(slot >= 0 && slot < 4, "must be 0, 1, 2, 3: %s", slot);
this.slot = slot; this.slot = slot;
return this; return this;
} }

View File

@ -18,7 +18,6 @@
*/ */
package org.jclouds.virtualbox.domain; package org.jclouds.virtualbox.domain;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import java.util.ArrayList; import java.util.ArrayList;
@ -47,10 +46,8 @@ public class NetworkSpec {
private List<NetworkInterfaceCard> networkInterfaceCards = new ArrayList<NetworkInterfaceCard>(); private List<NetworkInterfaceCard> networkInterfaceCards = new ArrayList<NetworkInterfaceCard>();
public Builder addNIC(long slot, NetworkInterfaceCard networkInterfaceCard) { public Builder addNIC(NetworkInterfaceCard networkInterfaceCard) {
checkArgument(slot >= 0 && slot < 4, "must be 0, 1, 2, 3: %s", slot); this.networkInterfaceCards.add(networkInterfaceCard);
NetworkInterfaceCard nic = NetworkInterfaceCard.builder().slot(slot).addNetworkAdapter(networkInterfaceCard.getNetworkAdapter()).build();
this.networkInterfaceCards.add(nic);
return this; return this;
} }

View File

@ -0,0 +1,55 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.jclouds.virtualbox.functions;
import static org.virtualbox_4_1.NetworkAdapterType.Am79C973;
import static org.virtualbox_4_1.NetworkAttachmentType.HostOnly;
import javax.annotation.Nullable;
import org.jclouds.virtualbox.domain.NetworkInterfaceCard;
import org.virtualbox_4_1.IMachine;
import org.virtualbox_4_1.INetworkAdapter;
import com.google.common.base.Function;
/**
* @author dralves
*/
public class AttachHostOnlyAdapter implements Function<IMachine, Void> {
private NetworkInterfaceCard networkInterfaceCard;
public AttachHostOnlyAdapter(NetworkInterfaceCard networkInterfaceCard) {
this.networkInterfaceCard = networkInterfaceCard;
}
@Override
public Void apply(@Nullable IMachine machine) {
INetworkAdapter iNetworkAdapter = machine.getNetworkAdapter(networkInterfaceCard.getSlot());
iNetworkAdapter.setAttachmentType(HostOnly);
iNetworkAdapter.setAdapterType(Am79C973);
iNetworkAdapter.setMACAddress(networkInterfaceCard.getNetworkAdapter().getMacAddress());
iNetworkAdapter.setHostOnlyInterface(networkInterfaceCard.getHostInterfaceName());
iNetworkAdapter.setEnabled(true);
machine.saveSettings();
return null;
}
}

View File

@ -49,6 +49,8 @@ public class AttachNicToMachine implements Function<NetworkInterfaceCard, Void>
} else if (hasBridgedAdapter(nic)) { } else if (hasBridgedAdapter(nic)) {
return machineUtils.writeLockMachineAndApply(vmName, new AttachBridgedAdapterToMachine(nic)); return machineUtils.writeLockMachineAndApply(vmName, new AttachBridgedAdapterToMachine(nic));
} else if (hasHostOnlyAdapter(nic)) {
return machineUtils.writeLockMachineAndApply(vmName, new AttachHostOnlyAdapter(nic));
} else } else
return null; return null;
} }
@ -62,4 +64,8 @@ public class AttachNicToMachine implements Function<NetworkInterfaceCard, Void>
return nic.getNetworkAdapter().getNetworkAttachmentType() return nic.getNetworkAdapter().getNetworkAttachmentType()
.equals(NetworkAttachmentType.Bridged); .equals(NetworkAttachmentType.Bridged);
} }
private boolean hasHostOnlyAdapter(NetworkInterfaceCard nic) {
return nic.getNetworkAdapter().getNetworkAttachmentType().equals(NetworkAttachmentType.HostOnly);
}
} }

View File

@ -37,6 +37,7 @@ import javax.annotation.PostConstruct;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.Constants; import org.jclouds.Constants;
import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.Image;
@ -72,7 +73,11 @@ import com.google.common.collect.Maps;
* @author dralves * @author dralves
* *
*/ */
@Singleton
public class MastersCache extends AbstractLoadingCache<Image, Master> { public class MastersCache extends AbstractLoadingCache<Image, Master> {
// TODO parameterize
public static final int MASTER_PORT = 2222;
@Resource @Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER) @Named(ComputeServiceConstants.COMPUTE_LOGGER)
@ -121,7 +126,7 @@ public class MastersCache extends AbstractLoadingCache<Image, Master> {
public synchronized Master get(Image key) throws ExecutionException { public synchronized Master get(Image key) throws ExecutionException {
// check if we have loaded this machine before // check if we have loaded this machine before
if (masters.containsKey(key.getId())) { if (masters.containsKey(key.getId())) {
return masters.get(key); return masters.get(key.getId());
} }
String guestAdditionsFileName = String.format("VBoxGuestAdditions_%s.iso", version); String guestAdditionsFileName = String.format("VBoxGuestAdditions_%s.iso", version);
@ -154,12 +159,12 @@ public class MastersCache extends AbstractLoadingCache<Image, Master> {
.controller(ideController).forceOverwrite(true).cleanUpMode(CleanupMode.Full).build(); .controller(ideController).forceOverwrite(true).cleanUpMode(CleanupMode.Full).build();
NetworkAdapter networkAdapter = NetworkAdapter.builder().networkAttachmentType(NetworkAttachmentType.NAT) NetworkAdapter networkAdapter = NetworkAdapter.builder().networkAttachmentType(NetworkAttachmentType.NAT)
.tcpRedirectRule("127.0.0.1", 2222, "", 22).build(); .tcpRedirectRule("127.0.0.1", MASTER_PORT, "", 22).build();
NetworkInterfaceCard networkInterfaceCard = NetworkInterfaceCard.builder().addNetworkAdapter(networkAdapter) NetworkInterfaceCard networkInterfaceCard = NetworkInterfaceCard.builder().addNetworkAdapter(networkAdapter)
.build(); .slot(0L).build();
NetworkSpec networkSpec = NetworkSpec.builder().addNIC(0L, networkInterfaceCard).build(); NetworkSpec networkSpec = NetworkSpec.builder().addNIC(networkInterfaceCard).build();
MasterSpec masterSpec = MasterSpec MasterSpec masterSpec = MasterSpec
.builder() .builder()
@ -189,6 +194,14 @@ public class MastersCache extends AbstractLoadingCache<Image, Master> {
return master; return master;
} }
@Override
public synchronized Master getIfPresent(Image key) {
if (masters.containsKey(key.getId())) {
return masters.get(key.getId());
}
return null;
}
private String getFilePathOrDownload(String httpUrl) throws ExecutionException { private String getFilePathOrDownload(String httpUrl) throws ExecutionException {
String fileName = httpUrl.substring(httpUrl.lastIndexOf('/') + 1, httpUrl.length()); String fileName = httpUrl.substring(httpUrl.lastIndexOf('/') + 1, httpUrl.length());
File localFile = new File(isosDir, fileName); File localFile = new File(isosDir, fileName);
@ -200,12 +213,4 @@ public class MastersCache extends AbstractLoadingCache<Image, Master> {
return localFile.getAbsolutePath(); return localFile.getAbsolutePath();
} }
@Override
public Master getIfPresent(Image key) {
if (masters.containsKey(key.getId())) {
return masters.get(key.getId());
}
return null;
}
} }

View File

@ -1,5 +1,5 @@
/** /**
mh * Licensed to jclouds, Inc. (jclouds) under one or more * Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file * contributor license agreements. See the NOTICE file
* distributed with this work for additional information * distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file * regarding copyright ownership. jclouds licenses this file
@ -19,13 +19,18 @@ mh * Licensed to jclouds, Inc. (jclouds) under one or more
package org.jclouds.virtualbox.functions; package org.jclouds.virtualbox.functions;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX; import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX;
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_NODE_PREFIX; import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_NODE_PREFIX;
import java.util.concurrent.atomic.AtomicInteger;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.compute.ComputeServiceAdapter.NodeAndInitialCredentials; import org.jclouds.compute.ComputeServiceAdapter.NodeAndInitialCredentials;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.options.RunScriptOptions;
import org.jclouds.domain.LoginCredentials; import org.jclouds.domain.LoginCredentials;
import org.jclouds.virtualbox.domain.CloneSpec; import org.jclouds.virtualbox.domain.CloneSpec;
import org.jclouds.virtualbox.domain.ExecutionType; import org.jclouds.virtualbox.domain.ExecutionType;
@ -35,6 +40,7 @@ import org.jclouds.virtualbox.domain.NetworkInterfaceCard;
import org.jclouds.virtualbox.domain.NetworkSpec; import org.jclouds.virtualbox.domain.NetworkSpec;
import org.jclouds.virtualbox.domain.NodeSpec; import org.jclouds.virtualbox.domain.NodeSpec;
import org.jclouds.virtualbox.domain.VmSpec; import org.jclouds.virtualbox.domain.VmSpec;
import org.jclouds.virtualbox.statements.SetIpAddress;
import org.jclouds.virtualbox.util.MachineUtils; import org.jclouds.virtualbox.util.MachineUtils;
import org.virtualbox_4_1.CleanupMode; import org.virtualbox_4_1.CleanupMode;
import org.virtualbox_4_1.IMachine; import org.virtualbox_4_1.IMachine;
@ -48,20 +54,43 @@ import com.google.common.base.Supplier;
@Singleton @Singleton
public class NodeCreator implements Function<NodeSpec, NodeAndInitialCredentials<IMachine>> { public class NodeCreator implements Function<NodeSpec, NodeAndInitialCredentials<IMachine>> {
// TODO parameterize
public static final int NODE_PORT_INIT = 3000;
// TODO parameterize
public static final String VMS_NETWORK = "33.33.33.";
// TODO parameterize
public static final String HOST_ONLY_IFACE_NAME = "vboxnet0";
// TODO parameterize
public static final boolean USE_LINKED = true;
private final Supplier<VirtualBoxManager> manager; private final Supplier<VirtualBoxManager> manager;
private final Function<CloneSpec, IMachine> cloner; private final Function<CloneSpec, IMachine> cloner;
private final AtomicInteger nodePorts;
private final AtomicInteger nodeIps;
private MachineUtils machineUtils;
private Function<IMachine, NodeMetadata> imachineToNodeMetadata;
@Inject @Inject
public NodeCreator(Supplier<VirtualBoxManager> manager, Function<CloneSpec, IMachine> cloner, public NodeCreator(Supplier<VirtualBoxManager> manager, Function<CloneSpec, IMachine> cloner,
MachineUtils machineUtils) { MachineUtils machineUtils, Function<IMachine, NodeMetadata> imachineToNodeMetadata) {
this.manager = manager; this.manager = manager;
this.cloner = cloner; this.cloner = cloner;
this.nodePorts = new AtomicInteger(NODE_PORT_INIT);
this.nodeIps = new AtomicInteger(1);
this.machineUtils = machineUtils;
this.imachineToNodeMetadata = imachineToNodeMetadata;
} }
@Override @Override
public NodeAndInitialCredentials<IMachine> apply(NodeSpec nodeSpec) { public NodeAndInitialCredentials<IMachine> apply(NodeSpec nodeSpec) {
checkNotNull(nodeSpec, "NodeSpec");
Master master = nodeSpec.getMaster(); Master master = nodeSpec.getMaster();
checkNotNull(master, "Master");
if (master.getMachine().getCurrentSnapshot() != null) { if (master.getMachine().getCurrentSnapshot() != null) {
ISession session; ISession session;
@ -81,21 +110,29 @@ public class NodeCreator implements Function<NodeSpec, NodeAndInitialCredentials
VmSpec cloneVmSpec = VmSpec.builder().id(cloneName).name(cloneName).memoryMB(512).cleanUpMode(CleanupMode.Full) VmSpec cloneVmSpec = VmSpec.builder().id(cloneName).name(cloneName).memoryMB(512).cleanUpMode(CleanupMode.Full)
.forceOverwrite(true).build(); .forceOverwrite(true).build();
NetworkAdapter networkAdapter = NetworkAdapter.builder().networkAttachmentType(NetworkAttachmentType.NAT) NetworkAdapter natAdapter = NetworkAdapter.builder().networkAttachmentType(NetworkAttachmentType.NAT)
.tcpRedirectRule("127.0.0.1", 2222, "", 22).build(); .tcpRedirectRule("127.0.0.1", this.nodePorts.getAndIncrement(), "", 22).build();
NetworkInterfaceCard networkInterfaceCard = NetworkInterfaceCard.builder().addNetworkAdapter(networkAdapter) NetworkInterfaceCard natIfaceCard = NetworkInterfaceCard.builder().addNetworkAdapter(natAdapter).slot(0L).build();
.build();
NetworkSpec networkSpec = NetworkSpec.builder().addNIC(0L, networkInterfaceCard).build(); NetworkAdapter hostOnlyAdapter = NetworkAdapter.builder().networkAttachmentType(NetworkAttachmentType.HostOnly)
.staticIp(VMS_NETWORK + this.nodeIps.getAndIncrement()).build();
CloneSpec cloneSpec = CloneSpec.builder().linked(false).master(master.getMachine()).network(networkSpec) NetworkInterfaceCard hostOnlyIfaceCard = NetworkInterfaceCard.builder().addNetworkAdapter(hostOnlyAdapter)
.addHostInterfaceName(HOST_ONLY_IFACE_NAME).slot(1L).build();
NetworkSpec networkSpec = NetworkSpec.builder().addNIC(natIfaceCard).addNIC(hostOnlyIfaceCard).build();
CloneSpec cloneSpec = CloneSpec.builder().linked(USE_LINKED).master(master.getMachine()).network(networkSpec)
.vm(cloneVmSpec).build(); .vm(cloneVmSpec).build();
IMachine cloned = cloner.apply(cloneSpec); IMachine cloned = cloner.apply(cloneSpec);
new LaunchMachineIfNotAlreadyRunning(manager.get(), ExecutionType.GUI, "").apply(cloned); new LaunchMachineIfNotAlreadyRunning(manager.get(), ExecutionType.GUI, "").apply(cloned);
machineUtils.runScriptOnNode(imachineToNodeMetadata.apply(cloned), new SetIpAddress(hostOnlyIfaceCard),
RunScriptOptions.NONE);
// TODO get credentials from somewhere else (they are also HC in IMachineToSshClient) // TODO get credentials from somewhere else (they are also HC in IMachineToSshClient)
NodeAndInitialCredentials<IMachine> nodeAndInitialCredentials = new NodeAndInitialCredentials<IMachine>(cloned, NodeAndInitialCredentials<IMachine> nodeAndInitialCredentials = new NodeAndInitialCredentials<IMachine>(cloned,
cloneName, LoginCredentials.builder().user("toor").password("password").authenticateSudo(true).build()); cloneName, LoginCredentials.builder().user("toor").password("password").authenticateSudo(true).build());

View File

@ -0,0 +1,117 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.
*/
/*
U * Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.jclouds.virtualbox.functions.admin;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Iterables.transform;
import java.util.Collections;
import java.util.List;
import javax.annotation.Resource;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.logging.Logger;
import org.jclouds.virtualbox.domain.ErrorCode;
import org.virtualbox_4_1.CleanupMode;
import org.virtualbox_4_1.DeviceType;
import org.virtualbox_4_1.IMachine;
import org.virtualbox_4_1.IMedium;
import org.virtualbox_4_1.IProgress;
import org.virtualbox_4_1.VBoxException;
import com.google.common.base.Function;
import com.google.common.base.Throwables;
import com.google.common.collect.Lists;
@Singleton
public class UnregisterMachineIfExistsAndForceDeleteItsMedia implements Function<IMachine, Void> {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
@Override
public Void apply(IMachine machine) {
List<IMedium> mediaToBeDeleted = Collections.emptyList();
try {
mediaToBeDeleted = machine.unregister(CleanupMode.Full);
} catch (VBoxException e) {
ErrorCode errorCode = ErrorCode.valueOf(e);
switch (errorCode) {
case VBOX_E_OBJECT_NOT_FOUND:
logger.debug("Machine %s does not exists, cannot unregister", machine.getName());
break;
default:
throw e;
}
}
List<IMedium> filteredMediaToBeDeleted = Lists.newArrayList(transform(mediaToBeDeleted,
new DeleteChildrenOfMedium()));
if (!filteredMediaToBeDeleted.isEmpty()) {
try {
IProgress deletion = machine.delete(filteredMediaToBeDeleted);
deletion.waitForCompletion(-1);
} catch (Exception e) {
logger.error(e, "Problem in deleting the media attached to %s", machine.getName());
Throwables.propagate(e);
}
}
return null;
}
private class DeleteChildrenOfMedium implements Function<IMedium, IMedium> {
@Override
public IMedium apply(IMedium medium) {
checkNotNull(medium.getChildren());
if (medium.getDeviceType().equals(DeviceType.HardDisk)) {
for (IMedium child : medium.getChildren()) {
IProgress deletion = child.deleteStorage();
deletion.waitForCompletion(-1);
}
}
return medium;
}
};
}

View File

@ -0,0 +1,76 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.jclouds.virtualbox.statements;
import static com.google.common.base.Preconditions.checkNotNull;
import org.jclouds.scriptbuilder.domain.OsFamily;
import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.virtualbox.domain.NetworkInterfaceCard;
import com.google.common.collect.ImmutableList;
/**
* Sets the ipaddress using ssh. Used for host-only networking
*
* @author dralves
*
*/
public class SetIpAddress implements Statement {
private String script;
public SetIpAddress(NetworkInterfaceCard networkInterfaceCard) {
String ipAddress = networkInterfaceCard.getNetworkAdapter().getStaticIp();
checkNotNull(ipAddress, "ip address");
int slot = (int) networkInterfaceCard.getSlot();
String iface = null;
switch (slot) {
case 0:
iface = "eth0";
break;
case 1:
iface = "eth1";
break;
case 2:
iface = "eth2";
break;
case 3:
iface = "eth3";
break;
default:
throw new IllegalArgumentException("slot must be 0,1,2,3 (was: " + slot + ")");
}
script = String.format("ifconfig %s %s;", iface, ipAddress);
}
@Override
public Iterable<String> functionDependencies(OsFamily family) {
return ImmutableList.of();
}
@Override
public String render(OsFamily family) {
if (checkNotNull(family, "family") == OsFamily.WINDOWS)
throw new UnsupportedOperationException("windows not yet implemented");
return script;
}
}

View File

@ -24,6 +24,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
import java.io.File; import java.io.File;
import java.net.URI; import java.net.URI;
import java.util.Properties; import java.util.Properties;
import java.util.concurrent.ExecutorService;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
@ -39,9 +40,10 @@ import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.OsFamily; import org.jclouds.compute.domain.OsFamily;
import org.jclouds.compute.domain.Template; import org.jclouds.compute.domain.Template;
import org.jclouds.compute.strategy.PrioritizeCredentialsFromTemplate; import org.jclouds.compute.strategy.PrioritizeCredentialsFromTemplate;
import org.jclouds.concurrent.MoreExecutors;
import org.jclouds.concurrent.config.ExecutorServiceModule;
import org.jclouds.logging.slf4j.config.SLF4JLoggingModule; import org.jclouds.logging.slf4j.config.SLF4JLoggingModule;
import org.jclouds.sshj.config.SshjSshClientModule; import org.jclouds.sshj.config.SshjSshClientModule;
import org.jclouds.virtualbox.compute.VirtualBoxComputeServiceAdapter;
import org.jclouds.virtualbox.config.VirtualBoxConstants; import org.jclouds.virtualbox.config.VirtualBoxConstants;
import org.jclouds.virtualbox.domain.IsoSpec; import org.jclouds.virtualbox.domain.IsoSpec;
import org.jclouds.virtualbox.domain.Master; import org.jclouds.virtualbox.domain.Master;
@ -109,6 +111,8 @@ public class BaseVirtualBoxClientLiveTest extends BaseVersionedServiceLiveTest {
protected PrioritizeCredentialsFromTemplate prioritizeCredentialsFromTemplate; protected PrioritizeCredentialsFromTemplate prioritizeCredentialsFromTemplate;
@Inject @Inject
protected LoadingCache<Image, Master> mastersCache; protected LoadingCache<Image, Master> mastersCache;
private final ExecutorService singleThreadExec = MoreExecutors.sameThreadExecutor();
@Override @Override
protected void setupCredentials() { protected void setupCredentials() {
@ -131,17 +135,10 @@ public class BaseVirtualBoxClientLiveTest extends BaseVersionedServiceLiveTest {
setupCredentials(); setupCredentials();
Properties overrides = new VirtualBoxPropertiesBuilder(setupProperties()).build(); Properties overrides = new VirtualBoxPropertiesBuilder(setupProperties()).build();
CacheNodeStoreModule hostModule = new CacheNodeStoreModule(ImmutableMap.of( context = new ComputeServiceContextFactory().createContext(provider, identity, credential, ImmutableSet
"host", .<Module> of(new SLF4JLoggingModule(), new SshjSshClientModule(), new ExecutorServiceModule(
Node.builder().id("host").name("host installing virtualbox").hostname("localhost") singleThreadExec, singleThreadExec)), overrides);
.osFamily(OsFamily.LINUX.toString()).osDescription(System.getProperty("os.name"))
.osVersion(System.getProperty("os.version")).group("ssh")
.username(System.getProperty("user.name"))
.credentialUrl(URI.create("file://" + System.getProperty("user.home") + "/.ssh/id_rsa"))
.build()));
context = new ComputeServiceContextFactory().createContext(provider, identity, credential,
ImmutableSet.<Module> of(new SLF4JLoggingModule(), new SshjSshClientModule(), hostModule), overrides);
context.utils().injector().injectMembers(this); context.utils().injector().injectMembers(this);
imageId = "ubuntu-11.04-server-i386"; imageId = "ubuntu-11.04-server-i386";
@ -157,6 +154,7 @@ public class BaseVirtualBoxClientLiveTest extends BaseVersionedServiceLiveTest {
checkNotNull(mastersCache.apply(template.getImage())); checkNotNull(mastersCache.apply(template.getImage()));
} }
protected void undoVm(VmSpec vmSpecification) { protected void undoVm(VmSpec vmSpecification) {
machineUtils.unlockMachineAndApplyOrReturnNullIfNotRegistered(vmSpecification.getVmId(), machineUtils.unlockMachineAndApplyOrReturnNullIfNotRegistered(vmSpecification.getVmId(),
new UnregisterMachineIfExistsAndDeleteItsMedia(vmSpecification)); new UnregisterMachineIfExistsAndDeleteItsMedia(vmSpecification));

View File

@ -58,20 +58,6 @@ public class VirtualBoxComputeServiceAdapterLiveTest extends BaseVirtualBoxClien
assertEquals(machine.getNode().getName(), machineName); assertEquals(machine.getNode().getName(), machineName);
doConnectViaSsh(machine.getNode(), prioritizeCredentialsFromTemplate.apply(template, machine.getCredentials())); doConnectViaSsh(machine.getNode(), prioritizeCredentialsFromTemplate.apply(template, machine.getCredentials()));
} }
@Test
public void testListHardwareProfiles() {
Iterable<IMachine> profiles = adapter.listHardwareProfiles();
assertEquals(1, Iterables.size(profiles));
//TODO: check state;
}
@Test
public void testListImages() {
Iterable<Image> iMageIterable = adapter.listImages();
assertEquals(1, Iterables.size(iMageIterable));
//TODO: check state;
}
protected void doConnectViaSsh(IMachine machine, LoginCredentials creds) { protected void doConnectViaSsh(IMachine machine, LoginCredentials creds) {
SshClient ssh = context.utils().injector().getInstance(IMachineToSshClient.class).apply(machine); SshClient ssh = context.utils().injector().getInstance(IMachineToSshClient.class).apply(machine);
@ -88,6 +74,20 @@ public class VirtualBoxComputeServiceAdapterLiveTest extends BaseVirtualBoxClien
} }
} }
@Test
public void testListHardwareProfiles() {
Iterable<IMachine> profiles = adapter.listHardwareProfiles();
assertEquals(1, Iterables.size(profiles));
//TODO: check state;
}
@Test
public void testListImages() {
Iterable<Image> iMageIterable = adapter.listImages();
assertEquals(1, Iterables.size(iMageIterable));
//TODO: check state;
}
@AfterClass @AfterClass
@Override @Override
protected void tearDown() throws Exception { protected void tearDown() throws Exception {

View File

@ -19,19 +19,56 @@
package org.jclouds.virtualbox.compute; package org.jclouds.virtualbox.compute;
import static org.testng.Assert.assertEquals;
import java.util.Set;
import javax.annotation.Resource;
import javax.inject.Named;
import org.jclouds.compute.RunNodesException;
import org.jclouds.compute.domain.ExecResponse;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.logging.Logger;
import org.jclouds.ssh.SshClient;
import org.jclouds.virtualbox.BaseVirtualBoxClientLiveTest; import org.jclouds.virtualbox.BaseVirtualBoxClientLiveTest;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.base.Predicate;
/** /**
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = "live", testName = "VirtualBoxExperimentLiveTest") @Test(groups = "live", singleThreaded = true, testName = "VirtualBoxExperimentLiveTest")
public class VirtualBoxExperimentLiveTest extends BaseVirtualBoxClientLiveTest { public class VirtualBoxExperimentLiveTest extends BaseVirtualBoxClientLiveTest {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
@Test @Test
public void testAndExperiment() { public void testLaunchCluster() throws RunNodesException {
context.getComputeService().listNodes(); int numNodes = 4;
final String clusterName = "test-launch-cluster";
Set<? extends NodeMetadata> nodes = context.getComputeService().createNodesInGroup(clusterName,
numNodes);
assertEquals(numNodes, nodes.size(), "wrong number of nodes");
for (NodeMetadata node : nodes) {
logger.debug("Created Node: %s", node);
SshClient client = context.utils().sshForNode().apply(node);
client.connect();
ExecResponse hello = client.exec("echo hello");
assertEquals(hello.getOutput().trim(), "hello");
}
context.getComputeService().destroyNodesMatching(new Predicate<NodeMetadata>() {
@Override
public boolean apply(NodeMetadata input) {
return input.getId().contains(clusterName);
}
});
} }
} }

View File

@ -99,7 +99,7 @@ public class CloneAndRegisterMachineFromIMachineIfNotAlreadyExistsLiveTest exten
NetworkInterfaceCard networkInterfaceCard = NetworkInterfaceCard.builder().addNetworkAdapter(networkAdapter) NetworkInterfaceCard networkInterfaceCard = NetworkInterfaceCard.builder().addNetworkAdapter(networkAdapter)
.build(); .build();
this.cloneNetworkSpec = NetworkSpec.builder().addNIC(0L, networkInterfaceCard).build(); this.cloneNetworkSpec = NetworkSpec.builder().addNIC(networkInterfaceCard).build();
sourceMachineSpec = MasterSpec.builder().iso(isoSpec).vm(sourceVmSpec).network(cloneNetworkSpec).build(); sourceMachineSpec = MasterSpec.builder().iso(isoSpec).vm(sourceVmSpec).network(cloneNetworkSpec).build();

View File

@ -105,7 +105,7 @@ public class CreateAndInstallVmLiveTest extends BaseVirtualBoxClientLiveTest {
NetworkInterfaceCard networkInterfaceCard = NetworkInterfaceCard.builder().addNetworkAdapter(networkAdapter) NetworkInterfaceCard networkInterfaceCard = NetworkInterfaceCard.builder().addNetworkAdapter(networkAdapter)
.build(); .build();
NetworkSpec networkSpec = NetworkSpec.builder().addNIC(0L, networkInterfaceCard).build(); NetworkSpec networkSpec = NetworkSpec.builder().addNIC(networkInterfaceCard).build();
masterSpec = MasterSpec masterSpec = MasterSpec
.builder() .builder()

View File

@ -80,7 +80,7 @@ public class CreateAndRegisterMachineFromIsoIfNotAlreadyExistsLiveTest extends
.builder().addNetworkAdapter(networkAdapter).build(); .builder().addNetworkAdapter(networkAdapter).build();
NetworkSpec networkSpec = NetworkSpec.builder() NetworkSpec networkSpec = NetworkSpec.builder()
.addNIC(0L, networkInterfaceCard).build(); .addNIC(networkInterfaceCard).build();
MasterSpec machineSpec = MasterSpec MasterSpec machineSpec = MasterSpec
.builder() .builder()

View File

@ -99,7 +99,7 @@ public class GuestAdditionsInstallerLiveTest extends
.builder().addNetworkAdapter(networkAdapter).build(); .builder().addNetworkAdapter(networkAdapter).build();
NetworkSpec networkSpec = NetworkSpec.builder() NetworkSpec networkSpec = NetworkSpec.builder()
.addNIC(0L, networkInterfaceCard).build(); .addNIC(networkInterfaceCard).build();
sourceMachineSpec = MasterSpec.builder().iso(isoSpec).vm(sourceVmSpec) sourceMachineSpec = MasterSpec.builder().iso(isoSpec).vm(sourceVmSpec)
.network(networkSpec).build(); .network(networkSpec).build();

View File

@ -90,7 +90,7 @@ public class IMachinePredicatesLiveTest extends BaseVirtualBoxClientLiveTest {
NetworkInterfaceCard networkInterfaceCard = NetworkInterfaceCard.builder().addNetworkAdapter(networkAdapter) NetworkInterfaceCard networkInterfaceCard = NetworkInterfaceCard.builder().addNetworkAdapter(networkAdapter)
.build(); .build();
this.networkSpec = NetworkSpec.builder().addNIC(0L, networkInterfaceCard).build(); this.networkSpec = NetworkSpec.builder().addNIC(networkInterfaceCard).build();
} }

View File

@ -0,0 +1,67 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.jclouds.virtualbox.statements;
import static junit.framework.Assert.assertEquals;
import org.jclouds.scriptbuilder.domain.OsFamily;
import org.jclouds.virtualbox.domain.NetworkAdapter;
import org.jclouds.virtualbox.domain.NetworkInterfaceCard;
import org.testng.annotations.Test;
import org.virtualbox_4_1.NetworkAttachmentType;
public class SetIpAddressTest {
@Test
public void testSetIpeth0() {
NetworkInterfaceCard networkInterfaceCard = NetworkInterfaceCard
.builder()
.slot(0L)
.addNetworkAdapter(
NetworkAdapter.builder().staticIp("127.0.0.1").networkAttachmentType(NetworkAttachmentType.NAT)
.build()).build();
SetIpAddress setIpAddressStmtm = new SetIpAddress(networkInterfaceCard);
assertEquals("ifconfig eth0 127.0.0.1;", setIpAddressStmtm.render(OsFamily.UNIX));
}
@Test
public void testSetIpeth3() {
NetworkInterfaceCard networkInterfaceCard = NetworkInterfaceCard
.builder()
.slot(3L)
.addNetworkAdapter(
NetworkAdapter.builder().staticIp("localhost").networkAttachmentType(NetworkAttachmentType.NAT)
.build()).build();
SetIpAddress setIpAddressStmtm = new SetIpAddress(networkInterfaceCard);
assertEquals("ifconfig eth3 localhost;", setIpAddressStmtm.render(OsFamily.UNIX));
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testThrowsIllegalArgumentExceptionOnWrongSlot() {
NetworkInterfaceCard networkInterfaceCard = NetworkInterfaceCard
.builder()
.slot(4L)
.addNetworkAdapter(
NetworkAdapter.builder().staticIp("localhost").networkAttachmentType(NetworkAttachmentType.NAT)
.build()).build();
new SetIpAddress(networkInterfaceCard);
}
}

View File

@ -124,7 +124,7 @@ public class ServerToNodeMetadata implements Function<Server, NodeMetadata> {
try { try {
image = Iterables.find(images.get(), new FindImageForServer(from)); image = Iterables.find(images.get(), new FindImageForServer(from));
} catch (NoSuchElementException e) { } catch (NoSuchElementException e) {
logger.warn("could not find a matching image for server %s", from); logger.debug("could not find a matching image for server %s", from);
} }
return image; return image;
} }
@ -134,8 +134,8 @@ public class ServerToNodeMetadata implements Function<Server, NodeMetadata> {
try { try {
hardware = Iterables.find(hardwares.get(), new FindHardwareForServer(from)); hardware = Iterables.find(hardwares.get(), new FindHardwareForServer(from));
} catch (NoSuchElementException e) { } catch (NoSuchElementException e) {
logger.warn("could not find a matching hardware for server %s", from); logger.debug("could not find a matching hardware for server %s", from);
} }
return hardware; return hardware;
} }
} }

View File

@ -354,8 +354,7 @@ public class GoGridLiveTestDisabled extends BaseVersionedServiceLiveTest {
socketOpen.apply(socket); socketOpen.apply(socket);
SshClient sshClient = new SshjSshClient(new BackoffLimitedRetryHandler(), socket, 60000, SshClient sshClient = context.utils().injector().getInstance(SshClient.Factory.class).create(socket, instanceCredentials);
instanceCredentials.identity, instanceCredentials.credential, null);
sshClient.connect(); sshClient.connect();
String output = sshClient.exec("df").getOutput(); String output = sshClient.exec("df").getOutput();
assertTrue(output.contains("Filesystem"), assertTrue(output.contains("Filesystem"),

View File

@ -129,8 +129,8 @@ public class ServerToNodeMetadata implements Function<Server, NodeMetadata> {
try { try {
return Iterables.find(images.get(), new FindImageForServer(location, from)).getOperatingSystem(); return Iterables.find(images.get(), new FindImageForServer(location, from)).getOperatingSystem();
} catch (NoSuchElementException e) { } catch (NoSuchElementException e) {
logger.warn("could not find a matching image for server %s in location %s", from, location); logger.debug("could not find a matching image for server %s in location %s", from, location);
} }
return null; return null;
} }
} }

View File

@ -129,7 +129,7 @@ public class SliceToNodeMetadata implements Function<Slice, NodeMetadata> {
try { try {
return Iterables.find(hardwares.get(), new FindHardwareForSlice(from)); return Iterables.find(hardwares.get(), new FindHardwareForSlice(from));
} catch (NoSuchElementException e) { } catch (NoSuchElementException e) {
logger.warn("could not find a matching hardware for slice %s", from); logger.debug("could not find a matching hardware for slice %s", from);
} }
return null; return null;
} }
@ -138,7 +138,7 @@ public class SliceToNodeMetadata implements Function<Slice, NodeMetadata> {
try { try {
return Iterables.find(images.get(), new FindImageForSlice(from)).getOperatingSystem(); return Iterables.find(images.get(), new FindImageForSlice(from)).getOperatingSystem();
} catch (NoSuchElementException e) { } catch (NoSuchElementException e) {
logger.warn("could not find a matching image for slice %s in location %s", from, location); logger.debug("could not find a matching image for slice %s in location %s", from, location);
} }
return null; return null;
} }