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:
adrian.f.cole 2009-07-21 16:50:58 +00:00
parent ea874483b0
commit c63e532271
6 changed files with 218 additions and 29 deletions

View File

@ -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;
/**
* @author Adrian Cole
*/
public class ExecResponse {
private final String error;
private final String output;
@ -20,4 +44,40 @@ public class ExecResponse {
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;
}
}

View File

@ -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;
import java.io.InputStream;

View File

@ -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;
/**

View File

@ -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;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
@ -11,6 +35,7 @@ import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import org.apache.commons.io.input.ProxyInputStream;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.jclouds.logging.Logger;
import org.jclouds.ssh.ExecResponse;
@ -20,7 +45,6 @@ import org.jclouds.util.Utils;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
@ -34,11 +58,27 @@ import com.jcraft.jsch.SftpException;
*/
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 int port;
private final String username;
private final String password;
private ChannelSftp sftp;
@Resource
protected Logger logger = Logger.NULL;
private Session session;
@ -54,10 +94,20 @@ public class JschSshConnection implements SshConnection {
}
public InputStream get(String path) {
checkConnected();
checkNotNull(path, "path");
checkConnected();
logger.debug("%s@%s:%d: Opening sftp Channel.", username, host.getHostAddress(), port);
ChannelSftp sftp = null;
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) {
throw new SshException(String.format("%s@%s:%d: Error getting path: %s", username, host
.getHostAddress(), port, path), e);
@ -65,17 +115,15 @@ public class JschSshConnection implements SshConnection {
}
private void checkConnected() {
checkState(sftp != null && sftp.isConnected(), String.format("%s@%s:%d: SFTP not connected!",
username, host.getHostAddress(), port));
checkState(session != null && session.isConnected(), String.format(
"%s@%s:%d: SFTP not connected!", username, host.getHostAddress(), port));
}
@PostConstruct
public void connect() {
if (sftp != null && sftp.isConnected())
return;
disconnect();
JSch jsch = new JSch();
session = null;
Channel channel = null;
try {
session = jsch.getSession(username, host.getHostAddress(), port);
} catch (JSchException e) {
@ -94,24 +142,16 @@ public class JschSshConnection implements SshConnection {
host.getHostAddress(), port), e);
}
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
public void disconnect() {
if (sftp != null && sftp.isConnected())
sftp.quit();
if (session != null && session.isConnected())
session.disconnect();
}
public ExecResponse exec(String command) {
checkConnected();
ChannelExec executor = null;
try {
try {

View File

@ -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;
import static org.testng.Assert.assertEquals;
@ -12,7 +35,6 @@ import org.jclouds.ssh.ExecResponse;
import org.jclouds.ssh.SshConnection;
import org.jclouds.ssh.jsch.config.JschSshConnectionModule;
import org.jclouds.util.Utils;
import org.testng.ITestContext;
import org.testng.annotations.BeforeGroups;
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 sshPass = System.getProperty("jclouds.test.ssh.password");
protected SshConnection connection;
@BeforeGroups(groups = { "live" })
public void setupConnection(ITestContext context) throws NumberFormatException,
UnknownHostException {
public SshConnection setupConnection() throws NumberFormatException, UnknownHostException {
int port = (sshPort != null) ? Integer.parseInt(sshPort) : 22;
InetAddress host = (sshHost != null) ? InetAddress.getByName(sshHost) : InetAddress
.getLocalHost();
if (sshUser == null || sshPass == null || sshUser.trim().equals("")
|| sshPass.trim().equals("")) {
System.err.println("ssh credentials not present. Tests will be lame");
connection = new SshConnection() {
return new SshConnection() {
public void connect() {
}
@ -72,19 +91,20 @@ public class JschSshConnectionLiveTest {
} else {
Injector i = Guice.createInjector(new JschSshConnectionModule());
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();
return connection;
}
}
public void testGetEtcPassword() throws IOException {
InputStream input = connection.get("/etc/passwd");
InputStream input = setupConnection().get("/etc/passwd");
String contents = Utils.toStringAndClose(input);
assert contents.indexOf("root") >= 0 : "no root in " + contents;
}
public void testExecHostname() throws IOException {
ExecResponse response = connection.exec("hostname");
ExecResponse response = setupConnection().exec("hostname");
assertEquals(response.getError(), "");
assertEquals(response.getOutput().trim(), InetAddress.getLocalHost().getHostName());
}

View File

@ -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;
import java.net.InetAddress;