diff options
Diffstat (limited to 'tools/python/xen/xend/XendClient.py')
-rw-r--r-- | tools/python/xen/xend/XendClient.py | 311 |
1 files changed, 311 insertions, 0 deletions
diff --git a/tools/python/xen/xend/XendClient.py b/tools/python/xen/xend/XendClient.py new file mode 100644 index 0000000000..13dc3dbb1e --- /dev/null +++ b/tools/python/xen/xend/XendClient.py @@ -0,0 +1,311 @@ +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com> +"""Client API for the HTTP interface on xend. +Callable as a script - see main(). +""" +import sys +import httplib +import types +from StringIO import StringIO +import urlparse + +from encode import * +import sxp +import PrettyPrint + +DEBUG = 0 + +class Foo(httplib.HTTPResponse): + + def begin(self): + fin = self.fp + while(1): + buf = fin.readline() + print "***", buf + if buf == '': + print + sys.exit() + + +def sxprio(sxpr): + io = StringIO() + sxp.show(sxpr, out=io) + print >> io + io.seek(0) + return io + +def fileof(val): + """Converter for passing configs. + Handles lists, files directly. + Assumes a string is a file name and passes its contents. + """ + if isinstance(val, types.ListType): + return sxprio(val) + if isinstance(val, types.StringType): + return file(val) + if hasattr(val, 'readlines'): + return val + +# todo: need to sort of what urls/paths are using for objects. +# e.g. for domains at the moment return '0'. +# should probably return abs path w.r.t. server, e.g. /xend/domain/0. +# As an arg, assume abs path is obj uri, otherwise just id. + +# Function to convert to full url: Xend.uri(path), e.g. +# maps /xend/domain/0 to http://wray-m-3.hpl.hp.com:8000/xend/domain/0 +# And should accept urls for ids? + +def urljoin(location, root, prefix='', rest=''): + prefix = str(prefix) + rest = str(rest) + base = 'http://' + location + root + prefix + url = urlparse.urljoin(base, rest) + return url + +def nodeurl(location, root, id=''): + return urljoin(location, root, 'node/', id) + +def domainurl(location, root, id=''): + return urljoin(location, root, 'domain/', id) + +def consoleurl(location, root, id=''): + return urljoin(location, root, 'console/', id) + +def deviceurl(location, root, id=''): + return urljoin(location, root, 'device/', id) + +def vneturl(location, root, id=''): + return urljoin(location, root, 'vnet/', id) + +def eventurl(location, root, id=''): + return urljoin(location, root, 'event/', id) + +def xend_request(url, method, data=None): + urlinfo = urlparse.urlparse(url) + (uproto, ulocation, upath, uparam, uquery, ufrag) = urlinfo + if DEBUG: print url, urlinfo + if uproto != 'http': + raise StandardError('Invalid protocol: ' + uproto) + if DEBUG: print '>xend_request', ulocation, upath, method, data + (hdr, args) = encode_data(data) + if data and method == 'GET': + upath += '?' + args + args = None + if method == "POST" and upath.endswith('/'): + upath = upath[:-1] + if DEBUG: print "ulocation=", ulocation, "upath=", upath, "args=", args + #hdr['User-Agent'] = 'Mozilla' + #hdr['Accept'] = 'text/html,text/plain' + conn = httplib.HTTPConnection(ulocation) + #conn.response_class = Foo + if DEBUG: conn.set_debuglevel(1) + conn.request(method, upath, args, hdr) + resp = conn.getresponse() + if DEBUG: print resp.status, resp.reason + if DEBUG: print resp.msg.headers + if resp.status in [204, 404]: + return None + if resp.status not in [200, 201, 202, 203]: + raise RuntimeError(resp.reason) + pin = sxp.Parser() + data = resp.read() + if DEBUG: print "***data" , data + if DEBUG: print "***" + pin.input(data); + pin.input_eof() + conn.close() + val = pin.get_val() + #if isinstance(val, types.ListType) and sxp.name(val) == 'val': + # val = val[1] + if isinstance(val, types.ListType) and sxp.name(val) == 'err': + raise RuntimeError(val[1]) + if DEBUG: print '**val='; sxp.show(val); print + return val + +def xend_get(url, args=None): + return xend_request(url, "GET", args) + +def xend_call(url, data): + return xend_request(url, "POST", data) + +class Xend: + + SRV_DEFAULT = "localhost:8000" + ROOT_DEFAULT = "/xend/" + + def __init__(self, srv=None, root=None): + self.bind(srv, root) + + def bind(self, srv=None, root=None): + if srv is None: srv = self.SRV_DEFAULT + if root is None: root = self.ROOT_DEFAULT + if not root.endswith('/'): root += '/' + self.location = srv + self.root = root + + def nodeurl(self, id=''): + return nodeurl(self.location, self.root, id) + + def domainurl(self, id=''): + return domainurl(self.location, self.root, id) + + def consoleurl(self, id=''): + return consoleurl(self.location, self.root, id) + + def deviceurl(self, id=''): + return deviceurl(self.location, self.root, id) + + def vneturl(self, id=''): + return vneturl(self.location, self.root, id) + + def eventurl(self, id=''): + return eventurl(self.location, self.root, id) + + def xend(self): + return xend_get(urljoin(self.location, self.root)) + + def xend_node(self): + return xend_get(self.nodeurl()) + + def xend_node_cpu_rrobin_slice_set(self, slice): + return xend_call(self.nodeurl(), + {'op' : 'cpu_rrobin_slice_set', + 'slice' : slice }) + + def xend_node_cpu_bvt_slice_set(self, slice): + return xend_call(self.nodeurl(), + {'op' : 'cpu_bvt_slice_set', + 'slice' : slice }) + + def xend_domains(self): + return xend_get(self.domainurl()) + + def xend_domain_create(self, conf): + return xend_call(self.domainurl(), + {'op' : 'create', + 'config' : fileof(conf) }) + + def xend_domain(self, id): + return xend_get(self.domainurl(id)) + + def xend_domain_unpause(self, id): + return xend_call(self.domainurl(id), + {'op' : 'unpause'}) + + def xend_domain_pause(self, id): + return xend_call(self.domainurl(id), + {'op' : 'pause'}) + + def xend_domain_shutdown(self, id): + return xend_call(self.domainurl(id), + {'op' : 'shutdown'}) + + def xend_domain_destroy(self, id): + return xend_call(self.domainurl(id), + {'op' : 'destroy'}) + + def xend_domain_save(self, id, filename): + return xend_call(self.domainurl(id), + {'op' : 'save', + 'file' : filename}) + + def xend_domain_restore(self, id, filename): + return xend_call(self.domainurl(id), + {'op' : 'restore', + 'file' : filename }) + + def xend_domain_migrate(self, id, dst): + return xend_call(self.domainurl(id), + {'op' : 'migrate', + 'destination': dst}) + + def xend_domain_pincpu(self, id, cpu): + return xend_call(self.domainurl(id), + {'op' : 'pincpu', + 'cpu' : cpu}) + + def xend_domain_cpu_bvt_set(self, id, mcuadv, warp, warpl, warpu): + return xend_call(self.domainurl(id), + {'op' : 'cpu_bvt_set', + 'mcuadv' : mvuadv, + 'warp' : warp, + 'warpl' : warpl, + 'warpu' : warpu }) + + def xend_domain_cpu_atropos_set(self, id, period, slice, latency, xtratime): + return xend_call(self.domainurl(id), + {'op' : 'cpu_atropos_set', + 'period' : period, + 'slice' : slice, + 'latency' : latency, + 'xtratime': xtratime }) + + def xend_domain_vifs(self, id): + return xend_get(self.domainurl(id), + { 'op' : 'vifs' }) + + def xend_domain_vif_ip_add(self, id, vif, ipaddr): + return xend_call(self.domainurl(id), + {'op' : 'vif_ip_add', + 'vif' : vif, + 'ip' : ipaddr }) + + def xend_domain_vbds(self, id): + return xend_get(self.domainurl(id), + {'op' : 'vbds'}) + + def xend_domain_vbd(self, id, vbd): + return xend_get(self.domainurl(id), + {'op' : 'vbd', + 'vbd' : vbd}) + + def xend_consoles(self): + return xend_get(self.consoleurl()) + + def xend_console(self, id): + return xend_get(self.consoleurl(id)) + + def xend_vnets(self): + return xend_get(self.vneturl()) + + def xend_vnet_create(self, conf): + return xend_call(self.vneturl(), + {'op': 'create', 'config': fileof(conf) }) + + def xend_vnet(self, id): + return xend_get(self.vneturl(id)) + + def xend_vnet_delete(self, id): + return xend_call(self.vneturl(id), + {'op': 'delete'}) + + def xend_event_inject(self, sxpr): + val = xend_call(self.eventurl(), + {'op': 'inject', 'event': fileof(sxpr) }) + + +def main(argv): + """Call an API function: + + python XendClient.py fn args... + + The leading 'xend_' on the function can be omitted. + Example: + + > python XendClient.py domains + (domain 0 8) + > python XendClient.py domain 0 + (domain (id 0) (name Domain-0) (memory 128)) + """ + server = Xend() + fn = argv[1] + if not fn.startswith('xend'): + fn = 'xend_' + fn + args = argv[2:] + val = getattr(server, fn)(*args) + PrettyPrint.prettyprint(val) + print + +if __name__ == "__main__": + main(sys.argv) +else: + server = Xend() |