ia64/xen-unstable
changeset 1850:e50c97665b67
bitkeeper revision 1.1108.1.4 (40fe51ffLxtDXSQ_TOJZQcpn_HcB3g)
Rework xend client to support synchronous and asynchronous
connections.
Rework xend client to support synchronous and asynchronous
connections.
author | mjw@wray-m-3.hpl.hp.com |
---|---|
date | Wed Jul 21 11:22:39 2004 +0000 (2004-07-21) |
parents | f26582ec895e |
children | fd5d2b14cf2a |
files | tools/python/xen/xend/XendClient.py |
line diff
1.1 --- a/tools/python/xen/xend/XendClient.py Tue Jul 20 14:55:40 2004 +0000 1.2 +++ b/tools/python/xen/xend/XendClient.py Wed Jul 21 11:22:39 2004 +0000 1.3 @@ -1,6 +1,8 @@ 1.4 +#!/usr/bin/env python 1.5 # Copyright (C) 2004 Mike Wray <mike.wray@hp.com> 1.6 """Client API for the HTTP interface on xend. 1.7 Callable as a script - see main(). 1.8 +Supports synchronous or asynchronous connection to xend. 1.9 1.10 This API is the 'control-plane' for xend. 1.11 The 'data-plane' is done separately. For example, consoles 1.12 @@ -11,9 +13,12 @@ import sys 1.13 import httplib 1.14 import types 1.15 from StringIO import StringIO 1.16 -import urlparse 1.17 + 1.18 1.19 from twisted.protocols import http 1.20 +from twisted.internet.protocol import ClientCreator 1.21 +from twisted.internet.defer import Deferred 1.22 +from twisted.internet import reactor 1.23 1.24 from encode import * 1.25 import sxp 1.26 @@ -22,40 +27,22 @@ import PrettyPrint 1.27 DEBUG = 0 1.28 1.29 class XendError(RuntimeError): 1.30 + """Error class for 'expected errors' when talking to xend. 1.31 + """ 1.32 pass 1.33 1.34 -class Foo(httplib.HTTPResponse): 1.35 - 1.36 - def begin(self): 1.37 - fin = self.fp 1.38 - while(1): 1.39 - buf = fin.readline() 1.40 - print "***", buf 1.41 - if buf == '': 1.42 - print 1.43 - sys.exit() 1.44 - 1.45 - 1.46 -def sxprio(sxpr): 1.47 - """Convert an sxpr to a string. 1.48 - """ 1.49 - io = StringIO() 1.50 - sxp.show(sxpr, out=io) 1.51 - print >> io 1.52 - io.seek(0) 1.53 - return io 1.54 - 1.55 def fileof(val): 1.56 - """Converter for passing configs. 1.57 + """Converter for passing configs or other 'large' data. 1.58 Handles lists, files directly. 1.59 Assumes a string is a file name and passes its contents. 1.60 """ 1.61 if isinstance(val, types.ListType): 1.62 - return sxprio(val) 1.63 + return sxp.to_string(val) 1.64 if isinstance(val, types.StringType): 1.65 return file(val) 1.66 if hasattr(val, 'readlines'): 1.67 return val 1.68 + raise XendError('cannot convert value') 1.69 1.70 # todo: need to sort of what urls/paths are using for objects. 1.71 # e.g. for domains at the moment return '0'. 1.72 @@ -66,98 +53,251 @@ def fileof(val): 1.73 # maps /xend/domain/0 to http://wray-m-3.hpl.hp.com:8000/xend/domain/0 1.74 # And should accept urls for ids? 1.75 1.76 -def urljoin(location, root, prefix='', rest=''): 1.77 - prefix = str(prefix) 1.78 - rest = str(rest) 1.79 - base = 'http://' + location + root + prefix 1.80 - url = urlparse.urljoin(base, rest) 1.81 - return url 1.82 +class URL: 1.83 + """A URL. 1.84 + """ 1.85 + 1.86 + def __init__(self, proto='http', host='localhost', port=None, path='', query=None, frag=None): 1.87 + self.proto = proto 1.88 + self.host = host 1.89 + if port: port = int(port) 1.90 + self.port = port 1.91 + self.path = path 1.92 + self.query = query 1.93 + self.frag = frag 1.94 + 1.95 + def url(self): 1.96 + """Get the full URL string including protocol, location and the full path. 1.97 + """ 1.98 + return self.proto + '://' + self.location() + self.fullpath() 1.99 1.100 -def nodeurl(location, root, id=''): 1.101 - return urljoin(location, root, 'node/', id) 1.102 + def location(self): 1.103 + """Get the location part of the URL, including host and port, if present. 1.104 + """ 1.105 + if self.port: 1.106 + return self.host + ':' + str(self.port) 1.107 + else: 1.108 + return self.host 1.109 1.110 -def domainurl(location, root, id=''): 1.111 - return urljoin(location, root, 'domain/', id) 1.112 - 1.113 -def consoleurl(location, root, id=''): 1.114 - return urljoin(location, root, 'console/', id) 1.115 + def fullpath(self): 1.116 + """Get the full path part of the URL, including query and fragment if present. 1.117 + """ 1.118 + u = [ self.path ] 1.119 + if self.query: 1.120 + u.append('?') 1.121 + u.append(self.query) 1.122 + if self.frag: 1.123 + u.append('#') 1.124 + u.append(self.frag) 1.125 + return ''.join(u) 1.126 1.127 -def deviceurl(location, root, id=''): 1.128 - return urljoin(location, root, 'device/', id) 1.129 + def relative(self, path='', query=None, frag=None): 1.130 + """Create a URL relative to this one. 1.131 + """ 1.132 + return URL(proto=self.proto, 1.133 + host=self.host, 1.134 + port=self.port, 1.135 + path=self.path + path, 1.136 + query=query, 1.137 + frag=frag) 1.138 1.139 -def vneturl(location, root, id=''): 1.140 - return urljoin(location, root, 'vnet/', id) 1.141 +class XendRequest: 1.142 + """A request to xend. 1.143 + """ 1.144 1.145 -def eventurl(location, root, id=''): 1.146 - return urljoin(location, root, 'event/', id) 1.147 + def __init__(self, url, method, args): 1.148 + """Create a request. Sets up the headers, argument data, and the 1.149 + url. 1.150 1.151 -def dmesgurl(location, root, id=''): 1.152 - return urljoin(location, root, 'node/dmesg/', id) 1.153 - 1.154 -def xend_request(url, method, data=None): 1.155 - """Make a request to xend. 1.156 - 1.157 - url xend request url 1.158 - method http method: POST or GET 1.159 - data request argument data (dict) 1.160 + @param url: the url to request 1.161 + @param method: request method, GET or POST 1.162 + @param args: dict containing request args, if any 1.163 + """ 1.164 + if url.proto != 'http': 1.165 + raise ValueError('Invalid protocol: ' + url.proto) 1.166 + (hdr, data) = encode_data(args) 1.167 + if args and method == 'GET': 1.168 + url.query = data 1.169 + data = None 1.170 + if method == "POST" and url.path.endswith('/'): 1.171 + url.path = url.path[:-1] 1.172 + 1.173 + self.headers = hdr 1.174 + self.data = data 1.175 + self.url = url 1.176 + self.method = method 1.177 + 1.178 +class XendClientProtocol: 1.179 + """Abstract class for xend clients. 1.180 """ 1.181 - urlinfo = urlparse.urlparse(url) 1.182 - (uproto, ulocation, upath, uparam, uquery, ufrag) = urlinfo 1.183 - if DEBUG: print url, urlinfo 1.184 - if uproto != 'http': 1.185 - raise StandardError('Invalid protocol: ' + uproto) 1.186 - if DEBUG: print '>xend_request', ulocation, upath, method, data 1.187 - (hdr, args) = encode_data(data) 1.188 - if data and method == 'GET': 1.189 - upath += '?' + args 1.190 - args = None 1.191 - if method == "POST" and upath.endswith('/'): 1.192 - upath = upath[:-1] 1.193 - if DEBUG: print "ulocation=", ulocation, "upath=", upath, "args=", args 1.194 - #hdr['User-Agent'] = 'Mozilla' 1.195 - #hdr['Accept'] = 'text/html,text/plain' 1.196 - conn = httplib.HTTPConnection(ulocation) 1.197 - #conn.response_class = Foo 1.198 - if DEBUG: conn.set_debuglevel(1) 1.199 - conn.request(method, upath, args, hdr) 1.200 - resp = conn.getresponse() 1.201 - if DEBUG: print resp.status, resp.reason 1.202 - if DEBUG: print resp.msg.headers 1.203 - if resp.status in [ http.NO_CONTENT ]: 1.204 - return None 1.205 - if resp.status not in [ http.OK, http.CREATED, http.ACCEPTED ]: 1.206 - raise XendError(resp.reason) 1.207 - pin = sxp.Parser() 1.208 - data = resp.read() 1.209 - if DEBUG: print "***data" , data 1.210 - if DEBUG: print "***" 1.211 - pin.input(data); 1.212 - pin.input_eof() 1.213 - conn.close() 1.214 - val = pin.get_val() 1.215 - #if isinstance(val, types.ListType) and sxp.name(val) == 'val': 1.216 - # val = val[1] 1.217 - if isinstance(val, types.ListType) and sxp.name(val) == 'xend.err': 1.218 - raise XendError(val[1]) 1.219 - if DEBUG: print '**val='; sxp.show(val); print 1.220 - return val 1.221 + 1.222 + def xendRequest(self, url, method, args=None): 1.223 + """Make a request to xend. 1.224 + Implement in a subclass. 1.225 + 1.226 + @param url: xend request url 1.227 + @param method: http method: POST or GET 1.228 + @param args: request arguments (dict) 1.229 + """ 1.230 + raise NotImplementedError() 1.231 + 1.232 + def xendGet(self, url, args=None): 1.233 + """Make a xend request using HTTP GET. 1.234 + Requests using GET are usually 'safe' and may be repeated without 1.235 + nasty side-effects. 1.236 + 1.237 + @param url: xend request url 1.238 + @param data: request arguments (dict) 1.239 + """ 1.240 + return self.xendRequest(url, "GET", args) 1.241 + 1.242 + def xendPost(self, url, args): 1.243 + """Make a xend request using HTTP POST. 1.244 + Requests using POST potentially cause side-effects, and should 1.245 + not be repeated unless you really want to repeat the side 1.246 + effect. 1.247 + 1.248 + @param url: xend request url 1.249 + @param args: request arguments (dict) 1.250 + """ 1.251 + return self.xendRequest(url, "POST", args) 1.252 + 1.253 + def handleStatus(self, version, status, message): 1.254 + """Handle the status returned from the request. 1.255 + """ 1.256 + status = int(status) 1.257 + if status in [ http.NO_CONTENT ]: 1.258 + return None 1.259 + if status not in [ http.OK, http.CREATED, http.ACCEPTED ]: 1.260 + return self.handleException(XendError(message)) 1.261 + return 'ok' 1.262 + 1.263 + def handleResponse(self, data): 1.264 + """Handle the data returned in response to the request. 1.265 + """ 1.266 + if data is None: return None 1.267 + try: 1.268 + pin = sxp.Parser() 1.269 + pin.input(data); 1.270 + pin.input_eof() 1.271 + val = pin.get_val() 1.272 + except sxp.ParseError, err: 1.273 + return self.handleException(err) 1.274 + if isinstance(val, types.ListType) and sxp.name(val) == 'xend.err': 1.275 + err = XendError(val[1]) 1.276 + return self.handleException(err) 1.277 + return val 1.278 + 1.279 + def handleException(self, err): 1.280 + """Handle an exception during the request. 1.281 + May be overridden in a subclass. 1.282 + """ 1.283 + raise err 1.284 + 1.285 +class SynchXendClientProtocol(XendClientProtocol): 1.286 + """A synchronous xend client. This will make a request, wait for 1.287 + the reply and return the result. 1.288 + """ 1.289 + 1.290 + def xendRequest(self, url, method, args=None): 1.291 + """Make a request to xend. 1.292 1.293 -def xend_get(url, args=None): 1.294 - """Make a xend request using GET. 1.295 - Requests using GET are 'safe' and may be repeated without 1.296 - nasty side-effects. 1.297 + @param url: xend request url 1.298 + @param method: http method: POST or GET 1.299 + @param args: request arguments (dict) 1.300 + """ 1.301 + self.request = XendRequest(url, method, args) 1.302 + conn = httplib.HTTPConnection(url.location()) 1.303 + if DEBUG: conn.set_debuglevel(1) 1.304 + conn.request(method, url.fullpath(), self.request.data, self.request.headers) 1.305 + resp = conn.getresponse() 1.306 + val = self.handleStatus(resp.version, resp.status, resp.reason) 1.307 + if val is None: 1.308 + data = None 1.309 + else: 1.310 + data = resp.read() 1.311 + conn.close() 1.312 + val = self.handleResponse(data) 1.313 + return val 1.314 + 1.315 +class AsynchXendClient(http.HTTPClient): 1.316 + """A subclass of twisted's HTTPClient to deal with a connection to xend. 1.317 + Makes the request when connected, and delegates handling responses etc. 1.318 + to its protocol (usually an AsynchXendClientProtocol instance). 1.319 """ 1.320 - return xend_request(url, "GET", args) 1.321 + def __init__(self, protocol, request): 1.322 + self.protocol = protocol 1.323 + self.request = request 1.324 + 1.325 + def connectionMade(self): 1.326 + request = self.request 1.327 + url = self.request.url 1.328 + self.sendCommand(request.method, url.fullpath()) 1.329 + self.sendHeader('Host', url.location()) 1.330 + for (k, v) in request.headers.items(): 1.331 + self.sendHeader(k, v) 1.332 + self.endHeaders() 1.333 + if request.data: 1.334 + self.transport.write(request.data) 1.335 1.336 -def xend_call(url, data): 1.337 - """Make xend request using POST. 1.338 - Requests using POST potentially cause side-effects and should 1.339 - not be repeated unless it really is wanted to do the side 1.340 - effect again. 1.341 + def handleStatus(self, version, status, message): 1.342 + return self.protocol.handleStatus(version, status, message) 1.343 + 1.344 + def handleResponse(self, data): 1.345 + return self.protocol.handleResponse(data) 1.346 + 1.347 +class AsynchXendClientProtocol(XendClientProtocol): 1.348 + """An asynchronous xend client. Uses twisted to connect to xend 1.349 + and make the request. It does not block waiting for the result, 1.350 + but sets up a deferred that is called when the result becomes available. 1.351 + 1.352 + Uses AsynchXendClient to manage the connection. 1.353 """ 1.354 - return xend_request(url, "POST", data) 1.355 + 1.356 + def __init__(self): 1.357 + self.err = None 1.358 + 1.359 + def xendRequest(self, url, method, args=None): 1.360 + """Make a request to xend. The returned deferred is called when 1.361 + the result is available. 1.362 + 1.363 + @param url: xend request url 1.364 + @param method: http method: POST or GET 1.365 + @param args: request arguments (dict) 1.366 + @return: deferred 1.367 + """ 1.368 + request = XendRequest(url, method, args) 1.369 + self.deferred = Deferred() 1.370 + clientCreator = ClientCreator(reactor, AsynchXendClient, self, request) 1.371 + clientCreator.connectTCP(url.host, url.port) 1.372 + return self.deferred 1.373 1.374 + def callErrback(self, err): 1.375 + if not self.deferred.called: 1.376 + self.err = err 1.377 + self.deferred.errback(err) 1.378 + return err 1.379 + 1.380 + def callCallback(self, val): 1.381 + if not self.deferred.called: 1.382 + self.deferred.callback(val) 1.383 + return val 1.384 + 1.385 + def handleException(self, err): 1.386 + return self.callErrback(err) 1.387 + 1.388 + def handleResponse(self, data): 1.389 + if self.err: return self.err 1.390 + val = XendClientProtocol.handleResponse(self, data) 1.391 + if isinstance(val, Exception): 1.392 + self.callErrback(val) 1.393 + else: 1.394 + self.callCallback(val) 1.395 + return val 1.396 + 1.397 class Xend: 1.398 + """Client interface to Xend. 1.399 + """ 1.400 1.401 """Default location of the xend server.""" 1.402 SRV_DEFAULT = "localhost:8000" 1.403 @@ -165,199 +305,262 @@ class Xend: 1.404 """Default path to the xend root on the server.""" 1.405 ROOT_DEFAULT = "/xend/" 1.406 1.407 - def __init__(self, srv=None, root=None): 1.408 + def __init__(self, client=None, srv=None, root=None): 1.409 + """Create a xend client interface. 1.410 + If the client protocol is not specified, the default 1.411 + is to use a synchronous protocol. 1.412 + 1.413 + @param client: client protocol to use 1.414 + @param srv: server host, and optional port (format host:port) 1.415 + @param root: xend root path on the server 1.416 + """ 1.417 + if client is None: 1.418 + client = SynchXendClientProtocol() 1.419 + self.client = client 1.420 self.bind(srv, root) 1.421 1.422 def bind(self, srv=None, root=None): 1.423 """Bind to a given server. 1.424 1.425 - srv server location (host:port) 1.426 - root server xend root path 1.427 + @param srv: server location (host:port) 1.428 + @param root: xend root path on the server 1.429 """ 1.430 if srv is None: srv = self.SRV_DEFAULT 1.431 if root is None: root = self.ROOT_DEFAULT 1.432 if not root.endswith('/'): root += '/' 1.433 - self.location = srv 1.434 - self.root = root 1.435 + (host, port) = srv.split(':', 1) 1.436 + self.url = URL(host=host, port=port, path=root) 1.437 + 1.438 + def xendGet(self, url, args=None): 1.439 + return self.client.xendGet(url, args) 1.440 + 1.441 + def xendPost(self, url, data): 1.442 + return self.client.xendPost(url, data) 1.443 1.444 def nodeurl(self, id=''): 1.445 - return nodeurl(self.location, self.root, id) 1.446 + return self.url.relative('node/' + id) 1.447 1.448 def domainurl(self, id=''): 1.449 - return domainurl(self.location, self.root, id) 1.450 + return self.url.relative('domain/' + id) 1.451 1.452 def consoleurl(self, id=''): 1.453 - return consoleurl(self.location, self.root, id) 1.454 + return self.url.relative('console/' + id) 1.455 1.456 def deviceurl(self, id=''): 1.457 - return deviceurl(self.location, self.root, id) 1.458 + return self.url.relative('device/' + id) 1.459 1.460 def vneturl(self, id=''): 1.461 - return vneturl(self.location, self.root, id) 1.462 + return self.url.relative('vnet/' + id) 1.463 1.464 def eventurl(self, id=''): 1.465 - return eventurl(self.location, self.root, id) 1.466 + return self.url.relative('event/' + id) 1.467 1.468 def dmesgurl(self, id=''): 1.469 - return dmesgurl(self.location, self.root, id) 1.470 + return self.url.relative('node/dmesg/' + id) 1.471 1.472 def xend(self): 1.473 - return xend_get(urljoin(self.location, self.root)) 1.474 + return self.xendGet(self.url) 1.475 1.476 def xend_node(self): 1.477 - return xend_get(self.nodeurl()) 1.478 + return self.xendGet(self.nodeurl()) 1.479 1.480 def xend_node_cpu_rrobin_slice_set(self, slice): 1.481 - return xend_call(self.nodeurl(), 1.482 - {'op' : 'cpu_rrobin_slice_set', 1.483 - 'slice' : slice }) 1.484 + return self.xendPost(self.nodeurl(), 1.485 + {'op' : 'cpu_rrobin_slice_set', 1.486 + 'slice' : slice }) 1.487 1.488 def xend_node_cpu_bvt_slice_set(self, ctx_allow): 1.489 - return xend_call(self.nodeurl(), 1.490 - {'op' : 'cpu_bvt_slice_set', 1.491 - 'ctx_allow' : ctx_allow }) 1.492 + return self.xendPost(self.nodeurl(), 1.493 + {'op' : 'cpu_bvt_slice_set', 1.494 + 'ctx_allow' : ctx_allow }) 1.495 1.496 def xend_node_cpu_fbvt_slice_set(self, ctx_allow): 1.497 - return xend_call(self.nodeurl(), 1.498 - {'op' : 'cpu_fbvt_slice_set', 1.499 - 'ctx_allow' : ctx_allow }) 1.500 + return self.xendPost(self.nodeurl(), 1.501 + {'op' : 'cpu_fbvt_slice_set', 1.502 + 'ctx_allow' : ctx_allow }) 1.503 1.504 def xend_domains(self): 1.505 - return xend_get(self.domainurl()) 1.506 + return self.xendGet(self.domainurl()) 1.507 1.508 def xend_domain_create(self, conf): 1.509 - return xend_call(self.domainurl(), 1.510 - {'op' : 'create', 1.511 - 'config' : fileof(conf) }) 1.512 + return self.xendPost(self.domainurl(), 1.513 + {'op' : 'create', 1.514 + 'config' : fileof(conf) }) 1.515 1.516 def xend_domain_restore(self, filename): 1.517 - return xend_call(self.domainurl(), 1.518 - {'op' : 'restore', 1.519 - 'file' : filename }) 1.520 + return self.xendPost(self.domainurl(), 1.521 + {'op' : 'restore', 1.522 + 'file' : filename }) 1.523 1.524 - def xend_domain_configure(self, id, config): 1.525 - return xend_call(self.domainurl(id), 1.526 - {'op' : 'configure', 1.527 - 'config' : fileof(conf) }) 1.528 + def xend_domain_configure(self, id, conf): 1.529 + return self.xendPost(self.domainurl(id), 1.530 + {'op' : 'configure', 1.531 + 'config' : fileof(conf) }) 1.532 1.533 def xend_domain(self, id): 1.534 - return xend_get(self.domainurl(id)) 1.535 + return self.xendGet(self.domainurl(id)) 1.536 1.537 def xend_domain_unpause(self, id): 1.538 - return xend_call(self.domainurl(id), 1.539 - {'op' : 'unpause' }) 1.540 + return self.xendPost(self.domainurl(id), 1.541 + {'op' : 'unpause' }) 1.542 1.543 def xend_domain_pause(self, id): 1.544 - return xend_call(self.domainurl(id), 1.545 - {'op' : 'pause' }) 1.546 + return self.xendPost(self.domainurl(id), 1.547 + {'op' : 'pause' }) 1.548 1.549 def xend_domain_shutdown(self, id, reason): 1.550 - return xend_call(self.domainurl(id), 1.551 - {'op' : 'shutdown', 1.552 - 'reason' : reason }) 1.553 + return self.xendPost(self.domainurl(id), 1.554 + {'op' : 'shutdown', 1.555 + 'reason' : reason }) 1.556 1.557 def xend_domain_destroy(self, id, reason): 1.558 - return xend_call(self.domainurl(id), 1.559 - {'op' : 'destroy', 1.560 - 'reason' : reason }) 1.561 + return self.xendPost(self.domainurl(id), 1.562 + {'op' : 'destroy', 1.563 + 'reason' : reason }) 1.564 1.565 def xend_domain_save(self, id, filename): 1.566 - return xend_call(self.domainurl(id), 1.567 - {'op' : 'save', 1.568 - 'file' : filename }) 1.569 + return self.xendPost(self.domainurl(id), 1.570 + {'op' : 'save', 1.571 + 'file' : filename }) 1.572 1.573 def xend_domain_migrate(self, id, dst): 1.574 - return xend_call(self.domainurl(id), 1.575 - {'op' : 'migrate', 1.576 - 'destination': dst }) 1.577 + return self.xendPost(self.domainurl(id), 1.578 + {'op' : 'migrate', 1.579 + 'destination': dst }) 1.580 1.581 def xend_domain_pincpu(self, id, cpu): 1.582 - return xend_call(self.domainurl(id), 1.583 - {'op' : 'pincpu', 1.584 - 'cpu' : cpu }) 1.585 + return self.xendPost(self.domainurl(id), 1.586 + {'op' : 'pincpu', 1.587 + 'cpu' : cpu }) 1.588 1.589 def xend_domain_cpu_bvt_set(self, id, mcuadv, warp, warpl, warpu): 1.590 - return xend_call(self.domainurl(id), 1.591 - {'op' : 'cpu_bvt_set', 1.592 - 'mcuadv' : mcuadv, 1.593 - 'warp' : warp, 1.594 - 'warpl' : warpl, 1.595 - 'warpu' : warpu }) 1.596 + return self.xendPost(self.domainurl(id), 1.597 + {'op' : 'cpu_bvt_set', 1.598 + 'mcuadv' : mcuadv, 1.599 + 'warp' : warp, 1.600 + 'warpl' : warpl, 1.601 + 'warpu' : warpu }) 1.602 1.603 def xend_domain_cpu_fbvt_set(self, id, mcuadv, warp, warpl, warpu): 1.604 - return xend_call(self.domainurl(id), 1.605 - {'op' : 'cpu_fbvt_set', 1.606 - 'mcuadv' : mcuadv, 1.607 - 'warp' : warp, 1.608 - 'warpl' : warpl, 1.609 - 'warpu' : warpu }) 1.610 - 1.611 + return self.xendPost(self.domainurl(id), 1.612 + {'op' : 'cpu_fbvt_set', 1.613 + 'mcuadv' : mcuadv, 1.614 + 'warp' : warp, 1.615 + 'warpl' : warpl, 1.616 + 'warpu' : warpu }) 1.617 + 1.618 1.619 def xend_domain_cpu_atropos_set(self, id, period, slice, latency, xtratime): 1.620 - return xend_call(self.domainurl(id), 1.621 - {'op' : 'cpu_atropos_set', 1.622 - 'period' : period, 1.623 - 'slice' : slice, 1.624 - 'latency' : latency, 1.625 - 'xtratime': xtratime }) 1.626 - 1.627 + return self.xendPost(self.domainurl(id), 1.628 + {'op' : 'cpu_atropos_set', 1.629 + 'period' : period, 1.630 + 'slice' : slice, 1.631 + 'latency' : latency, 1.632 + 'xtratime': xtratime }) 1.633 + 1.634 def xend_domain_vifs(self, id): 1.635 - return xend_get(self.domainurl(id), 1.636 - { 'op' : 'vifs' }) 1.637 + return self.xendGet(self.domainurl(id), 1.638 + { 'op' : 'vifs' }) 1.639 1.640 def xend_domain_vif(self, id, vif): 1.641 - return xend_get(self.domainurl(id), 1.642 - { 'op' : 'vif', 1.643 - 'vif' : vif }) 1.644 + return self.xendGet(self.domainurl(id), 1.645 + { 'op' : 'vif', 1.646 + 'vif' : vif }) 1.647 1.648 def xend_domain_vbds(self, id): 1.649 - return xend_get(self.domainurl(id), 1.650 - {'op' : 'vbds'}) 1.651 - 1.652 + return self.xendGet(self.domainurl(id), 1.653 + {'op' : 'vbds'}) 1.654 + 1.655 def xend_domain_vbd(self, id, vbd): 1.656 - return xend_get(self.domainurl(id), 1.657 - {'op' : 'vbd', 1.658 - 'vbd' : vbd }) 1.659 + return self.xendGet(self.domainurl(id), 1.660 + {'op' : 'vbd', 1.661 + 'vbd' : vbd }) 1.662 1.663 def xend_domain_device_create(self, id, config): 1.664 - return xend_call(self.domainurl(id), 1.665 - {'op' : 'device_create', 1.666 - 'config' : fileof(config) }) 1.667 + return self.xendPost(self.domainurl(id), 1.668 + {'op' : 'device_create', 1.669 + 'config' : fileof(config) }) 1.670 1.671 def xend_domain_device_destroy(self, id, type, idx): 1.672 - return xend_call(self.domainurl(id), 1.673 - {'op' : 'device_destroy', 1.674 - 'type' : type, 1.675 - 'index' : idx }) 1.676 - 1.677 + return self.xendPost(self.domainurl(id), 1.678 + {'op' : 'device_destroy', 1.679 + 'type' : type, 1.680 + 'index' : idx }) 1.681 + 1.682 def xend_consoles(self): 1.683 - return xend_get(self.consoleurl()) 1.684 + return self.xendGet(self.consoleurl()) 1.685 1.686 def xend_console(self, id): 1.687 - return xend_get(self.consoleurl(id)) 1.688 + return self.xendGet(self.consoleurl(id)) 1.689 1.690 def xend_vnets(self): 1.691 - return xend_get(self.vneturl()) 1.692 + return self.xendGet(self.vneturl()) 1.693 1.694 def xend_vnet_create(self, conf): 1.695 - return xend_call(self.vneturl(), 1.696 - {'op': 'create', 'config': fileof(conf) }) 1.697 + return self.xendPost(self.vneturl(), 1.698 + {'op' : 'create', 1.699 + 'config' : fileof(conf) }) 1.700 1.701 def xend_vnet(self, id): 1.702 - return xend_get(self.vneturl(id)) 1.703 + return self.xendGet(self.vneturl(id)) 1.704 1.705 def xend_vnet_delete(self, id): 1.706 - return xend_call(self.vneturl(id), 1.707 - {'op': 'delete' }) 1.708 + return self.xendPost(self.vneturl(id), 1.709 + {'op' : 'delete' }) 1.710 1.711 def xend_event_inject(self, sxpr): 1.712 - val = xend_call(self.eventurl(), 1.713 - {'op': 'inject', 'event': fileof(sxpr) }) 1.714 + val = self.xendPost(self.eventurl(), 1.715 + {'op' : 'inject', 1.716 + 'event' : fileof(sxpr) }) 1.717 1.718 def xend_dmesg(self): 1.719 - return xend_get(self.dmesgurl()) 1.720 + return self.xendGet(self.dmesgurl()) 1.721 1.722 1.723 +def synchmain(srv, argv): 1.724 + xend = Xend(srv=srv) 1.725 + if len(argv) > 1: 1.726 + fn = argv[0] 1.727 + else: 1.728 + fn = 'xend' 1.729 + if not fn.startswith('xend'): 1.730 + fn = 'xend_' + fn 1.731 + args = argv[1:] 1.732 + try: 1.733 + val = getattr(xend, fn)(*args) 1.734 + PrettyPrint.prettyprint(val) 1.735 + except XendError, err: 1.736 + print 'ERROR:', err 1.737 + sys.exit(1) 1.738 + 1.739 +def xendmain(srv, asynch, fn, args): 1.740 + if asynch: 1.741 + client = AsynchXendClientProtocol() 1.742 + else: 1.743 + client = None 1.744 + xend = Xend(srv=srv, client=client) 1.745 + xend.rc = 0 1.746 + try: 1.747 + v = getattr(xend, fn)(*args) 1.748 + except XendError, err: 1.749 + print 'ERROR:', err 1.750 + return 1 1.751 + if asynch: 1.752 + def cbok(val): 1.753 + PrettyPrint.prettyprint(val) 1.754 + reactor.stop() 1.755 + def cberr(err): 1.756 + print 'ERROR:', err 1.757 + xend.rc = 1 1.758 + reactor.stop() 1.759 + v.addCallback(cbok) 1.760 + v.addErrback(cberr) 1.761 + reactor.run() 1.762 + return xend.rc 1.763 + else: 1.764 + PrettyPrint.prettyprint(v) 1.765 + return 0 1.766 + 1.767 def main(argv): 1.768 """Call an API function: 1.769 1.770 @@ -367,18 +570,33 @@ def main(argv): 1.771 Example: 1.772 1.773 > python XendClient.py domains 1.774 - (domain 0 8) 1.775 + (0 8) 1.776 > python XendClient.py domain 0 1.777 (domain (id 0) (name Domain-0) (memory 128)) 1.778 """ 1.779 - server = Xend() 1.780 - fn = argv[1] 1.781 + global DEBUG 1.782 + from getopt import getopt 1.783 + short_options = 'x:ad' 1.784 + long_options = ['xend=', 'asynch', 'debug'] 1.785 + (options, args) = getopt(argv[1:], short_options, long_options) 1.786 + srv = None 1.787 + asynch = 0 1.788 + for k, v in options: 1.789 + if k in ['-x', '--xend']: 1.790 + srv = v 1.791 + elif k in ['-a', '--asynch']: 1.792 + asynch = 1 1.793 + elif k in ['-d', '--DEBUG']: 1.794 + DEBUG = 1 1.795 + if len(args): 1.796 + fn = args[0] 1.797 + args = args[1:] 1.798 + else: 1.799 + fn = 'xend' 1.800 + args = [] 1.801 if not fn.startswith('xend'): 1.802 fn = 'xend_' + fn 1.803 - args = argv[2:] 1.804 - val = getattr(server, fn)(*args) 1.805 - PrettyPrint.prettyprint(val) 1.806 - print 1.807 + sys.exit(xendmain(srv, asynch, fn, args)) 1.808 1.809 if __name__ == "__main__": 1.810 main(sys.argv)