diff --git a/.rootkeys b/.rootkeys index b8f1f7b07b..40189aedaa 100644 --- a/.rootkeys +++ b/.rootkeys @@ -365,6 +365,35 @@ 40c9c469yrm31i60pGKslTi2Zgpotg tools/python/xen/xend/server/messages.py 40c9c46925x-Rjb0Cv2f1-l2jZrPYg tools/python/xen/xend/server/netif.py 40c9c469ZqILEQ8x6yWy0_51jopiCg tools/python/xen/xend/server/params.py +40fcefb2qm13BbRZBydAatOavaS0fQ tools/python/xen/xend/sv/DomInfo.py +40fcefb2-RIU8GB67mJMRzybME9bxw tools/python/xen/xend/sv/DomList.py +40fcefb23FfQn-ZBCbcHqA0cPGqQxw tools/python/xen/xend/sv/GenTabbed.py +40fcefb2QZAn3u3sX-M7NXBjOv5HGg tools/python/xen/xend/sv/HTMLBase.py +40fcefb2vnfDbl4w_yCTedROPuqs0g tools/python/xen/xend/sv/Main.py +40fcefb2K1xqVVT4D-p7nL2GzS4scg tools/python/xen/xend/sv/Main.rpy +40fcefb24h-04WaHag-Tg4nxWPhTig tools/python/xen/xend/sv/NodeInfo.py +40fcefb2Sif__6AqrANeBQZZfvP-6w tools/python/xen/xend/sv/TabView.py +40fcefb23s0sQlDfl4sPP0Un8oZGhg tools/python/xen/xend/sv/XendClientDeferred.py +40fcefb2DqteqCCZYDCvvh4Q5jBd0w tools/python/xen/xend/sv/__init__.py +40fcefb2Nhe-sT74KBB_3mYQg9Dl4Q tools/python/xen/xend/sv/images/internet copy.jpg +40fcefb2QmVa4xdjdnSTXEdF2fZCDA tools/python/xen/xend/sv/images/internet.jpg +40fcefb2g8Ez5jJIPHGN_KX7GtxV4w tools/python/xen/xend/sv/images/internet.psd +40fcefb3wXQMsl9WkgQAVtdrupm4sw tools/python/xen/xend/sv/images/left-end-highlight.jpg +40fcefb3K6ESt5sQhD9aCQRscQIlXQ tools/python/xen/xend/sv/images/left-end-no-highlight.jpg +40fcefb3BUT98zPzW8kAFKuxGdh4XA tools/python/xen/xend/sv/images/middle-highlight.jpg +40fcefb38OTgsUKHBpwshLLIsiIaCA tools/python/xen/xend/sv/images/middle-no-highlight.jpg +40fcefb32SPtrw36c4S6YGFlLvkKuw tools/python/xen/xend/sv/images/orb_01.jpg +40fcefb3Ok5qkX3iM7ZEPVkRInrUpg tools/python/xen/xend/sv/images/orb_02.jpg +40fcefb3JnT5XeKTuVF4yUMGOtuNZg tools/python/xen/xend/sv/images/right-end-highlight.jpg +40fcefb3-DuYOS7noo2W7b_0p7TOUg tools/python/xen/xend/sv/images/right-end-no-highlight.jpg +40fcefb3qNbAZR5FYGPAZ9sFPVMTDA tools/python/xen/xend/sv/images/seperator-left-highlight.jpg +40fcefb3dgsa24WLk_BJeYQHrDLuOg tools/python/xen/xend/sv/images/seperator-right-highlight.jpg +40fcefb3FtiX4Pd2kT8wDlp8u8xRhQ tools/python/xen/xend/sv/images/seperator.jpg +40fcefb3yMSrZvApO9ToIi-iQwnchA tools/python/xen/xend/sv/images/xen.png +40fcefb310mW7U0p7JMoBQVnjf76xg tools/python/xen/xend/sv/inc/bottom.htm +40fcefb3zGC9XNBkSwTEobCoq8YClA tools/python/xen/xend/sv/inc/style.css +40fcefb4oxovdYkUvExZSkHN0cy_Ow tools/python/xen/xend/sv/inc/top.htm +40fcefb4rnaZNjqsBu7A5V2rlLyqRw tools/python/xen/xend/sv/util.py 40c9c469LNxLVizOUpOjEaTKKCm8Aw tools/python/xen/xend/sxp.py 40d05079aFRp6NQdo5wIh5Ly31c0cg tools/python/xen/xm/__init__.py 40cf2937gKQcATgXKGtNeWb1PDH5nA tools/python/xen/xm/create.py diff --git a/tools/python/xen/xend/server/SrvServer.py b/tools/python/xen/xend/server/SrvServer.py index 9bc42f4217..1ce3446058 100644 --- a/tools/python/xen/xend/server/SrvServer.py +++ b/tools/python/xen/xend/server/SrvServer.py @@ -25,8 +25,8 @@ # todo Support security settings etc. in the config file. # todo Support command-line args. -from twisted.web import server -from twisted.web import resource +from twisted.web import server, static +from twisted.web import resource, script from twisted.internet import reactor from xen.xend import XendRoot @@ -44,8 +44,12 @@ def create(port=None, interface=None, bridge=0): if bridge or xroot.rebooted: Vifctl.network('start') root = resource.Resource() + sv = static.File( "/usr/lib/python2.2/site-packages/xen/xend/sv/" ) + sv.indexNames=['Main.rpy'] + sv.processors={'.rpy':script.ResourceScript} xend = SrvRoot() root.putChild('xend', xend) + root.putChild('sv', sv) site = server.Site(root) reactor.listenTCP(port, site, interface=interface) diff --git a/tools/python/xen/xend/sv/DomInfo.py b/tools/python/xen/xend/sv/DomInfo.py new file mode 100755 index 0000000000..3c5642a770 --- /dev/null +++ b/tools/python/xen/xend/sv/DomInfo.py @@ -0,0 +1,99 @@ +from HTMLBase import HTMLBase +from XendClientDeferred import server +from xen.xend import PrettyPrint + +from xen.xend.sv.util import * +from xen.xend.sv.GenTabbed import * + +class DomInfo( GenTabbed ): + + def __init__( self, urlWriter, callback ): + + 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 ) + + def write_BODY( self, request ): + dom = request.args.get('dom') + + if dom is None or len(dom) != 1: + request.write( "

