Index: boto/manage/cmdshell.py |
diff --git a/boto/manage/cmdshell.py b/boto/manage/cmdshell.py |
index cbd2e60490b586e94c7e77339f3f8d6ee757a398..2275fa0404472ca9b4b3462cb71d2d2c32493796 100644 |
--- a/boto/manage/cmdshell.py |
+++ b/boto/manage/cmdshell.py |
@@ -72,21 +72,28 @@ class SSHClient(object): |
retry += 1 |
print 'Could not establish SSH connection' |
+ def open_sftp(self): |
+ return self._ssh_client.open_sftp() |
+ |
def get_file(self, src, dst): |
- sftp_client = self._ssh_client.open_sftp() |
+ sftp_client = self.open_sftp() |
sftp_client.get(src, dst) |
def put_file(self, src, dst): |
- sftp_client = self._ssh_client.open_sftp() |
+ sftp_client = self.open_sftp() |
sftp_client.put(src, dst) |
+ def open(self, filename, mode='r', bufsize=-1): |
+ """ |
+ Open a file on the remote system and return a file-like object. |
+ """ |
+ sftp_client = self.open_sftp() |
+ return sftp_client.open(filename, mode, bufsize) |
+ |
def listdir(self, path): |
- sftp_client = self._ssh_client.open_sftp() |
+ sftp_client = self.open_sftp() |
return sftp_client.listdir(path) |
- def open_sftp(self): |
- return self._ssh_client.open_sftp() |
- |
def isdir(self, path): |
status = self.run('[ -d %s ] || echo "FALSE"' % path) |
if status[1].startswith('FALSE'): |
@@ -100,24 +107,43 @@ class SSHClient(object): |
return 1 |
def shell(self): |
+ """ |
+ Start an interactive shell session on the remote host. |
+ """ |
channel = self._ssh_client.invoke_shell() |
interactive_shell(channel) |
def run(self, command): |
- boto.log.info('running:%s on %s' % (command, self.server.instance_id)) |
- log_fp = StringIO.StringIO() |
+ """ |
+ Execute a command on the remote host. Return a tuple containing |
+ an integer status and a two strings, the first containing stdout |
+ and the second containing stderr from the command. |
+ """ |
+ boto.log.debug('running:%s on %s' % (command, self.server.instance_id)) |
status = 0 |
try: |
t = self._ssh_client.exec_command(command) |
except paramiko.SSHException: |
status = 1 |
- log_fp.write(t[1].read()) |
- log_fp.write(t[2].read()) |
+ std_out = t[1].read() |
+ std_err = t[2].read() |
t[0].close() |
t[1].close() |
t[2].close() |
- boto.log.info('output: %s' % log_fp.getvalue()) |
- return (status, log_fp.getvalue()) |
+ boto.log.debug('stdout: %s' % std_out) |
+ boto.log.debug('stderr: %s' % std_err) |
+ return (status, std_out, std_err) |
+ |
+ def run_pty(self, command): |
+ """ |
+ Execute a command on the remote host with a pseudo-terminal. |
+ Returns a string containing the output of the command. |
+ """ |
+ boto.log.debug('running:%s on %s' % (command, self.server.instance_id)) |
+ channel = self._ssh_client.get_transport().open_session() |
+ channel.get_pty() |
+ channel.exec_command(command) |
+ return channel.recv(1024) |
def close(self): |
transport = self._ssh_client.get_transport() |
@@ -166,9 +192,50 @@ class LocalClient(object): |
def close(self): |
pass |
+class FakeServer(object): |
+ """ |
+ A little class to fake out SSHClient (which is expecting a |
+ :class`boto.manage.server.Server` instance. This allows us |
+ to |
+ """ |
+ def __init__(self, instance, ssh_key_file): |
+ self.instance = instance |
+ self.ssh_key_file = ssh_key_file |
+ self.hostname = instance.dns_name |
+ self.instance_id = self.instance.id |
+ |
def start(server): |
instance_id = boto.config.get('Instance', 'instance-id', None) |
if instance_id == server.instance_id: |
return LocalClient(server) |
else: |
return SSHClient(server) |
+ |
+def sshclient_from_instance(instance, ssh_key_file, |
+ host_key_file='~/.ssh/known_hosts', |
+ user_name='root', ssh_pwd=None): |
+ """ |
+ Create and return an SSHClient object given an |
+ instance object. |
+ |
+ :type instance: :class`boto.ec2.instance.Instance` object |
+ :param instance: The instance object. |
+ |
+ :type ssh_key_file: str |
+ :param ssh_key_file: A path to the private key file used |
+ to log into instance. |
+ |
+ :type host_key_file: str |
+ :param host_key_file: A path to the known_hosts file used |
+ by the SSH client. |
+ Defaults to ~/.ssh/known_hosts |
+ :type user_name: str |
+ :param user_name: The username to use when logging into |
+ the instance. Defaults to root. |
+ |
+ :type ssh_pwd: str |
+ :param ssh_pwd: The passphrase, if any, associated with |
+ private key. |
+ """ |
+ s = FakeServer(instance, ssh_key_file) |
+ return SSHClient(s, host_key_file, user_name, ssh_pwd) |