~justin-fathomdb/nova/justinsb-openstack-api-volumes

« back to all changes in this revision

Viewing changes to vendor/boto/boto/manage/cmdshell.py

  • Committer: Jesse Andrews
  • Date: 2010-05-28 06:05:26 UTC
  • Revision ID: git-v1:bf6e6e718cdc7488e2da87b21e258ccc065fe499
initial commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (c) 2006-2009 Mitch Garnaat http://garnaat.org/
 
2
#
 
3
# Permission is hereby granted, free of charge, to any person obtaining a
 
4
# copy of this software and associated documentation files (the
 
5
# "Software"), to deal in the Software without restriction, including
 
6
# without limitation the rights to use, copy, modify, merge, publish, dis-
 
7
# tribute, sublicense, and/or sell copies of the Software, and to permit
 
8
# persons to whom the Software is furnished to do so, subject to the fol-
 
9
# lowing conditions:
 
10
#
 
11
# The above copyright notice and this permission notice shall be included
 
12
# in all copies or substantial portions of the Software.
 
13
#
 
14
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 
15
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
 
16
# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
 
17
# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
 
18
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 
19
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 
20
# IN THE SOFTWARE.
 
21
 
 
22
from boto.mashups.interactive import interactive_shell
 
23
import boto
 
24
import os
 
25
import time
 
26
import shutil
 
27
import StringIO
 
28
import paramiko
 
29
import socket
 
30
import subprocess
 
31
 
 
32
 
 
33
class SSHClient(object):
 
34
 
 
35
    def __init__(self, server, host_key_file='~/.ssh/known_hosts', uname='root'):
 
36
        self.server = server
 
37
        self.host_key_file = host_key_file
 
38
        self.uname = uname
 
39
        self._pkey = paramiko.RSAKey.from_private_key_file(server.ssh_key_file)
 
40
        self._ssh_client = paramiko.SSHClient()
 
41
        self._ssh_client.load_system_host_keys()
 
42
        self._ssh_client.load_host_keys(os.path.expanduser(host_key_file))
 
43
        self._ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
 
44
        self.connect()
 
45
 
 
46
    def connect(self):
 
47
        retry = 0
 
48
        while retry < 5:
 
49
            try:
 
50
                self._ssh_client.connect(self.server.hostname, username=self.uname, pkey=self._pkey)
 
51
                return
 
52
            except socket.error, (value,message):
 
53
                if value == 61:
 
54
                    print 'SSH Connection refused, will retry in 5 seconds'
 
55
                    time.sleep(5)
 
56
                    retry += 1
 
57
                else:
 
58
                    raise
 
59
            except paramiko.BadHostKeyException:
 
60
                print "%s has an entry in ~/.ssh/known_hosts and it doesn't match" % self.server.hostname
 
61
                print 'Edit that file to remove the entry and then hit return to try again'
 
62
                raw_input('Hit Enter when ready')
 
63
                retry += 1
 
64
            except EOFError:
 
65
                print 'Unexpected Error from SSH Connection, retry in 5 seconds'
 
66
                time.sleep(5)
 
67
                retry += 1
 
68
        print 'Could not establish SSH connection'
 
69
 
 
70
    def get_file(self, src, dst):
 
71
        sftp_client = self._ssh_client.open_sftp()
 
72
        sftp_client.get(src, dst)
 
73
 
 
74
    def put_file(self, src, dst):
 
75
        sftp_client = self._ssh_client.open_sftp()
 
76
        sftp_client.put(src, dst)
 
77
 
 
78
    def listdir(self, path):
 
79
        sftp_client = self._ssh_client.open_sftp()
 
80
        return sftp_client.listdir(path)
 
81
 
 
82
    def open_sftp(self):
 
83
        return self._ssh_client.open_sftp()
 
84
 
 
85
    def isdir(self, path):
 
86
        status = self.run('[ -d %s ] || echo "FALSE"' % path)
 
87
        if status[1].startswith('FALSE'):
 
88
            return 0
 
89
        return 1
 
90
 
 
91
    def exists(self, path):
 
92
        status = self.run('[ -a %s ] || echo "FALSE"' % path)
 
93
        if status[1].startswith('FALSE'):
 
94
            return 0
 
95
        return 1
 
96
 
 
97
    def shell(self):
 
98
        channel = self._ssh_client.invoke_shell()
 
99
        interactive_shell(channel)
 
100
 
 
101
    def run(self, command):
 
102
        boto.log.info('running:%s on %s' % (command, self.server.instance_id))
 
103
        log_fp = StringIO.StringIO()
 
104
        status = 0
 
105
        try:
 
106
            t = self._ssh_client.exec_command(command)
 
107
        except paramiko.SSHException:
 
108
            status = 1
 
109
        log_fp.write(t[1].read())
 
110
        log_fp.write(t[2].read())
 
111
        t[0].close()
 
112
        t[1].close()
 
113
        t[2].close()
 
114
        boto.log.info('output: %s' % log_fp.getvalue())
 
115
        return (status, log_fp.getvalue())
 
116
 
 
117
    def close(self):
 
118
        transport = self._ssh_client.get_transport()
 
119
        transport.close()
 
120
        self.server.reset_cmdshell()
 
121
 
 
122
class LocalClient(object):
 
123
 
 
124
    def __init__(self, server, host_key_file=None, uname='root'):
 
125
        self.server = server
 
126
        self.host_key_file = host_key_file
 
127
        self.uname = uname
 
128
 
 
129
    def get_file(self, src, dst):
 
130
        shutil.copyfile(src, dst)
 
131
 
 
132
    def put_file(self, src, dst):
 
133
        shutil.copyfile(src, dst)
 
134
 
 
135
    def listdir(self, path):
 
136
        return os.listdir(path)
 
137
 
 
138
    def isdir(self, path):
 
139
        return os.path.isdir(path)
 
140
 
 
141
    def exists(self, path):
 
142
        return os.path.exists(path)
 
143
 
 
144
    def shell(self):
 
145
        raise NotImplementedError, 'shell not supported with LocalClient'
 
146
 
 
147
    def run(self):
 
148
        boto.log.info('running:%s' % self.command)
 
149
        log_fp = StringIO.StringIO()
 
150
        process = subprocess.Popen(self.command, shell=True, stdin=subprocess.PIPE,
 
151
                                   stdout=subprocess.PIPE, stderr=subprocess.PIPE)
 
152
        while process.poll() == None:
 
153
            time.sleep(1)
 
154
            t = process.communicate()
 
155
            log_fp.write(t[0])
 
156
            log_fp.write(t[1])
 
157
        boto.log.info(log_fp.getvalue())
 
158
        boto.log.info('output: %s' % log_fp.getvalue())
 
159
        return (process.returncode, log_fp.getvalue())
 
160
 
 
161
    def close(self):
 
162
        pass
 
163
 
 
164
def start(server):
 
165
    instance_id = boto.config.get('Instance', 'instance-id', None)
 
166
    if instance_id == server.instance_id:
 
167
        return LocalClient(server)
 
168
    else:
 
169
        return SSHClient(server)