Please Select a Domain

" ) + return None + else: + self.dom = dom[0] + + GenTabbed.write_BODY( self, request ) + +class DomGenTab( GeneralTab ): + + def __init__( self ): + + titles = {} + + titles[ 'ID' ] = 'dom' + titles[ 'Name' ] = 'name' + titles[ 'CPU' ] = 'cpu' + titles[ 'Memory' ] = ( 'mem', memoryFormatter ) + titles[ 'State' ] = ( 'state', stateFormatter ) + titles[ 'Total CPU' ] = ( 'cpu_time', smallTimeFormatter ) + titles[ 'Up Time' ] = ( 'up_time', bigTimeFormatter ) + + GeneralTab.__init__( self, "General Domain Info", {}, titles ) + + def write_BODY( self, request, callback ): + dom = request.args.get('dom') + + if dom is None or len(dom) != 1: + request.write( "

Please Select a Domain

" ) + return None + 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 + + GeneralTab.write_BODY( self, request, callback ) + +class DomSXPTab( PreTab ): + + def __init__( self ): + 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 ): + dom = request.args.get('dom') + + if dom is None or len(dom) != 1: + request.write( "

Please Select a Domain

" ) + return None + else: + self.dom = dom[0] + + deferred = server.xend_domain( self.dom ) + + deferred.addCallback( self.fn, request ) + deferred.addCallback( self.fn2, callback ) + def errback( x ): + print ">err ", x + deferred.addErrback( errback ) \ No newline at end of file diff --git a/tools/python/xen/xend/sv/DomList.py b/tools/python/xen/xend/sv/DomList.py new file mode 100755 index 0000000000..8fa74dff93 --- /dev/null +++ b/tools/python/xen/xend/sv/DomList.py @@ -0,0 +1,101 @@ +from twisted.web import resource +from twisted.web.server import NOT_DONE_YET + +from XendClientDeferred import server as XendServer +from xen.xend import sxp + +from xen.xend.sv.HTMLBase import HTMLBase +from xen.xend.sv.util import * + +from twisted.internet import reactor + +class DomList( HTMLBase ): + + isLeaf = True + + def __init__( self, urlWriter, callback ): + 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 ): + + 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 = "%(dom)-4d\n" % domInfoHash + + url = self.urlWriter( "mod=info&dom=%(dom)-4d" % domInfoHash ) + + domStr += "%s\n" % ( url, domInfoHash['name'] ) + + if self.long: + domStr += "%(mem)7d\n" % domInfoHash + domStr += "%(cpu)3d\n" % domInfoHash + + domStr += "%(state)5s\n" % domInfoHash + + if self.long: + domStr += "%(cpu_time)7.1f\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\n" ) + + if self.head: + request.write( "" ) + self.write_DOMAIN_HEAD( request, self.long ) + request.write( "" ) + + odd = True + for domain in self.rendered_domains.values(): + if odd: + request.write( "\n" ) + odd = False + else: + request.write( "\n" ) + odd = True + request.write( domain ) + request.write( "\n" ) + + request.write( "
\n" ) + + self.callback( request ) + + def write_DOMAIN_HEAD( self, request, long=True ): + request.write( "Domain\n" ) + request.write( "Name\n" ) + if long: + request.write( "Memory / Mb\n" ) + request.write( "CPU\n" ) + request.write( "State\n" ) + if long: + request.write( "CPU time / s\n" ) + diff --git a/tools/python/xen/xend/sv/GenTabbed.py b/tools/python/xen/xend/sv/GenTabbed.py new file mode 100755 index 0000000000..4f34a0692c --- /dev/null +++ b/tools/python/xen/xend/sv/GenTabbed.py @@ -0,0 +1,103 @@ +import types + +from HTMLBase import HTMLBase +from TabView import TabView + +class GenTabbed( HTMLBase ): + + def __init__( self, urlWriter, tabStrings, tabObjects, callback ): + 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') + + if tab is None or len( tab) != 1: + self.tab = 0 + else: + self.tab = int( tab[0] ) + + request.write( "" ) + request.write( "
" ) + + TabView( self.tab, self.tabStrings, self.urlWriter ).write_BODY( request ) + + request.write( "
" ) + + render_tab = self.tabObjects[ self.tab ]() + + if render_tab is None: + request.write( "

