Search code examples
pythonwindowslinuxtwisted

python execute remote program


I'm re-writing a legacy Windows application using Python and running on Linux. Initially, the new application needs to call the legacy application so that we have consistent results between customers still using the legacy application and customers using the new application.

So I have a Linux box, sitting right next to a Windows box and I want a process on the Linux box to execute a command on the Windows box and capture the result (synchronously).

My initial thought was to write a web service on the Windows box, but that would mean running a web server on the Windows machine in addition to the legacy application.

So then I thought that using Twisted.Conch might allow me to just execute a command over the network without the additional overhead of running a web server, but I assume there is also overhead with running an ssh server on the Windows machine.

What are some alternative ways that I can initiate a synchronous process on a different machine, using Python, besides a web service or ssh, or is a web service or ssh the best approach? Also, if a web service or ssh are the best routes to pursue, is Twisted something that I should consider using?


Solution

  • I ended up going with SSH + Twisted. On the windows machine I setup freeSSHd as a Windows service. After hacking away trying to get paramiko to work and running into tons of problems getting my public/private keys to work, I decided to try Twisted, and it only took a few minutes to get it working. So, I wrote/stole this based on the Twisted documentation to accomplish what I needed as far as the SSH client side from Linux.

    from twisted.conch.ssh import transport
    from twisted.internet import defer
    from twisted.conch.ssh import keys, userauth
    from twisted.conch.ssh import connection
    from twisted.conch.ssh import channel, common
    from twisted.internet import protocol, reactor
    
    class ClientTransport(transport.SSHClientTransport):
        def verifyHostKey(self, pubKey, fingerprint):
            return defer.succeed(1)
        def connectionSecure(self):
            self.requestService(ClientUserAuth('USERHERE', ClientConnection()))
    
    class ClientUserAuth(userauth.SSHUserAuthClient):
        def getPassword(self, prompt=None):
            return 
        def getPublicKey(self):
            return keys.Key.fromString(data=publicKey)
        def getPrivateKey(self):
            return defer.succeed(keys.Key.fromString(data=privateKey))
    
    class ClientConnection(connection.SSHConnection):
        def serviceStarted(self):
            self.openChannel(CatChannel(conn=self))
    
    class CatChannel(channel.SSHChannel):
        name = 'session'
        def channelOpen(self, data):
            data = 'abcdefghijklmnopqrstuvwxyz' * 300
            self.return_data = ''
            self.conn.sendRequest(self, 'exec', common.NS('C:\helloworld %-10000s' % data), wantReply=True)
        def dataReceived(self, data):
            self.return_data += data
        def closed(self):
            print "got %d bytes of data back from Windows" % len(self.return_data)
            print self.return_data
            self.loseConnection()
            reactor.stop()
    
    if __name__ == "__main__":
        factory = protocol.ClientFactory()
        factory.protocol = ClientTransport
        reactor.connectTCP('123.123.123.123', 22, factory)
        reactor.run()
    

    This has been working great!