ia64/xen-unstable
changeset 10488:c2cbcccc44f4
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
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
author | root@rhesis.austin.ibm.com |
---|---|
date | Tue Jun 20 10:25:21 2006 +0100 (2006-06-20) |
parents | 95ac3f0f79bc |
children | 1297dc315308 |
files | tools/python/xen/util/xmlrpclib2.py |
line diff
1.1 --- a/tools/python/xen/util/xmlrpclib2.py Tue Jun 20 10:25:20 2006 +0100 1.2 +++ b/tools/python/xen/util/xmlrpclib2.py Tue Jun 20 10:25:21 2006 +0100 1.3 @@ -24,14 +24,68 @@ import string 1.4 import types 1.5 1.6 from httplib import HTTPConnection, HTTP 1.7 -from xmlrpclib import Transport 1.8 +from xmlrpclib import Transport, getparser, Fault 1.9 from SimpleXMLRPCServer import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler 1.10 -import xmlrpclib, socket, os, stat 1.11 +from subprocess import Popen, PIPE 1.12 +from getpass import getuser 1.13 +from fcntl import ioctl 1.14 +import xmlrpclib, socket, os, stat, termios, errno 1.15 import SocketServer 1.16 1.17 -import xen.xend.XendClient 1.18 from xen.xend.XendLogging import log 1.19 1.20 +class SSHTransport(object): 1.21 + def __init__(self, host, user, askpass=None): 1.22 + self.host = host 1.23 + self.user = user 1.24 + self.askpass = askpass 1.25 + self.ssh = None 1.26 + 1.27 + def getssh(self): 1.28 + if self.ssh == None: 1.29 + if self.askpass: 1.30 + f = open('/dev/tty', 'w') 1.31 + try: 1.32 + os.environ['SSH_ASKPASS'] = self.askpass 1.33 + ioctl(f.fileno(), termios.TIOCNOTTY) 1.34 + finally: 1.35 + f.close() 1.36 + 1.37 + cmd = ['ssh', '%s@%s' % (self.user, self.host), 'xm serve'] 1.38 + try: 1.39 + self.ssh = Popen(cmd, bufsize=0, stdin=PIPE, stdout=PIPE) 1.40 + except OSError, (err, msg): 1.41 + if err == errno.ENOENT: 1.42 + raise Fault(0, "ssh executable not found!") 1.43 + raise 1.44 + return self.ssh 1.45 + 1.46 + def request(self, host, handler, request_body, verbose=0): 1.47 + p, u = getparser() 1.48 + ssh = self.getssh() 1.49 + ssh.stdin.write("""POST /%s HTTP/1.1 1.50 +User-Agent: Xen 1.51 +Host: %s 1.52 +Content-Type: text/xml 1.53 +Content-Length: %d 1.54 + 1.55 +%s""" % (handler, host, len(request_body), request_body)) 1.56 + ssh.stdin.flush() 1.57 + 1.58 + content_length = 0 1.59 + line = ssh.stdout.readline() 1.60 + if line.split()[1] != '200': 1.61 + raise Fault(0, 'Server returned %s' % (' '.join(line[1:]))) 1.62 + 1.63 + while line not in ['', '\r\n', '\n']: 1.64 + if line.lower().startswith('content-length:'): 1.65 + content_length = int(line[15:].strip()) 1.66 + line = ssh.stdout.readline() 1.67 + content = ssh.stdout.read(content_length) 1.68 + p.feed(content) 1.69 + p.close() 1.70 + return u.close() 1.71 + 1.72 1.73 # A new ServerProxy that also supports httpu urls. An http URL comes in the 1.74 # form: 1.75 @@ -100,10 +154,25 @@ class ServerProxy(xmlrpclib.ServerProxy) 1.76 if protocol == 'httpu': 1.77 uri = 'http:' + rest 1.78 transport = UnixTransport() 1.79 + elif protocol == 'ssh': 1.80 + if not rest.startswith('//'): 1.81 + raise ValueError("Invalid ssh URL '%s'" % uri) 1.82 + rest = rest[2:] 1.83 + user = getuser() 1.84 + path = 'RPC2' 1.85 + if rest.find('@') != -1: 1.86 + (user, rest) = rest.split('@', 1) 1.87 + if rest.find('/') != -1: 1.88 + (host, rest) = rest.split('/', 1) 1.89 + if len(rest) > 0: 1.90 + path = rest 1.91 + else: 1.92 + host = rest 1.93 + transport = SSHTransport(host, user) 1.94 + uri = 'http://%s/%s' % (host, path) 1.95 xmlrpclib.ServerProxy.__init__(self, uri, transport, encoding, 1.96 verbose, allow_none) 1.97 1.98 - 1.99 def __request(self, methodname, params): 1.100 response = xmlrpclib.ServerProxy.__request(self, methodname, params) 1.101 1.102 @@ -150,6 +219,7 @@ class TCPXMLRPCServer(SocketServer.Threa 1.103 except xmlrpclib.Fault, fault: 1.104 response = xmlrpclib.dumps(fault) 1.105 except Exception, exn: 1.106 + import xen.xend.XendClient 1.107 log.exception(exn) 1.108 response = xmlrpclib.dumps( 1.109 xmlrpclib.Fault(xen.xend.XendClient.ERROR_INTERNAL, str(exn)))