Bad Tab

" ) + self.finish_BODY( request ) + else: + render_tab.write_BODY( request, self.finish_BODY ) + + def finish_BODY( self, request ): + + request.write( "
" ) + + self.callback( request ) + +class PreTab( HTMLBase ): + + def __init__( self, source ): + HTMLBase.__init__( self ) + self.source = source + + def write_BODY( self, request, callback ): + + request.write( "
" )
+        
+        request.write( self.source )
+        
+        request.write( "
" ) + + callback( request ) + +class GeneralTab( HTMLBase ): + + def __init__( self, title, dict, titles ): + HTMLBase.__init__( self ) + self.title = title + self.dict = dict + self.titles = titles + + def write_BODY( self, request, callback ): + + request.write( "

%s

" % self.title ) + + request.write( "" ) + + def writeAttr( niceName, attr, formatter=None ): + if type( attr ) is types.TupleType: + ( attr, formatter ) = attr + + if attr in self.dict: + if formatter: + temp = formatter( self.dict[ attr ] ) + else: + temp = str( self.dict[ attr ] ) + request.write( "" % ( niceName, temp ) ) + + for niceName, attr in self.titles.items(): + writeAttr( niceName, attr ) + + request.write( "

%s:

%s

" ) + + callback( request ) + +class NullTab( HTMLBase ): + + def __init__( self ): + HTMLBase.__init__( self ) + self.title = "Null Tab" + + def write_BODY( self, request, callback ): + request.write( "

%s

" % self.title ) + callback( request ) + + \ No newline at end of file diff --git a/tools/python/xen/xend/sv/HTMLBase.py b/tools/python/xen/xend/sv/HTMLBase.py new file mode 100755 index 0000000000..da8c03b366 --- /dev/null +++ b/tools/python/xen/xend/sv/HTMLBase.py @@ -0,0 +1,30 @@ +from twisted.web import server, resource +from twisted.internet import reactor + +class HTMLBase( resource.Resource ): + + isLeaf = True + + defaultPath = "/usr/lib/python2.2/site-packages/xen/xend/sv/" + + def __init__( self ): + resource.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_BOTTOM( request ) + request.finish() + + def write_BODY( self, request ): + request.write( "BODY" ) + + def write_TOP( self, request ): + f = open( self.defaultPath + 'inc/top.htm', 'r' ) + request.write( f.read() ) + + def write_BOTTOM( self, request ): + f = open( self.defaultPath + 'inc/bottom.htm', 'r' ) + request.write( f.read() ) \ No newline at end of file diff --git a/tools/python/xen/xend/sv/Main.py b/tools/python/xen/xend/sv/Main.py new file mode 100755 index 0000000000..366e8a8124 --- /dev/null +++ b/tools/python/xen/xend/sv/Main.py @@ -0,0 +1,81 @@ +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.xend.sv import DomList, NodeInfo, DomInfo + +class Main( HTMLBase ): + + isLeaf = True + + def __init__( self ): + HTMLBase.__init__(self) + + def render_POST( self, request ): + return self.render_GET( request ) + + def mainUrlWriter( self, s ): + return "Main.rpy?%s" % s + + def write_BODY( self, request, callback ): + + self.callback = callback + + request.write( "\n\n" ) + request.write( "\n" ) + request.write( " " ) + request.write( " \n" ) + request.write( " " ) + request.write( " \n" ) + request.write( " " ) + request.write( "\n" ) + + request.write( "
 " ) + request.write( " " ) + request.write( " " ) + request.write( " " ) + request.write( "
" ) + request.write( "
" ) + + request.write( "

Node details

" ) + request.write( "

Domains summary

" ) + + DomList.DomList( self.mainUrlWriter, self.continue_BODY ).write_BODY( request, True, False ) + + return NOT_DONE_YET + + def continue_BODY( self, request ): + request.write( "
" ) + request.write( "  " ) + request.write( "
 " ) + request.write( " " ) + request.write( " " ) + request.write( " " ) + request.write( "
" ) + + mod = request.args.get('mod') + + if mod is None or len(mod) != 1: + request.write( '

Please select a module

' ) + self.finish_BODY( request ) + elif mod[0] == 'info': + DomInfo.DomInfo( self.mainUrlWriter, self.finish_BODY ).write_BODY( request ) + elif mod[0] == 'list': + DomList.DomList( self.mainUrlWriter, self.finish_BODY ).write_BODY( request ) + elif mod[0] == 'node': + NodeInfo.NodeInfo( self.mainUrlWriter, self.finish_BODY ).write_BODY( request ) + else: + request.write( '

Invalid module. Please select another

' ) + self.finish_BODY( request ) + + def finish_BODY( self, request ): + + request.write( "
" ) + request.write( "
 
\n" ) + + self.callback( request ) + \ No newline at end of file diff --git a/tools/python/xen/xend/sv/Main.rpy b/tools/python/xen/xend/sv/Main.rpy new file mode 100755 index 0000000000..90698027a6 --- /dev/null +++ b/tools/python/xen/xend/sv/Main.rpy @@ -0,0 +1,3 @@ +from xen.xend.sv.Main import * + +resource = Main() \ No newline at end of file diff --git a/tools/python/xen/xend/sv/NodeInfo.py b/tools/python/xen/xend/sv/NodeInfo.py new file mode 100755 index 0000000000..7d69f4eb50 --- /dev/null +++ b/tools/python/xen/xend/sv/NodeInfo.py @@ -0,0 +1,47 @@ +from xen.xend import XendDmesg +from xen.xend import XendNode + +from xen.xend.sv.util import * +from xen.xend.sv.GenTabbed import * +from xen.xend.sv.HTMLBase import HTMLBase + +class NodeInfo( GenTabbed ): + + def __init__( self, urlWriter, callback ): + + def newUrlWriter( url ): + return urlWriter( "mod=node%s" % url ) + + GenTabbed.__init__( self, newUrlWriter, [ 'General', 'Dmesg' ], [ NodeGeneralTab, NodeDmesgTab ], callback ) + +class NodeGeneralTab( GeneralTab ): + + def __init__( self ): + + nodeInfo = XendNode.instance().info() + + dictNodeInfo = {} + + for l in nodeInfo: + dictNodeInfo[ l[0] ] = l[1] + + dictTitles = {} + dictTitles[ 'System' ] = 'system' + dictTitles[ 'Hostname' ] = 'host' + dictTitles[ 'Release' ] = 'release' + dictTitles[ 'Version' ] ='version' + dictTitles[ 'Machine' ] = 'machine' + dictTitles[ 'Cores' ] = 'cores' + dictTitles[ 'Hyperthreading' ] = ( 'hyperthreads_per_core', hyperthreadFormatter ) + dictTitles[ 'CPU Speed' ] = ( 'cpu_mhz', cpuFormatter ) + dictTitles[ 'Memory' ] = ( 'memory', memoryFormatter ) + dictTitles[ 'Free Memory' ] = ( 'free_memory', memoryFormatter ) + + GeneralTab.__init__( self, title="General Node Info", dict=dictNodeInfo, titles=dictTitles ) + +class NodeDmesgTab( PreTab ): + + def __init__( self ): + self.xd = XendDmesg.instance() + PreTab.__init__( self, self.xd.info()[0] ) + \ No newline at end of file diff --git a/tools/python/xen/xend/sv/TabView.py b/tools/python/xen/xend/sv/TabView.py new file mode 100755 index 0000000000..70c485c329 --- /dev/null +++ b/tools/python/xen/xend/sv/TabView.py @@ -0,0 +1,49 @@ +from xen.xend.sv.HTMLBase import HTMLBase + +class TabView( HTMLBase ): + + def __init__( self, tab, tabs, urlWriter ): + HTMLBase.__init__(self) + self.tab = tab # interger - tab id + self.tabs = tabs + self.urlWriter = urlWriter + + def write_BODY( self, request ): + request.write( "" ) + request.write( "" ) + + if self.tab == 0: + image = "left-end-highlight.jpg" + else: + image = "left-end-no-highlight.jpg" + + request.write( "" % image ) + + count = len( self.tabs ) + + for i in range( count ): + + if i == self.tab: + image = "middle-highlight.jpg" + else: + image = "middle-no-highlight.jpg" + + request.write( "" % ( image, self.urlWriter( "&tab=%s" % i ), self.tabs[ i ] ) ) + + if i < count-1: + if i == self.tab: + image = "seperator-left-highlight.jpg" + elif self.tab == i+1: + image = "seperator-right-highlight.jpg" + else: + image = "seperator.jpg" + + request.write( "" % image ) + + if self.tab == count - 1: + image = "right-end-highlight.jpg" + else: + image = "right-end-no-highlight.jpg" + + request.write( "" % image ) + request.write( "

%s

" ) diff --git a/tools/python/xen/xend/sv/XendClientDeferred.py b/tools/python/xen/xend/sv/XendClientDeferred.py new file mode 100755 index 0000000000..9f8a16d129 --- /dev/null +++ b/tools/python/xen/xend/sv/XendClientDeferred.py @@ -0,0 +1,363 @@ +# Copyright (C) 2004 Tom Wilkie +# Copyright (C) 2004 Mike Wray +"""Client API for the HTTP interface on xend. +Callable as a script - see main(). + +This API is the 'control-plane' for xend. +The 'data-plane' is done separately. For example, consoles +are accessed via sockets on xend, but the list of consoles +is accessible via this API. + +This one is similar to mikes, but works in an async fashion +""" +import sys +import httplib +import types +from StringIO import StringIO +import urlparse + +from xen.xend.encode import * +from xen.xend.sxp import * +from xen.xend.PrettyPrint import prettyprint + +from twisted.protocols.http import HTTPClient +from twisted.internet.protocol import ClientCreator +from twisted.internet.defer import Deferred +from twisted.internet import reactor + +DEBUG = 0 + +class XendRequest( HTTPClient ): + def __init__(self, deferred, urls): + self.urls = urls + self.deferred = deferred + + def connectionMade(self): + self.sendCommand('GET', self.urls[2]) + self.sendHeader('Host', '%s:%d' % (self.urls[0], self.urls[1]) ) + self.endHeaders() + + def handleResponse(self, data): + self.deferred.callback( data ) + +def process_SXP( sexp ): + pin = Parser() + pin.input(sexp) + pin.input_eof() + return pin.get_val() + +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) + """ + urlinfo = urlparse.urlparse(url) + (uproto, ulocation, upath, uparam, uquery, ufrag) = urlinfo + (hdr, args) = encode_data(data) + if data and method == 'GET': + upath += '?' + args + args = None + if method == "POST" and upath.endswith('/'): + upath = upath[:-1] + + deferred = Deferred() + + clientCreator = ClientCreator( reactor, XendRequest, deferred, (ulocation, 8000, upath) ) + clientCreator.connectTCP( ulocation, 8000 ) + + deferred.addCallback( process_SXP ) + + return deferred + +class XendError(RuntimeError): + 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. + 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_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 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. + """ + return xend_request(url, "POST", data) + +class Xend: + + """Default location of the xend server.""" + SRV_DEFAULT = "localhost" + + """Default path to the xend root on the server.""" + ROOT_DEFAULT = "/xend/" + + def __init__(self, srv=None, root=None): + 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 + """ + 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, ctx_allow): + return xend_call(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 }) + + 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, reason): + return xend_call(self.domainurl(id), + {'op' : 'shutdown', + 'reason' : reason }) + + 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' : 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 }) + + + 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:] + deferred = getattr(server, fn)(*args) + deferred.addCallback( prettyprint ) + reactor.run() + print + +if __name__ == "__main__": + main(sys.argv) +else: + server = Xend() diff --git a/tools/python/xen/xend/sv/__init__.py b/tools/python/xen/xend/sv/__init__.py new file mode 100755 index 0000000000..8d1c8b69c3 --- /dev/null +++ b/tools/python/xen/xend/sv/__init__.py @@ -0,0 +1 @@ + diff --git a/tools/python/xen/xend/sv/images/internet copy.jpg b/tools/python/xen/xend/sv/images/internet copy.jpg new file mode 100755 index 0000000000..92eafeb9fe Binary files /dev/null and b/tools/python/xen/xend/sv/images/internet copy.jpg differ diff --git a/tools/python/xen/xend/sv/images/internet.jpg b/tools/python/xen/xend/sv/images/internet.jpg new file mode 100755 index 0000000000..74a03c3a78 Binary files /dev/null and b/tools/python/xen/xend/sv/images/internet.jpg differ diff --git a/tools/python/xen/xend/sv/images/internet.psd b/tools/python/xen/xend/sv/images/internet.psd new file mode 100644 index 0000000000..a2e9d1754f Binary files /dev/null and b/tools/python/xen/xend/sv/images/internet.psd differ diff --git a/tools/python/xen/xend/sv/images/left-end-highlight.jpg b/tools/python/xen/xend/sv/images/left-end-highlight.jpg new file mode 100644 index 0000000000..3922eb593a Binary files /dev/null and b/tools/python/xen/xend/sv/images/left-end-highlight.jpg differ diff --git a/tools/python/xen/xend/sv/images/left-end-no-highlight.jpg b/tools/python/xen/xend/sv/images/left-end-no-highlight.jpg new file mode 100644 index 0000000000..ded4e3933b Binary files /dev/null and b/tools/python/xen/xend/sv/images/left-end-no-highlight.jpg differ diff --git a/tools/python/xen/xend/sv/images/middle-highlight.jpg b/tools/python/xen/xend/sv/images/middle-highlight.jpg new file mode 100644 index 0000000000..db9829d9bf Binary files /dev/null and b/tools/python/xen/xend/sv/images/middle-highlight.jpg differ diff --git a/tools/python/xen/xend/sv/images/middle-no-highlight.jpg b/tools/python/xen/xend/sv/images/middle-no-highlight.jpg new file mode 100644 index 0000000000..da3b4f68a0 Binary files /dev/null and b/tools/python/xen/xend/sv/images/middle-no-highlight.jpg differ diff --git a/tools/python/xen/xend/sv/images/orb_01.jpg b/tools/python/xen/xend/sv/images/orb_01.jpg new file mode 100755 index 0000000000..e30efc4985 Binary files /dev/null and b/tools/python/xen/xend/sv/images/orb_01.jpg differ diff --git a/tools/python/xen/xend/sv/images/orb_02.jpg b/tools/python/xen/xend/sv/images/orb_02.jpg new file mode 100755 index 0000000000..e5ebc8e4b1 Binary files /dev/null and b/tools/python/xen/xend/sv/images/orb_02.jpg differ diff --git a/tools/python/xen/xend/sv/images/right-end-highlight.jpg b/tools/python/xen/xend/sv/images/right-end-highlight.jpg new file mode 100644 index 0000000000..1ffee341ab Binary files /dev/null and b/tools/python/xen/xend/sv/images/right-end-highlight.jpg differ diff --git a/tools/python/xen/xend/sv/images/right-end-no-highlight.jpg b/tools/python/xen/xend/sv/images/right-end-no-highlight.jpg new file mode 100644 index 0000000000..0ddd058d67 Binary files /dev/null and b/tools/python/xen/xend/sv/images/right-end-no-highlight.jpg differ diff --git a/tools/python/xen/xend/sv/images/seperator-left-highlight.jpg b/tools/python/xen/xend/sv/images/seperator-left-highlight.jpg new file mode 100644 index 0000000000..c90f4ffd12 Binary files /dev/null and b/tools/python/xen/xend/sv/images/seperator-left-highlight.jpg differ diff --git a/tools/python/xen/xend/sv/images/seperator-right-highlight.jpg b/tools/python/xen/xend/sv/images/seperator-right-highlight.jpg new file mode 100644 index 0000000000..f37e6cd546 Binary files /dev/null and b/tools/python/xen/xend/sv/images/seperator-right-highlight.jpg differ diff --git a/tools/python/xen/xend/sv/images/seperator.jpg b/tools/python/xen/xend/sv/images/seperator.jpg new file mode 100644 index 0000000000..c77e2c5500 Binary files /dev/null and b/tools/python/xen/xend/sv/images/seperator.jpg differ diff --git a/tools/python/xen/xend/sv/images/xen.png b/tools/python/xen/xend/sv/images/xen.png new file mode 100644 index 0000000000..344c361b3c Binary files /dev/null and b/tools/python/xen/xend/sv/images/xen.png differ diff --git a/tools/python/xen/xend/sv/inc/bottom.htm b/tools/python/xen/xend/sv/inc/bottom.htm new file mode 100755 index 0000000000..4d4a7e5285 --- /dev/null +++ b/tools/python/xen/xend/sv/inc/bottom.htm @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/tools/python/xen/xend/sv/inc/style.css b/tools/python/xen/xend/sv/inc/style.css new file mode 100644 index 0000000000..e819f9254e --- /dev/null +++ b/tools/python/xen/xend/sv/inc/style.css @@ -0,0 +1,30 @@ + +P {font-family: verdana, arial; font-size: 12px; color: black} +.small {font-size: 10px} + +TD.domainInfo {font-family: verdana, arial; font-size: 10px; color: black} +TD.domainInfoHead {font-family: verdana, arial; font-size: 10px; color: white; font-face: bold} + +TD.domainInfoHead {background-color: black} +TR.domainInfoOdd {background-color: white} +TR.domainInfoEven {background-color: lightgrey} + +body { + width: 670px; + margin: 0px; + padding: 0px; + background-color: #fff; + background-image: url(../images/orb_02.jpg); + background-repeat: repeat-y; + background-position: left top; + font-family: Arial, Helvetica, sans-serif; + font-weight: bold; + color: #333333; + letter-spacing: 0px; + scrollbar-base-color: #333333; + scrollbar-track-color: #666666; + scrollbar-face-color: #fff; + + + } + \ No newline at end of file diff --git a/tools/python/xen/xend/sv/inc/top.htm b/tools/python/xen/xend/sv/inc/top.htm new file mode 100755 index 0000000000..ace62cb6bd --- /dev/null +++ b/tools/python/xen/xend/sv/inc/top.htm @@ -0,0 +1,8 @@ + + + + Xen + + + + \ No newline at end of file diff --git a/tools/python/xen/xend/sv/util.py b/tools/python/xen/xend/sv/util.py new file mode 100755 index 0000000000..06b7017b0b --- /dev/null +++ b/tools/python/xen/xend/sv/util.py @@ -0,0 +1,64 @@ +from xen.xend.sv.XendClientDeferred import server +from xen.xend import sxp + +def getDomInfoHash( domain ): + deferred = server.xend_domain( int( domain ) ) + deferred.addCallback( procDomInfo, domain ) + return deferred + +def procDomInfo( domInfo, domain ): + d = {} + d['dom'] = int( domain ) + d['name'] = sxp.child_value( domInfo, 'name' ) + d['mem'] = int( sxp.child_value( domInfo, 'memory' ) ) + d['cpu'] = int( sxp.child_value( domInfo, 'cpu' ) ) + d['state'] = sxp.child_value( domInfo, 'state' ) + d['cpu_time'] = float( sxp.child_value( domInfo, 'cpu_time' ) ) + if( sxp.child_value( domInfo, 'up_time' ) ): + d['up_time'] = float( sxp.child_value( domInfo, 'up_time' ) ) + if( sxp.child_value( domInfo, 'start_time' ) ): + d['start_time'] = float( sxp.child_value( domInfo, 'start_time' ) ) + return d + +def bigTimeFormatter( time ): + weeks = time // 604800 + remainder = time % 604800 + days = remainder // 86400 + + remainder = remainder % 86400 + + hms = smallTimeFormatter( remainder ) + + return "%d weeks, %d days, %s" % ( weeks, days, hms ) + +def smallTimeFormatter( time ): + hours = time // 3600 + remainder = time % 3600 + mins = remainder // 60 + secs = time % 60 + return "%02d:%02d:%04.1f (hh:mm:ss.s)" % ( hours, mins, secs ) + +def stateFormatter( state ): + states = [ 'Running', 'Blocked', 'Paused', 'Shutdown', 'Crashed' ] + + for i in range( len( state ) ): + if state[i] != "-": + return states[ i ] + " (%s)" % state + + return state + +def memoryFormatter( mem ): + return "%7dMb" % mem + +def cpuFormatter( mhz ): + if mhz > 1000: + ghz = float( mhz ) / 1000.0 + return "%4.2fGHz" % ghz + else: + return "%4dMHz" % mhz + +def hyperthreadFormatter( threads ): + if int( threads ) > 1: + return "Yes (%d)" % threads + else: + return "No" \ No newline at end of file