ia64/xen-unstable

view tools/python/xen/xend/XendProtocol.py @ 6538:84ee014ebd41

Merge xen-vtx-unstable.hg
author adsharma@los-vmm.sc.intel.com
date Wed Aug 17 12:34:38 2005 -0800 (2005-08-17)
parents 23979fb12c49 f40c6650152e
children 99914b54f7bf
line source
1 #============================================================================
2 # This library is free software; you can redistribute it and/or
3 # modify it under the terms of version 2.1 of the GNU Lesser General Public
4 # License as published by the Free Software Foundation.
5 #
6 # This library is distributed in the hope that it will be useful,
7 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9 # Lesser General Public License for more details.
10 #
11 # You should have received a copy of the GNU Lesser General Public
12 # License along with this library; if not, write to the Free Software
13 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
14 #============================================================================
15 # Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
16 #============================================================================
18 import socket
19 import httplib
20 import types
22 from encode import *
23 import sxp
25 from xen.xend import XendRoot; xroot = XendRoot.instance()
27 DEBUG = 0
29 HTTP_OK = 200
30 HTTP_CREATED = 201
31 HTTP_ACCEPTED = 202
32 HTTP_NO_CONTENT = 204
34 class XendError(RuntimeError):
35 """Error class for 'expected errors' when talking to xend.
36 """
37 pass
39 class XendRequest:
40 """A request to xend.
41 """
43 def __init__(self, url, method, args):
44 """Create a request. Sets up the headers, argument data, and the
45 url.
47 @param url: the url to request
48 @param method: request method, GET or POST
49 @param args: dict containing request args, if any
50 """
51 if url.proto != 'http':
52 raise ValueError('Invalid protocol: ' + url.proto)
53 (hdr, data) = encode_data(args)
54 if args and method == 'GET':
55 url.query = data
56 data = None
57 if method == "POST" and url.path.endswith('/'):
58 url.path = url.path[:-1]
60 self.headers = hdr
61 self.data = data
62 self.url = url
63 self.method = method
65 class XendClientProtocol:
66 """Abstract class for xend clients.
67 """
68 def xendRequest(self, url, method, args=None):
69 """Make a request to xend.
70 Implement in a subclass.
72 @param url: xend request url
73 @param method: http method: POST or GET
74 @param args: request arguments (dict)
75 """
76 raise NotImplementedError()
78 def xendGet(self, url, args=None):
79 """Make a xend request using HTTP GET.
80 Requests using GET are usually 'safe' and may be repeated without
81 nasty side-effects.
83 @param url: xend request url
84 @param data: request arguments (dict)
85 """
86 return self.xendRequest(url, "GET", args)
88 def xendPost(self, url, args):
89 """Make a xend request using HTTP POST.
90 Requests using POST potentially cause side-effects, and should
91 not be repeated unless you really want to repeat the side
92 effect.
94 @param url: xend request url
95 @param args: request arguments (dict)
96 """
97 return self.xendRequest(url, "POST", args)
99 def handleStatus(self, version, status, message):
100 """Handle the status returned from the request.
101 """
102 status = int(status)
103 if status in [ HTTP_NO_CONTENT ]:
104 return None
105 if status not in [ HTTP_OK, HTTP_CREATED, HTTP_ACCEPTED ]:
106 return self.handleException(XendError(message))
107 return 'ok'
109 def handleResponse(self, data):
110 """Handle the data returned in response to the request.
111 """
112 if data is None: return None
113 type = self.getHeader('Content-Type')
114 if type != sxp.mime_type:
115 return data
116 try:
117 pin = sxp.Parser()
118 pin.input(data);
119 pin.input_eof()
120 val = pin.get_val()
121 except sxp.ParseError, err:
122 return self.handleException(err)
123 if isinstance(val, types.ListType) and sxp.name(val) == 'xend.err':
124 err = XendError(val[1])
125 return self.handleException(err)
126 return val
128 def handleException(self, err):
129 """Handle an exception during the request.
130 May be overridden in a subclass.
131 """
132 raise err
134 def getHeader(self, key):
135 """Get a header from the response.
136 Case is ignored in the key.
138 @param key: header key
139 @return: header
140 """
141 raise NotImplementedError()
143 class HttpXendClientProtocol(XendClientProtocol):
144 """A synchronous xend client. This will make a request, wait for
145 the reply and return the result.
146 """
148 resp = None
149 request = None
151 def makeConnection(self, url):
152 return httplib.HTTPConnection(url.location())
154 def makeRequest(self, url, method, args):
155 return XendRequest(url, method, args)
157 def xendRequest(self, url, method, args=None):
158 """Make a request to xend.
160 @param url: xend request url
161 @param method: http method: POST or GET
162 @param args: request arguments (dict)
163 """
164 self.request = self.makeRequest(url, method, args)
165 conn = self.makeConnection(url)
166 if DEBUG: conn.set_debuglevel(1)
167 conn.request(method, url.fullpath(), self.request.data, self.request.headers)
168 resp = conn.getresponse()
169 self.resp = resp
170 val = self.handleStatus(resp.version, resp.status, resp.reason)
171 if val is None:
172 data = None
173 else:
174 data = resp.read()
175 conn.close()
176 val = self.handleResponse(data)
177 return val
179 def getHeader(self, key):
180 return self.resp.getheader(key)
182 class UnixConnection(httplib.HTTPConnection):
183 """Subclass of Python library HTTPConnection that uses a unix-domain socket.
184 """
186 def __init__(self, path):
187 httplib.HTTPConnection.__init__(self, 'localhost')
188 self.path = path
190 def connect(self):
191 sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
192 sock.connect(self.path)
193 self.sock = sock
195 class UnixXendClientProtocol(HttpXendClientProtocol):
196 """A synchronous xend client using a unix-domain socket.
197 """
199 def __init__(self, path=None):
200 if path is None:
201 path = xroot.get_xend_unix_path()
202 self.path = path
204 def makeConnection(self, url):
205 return UnixConnection(self.path)