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
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)))