bitkeeper revision 1.1108.2.17 (40ffde2eqJ67r1igRaAha9mzkh_gLA)

Removed async code from sv, and now used xend http interface for node info
This commit is contained in:
tw275@labyrinth.cl.cam.ac.uk committed 2004-07-22 15:33:02 +00:00
1 parent 332f9ea88f
commit 6a9797b8af
8 files changed
+519 -384

No files matched your search

+16 -33
View File
@@ -1,20 +1,20 @@
from HTMLBase import HTMLBase
from XendClientDeferred import server
from xen.xend.XendClient import aserver as server
from xen.xend import PrettyPrint
from xen.sv.HTMLBase import HTMLBase
from xen.sv.util import *
from xen.sv.GenTabbed import *
class DomInfo( GenTabbed ):
def __init__( self, urlWriter, callback ):
def __init__( self, urlWriter ):
self.dom = 0;
def tabUrlWriter( tab ):
return urlWriter( "mod=info&dom=%s%s" % ( self.dom, tab ) )
GenTabbed.__init__( self, tabUrlWriter, [ 'General', 'SXP', 'Devices' ], [ DomGenTab, DomSXPTab, NullTab ], callback )
GenTabbed.__init__( self, tabUrlWriter, [ 'General', 'SXP', 'Devices' ], [ DomGenTab, DomSXPTab, NullTab ] )
def write_BODY( self, request ):
dom = request.args.get('dom')
@@ -43,7 +43,8 @@ class DomGenTab( GeneralTab ):
GeneralTab.__init__( self, "General Domain Info", {}, titles )
def write_BODY( self, request, callback ):
def write_BODY( self, request ):
dom = request.args.get('dom')
if dom is None or len(dom) != 1:
@@ -52,14 +53,9 @@ class DomGenTab( GeneralTab ):
else:
self.dom = dom[0]
deferred = getDomInfoHash( self.dom )
deferred.addCallback( self.continue_BODY, request, callback )
def continue_BODY( self, dict, request, callback ):
self.dict = dict
self.dict = getDomInfoHash( self.dom )
GeneralTab.write_BODY( self, request, callback )
GeneralTab.write_BODY( self, request )
class DomSXPTab( PreTab ):
@@ -67,21 +63,8 @@ class DomSXPTab( PreTab ):
self.dom = 0
PreTab.__init__( self, "" )
def fn( self, x, request ):
class tmp:
def __init__( self ):
self.str = ""
def write( self, str ):
self.str = self.str + str
temp = tmp()
PrettyPrint.prettyprint( x, out=temp )
self.source = temp.str
return request
def fn2( self, request, callback ):
PreTab.write_BODY( self, request, callback )
def write_BODY( self, request, callback ):
def write_BODY( self, request ):
dom = request.args.get('dom')
if dom is None or len(dom) != 1:
@@ -90,10 +73,10 @@ class DomSXPTab( PreTab ):
else:
self.dom = dom[0]
deferred = server.xend_domain( self.dom )
domInfo = server.xend_domain( self.dom )
deferred.addCallback( self.fn, request )
deferred.addCallback( self.fn2, callback )
def errback( x ):
print ">err ", x
deferred.addErrback( errback )
self.source = sxp2string( domInfo )
PreTab.write_BODY( self, request )
+20 -59
View File
@@ -1,93 +1,54 @@
from twisted.web import resource
from twisted.web.server import NOT_DONE_YET
from xen.xend.XendClient import server as XendServer
from xen.xend.XendClient import server
from xen.xend import sxp
from xen.sv.HTMLBase import HTMLBase
from xen.sv.util import *
from twisted.internet import reactor
class DomList( HTMLBase ):
isLeaf = True
def __init__( self, urlWriter, callback ):
def __init__( self, urlWriter ):
HTMLBase.__init__(self)
self.urlWriter = urlWriter
self.head = None
self.long = None
self.rendered_domains = {}
self.domCount = 0
self.callback = callback
def write_BODY( self, request, head=True, long=True ):
deferred = XendServer.xend_domains()
deferred.addCallback( self.get_domain_info, request )
deferred.addErrback( self.errback )
self.head = head
self.long = long
def errback( self, err ):
print 'errback>', err
def get_domain_info( self, domains, request ):
domains = server.xend_domains()
self.domCount = len( domains )
for domain in domains:
deferred = getDomInfoHash( domain )
deferred.addCallback( self.render_domain, request )
deferred.addErrback( self.errback )
def render_domain( self, domInfoHash, request ):
domStr = "<td class='domainInfo' align='center'>%(dom)-4d</td>\n" % domInfoHash
url = self.urlWriter( "mod=info&dom=%(dom)-4d" % domInfoHash )
domStr += "<td class='domainInfo' align='center'><a href='%s'>%s</a></td>\n" % ( url, domInfoHash['name'] )
if self.long:
domStr += "<td class='domainInfo' align='center'>%(mem)7d</td>\n" % domInfoHash
domStr += "<td class='domainInfo' align='center'>%(cpu)3d</td>\n" % domInfoHash
domStr += "<td class='domainInfo' align='center'>%(state)5s</td>\n" % domInfoHash
if self.long:
domStr += "<td class='domainInfo' align='center'>%(cpu_time)7.1f</td>\n" % domInfoHash
self.rendered_domains[ domInfoHash[ 'dom' ] ] = domStr
self.domCount -= 1
if self.domCount == 0:
self.finish_write_BODY( request )
def finish_write_BODY( self, request ):
request.write( "\n<table style='border:0px solid white' cellspacing='0' cellpadding='0' border='0' width='100%'>\n" )
if self.head:
if head:
request.write( "<tr class='domainInfoHead'>" )
self.write_DOMAIN_HEAD( request, self.long )
self.write_DOMAIN_HEAD( request, long )
request.write( "</tr>" )
odd = True
for domain in self.rendered_domains.values():
for domain in domains:
if odd:
request.write( "<tr class='domainInfoOdd'>\n" )
odd = False
else:
request.write( "<tr class='domainInfoEven'>\n" )
odd = True
request.write( domain )
self.write_DOMAIN( request, getDomInfoHash( domain ), long )
request.write( "</tr>\n" )
request.write( "</table>\n" )
def write_DOMAIN( self, request, domInfoHash, long=True ):
request.write( "<td class='domainInfo' align='center'>%(dom)-4d</td>\n" % domInfoHash )
self.callback( request )
url = self.urlWriter( "mod=info&dom=%(dom)-4d" % domInfoHash )
request.write( "<td class='domainInfo' align='center'><a href='%s'>%s</a></td>\n" % ( url, domInfoHash['name'] ) )
if long:
request.write( "<td class='domainInfo' align='center'>%(mem)7d</td>\n" % domInfoHash )
request.write( "<td class='domainInfo' align='center'>%(cpu)3d</td>\n" % domInfoHash )
request.write( "<td class='domainInfo' align='center'>%(state)5s</td>\n" % domInfoHash )
if long:
request.write( "<td class='domainInfo' align='center'>%(cpu_time)7.1f</td>\n" % domInfoHash )
def write_DOMAIN_HEAD( self, request, long=True ):
request.write( "<td class='domainInfoHead' align='center'>Domain</td>\n" )
+7 -17
View File
@@ -5,13 +5,12 @@ from xen.sv.TabView import TabView
class GenTabbed( HTMLBase ):
def __init__( self, urlWriter, tabStrings, tabObjects, callback ):
def __init__( self, urlWriter, tabStrings, tabObjects ):
HTMLBase.__init__(self)
self.tab = 0;
self.tabStrings = tabStrings
self.tabObjects = tabObjects
self.urlWriter = urlWriter
self.callback = callback
def write_BODY( self, request, urlWriter = None ):
tab = request.args.get('tab')
@@ -34,29 +33,23 @@ class GenTabbed( HTMLBase ):
request.write( "<p>Bad Tab</p>" )
self.finish_BODY( request )
else:
render_tab.write_BODY( request, self.finish_BODY )
render_tab.write_BODY( request )
def finish_BODY( self, request ):
request.write( "</td></tr></table>" )
self.callback( request )
class PreTab( HTMLBase ):
def __init__( self, source ):
HTMLBase.__init__( self )
self.source = source
def write_BODY( self, request, callback ):
def write_BODY( self, request ):
request.write( "<div style='display: block; overflow: auto; border: 0px solid black; height: 400px; width: 540px; padding: 5px; z-index:0; align: center'><pre>" )
request.write( self.source )
request.write( "</pre></div>" )
callback( request )
class GeneralTab( HTMLBase ):
@@ -66,7 +59,7 @@ class GeneralTab( HTMLBase ):
self.dict = dict
self.titles = titles
def write_BODY( self, request, callback ):
def write_BODY( self, request ):
request.write( "<p><u>%s</u></p>" % self.title )
@@ -87,17 +80,14 @@ class GeneralTab( HTMLBase ):
writeAttr( niceName, attr )
request.write( "</table>" )
callback( request )
class NullTab( HTMLBase ):
def __init__( self ):
HTMLBase.__init__( self )
self.title = "Null Tab"
def write_BODY( self, request, callback ):
def write_BODY( self, request ):
request.write( "<p>%s</p>" % self.title )
callback( request )
+10 -12
View File
@@ -1,27 +1,25 @@
from twisted.web import server, resource
from twisted.internet import reactor
from twisted.web.resource import Resource
class HTMLBase( Resource ):
class HTMLBase( resource.Resource ):
isLeaf = True
def __init__( self ):
resource.Resource.__init__(self)
Resource.__init__(self)
def render_GET( self, request ):
self.write_TOP( request )
return self.write_BODY( request, self.finish_render_GET )
def finish_render_GET( self, request ):
self.write_BODY( request )
self.write_BOTTOM( request )
request.finish()
return ''
def write_BODY( self, request ):
request.write( "BODY" )
request.write( "BODY" )
def write_TOP( self, request ):
request.write( '<html><head><title>Xen</title><link rel="stylesheet" type="text/css" href="inc/style.css" />' )
request.write( '</head><body>' )
def write_BOTTOM( self, request ):
request.write( "</body></html>" )
request.write( "</body></html>" )
+6 -24
View File
@@ -1,11 +1,4 @@
from twisted.web import resource
from twisted.web.server import NOT_DONE_YET
from xen.xend.XendClient import server as XendServer
from xen.xend import sxp
from HTMLBase import HTMLBase
from xen.sv.HTMLBase import HTMLBase
from xen.sv import DomList, NodeInfo, DomInfo
class Main( HTMLBase ):
@@ -21,10 +14,8 @@ class Main( HTMLBase ):
def mainUrlWriter( self, s ):
return "Main.rpy?%s" % s
def write_BODY( self, request, callback ):
def write_BODY( self, request ):
self.callback = callback
request.write( "\n<table style='border:0px solid black; background: url(images/orb_01.jpg) no-repeat' cellspacing='0' cellpadding='0' border='0' width='780px' height='536px'>\n" )
request.write( "<tr>\n" )
request.write( " <td width='15px'>&nbsp;</td>" )
@@ -37,11 +28,8 @@ class Main( HTMLBase ):
request.write( " <p class='small'><a href='Main.rpy?mod=node'>Node details</a></p>" )
request.write( " <p class='small'><a href='Main.rpy?mod=list'>Domains summary</a></p>" )
DomList.DomList( self.mainUrlWriter, self.continue_BODY ).write_BODY( request, True, False )
DomList.DomList( self.mainUrlWriter ).write_BODY( request, True, False )
return NOT_DONE_YET
def continue_BODY( self, request ):
request.write( " </td></tr>" )
request.write( " </table>" )
request.write( " &nbsp;" )
@@ -56,18 +44,14 @@ class Main( HTMLBase ):
if mod is None or len(mod) != 1:
request.write( '<p>Please select a module</p>' )
self.finish_BODY( request )
elif mod[0] == 'info':
DomInfo.DomInfo( self.mainUrlWriter, self.finish_BODY ).write_BODY( request )
DomInfo.DomInfo( self.mainUrlWriter ).write_BODY( request )
elif mod[0] == 'list':
DomList.DomList( self.mainUrlWriter, self.finish_BODY ).write_BODY( request )
DomList.DomList( self.mainUrlWriter ).write_BODY( request )
elif mod[0] == 'node':
NodeInfo.NodeInfo( self.mainUrlWriter, self.finish_BODY ).write_BODY( request )
NodeInfo.NodeInfo( self.mainUrlWriter ).write_BODY( request )
else:
request.write( '<p>Invalid module. Please select another</p>' )
self.finish_BODY( request )
def finish_BODY( self, request ):
request.write( " </td></tr>" )
request.write( " </table>" )
@@ -77,5 +61,3 @@ class Main( HTMLBase ):
request.write( "</table>\n" )
self.callback( request )
+11 -8
View File
@@ -1,24 +1,27 @@
from xen.xend import XendDmesg
from xen.xend import XendNode
from xen.xend.XendClient import server
from xen.sv.util import *
from xen.sv.GenTabbed import *
from xen.sv.HTMLBase import HTMLBase
class NodeInfo( GenTabbed ):
def __init__( self, urlWriter, callback ):
def __init__( self, urlWriter ):
def newUrlWriter( url ):
return urlWriter( "mod=node%s" % url )
GenTabbed.__init__( self, newUrlWriter, [ 'General', 'Dmesg' ], [ NodeGeneralTab, NodeDmesgTab ], callback )
GenTabbed.__init__( self, newUrlWriter, [ 'General', 'Dmesg' ], [ NodeGenTab, NodeDmesgTab ] )
class NodeGenTab( PreTab ):
def __init__( self ):
text = sxp2string( server.xend_node() )
PreTab.__init__( self, text )
class NodeGeneralTab( GeneralTab ):
def __init__( self ):
nodeInfo = XendNode.instance().info()
nodeInfo = server.xend_node()
dictNodeInfo = {}
@@ -42,6 +45,6 @@ class NodeGeneralTab( GeneralTab ):
class NodeDmesgTab( PreTab ):
def __init__( self ):
self.xd = XendDmesg.instance()
PreTab.__init__( self, self.xd.info()[0] )
dmesg = server.xend_node_dmesg()
PreTab.__init__( self, dmesg[ 1 ] )
+15 -5
View File
@@ -1,12 +1,9 @@
from xen.xend.XendClient import server
from xen.xend import sxp
from xen.xend import PrettyPrint
def getDomInfoHash( domain ):
deferred = server.xend_domain( int( domain ) )
deferred.addCallback( procDomInfo, domain )
return deferred
def procDomInfo( domInfo, domain ):
domInfo = server.xend_domain( int( domain ) )
d = {}
d['dom'] = int( domain )
d['name'] = sxp.child_value( domInfo, 'name' )
@@ -19,7 +16,20 @@ def procDomInfo( domInfo, domain ):
if( sxp.child_value( domInfo, 'start_time' ) ):
d['start_time'] = float( sxp.child_value( domInfo, 'start_time' ) )
return d
def sxp2hash( sxp ):
pass
def sxp2string( sxp ):
class tmp:
def __init__( self ):
self.str = ""
def write( self, str ):
self.str = self.str + str
temp = tmp()
PrettyPrint.prettyprint( sxp, out=temp )
return temp.str
def bigTimeFormatter( time ):
weeks = time // 604800
remainder = time % 604800
+434 -226
View File
@@ -1,6 +1,8 @@
#!/usr/bin/env python
# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
"""Client API for the HTTP interface on xend.
Callable as a script - see main().
Supports synchronous or asynchronous connection to xend.
This API is the 'control-plane' for xend.
The 'data-plane' is done separately. For example, consoles
@@ -11,9 +13,12 @@ import sys
import httplib
import types
from StringIO import StringIO
import urlparse
from twisted.protocols import http
from twisted.internet.protocol import ClientCreator
from twisted.internet.defer import Deferred
from twisted.internet import reactor
from encode import *
import sxp
@@ -22,40 +27,22 @@ import PrettyPrint
DEBUG = 0
class XendError(RuntimeError):
"""Error class for 'expected errors' when talking to xend.
"""
pass
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):
"""Convert an sxpr to a string.
"""
io = StringIO()
sxp.show(sxpr, out=io)
print >> io
io.seek(0)
return io
def fileof(val):
"""Converter for passing configs.
"""Converter for passing configs or other 'large' data.
Handles lists, files directly.
Assumes a string is a file name and passes its contents.
"""
if isinstance(val, types.ListType):
return sxprio(val)
return sxp.to_string(val)
if isinstance(val, types.StringType):
return file(val)
if hasattr(val, 'readlines'):
return val
raise XendError('cannot convert value')
# todo: need to sort of what urls/paths are using for objects.
# e.g. for domains at the moment return '0'.
@@ -66,98 +53,253 @@ def fileof(val):
# 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 dmesgurl(location, root, id=''):
return urljoin(location, root, 'node/dmesg/', id)
def xend_request(url, method, data=None):
"""Make a request to xend.
url xend request url
method http method: POST or GET
data request argument data (dict)
class URL:
"""A URL.
"""
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 [ http.NO_CONTENT ]:
return None
if resp.status not in [ http.OK, http.CREATED, http.ACCEPTED ]:
raise XendError(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) == 'xend.err':
raise XendError(val[1])
if DEBUG: print '**val='; sxp.show(val); print
return val
def xend_get(url, args=None):
"""Make a xend request using GET.
Requests using GET are 'safe' and may be repeated without
nasty side-effects.
"""
return xend_request(url, "GET", args)
def __init__(self, proto='http', host='localhost', port=None, path='', query=None, frag=None):
self.proto = proto
self.host = host
if port: port = int(port)
self.port = port
self.path = path
self.query = query
self.frag = frag
def xend_call(url, data):
"""Make xend request using POST.
Requests using POST potentially cause side-effects and should
not be repeated unless it really is wanted to do the side
effect again.
def url(self):
"""Get the full URL string including protocol, location and the full path.
"""
return self.proto + '://' + self.location() + self.fullpath()
def location(self):
"""Get the location part of the URL, including host and port, if present.
"""
if self.port:
return self.host + ':' + str(self.port)
else:
return self.host
def fullpath(self):
"""Get the full path part of the URL, including query and fragment if present.
"""
u = [ self.path ]
if self.query:
u.append('?')
u.append(self.query)
if self.frag:
u.append('#')
u.append(self.frag)
return ''.join(u)
def relative(self, path='', query=None, frag=None):
"""Create a URL relative to this one.
"""
return URL(proto=self.proto,
host=self.host,
port=self.port,
path=self.path + path,
query=query,
frag=frag)
class XendRequest:
"""A request to xend.
"""
return xend_request(url, "POST", data)
def __init__(self, url, method, args):
"""Create a request. Sets up the headers, argument data, and the
url.
@param url: the url to request
@param method: request method, GET or POST
@param args: dict containing request args, if any
"""
if url.proto != 'http':
raise ValueError('Invalid protocol: ' + url.proto)
(hdr, data) = encode_data(args)
if args and method == 'GET':
url.query = data
data = None
if method == "POST" and url.path.endswith('/'):
url.path = url.path[:-1]
self.headers = hdr
self.data = data
self.url = url
self.method = method
class XendClientProtocol:
"""Abstract class for xend clients.
"""
def xendRequest(self, url, method, args=None):
"""Make a request to xend.
Implement in a subclass.
@param url: xend request url
@param method: http method: POST or GET
@param args: request arguments (dict)
"""
raise NotImplementedError()
def xendGet(self, url, args=None):
"""Make a xend request using HTTP GET.
Requests using GET are usually 'safe' and may be repeated without
nasty side-effects.
@param url: xend request url
@param data: request arguments (dict)
"""
return self.xendRequest(url, "GET", args)
def xendPost(self, url, args):
"""Make a xend request using HTTP POST.
Requests using POST potentially cause side-effects, and should
not be repeated unless you really want to repeat the side
effect.
@param url: xend request url
@param args: request arguments (dict)
"""
return self.xendRequest(url, "POST", args)
def handleStatus(self, version, status, message):
"""Handle the status returned from the request.
"""
status = int(status)
if status in [ http.NO_CONTENT ]:
return None
if status not in [ http.OK, http.CREATED, http.ACCEPTED ]:
return self.handleException(XendError(message))
return 'ok'
def handleResponse(self, data):
"""Handle the data returned in response to the request.
"""
if data is None: return None
try:
pin = sxp.Parser()
pin.input(data);
pin.input_eof()
val = pin.get_val()
except sxp.ParseError, err:
return self.handleException(err)
if isinstance(val, types.ListType) and sxp.name(val) == 'xend.err':
err = XendError(val[1])
return self.handleException(err)
return val
def handleException(self, err):
"""Handle an exception during the request.
May be overridden in a subclass.
"""
raise err
class SynchXendClientProtocol(XendClientProtocol):
"""A synchronous xend client. This will make a request, wait for
the reply and return the result.
"""
def xendRequest(self, url, method, args=None):
"""Make a request to xend.
@param url: xend request url
@param method: http method: POST or GET
@param args: request arguments (dict)
"""
self.request = XendRequest(url, method, args)
conn = httplib.HTTPConnection(url.location())
if DEBUG: conn.set_debuglevel(1)
conn.request(method, url.fullpath(), self.request.data, self.request.headers)
resp = conn.getresponse()
val = self.handleStatus(resp.version, resp.status, resp.reason)
if val is None:
data = None
else:
data = resp.read()
conn.close()
val = self.handleResponse(data)
return val
class AsynchXendClient(http.HTTPClient):
"""A subclass of twisted's HTTPClient to deal with a connection to xend.
Makes the request when connected, and delegates handling responses etc.
to its protocol (usually an AsynchXendClientProtocol instance).
"""
def __init__(self, protocol, request):
self.protocol = protocol
self.request = request
def connectionMade(self):
request = self.request
url = self.request.url
self.sendCommand(request.method, url.fullpath())
self.sendHeader('Host', url.location())
for (k, v) in request.headers.items():
self.sendHeader(k, v)
if request.data:
self.sendHeader('Content-Length', len(request.data))
self.endHeaders()
if request.data:
self.transport.write(request.data)
def handleStatus(self, version, status, message):
return self.protocol.handleStatus(version, status, message)
def handleResponse(self, data):
return self.protocol.handleResponse(data)
class AsynchXendClientProtocol(XendClientProtocol):
"""An asynchronous xend client. Uses twisted to connect to xend
and make the request. It does not block waiting for the result,
but sets up a deferred that is called when the result becomes available.
Uses AsynchXendClient to manage the connection.
"""
def __init__(self):
self.err = None
def xendRequest(self, url, method, args=None):
"""Make a request to xend. The returned deferred is called when
the result is available.
@param url: xend request url
@param method: http method: POST or GET
@param args: request arguments (dict)
@return: deferred
"""
request = XendRequest(url, method, args)
self.deferred = Deferred()
clientCreator = ClientCreator(reactor, AsynchXendClient, self, request)
clientCreator.connectTCP(url.host, url.port)
return self.deferred
def callErrback(self, err):
if not self.deferred.called:
self.err = err
self.deferred.errback(err)
return err
def callCallback(self, val):
if not self.deferred.called:
self.deferred.callback(val)
return val
def handleException(self, err):
return self.callErrback(err)
def handleResponse(self, data):
if self.err: return self.err
val = XendClientProtocol.handleResponse(self, data)
if isinstance(val, Exception):
self.callErrback(val)
else:
self.callCallback(val)
return val
class Xend:
"""Client interface to Xend.
"""
"""Default location of the xend server."""
SRV_DEFAULT = "localhost:8000"
@@ -165,222 +307,288 @@ class Xend:
"""Default path to the xend root on the server."""
ROOT_DEFAULT = "/xend/"
def __init__(self, srv=None, root=None):
def __init__(self, client=None, srv=None, root=None):
"""Create a xend client interface.
If the client protocol is not specified, the default
is to use a synchronous protocol.
@param client: client protocol to use
@param srv: server host, and optional port (format host:port)
@param root: xend root path on the server
"""
if client is None:
client = SynchXendClientProtocol()
self.client = client
self.bind(srv, root)
def bind(self, srv=None, root=None):
"""Bind to a given server.
srv server location (host:port)
root server xend root path
@param srv: server location (host:port)
@param root: xend root path on the server
"""
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
(host, port) = srv.split(':', 1)
self.url = URL(host=host, port=port, path=root)
def xendGet(self, url, args=None):
return self.client.xendGet(url, args)
def xendPost(self, url, data):
return self.client.xendPost(url, data)
def nodeurl(self, id=''):
return nodeurl(self.location, self.root, id)
return self.url.relative('node/' + str(id))
def domainurl(self, id=''):
return domainurl(self.location, self.root, id)
return self.url.relative('domain/' + str(id))
def consoleurl(self, id=''):
return consoleurl(self.location, self.root, id)
return self.url.relative('console/' + str(id))
def deviceurl(self, id=''):
return deviceurl(self.location, self.root, id)
return self.url.relative('device/' + str(id))
def vneturl(self, id=''):
return vneturl(self.location, self.root, id)
return self.url.relative('vnet/' + str(id))
def eventurl(self, id=''):
return eventurl(self.location, self.root, id)
return self.url.relative('event/' + str(id))
def dmesgurl(self, id=''):
return dmesgurl(self.location, self.root, id)
return self.url.relative('node/dmesg/' + str(id))
def xend(self):
return xend_get(urljoin(self.location, self.root))
return self.xendGet(self.url)
def xend_node(self):
return xend_get(self.nodeurl())
return self.xendGet(self.nodeurl())
def xend_node_dmesg(self):
return self.xendGet(self.dmesgurl())
def xend_node_cpu_rrobin_slice_set(self, slice):
return xend_call(self.nodeurl(),
{'op' : 'cpu_rrobin_slice_set',
'slice' : slice })
return self.xendPost(self.nodeurl(),
{'op' : 'cpu_rrobin_slice_set',
'slice' : slice })
def xend_node_cpu_bvt_slice_set(self, ctx_allow):
return xend_call(self.nodeurl(),
{'op' : 'cpu_bvt_slice_set',
'ctx_allow' : ctx_allow })
return self.xendPost(self.nodeurl(),
{'op' : 'cpu_bvt_slice_set',
'ctx_allow' : ctx_allow })
def xend_node_cpu_fbvt_slice_set(self, ctx_allow):
return xend_call(self.nodeurl(),
{'op' : 'cpu_fbvt_slice_set',
'ctx_allow' : ctx_allow })
return self.xendPost(self.nodeurl(),
{'op' : 'cpu_fbvt_slice_set',
'ctx_allow' : ctx_allow })
def xend_domains(self):
return xend_get(self.domainurl())
return self.xendGet(self.domainurl())
def xend_domain_create(self, conf):
return xend_call(self.domainurl(),
{'op' : 'create',
'config' : fileof(conf) })
return self.xendPost(self.domainurl(),
{'op' : 'create',
'config' : fileof(conf) })
def xend_domain_restore(self, filename):
return xend_call(self.domainurl(),
{'op' : 'restore',
'file' : filename })
return self.xendPost(self.domainurl(),
{'op' : 'restore',
'file' : filename })
def xend_domain_configure(self, id, config):
return xend_call(self.domainurl(id),
{'op' : 'configure',
'config' : fileof(conf) })
def xend_domain_configure(self, id, conf):
return self.xendPost(self.domainurl(id),
{'op' : 'configure',
'config' : fileof(conf) })
def xend_domain(self, id):
return xend_get(self.domainurl(id))
return self.xendGet(self.domainurl(id))
def xend_domain_unpause(self, id):
return xend_call(self.domainurl(id),
{'op' : 'unpause' })
return self.xendPost(self.domainurl(id),
{'op' : 'unpause' })
def xend_domain_pause(self, id):
return xend_call(self.domainurl(id),
{'op' : 'pause' })
return self.xendPost(self.domainurl(id),
{'op' : 'pause' })
def xend_domain_shutdown(self, id, reason):
return xend_call(self.domainurl(id),
{'op' : 'shutdown',
'reason' : reason })
return self.xendPost(self.domainurl(id),
{'op' : 'shutdown',
'reason' : reason })
def xend_domain_destroy(self, id, reason):
return xend_call(self.domainurl(id),
{'op' : 'destroy',
'reason' : reason })
return self.xendPost(self.domainurl(id),
{'op' : 'destroy',
'reason' : reason })
def xend_domain_save(self, id, filename):
return xend_call(self.domainurl(id),
{'op' : 'save',
'file' : filename })
return self.xendPost(self.domainurl(id),
{'op' : 'save',
'file' : filename })
def xend_domain_migrate(self, id, dst):
return xend_call(self.domainurl(id),
{'op' : 'migrate',
'destination': dst })
return self.xendPost(self.domainurl(id),
{'op' : 'migrate',
'destination': dst })
def xend_domain_pincpu(self, id, cpu):
return xend_call(self.domainurl(id),
{'op' : 'pincpu',
'cpu' : cpu })
return self.xendPost(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' : mcuadv,
'warp' : warp,
'warpl' : warpl,
'warpu' : warpu })
return self.xendPost(self.domainurl(id),
{'op' : 'cpu_bvt_set',
'mcuadv' : mcuadv,
'warp' : warp,
'warpl' : warpl,
'warpu' : warpu })
def xend_domain_cpu_fbvt_set(self, id, mcuadv, warp, warpl, warpu):
return xend_call(self.domainurl(id),
{'op' : 'cpu_fbvt_set',
'mcuadv' : mcuadv,
'warp' : warp,
'warpl' : warpl,
'warpu' : warpu })
return self.xendPost(self.domainurl(id),
{'op' : 'cpu_fbvt_set',
'mcuadv' : mcuadv,
'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 })
return self.xendPost(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' })
return self.xendGet(self.domainurl(id),
{ 'op' : 'vifs' })
def xend_domain_vif(self, id, vif):
return xend_get(self.domainurl(id),
{ 'op' : 'vif',
'vif' : vif })
return self.xendGet(self.domainurl(id),
{ 'op' : 'vif',
'vif' : vif })
def xend_domain_vbds(self, id):
return xend_get(self.domainurl(id),
{'op' : 'vbds'})
return self.xendGet(self.domainurl(id),
{'op' : 'vbds'})
def xend_domain_vbd(self, id, vbd):
return xend_get(self.domainurl(id),
{'op' : 'vbd',
'vbd' : vbd })
return self.xendGet(self.domainurl(id),
{'op' : 'vbd',
'vbd' : vbd })
def xend_domain_device_create(self, id, config):
return xend_call(self.domainurl(id),
{'op' : 'device_create',
'config' : fileof(config) })
return self.xendPost(self.domainurl(id),
{'op' : 'device_create',
'config' : fileof(config) })
def xend_domain_device_destroy(self, id, type, idx):
return xend_call(self.domainurl(id),
{'op' : 'device_destroy',
'type' : type,
'index' : idx })
return self.xendPost(self.domainurl(id),
{'op' : 'device_destroy',
'type' : type,
'index' : idx })
def xend_consoles(self):
return xend_get(self.consoleurl())
return self.xendGet(self.consoleurl())
def xend_console(self, id):
return xend_get(self.consoleurl(id))
return self.xendGet(self.consoleurl(id))
def xend_vnets(self):
return xend_get(self.vneturl())
return self.xendGet(self.vneturl())
def xend_vnet_create(self, conf):
return xend_call(self.vneturl(),
{'op': 'create', 'config': fileof(conf) })
return self.xendPost(self.vneturl(),
{'op' : 'create',
'config' : fileof(conf) })
def xend_vnet(self, id):
return xend_get(self.vneturl(id))
return self.xendGet(self.vneturl(id))
def xend_vnet_delete(self, id):
return xend_call(self.vneturl(id),
{'op': 'delete' })
return self.xendPost(self.vneturl(id),
{'op' : 'delete' })
def xend_event_inject(self, sxpr):
val = xend_call(self.eventurl(),
{'op': 'inject', 'event': fileof(sxpr) })
val = self.xendPost(self.eventurl(),
{'op' : 'inject',
'event' : fileof(sxpr) })
def xend_dmesg(self):
return xend_get(self.dmesgurl())
return self.xendGet(self.dmesgurl())
def xendmain(srv, asynch, fn, args):
if asynch:
client = AsynchXendClientProtocol()
else:
client = None
xend = Xend(srv=srv, client=client)
xend.rc = 0
try:
v = getattr(xend, fn)(*args)
except XendError, err:
print 'ERROR:', err
return 1
if asynch:
def cbok(val):
PrettyPrint.prettyprint(val)
reactor.stop()
def cberr(err):
print 'ERROR:', err
xend.rc = 1
reactor.stop()
v.addCallback(cbok)
v.addErrback(cberr)
reactor.run()
return xend.rc
else:
PrettyPrint.prettyprint(v)
return 0
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
python XendClient.py domains
(0 8)
python XendClient.py domain 0
(domain (id 0) (name Domain-0) (memory 128))
"""
server = Xend()
fn = argv[1]
global DEBUG
from getopt import getopt
short_options = 'x:ad'
long_options = ['xend=', 'asynch', 'debug']
(options, args) = getopt(argv[1:], short_options, long_options)
srv = None
asynch = 0
for k, v in options:
if k in ['-x', '--xend']:
srv = v
elif k in ['-a', '--asynch']:
asynch = 1
elif k in ['-d', '--debug']:
DEBUG = 1
if len(args):
fn = args[0]
args = args[1:]
else:
fn = 'xend'
args = []
if not fn.startswith('xend'):
fn = 'xend_' + fn
args = argv[2:]
val = getattr(server, fn)(*args)
PrettyPrint.prettyprint(val)
print
sys.exit(xendmain(srv, asynch, fn, args))
if __name__ == "__main__":
main(sys.argv)
else:
server = Xend()
aserver = Xend( AsynchXendClientProtocol() )
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.