From: root@rhesis.austin.ibm.com Date: Tue, 20 Jun 2006 09:25:21 +0000 (+0100) Subject: This patch adds client side support for XML-RPC over ssh. It differs from X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~15921^2~23 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=321c94c756e55158c3f5e841217d1d9a35c2a939;p=xen.git This patch adds client side support for XML-RPC over ssh. It differs from the previous submission in that it now uses lazy evaluation to connect to the remote server and provides more user friendly error messages if ssh is not available. Signed-off-by: Anthony Liguori --- diff --git a/tools/python/xen/util/xmlrpclib2.py b/tools/python/xen/util/xmlrpclib2.py index 442487cce5..2a70d13961 100644 --- a/tools/python/xen/util/xmlrpclib2.py +++ b/tools/python/xen/util/xmlrpclib2.py @@ -24,14 +24,68 @@ import string import types from httplib import HTTPConnection, HTTP -from xmlrpclib import Transport +from xmlrpclib import Transport, getparser, Fault from SimpleXMLRPCServer import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler -import xmlrpclib, socket, os, stat +from subprocess import Popen, PIPE +from getpass import getuser +from fcntl import ioctl +import xmlrpclib, socket, os, stat, termios, errno import SocketServer -import xen.xend.XendClient from xen.xend.XendLogging import log +class SSHTransport(object): + def __init__(self, host, user, askpass=None): + self.host = host + self.user = user + self.askpass = askpass + self.ssh = None + + def getssh(self): + if self.ssh == None: + if self.askpass: + f = open('/dev/tty', 'w') + try: + os.environ['SSH_ASKPASS'] = self.askpass + ioctl(f.fileno(), termios.TIOCNOTTY) + finally: + f.close() + + cmd = ['ssh', '%s@%s' % (self.user, self.host), 'xm serve'] + try: + self.ssh = Popen(cmd, bufsize=0, stdin=PIPE, stdout=PIPE) + except OSError, (err, msg): + if err == errno.ENOENT: + raise Fault(0, "ssh executable not found!") + raise + return self.ssh + + def request(self, host, handler, request_body, verbose=0): + p, u = getparser() + ssh = self.getssh() + ssh.stdin.write("""POST /%s HTTP/1.1 +User-Agent: Xen +Host: %s +Content-Type: text/xml +Content-Length: %d + +%s""" % (handler, host, len(request_body), request_body)) + ssh.stdin.flush() + + content_length = 0 + line = ssh.stdout.readline() + if line.split()[1] != '200': + raise Fault(0, 'Server returned %s' % (' '.join(line[1:]))) + + while line not in ['', '\r\n', '\n']: + if line.lower().startswith('content-length:'): + content_length = int(line[15:].strip()) + line = ssh.stdout.readline() + content = ssh.stdout.read(content_length) + p.feed(content) + p.close() + return u.close() + # A new ServerProxy that also supports httpu urls. An http URL comes in the # form: @@ -100,10 +154,25 @@ class ServerProxy(xmlrpclib.ServerProxy): if protocol == 'httpu': uri = 'http:' + rest transport = UnixTransport() + elif protocol == 'ssh': + if not rest.startswith('//'): + raise ValueError("Invalid ssh URL '%s'" % uri) + rest = rest[2:] + user = getuser() + path = 'RPC2' + if rest.find('@') != -1: + (user, rest) = rest.split('@', 1) + if rest.find('/') != -1: + (host, rest) = rest.split('/', 1) + if len(rest) > 0: + path = rest + else: + host = rest + transport = SSHTransport(host, user) + uri = 'http://%s/%s' % (host, path) xmlrpclib.ServerProxy.__init__(self, uri, transport, encoding, verbose, allow_none) - def __request(self, methodname, params): response = xmlrpclib.ServerProxy.__request(self, methodname, params) @@ -150,6 +219,7 @@ class TCPXMLRPCServer(SocketServer.ThreadingMixIn, SimpleXMLRPCServer): except xmlrpclib.Fault, fault: response = xmlrpclib.dumps(fault) except Exception, exn: + import xen.xend.XendClient log.exception(exn) response = xmlrpclib.dumps( xmlrpclib.Fault(xen.xend.XendClient.ERROR_INTERNAL, str(exn)))