views:

150

answers:

6

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?

+1  A: 

Try QAM with RabbitMQ.

Marcelo Cantos
Thanks, I will take a look - if I end up using this over any other submitted answers I will accept this one.
Matthew J Morrison
A: 

I frequently use a little program called winexe, which is part of the Samba suite (or, in the version I use, there's a tweaked one in Zenoss).

Here's what the command syntax looks like, and here are some installation options.

ewall
this could potentially work - I'm a little turned off by the lack of documentation that I've been able to find.
Matthew J Morrison
Understandable. There doesn't appear to be a manpage included with the install either, but at least `winexe --help` gives a very full listing of all the command options.
ewall
A: 

I'd use SSH, it's simple to set up, it is easily extendable and well documented. I've personally had very bad experiences with Twisted (it almost got me fired once) so I would not recommend that. When you say "overhead" I assume you mean system resources required to run an SSH server? Really, on half modern equipment SSH is a trivial load on the system unless you are expecting huge traffic levels. You could setup a LAN service, but that wouldn't be much different from a IP service.

Ryan Jenkins
Why did Twisted almost get you fired?
Echo
I would also be interested to hear how Twisted almost got you fired.
Matthew J Morrison
Please refrain from spreading FUD in answers.
Glyph
Maybe that came out wrong, I should have said I almost got myself fired because I hoped into using Twisted on a project for a client when I had never tried it before, after pulling my hair out over not quite being able to do what I wanted, I abandoned it and wrote redid the whole project using a series of remote scripts and SSH. I perceive Twisted to be hard to use, YMMV.
Ryan Jenkins
+2  A: 

Another option is paramiko. It's a Python library that implements SSH. I've used it to remotely execute commands and transfer files to windows boxes running an SSH server. The problem is it doesn't properly capture stdout on windows due to the peculiarities of the windows command shell. You may have the same problem with a solution based on twisted.

What kind of results are you trying to capture?

Simon Hibbs
I'm not entirely sure yet what the results will look like, at this point, I'm assuming that i'm going to need to get them from stdout.
Matthew J Morrison
I'm accepting this answer, not because it is necessarily "correct" I don't think there really is a right or wrong answer to this question, but I'm going to go the SSH route and most likely use Paramiko.
Matthew J Morrison
+1  A: 

RPC is the right answer IMO.

I think:

  • using SimpleXMLRPCServer for the windows machine
  • using xmlrpclib for the linux machine

from the standard library would give you the most freedom. You implement what you need and you don't have to worry about windows APIs, overblown technologies as DCOM, etc., you are in python land, even on the windows machine.

Sidenote: Twisted is of course always an excellent option, so don't worry about that; I think Apples CalDav server runs on Twisted too.

zovision
+1  A: 

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!

Matthew J Morrison