[Twisted-Python] Running commands (ssh) from a GUI client
Paul_S_Johnson at mnb.uscourts.gov
Paul_S_Johnson at mnb.uscourts.gov
Tue Oct 9 11:39:38 MDT 2007
Raul,
This is simply some work-in-progress code, but is basically what you are
looking for even written for PythonCard. This takes a list of three
commands and runs them in the order given using deferreds to wait for the
previous to complete before executing the next.
This took me about forever to get it this far. If you make and significant
improvements, please share.
One remaining mystery is how to switch users once logged in. For example,
I need to run some things as root.
Paul
============================================
from twisted.conch import error
from twisted.conch.ssh import transport, connection, keys, userauth,
channel, common
from twisted.internet import defer, protocol, reactor
import sys, getpass, os, string
from PythonCard import model, twistedModel
class ClientCommandTransport(transport.SSHClientTransport):
def __init__(self, username, password, cmds, caller):
self.username = username
self.password = password
self.cmds = cmds
self.caller = caller
def verifyHostKey(self, pubKey, fingerprint):
# in a real app, you should verify that the fingerprint matches
# the one you expected to get from this server
return defer.succeed(True)
def connectionSecure(self):
self.requestService(PasswordAuth(self.username, self.password,
ClientConnection(self.cmds, self.caller)))
class PasswordAuth(userauth.SSHUserAuthClient):
def __init__(self, user, password, connection):
userauth.SSHUserAuthClient.__init__(self, user, connection)
self.password = password
def getPassword(self, prompt=None):
return defer.succeed(self.password)
class ClientConnection(connection.SSHConnection):
def __init__(self, cmds, caller, *args, **kwargs):
connection.SSHConnection.__init__(self)
self.cmds = cmds
self.caller = caller
#======================
def serviceStarted(self):
self.d = defer.Deferred()
self.d.addCallback(self._cbFirst)
self.d.addErrback(self._ebFirst)
self.openChannel(CommandChannel(self.cmds[0], lastcmd=0,
conn=self))
def _cbFirst(self, result):
print 'CALLBACK Result 1:', result
self.caller.responses.append(result.rstrip())
self.d = defer.Deferred()
self.d.addCallback(self._cbSecond)
self.d.addErrback(self._ebSecond)
self.openChannel(CommandChannel(self.cmds[1], lastcmd=0,
conn=self))
def _ebFirst(self, f):
self.caller.responses.append(None)
print "Error 1"
self.d = defer.Deferred()
self.d.addCallback(self._cbSecond)
self.d.addErrback(self._ebSecond)
self.openChannel(CommandChannel(self.cmds[1], lastcmd=0,
conn=self))
#log.err()
def _cbSecond(self, result):
print 'CALLBACK Result 2:', result
self.caller.responses.append(result.rstrip())
self.d = defer.Deferred()
self.d.addCallback(self._cbThird)
self.d.addErrback(self._ebThird)
self.openChannel(CommandChannel(self.cmds[2], lastcmd=1,
conn=self))
def _ebSecond(self, f):
self.caller.responses.append(None)
self.d = defer.Deferred()
self.d.addCallback(self._cbThird)
self.d.addErrback(self._ebThird)
self.openChannel(CommandChannel(self.cmds[2], lastcmd=1,
conn=self))
#log.err()
def _cbThird(self, result):
self.caller.responses.append(result.rstrip())
print 'CALLBACK Result 3:', result
#reactor.stop()
def _ebThird(self, f):
self.caller.responses.append(None)
log.err()
#reactor.stop()
#======================
class CommandChannel(channel.SSHChannel):
name = 'session'
def __init__(self, command, lastcmd, *args, **kwargs):
channel.SSHChannel.__init__(self, *args, **kwargs)
self.command = command
self.lastcmd = lastcmd
self.data = ""
def channelOpen(self, data):
self.conn.sendRequest(self, 'exec', common.NS(self.command),
wantReply=True).addCallback(self._gotResponse)
def _gotResponse(self, _):
#print "RESPONSE"
self.conn.sendEOF(self)
def dataReceived(self, data):
#print "Data Received:", data
self.data += data
def closed(self):
self.conn.d.callback(self.data)
self.loseConnection()
## if self.lastcmd:
## print "closing reactor."
## reactor.stop()
class ClientCommandFactory(protocol.ClientFactory):
def __init__(self, username, password, cmds, caller):
self.username = username
self.password = password
self.cmds = cmds
self.caller = caller
def buildProtocol(self, addr):
protocol = ClientCommandTransport(self.username, self.password,
self.cmds, self.caller)
return protocol
class SSH():
""" Contains a SSH connection, runs commands, and stores results. """
def __init__(self, host, username, password, cmds):
self.host = host
self.username = username
self.password = password
self.cmds = cmds
self.responses = []
self.run_commands()
def run_commands(self):
factory = ClientCommandFactory(self.username, self.password,
self.cmds, self)
reactor.connectTCP(self.host, 22, factory)
#reactor.registerWxApp(app)
#reactor.run()
#from PythonCard import model
class Dashboard(model.Background):
def on_initialize(self, event):
self.responses = []
def on_btSend_mouseClick(self, event):
print "Hello World!"
self.run_commands("myhost", "myusername", "mypassword", ["id",
"pwd", "ls -l"])
#for i, response in enumerate(self.ssh.responses):
# print i, response
# print "=" * 25
def on_btCheck_mouseClick(self, event):
""" Check it out! """
for i, response in enumerate(self.responses):
print i, response
print "=" * 25
print "Done."
""" Contains a SSH connection, runs commands, and stores results. """
#def __init__(self, host, username, password, cmds):
def run_commands(self, host, username, password, cmds):
self.host = host
self.username = username
self.password = password
self.cmds = cmds
self.responses = []
self.factory = ClientCommandFactory(self.username, self.password,
self.cmds, self)
reactor.connectTCP(self.host, 22, self.factory)
#reactor.run()
for i, response in enumerate(self.responses):
print i, response
print "=" * 25
#print "\nDone."
if __name__ == '__main__':
app = twistedModel.TwistedApplication(Dashboard)
app.MainLoop()
Here's the PythonCard resource file:
{'application':{'type':'Application',
'name':'Minimal',
'backgrounds': [
{'type':'Background',
'name':'bgMin',
'title':'Minimal PythonCard Application',
'size':(382, 271),
'menubar': {'type':'MenuBar',
'menus': [
{'type':'Menu',
'name':'menuFile',
'label':'&File',
'items': [
{'type':'MenuItem',
'name':'menuFileExit',
'label':'E&xit\tAlt+X',
'command':'exit',
},
]
},
]
},
'components': [
{'type':'Button',
'name':'btCheck',
'position':(210, 186),
'label':u'Check',
},
{'type':'Button',
'name':'btSend',
'position':(102, 185),
'label':u'Send',
},
{'type':'CodeEditor',
'name':'ceReponse',
'position':(6, 33),
'size':(360, 141),
'backgroundColor':(255, 255, 255, 255),
},
{'type':'TextField',
'name':'field1',
'position':(5, 5),
'size':(150, -1),
'text':u'Hello PythonCard',
},
] # end components
} # end background
] # end backgrounds
} }
twisted-python-bounces at twistedmatrix.com wrote on 10/07/2007 01:04:56 PM:
> Hi list, this is my first post :p
>
> I'm new to Twisted/Conch and I was wondering how can I modify the
> sshsimpleclient.py in order to run several commands, on a user
> request mode, without the need to authenticate just before every
> command, just like a normal interactive ssh session. This is for a
> GUI front end I'm writing (PythonCard) that will execute some
> benchmarks on a remote server.
>
> Thanks in advance...
>
> Raul_______________________________________________
> Twisted-Python mailing list
> Twisted-Python at twistedmatrix.com
> http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
-------------- next part --------------
An HTML attachment was scrubbed...
URL: </pipermail/twisted-python/attachments/20071009/8fea0ee3/attachment.html>
More information about the Twisted-Python
mailing list