156
153
raise NotImplementedError(self.connect_sftp)
158
155
def connect_ssh(self, username, password, host, port, command):
159
"""Make an SSH connection.
156
"""Make an SSH connection, and return a pipe-like object.
161
:returns: something with a `close` method, and a `get_filelike_channels`
162
method that returns a pair of (read, write) filelike objects.
158
(This is currently unused, it's just here to indicate future directions
164
161
raise NotImplementedError(self.connect_ssh)
166
def _raise_connection_error(self, host, port=None, orig_error=None,
167
msg='Unable to connect to SSH host'):
168
"""Raise a SocketConnectionError with properly formatted host.
170
This just unifies all the locations that try to raise ConnectionError,
171
so that they format things properly.
173
raise SocketConnectionError(host=host, port=port, msg=msg,
174
orig_error=orig_error)
177
164
class LoopbackVendor(SSHVendor):
178
165
"""SSH "vendor" that connects over a plain TCP socket, not SSH."""
183
170
sock.connect((host, port))
184
171
except socket.error, e:
185
self._raise_connection_error(host, port=port, orig_error=e)
172
raise ConnectionError('Unable to connect to SSH host %s:%s: %s'
186
174
return SFTPClient(LoopbackSFTP(sock))
188
176
register_ssh_vendor('loopback', LoopbackVendor())
191
class _ParamikoSSHConnection(object):
192
def __init__(self, channel):
193
self.channel = channel
195
def get_filelike_channels(self):
196
return self.channel.makefile('rb'), self.channel.makefile('wb')
199
return self.channel.close()
202
179
class ParamikoVendor(SSHVendor):
203
180
"""Vendor that uses paramiko."""
205
def _connect(self, username, password, host, port):
182
def connect_sftp(self, username, password, host, port):
206
183
global SYSTEM_HOSTKEYS, BZR_HOSTKEYS
241
217
['Try editing %s or %s' % (filename1, filename2)])
243
219
_paramiko_auth(username, password, host, t)
246
def connect_sftp(self, username, password, host, port):
247
t = self._connect(username, password, host, port)
249
return t.open_sftp_client()
250
except paramiko.SSHException, e:
251
self._raise_connection_error(host, port=port, orig_error=e,
252
msg='Unable to start sftp client')
254
def connect_ssh(self, username, password, host, port, command):
255
t = self._connect(username, password, host, port)
257
channel = t.open_session()
258
cmdline = ' '.join(command)
259
channel.exec_command(cmdline)
260
return _ParamikoSSHConnection(channel)
261
except paramiko.SSHException, e:
262
self._raise_connection_error(host, port=port, orig_error=e,
263
msg='Unable to invoke remote bzr')
265
if paramiko is not None:
266
register_ssh_vendor('paramiko', ParamikoVendor())
222
sftp = t.open_sftp_client()
223
except paramiko.SSHException, e:
224
raise ConnectionError('Unable to start sftp client %s:%d' %
228
register_ssh_vendor('paramiko', ParamikoVendor())
269
231
class SubprocessVendor(SSHVendor):
270
232
"""Abstract base class for vendors that use pipes to a subprocess."""
272
def _connect(self, argv):
273
proc = subprocess.Popen(argv,
274
stdin=subprocess.PIPE,
275
stdout=subprocess.PIPE,
276
**os_specific_subprocess_params())
277
return SSHSubprocess(proc)
279
234
def connect_sftp(self, username, password, host, port):
281
236
argv = self._get_vendor_specific_argv(username, host, port,
282
237
subsystem='sftp')
283
sock = self._connect(argv)
238
proc = subprocess.Popen(argv,
239
stdin=subprocess.PIPE,
240
stdout=subprocess.PIPE,
241
**os_specific_subprocess_params())
242
sock = SSHSubprocess(proc)
284
243
return SFTPClient(sock)
285
244
except (EOFError, paramiko.SSHException), e:
286
self._raise_connection_error(host, port=port, orig_error=e)
287
except (OSError, IOError), e:
288
# If the machine is fast enough, ssh can actually exit
289
# before we try and send it the sftp request, which
290
# raises a Broken Pipe
291
if e.errno not in (errno.EPIPE,):
293
self._raise_connection_error(host, port=port, orig_error=e)
295
def connect_ssh(self, username, password, host, port, command):
297
argv = self._get_vendor_specific_argv(username, host, port,
299
return self._connect(argv)
300
except (EOFError), e:
301
self._raise_connection_error(host, port=port, orig_error=e)
302
except (OSError, IOError), e:
303
# If the machine is fast enough, ssh can actually exit
304
# before we try and send it the sftp request, which
305
# raises a Broken Pipe
306
if e.errno not in (errno.EPIPE,):
308
self._raise_connection_error(host, port=port, orig_error=e)
245
raise ConnectionError('Unable to connect to SSH host %s:%s: %s'
247
except (OSError, IOError), e:
248
# If the machine is fast enough, ssh can actually exit
249
# before we try and send it the sftp request, which
250
# raises a Broken Pipe
251
if e.errno not in (errno.EPIPE,):
253
raise ConnectionError('Unable to connect to SSH host %s:%s: %s'
310
256
def _get_vendor_specific_argv(self, username, host, port, subsystem=None,