From p.rouse at rms.co.uk Tue Oct 23 06:25:25 2007 From: p.rouse at rms.co.uk (Paul Rouse) Date: Tue, 23 Oct 2007 14:25:25 +0100 Subject: [paramiko] Suggested addition to get channel from SSHClient (with patch) Message-ID: This is a suggestion that SSHClient should provide methods for opening channels of any types (not just one on which a shell has been invoked). My reason is this: arguably the most useful service provided by SSHClient is its high-level handling of the SSH connection, particularly authentication. Once set up, though, there is sometimes a need to have more control over the channels, for example setting timeouts or merging stderr with stdout. It seems a shame to abandon the authentication aspects of SSHClient simply so that arbitrary channels can be opened (and it is probably even worse to get round it by accessing its private _transport attribute!) I have included a patch which simply exposes channel-creation methods on the underlying Transport. The alternative would be to provide direct access to the Transport, but to me that alternative does seem to cut too much across the levels. - Paul Rouse --- client.py 2007-10-23 12:30:07.000000000 +0100 +++ ../../paramiko-copy/client.py 2007-10-19 10:32:45.000000000 +0100 @@ -348,6 +348,39 @@ @rtype: L{SFTPClient} """ return self._transport.open_sftp_client() + + def open_channel (self, kind, dest_addr=None, src_addr=None): + """Request a new channel to the server. L{Channel}s are socket-like + objects used for the actual transfer of data across the session. + + This method simply calls + L{open_channel} + on the underlying L{transport}, and has + the same parameters and results. + """ + return self._transport.open_channel (kind, dest_addr, src_addr) + + def open_x11_channel (self, src_addr=None): + """Request a new channel to the client, of type C{"x11"}. This + is equivalent to C{open_channel('x11', src_addr=src_addr)}. + + This method simply calls + L{open_x11_channel} + on the underlying L{transport}, and has + the same parameters and results. + """ + return self._transport.open_x11_channel (src_addr) + + def open_session (self): + """Request a new channel to the server, of type C{"session"}. This + is equivalent to C{open_channel('session')}. + + This method simply calls + L{open_session} + on the underlying L{transport}, and has + the same parameters and results. + """ + return self._transport.open_session () def _auth(self, username, password, pkey, key_filename): """ _____________________________________________________________________ This message has been checked for all known viruses by the RMS Services Ltd Virus Scanning Service. For further information visit http://www.rms.co.uk or call UK 01454 281265 -------------- next part -------------- An embedded and charset-unspecified text was scrubbed... Name: patch.txt Url: http://www.lag.net/pipermail/paramiko/attachments/20071023/0df561a2/attachment.txt From lists at richardcooper.net Thu Oct 25 13:08:33 2007 From: lists at richardcooper.net (Richard Cooper) Date: Thu, 25 Oct 2007 21:08:33 +0100 Subject: [paramiko] Possible bug in Channel.fileno() Message-ID: Hi all, I've been playing with using paramiko with select.select() and I think I may have found a bug. My code looks like this (simplified): """ ssh_server = paramiko.Transport((host, 22)) ssh_server.connect(username=username, password=password) session = ssh_server.open_session() session.exec_command(command) while 1: (r, w, e) = select.select([session], [], [], 10) if r: got_data = False if session.recv_ready(): data = r[0].recv(4096) if data: got_data = True print '**STDOUT**' print data if session.recv_stderr_ready(): data = r[0].recv_stderr(4096) if data: got_data = True print '**STDERR**' print data if not got_data: break """ I noticed that the select.select() call returns when there is stdout data waiting but it blocks if there is stderr data waiting but nothing on stdout. The obvious fix seems to be to add the following code to Channel.fileno() self.in_stderr_buffer.set_event(self._pipe) to match the existing self.in_buffer.set_event(self._pipe) That fixes the problem for me but I have no idea if it's the right fix or even if I'm using select.select() correctly . Does it look right to you? I was going to check if this had already been fixed in bazaar but the "browse the source using loggerhead" link on http://www.lag.net/ paramiko/ isn't working. Regards, - Richard From lists at richardcooper.net Thu Oct 25 14:28:51 2007 From: lists at richardcooper.net (Richard Cooper) Date: Thu, 25 Oct 2007 22:28:51 +0100 Subject: [paramiko] Wrong email address on mailman page Message-ID: <2B168260-8BA9-4C54-894A-32A8B6A76A63@richardcooper.net> According to http://www.lag.net/mailman/listinfo/paramiko the address of this list is paramiko at www.lag.net. It took me a few failed messages before I guessed that it is actually paramiko at lag.net Regards, - Richard From robey at lag.net Sun Oct 28 15:06:34 2007 From: robey at lag.net (Robey Pointer) Date: Sun, 28 Oct 2007 15:06:34 -0700 Subject: [paramiko] Wrong email address on mailman page In-Reply-To: <2B168260-8BA9-4C54-894A-32A8B6A76A63@richardcooper.net> References: <2B168260-8BA9-4C54-894A-32A8B6A76A63@richardcooper.net> Message-ID: On 25 Oct 2007, at 14:28, Richard Cooper wrote: > According to http://www.lag.net/mailman/listinfo/paramiko the address > of this list is paramiko at www.lag.net. > > It took me a few failed messages before I guessed that it is actually > paramiko at lag.net Thanks! I think I fixed it now. robey From robey at lag.net Sun Oct 28 20:10:41 2007 From: robey at lag.net (Robey Pointer) Date: Sun, 28 Oct 2007 20:10:41 -0700 Subject: [paramiko] Possible bug in Channel.fileno() In-Reply-To: References: Message-ID: On 25 Oct 2007, at 13:08, Richard Cooper wrote: > I noticed that the select.select() call returns when there is stdout > data waiting but it blocks if there is stderr data waiting but > nothing on stdout. The obvious fix seems to be to add the following > code to Channel.fileno() > > self.in_stderr_buffer.set_event(self._pipe) > > to match the existing > > self.in_buffer.set_event(self._pipe) > > That fixes the problem for me but I have no idea if it's the right > fix or even if I'm using select.select() correctly . Does it look > right to you? I verified this is happening. The fix wasn't quite as simple as that (since either stdout or stderr needs to be able to trigger the select), but I think I got it in change 450. > I was going to check if this had already been fixed in bazaar but the > "browse the source using loggerhead" link on http://www.lag.net/ > paramiko/ isn't working. Oops! Should be back now. robey From erick_bodine at comcast.net Tue Oct 30 12:14:40 2007 From: erick_bodine at comcast.net (erick_bodine at comcast.net) Date: Tue, 30 Oct 2007 19:14:40 +0000 Subject: [paramiko] retrieving remote file via paramiko/scp Message-ID: <103020071914.24096.472782A0000123B200005E2022073000330A02070B010DA1050C079D0A@comcast.net> There was a thread earlier in the year (May) about sending a file using "scp" and paramiko which was very helpfull. I found the need to do the reverse action and came up with the following solution. It is more than a little rough and currently only works one file at a time, so no directory recursion. Feel free to comment/use. def read_file(self, remote_file, local_file=None): chan = self._trans.open_session() chan.exec_command("scp -v -f %s" % remote_file) # Send \0 chan.send('\0') filesize='' rfilename='' while True: # Ack chunk = chan.recv(1) if chunk != 'C': print "Ack error [%s]: Does the remote file exist??" % chunk break # read file permissions ie.'0644' permissions = chan.recv(5) # Get the size of the remote file. buf = '' while True: chunk = chan.recv(1) if chunk < 0: print "error "; break if chunk == ' ' or chunk == '\n': break else: buf = buf + chunk filesize = int(buf) # Get the remote filename. buf='' while True: chunk = chan.recv(1) if chunk < 0: print "error "; break if chunk == ' ' or chunk == '\n': break else: buf = buf + chunk rfilename = buf print "filesize: %d, mode: %s, filename: %s" % (filesize, permissions, rfilename) # Send \0, again. chan.send('\0') # Read the file contents total = 0 read_chunk = 1024 if local_file: rfilename = local_file fh = open(rfilename, 'wb') while total <= filesize: chunk = chan.recv(read_chunk) fh.write(chunk) total = total+read_chunk fh.truncate(filesize) fh.close() chan.send('\0') break print "got all the chunks?" chan.send('\0') chan.close() t.close() -- --ERick