mirror of https://github.com/apache/jclouds.git
Issue 79: improved session handling
git-svn-id: http://jclouds.googlecode.com/svn/trunk@1825 3d8758e0-26b5-11de-8745-db77d3ebf521
This commit is contained in:
parent
ea874483b0
commit
c63e532271
|
@ -1,9 +1,33 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
|
||||||
|
*
|
||||||
|
* ====================================================================
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
* ====================================================================
|
||||||
|
*/
|
||||||
package org.jclouds.ssh;
|
package org.jclouds.ssh;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
*/
|
*/
|
||||||
public class ExecResponse {
|
public class ExecResponse {
|
||||||
|
|
||||||
private final String error;
|
private final String error;
|
||||||
private final String output;
|
private final String output;
|
||||||
|
|
||||||
|
@ -20,4 +44,40 @@ public class ExecResponse {
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "ExecResponse [error=" + error + ", output=" + output + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result + ((error == null) ? 0 : error.hashCode());
|
||||||
|
result = prime * result + ((output == null) ? 0 : output.hashCode());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
ExecResponse other = (ExecResponse) obj;
|
||||||
|
if (error == null) {
|
||||||
|
if (other.error != null)
|
||||||
|
return false;
|
||||||
|
} else if (!error.equals(other.error))
|
||||||
|
return false;
|
||||||
|
if (output == null) {
|
||||||
|
if (other.output != null)
|
||||||
|
return false;
|
||||||
|
} else if (!output.equals(other.output))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,3 +1,26 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
|
||||||
|
*
|
||||||
|
* ====================================================================
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
* ====================================================================
|
||||||
|
*/
|
||||||
package org.jclouds.ssh;
|
package org.jclouds.ssh;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
|
@ -1,3 +1,26 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
|
||||||
|
*
|
||||||
|
* ====================================================================
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
* ====================================================================
|
||||||
|
*/
|
||||||
package org.jclouds.ssh;
|
package org.jclouds.ssh;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,9 +1,33 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
|
||||||
|
*
|
||||||
|
* ====================================================================
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
* ====================================================================
|
||||||
|
*/
|
||||||
package org.jclouds.ssh.jsch;
|
package org.jclouds.ssh.jsch;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkArgument;
|
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 static com.google.common.base.Preconditions.checkState;
|
import static com.google.common.base.Preconditions.checkState;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
|
|
||||||
|
@ -11,6 +35,7 @@ import javax.annotation.PostConstruct;
|
||||||
import javax.annotation.PreDestroy;
|
import javax.annotation.PreDestroy;
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
import org.apache.commons.io.input.ProxyInputStream;
|
||||||
import org.apache.commons.io.output.ByteArrayOutputStream;
|
import org.apache.commons.io.output.ByteArrayOutputStream;
|
||||||
import org.jclouds.logging.Logger;
|
import org.jclouds.logging.Logger;
|
||||||
import org.jclouds.ssh.ExecResponse;
|
import org.jclouds.ssh.ExecResponse;
|
||||||
|
@ -20,7 +45,6 @@ import org.jclouds.util.Utils;
|
||||||
|
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.assistedinject.Assisted;
|
import com.google.inject.assistedinject.Assisted;
|
||||||
import com.jcraft.jsch.Channel;
|
|
||||||
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.JSch;
|
||||||
|
@ -34,11 +58,27 @@ import com.jcraft.jsch.SftpException;
|
||||||
*/
|
*/
|
||||||
public class JschSshConnection implements SshConnection {
|
public class JschSshConnection implements SshConnection {
|
||||||
|
|
||||||
|
private final class CloseFtpChannelOnCloseInputStream extends ProxyInputStream {
|
||||||
|
|
||||||
|
private final ChannelSftp sftp;
|
||||||
|
|
||||||
|
private CloseFtpChannelOnCloseInputStream(InputStream proxy, ChannelSftp sftp) {
|
||||||
|
super(proxy);
|
||||||
|
this.sftp = sftp;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
super.close();
|
||||||
|
if (sftp != null)
|
||||||
|
sftp.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private final InetAddress host;
|
private final InetAddress host;
|
||||||
private final int port;
|
private final int port;
|
||||||
private final String username;
|
private final String username;
|
||||||
private final String password;
|
private final String password;
|
||||||
private ChannelSftp sftp;
|
|
||||||
@Resource
|
@Resource
|
||||||
protected Logger logger = Logger.NULL;
|
protected Logger logger = Logger.NULL;
|
||||||
private Session session;
|
private Session session;
|
||||||
|
@ -54,10 +94,20 @@ public class JschSshConnection implements SshConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
public InputStream get(String path) {
|
public InputStream get(String path) {
|
||||||
checkConnected();
|
|
||||||
checkNotNull(path, "path");
|
checkNotNull(path, "path");
|
||||||
|
|
||||||
|
checkConnected();
|
||||||
|
logger.debug("%s@%s:%d: Opening sftp Channel.", username, host.getHostAddress(), port);
|
||||||
|
ChannelSftp sftp = null;
|
||||||
try {
|
try {
|
||||||
return sftp.get(path);
|
sftp = (ChannelSftp) session.openChannel("sftp");
|
||||||
|
sftp.connect();
|
||||||
|
} catch (JSchException e) {
|
||||||
|
throw new SshException(String.format("%s@%s:%d: Error connecting to sftp.", username, host
|
||||||
|
.getHostAddress(), port), e);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return new CloseFtpChannelOnCloseInputStream(sftp.get(path), sftp);
|
||||||
} catch (SftpException e) {
|
} catch (SftpException e) {
|
||||||
throw new SshException(String.format("%s@%s:%d: Error getting path: %s", username, host
|
throw new SshException(String.format("%s@%s:%d: Error getting path: %s", username, host
|
||||||
.getHostAddress(), port, path), e);
|
.getHostAddress(), port, path), e);
|
||||||
|
@ -65,17 +115,15 @@ public class JschSshConnection implements SshConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkConnected() {
|
private void checkConnected() {
|
||||||
checkState(sftp != null && sftp.isConnected(), String.format("%s@%s:%d: SFTP not connected!",
|
checkState(session != null && session.isConnected(), String.format(
|
||||||
username, host.getHostAddress(), port));
|
"%s@%s:%d: SFTP not connected!", username, host.getHostAddress(), port));
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostConstruct
|
@PostConstruct
|
||||||
public void connect() {
|
public void connect() {
|
||||||
if (sftp != null && sftp.isConnected())
|
disconnect();
|
||||||
return;
|
|
||||||
JSch jsch = new JSch();
|
JSch jsch = new JSch();
|
||||||
session = null;
|
session = null;
|
||||||
Channel channel = null;
|
|
||||||
try {
|
try {
|
||||||
session = jsch.getSession(username, host.getHostAddress(), port);
|
session = jsch.getSession(username, host.getHostAddress(), port);
|
||||||
} catch (JSchException e) {
|
} catch (JSchException e) {
|
||||||
|
@ -94,24 +142,16 @@ public class JschSshConnection implements SshConnection {
|
||||||
host.getHostAddress(), port), e);
|
host.getHostAddress(), port), e);
|
||||||
}
|
}
|
||||||
logger.debug("%s@%s:%d: Session connected.", username, host.getHostAddress(), port);
|
logger.debug("%s@%s:%d: Session connected.", username, host.getHostAddress(), port);
|
||||||
logger.debug("%s@%s:%d: Opening sftp Channel.", username, host.getHostAddress(), port);
|
|
||||||
try {
|
|
||||||
channel = session.openChannel("sftp");
|
|
||||||
channel.connect();
|
|
||||||
} catch (JSchException e) {
|
|
||||||
throw new SshException(String.format("%s@%s:%d: Error connecting to sftp.", username, host
|
|
||||||
.getHostAddress(), port), e);
|
|
||||||
}
|
|
||||||
sftp = (ChannelSftp) channel;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@PreDestroy
|
@PreDestroy
|
||||||
public void disconnect() {
|
public void disconnect() {
|
||||||
if (sftp != null && sftp.isConnected())
|
if (session != null && session.isConnected())
|
||||||
sftp.quit();
|
session.disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ExecResponse exec(String command) {
|
public ExecResponse exec(String command) {
|
||||||
|
checkConnected();
|
||||||
ChannelExec executor = null;
|
ChannelExec executor = null;
|
||||||
try {
|
try {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -1,3 +1,26 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
|
||||||
|
*
|
||||||
|
* ====================================================================
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
* ====================================================================
|
||||||
|
*/
|
||||||
package org.jclouds.ssh.jsch;
|
package org.jclouds.ssh.jsch;
|
||||||
|
|
||||||
import static org.testng.Assert.assertEquals;
|
import static org.testng.Assert.assertEquals;
|
||||||
|
@ -12,7 +35,6 @@ import org.jclouds.ssh.ExecResponse;
|
||||||
import org.jclouds.ssh.SshConnection;
|
import org.jclouds.ssh.SshConnection;
|
||||||
import org.jclouds.ssh.jsch.config.JschSshConnectionModule;
|
import org.jclouds.ssh.jsch.config.JschSshConnectionModule;
|
||||||
import org.jclouds.util.Utils;
|
import org.jclouds.util.Utils;
|
||||||
import org.testng.ITestContext;
|
|
||||||
import org.testng.annotations.BeforeGroups;
|
import org.testng.annotations.BeforeGroups;
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
@ -31,18 +53,15 @@ public class JschSshConnectionLiveTest {
|
||||||
protected static final String sshUser = System.getProperty("jclouds.test.ssh.username");
|
protected static final String sshUser = System.getProperty("jclouds.test.ssh.username");
|
||||||
protected static final String sshPass = System.getProperty("jclouds.test.ssh.password");
|
protected static final String sshPass = System.getProperty("jclouds.test.ssh.password");
|
||||||
|
|
||||||
protected SshConnection connection;
|
|
||||||
|
|
||||||
@BeforeGroups(groups = { "live" })
|
@BeforeGroups(groups = { "live" })
|
||||||
public void setupConnection(ITestContext context) throws NumberFormatException,
|
public SshConnection setupConnection() throws NumberFormatException, UnknownHostException {
|
||||||
UnknownHostException {
|
|
||||||
int port = (sshPort != null) ? Integer.parseInt(sshPort) : 22;
|
int port = (sshPort != null) ? Integer.parseInt(sshPort) : 22;
|
||||||
InetAddress host = (sshHost != null) ? InetAddress.getByName(sshHost) : InetAddress
|
InetAddress host = (sshHost != null) ? InetAddress.getByName(sshHost) : InetAddress
|
||||||
.getLocalHost();
|
.getLocalHost();
|
||||||
if (sshUser == null || sshPass == null || sshUser.trim().equals("")
|
if (sshUser == null || sshPass == null || sshUser.trim().equals("")
|
||||||
|| sshPass.trim().equals("")) {
|
|| sshPass.trim().equals("")) {
|
||||||
System.err.println("ssh credentials not present. Tests will be lame");
|
System.err.println("ssh credentials not present. Tests will be lame");
|
||||||
connection = new SshConnection() {
|
return new SshConnection() {
|
||||||
|
|
||||||
public void connect() {
|
public void connect() {
|
||||||
}
|
}
|
||||||
|
@ -72,19 +91,20 @@ public class JschSshConnectionLiveTest {
|
||||||
} else {
|
} else {
|
||||||
Injector i = Guice.createInjector(new JschSshConnectionModule());
|
Injector i = Guice.createInjector(new JschSshConnectionModule());
|
||||||
SshConnection.Factory factory = i.getInstance(SshConnection.Factory.class);
|
SshConnection.Factory factory = i.getInstance(SshConnection.Factory.class);
|
||||||
connection = factory.create(host, port, sshUser, sshPass);
|
SshConnection connection = factory.create(host, port, sshUser, sshPass);
|
||||||
connection.connect();
|
connection.connect();
|
||||||
|
return connection;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testGetEtcPassword() throws IOException {
|
public void testGetEtcPassword() throws IOException {
|
||||||
InputStream input = connection.get("/etc/passwd");
|
InputStream input = setupConnection().get("/etc/passwd");
|
||||||
String contents = Utils.toStringAndClose(input);
|
String contents = Utils.toStringAndClose(input);
|
||||||
assert contents.indexOf("root") >= 0 : "no root in " + contents;
|
assert contents.indexOf("root") >= 0 : "no root in " + contents;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testExecHostname() throws IOException {
|
public void testExecHostname() throws IOException {
|
||||||
ExecResponse response = connection.exec("hostname");
|
ExecResponse response = setupConnection().exec("hostname");
|
||||||
assertEquals(response.getError(), "");
|
assertEquals(response.getError(), "");
|
||||||
assertEquals(response.getOutput().trim(), InetAddress.getLocalHost().getHostName());
|
assertEquals(response.getOutput().trim(), InetAddress.getLocalHost().getHostName());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,26 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
|
||||||
|
*
|
||||||
|
* ====================================================================
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
* ====================================================================
|
||||||
|
*/
|
||||||
package org.jclouds.ssh.jsch.config;
|
package org.jclouds.ssh.jsch.config;
|
||||||
|
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
|
|
Loading…
Reference in New Issue