# HG changeset patch
# User kaf24@xxxxxxxxxxxxxxxxxxxx
# Node ID 6c24d2b4f3eaf85e64879b03f159a2edce4e3719
# Parent  d63b100b327ab8354bc9a71c38dbca436c64c0a5
# Parent  df19d43b95d03054fa4534fe8449e0c05aaec1fc
Manual merge.
diff -r d63b100b327a -r 6c24d2b4f3ea tools/Makefile
--- a/tools/Makefile    Tue Jul 26 10:09:06 2005
+++ b/tools/Makefile    Tue Jul 26 15:16:12 2005
@@ -13,6 +13,7 @@
 SUBDIRS += pygrub
 SUBDIRS += firmware
 SUBDIRS += policy
+SUBDIRS += sv
 
 .PHONY: all install clean check check_clean ioemu eioemuinstall ioemuclean
 
diff -r d63b100b327a -r 6c24d2b4f3ea tools/python/setup.py
--- a/tools/python/setup.py     Tue Jul 26 10:09:06 2005
+++ b/tools/python/setup.py     Tue Jul 26 15:16:12 2005
@@ -51,6 +51,7 @@
                          'xen.xend.xenstore',
                          'xen.xm',
                          'xen.web',
+                                                'xen.sv'
                          ],
       ext_package = "xen.lowlevel",
       ext_modules = [ xc, xu, xs ]
diff -r d63b100b327a -r 6c24d2b4f3ea tools/python/xen/sv/CreateDomain.py
--- /dev/null   Tue Jul 26 10:09:06 2005
+++ b/tools/python/xen/sv/CreateDomain.py       Tue Jul 26 15:16:12 2005
@@ -0,0 +1,163 @@
+from xen.sv.Wizard import *
+from xen.sv.util import *
+from xen.sv.GenTabbed import PreTab
+
+from xen.xm.create import make_config, OptVals
+
+from xen.xend.XendClient import server
+
+class CreateDomain( Wizard ):
+    def __init__( self, urlWriter ):
+       
+       sheets = [ CreatePage0,
+                  CreatePage1,
+                  CreatePage2,
+                   CreatePage3,
+                   CreatePage4,
+                   CreateFinish ]
+    
+       Wizard.__init__( self, urlWriter, "Create Domain", sheets )
+       
+class CreatePage0( Sheet ):
+
+    def __init__( self, urlWriter ):
+        Sheet.__init__( self, urlWriter, "General", 0 )
+        self.addControl( InputControl( 'name', 'VM Name', 'VM Name:', 
"[\\w|\\S]+", "You must enter a name in this field" ) )
+        self.addControl( InputControl( 'memory', '64', 'Memory (Mb):', 
"[\\d]+", "You must enter a number in this field" ) )
+        self.addControl( InputControl( 'cpu', '0', 'CPU:', "[\\d]+", "You must 
enter a number in this feild" ) )
+        self.addControl( InputControl( 'cpu_weight', '1', 'CPU Weight:', 
"[\\d]+", "You must enter a number in this feild" ) )
+                        
+class CreatePage1( Sheet ):
+
+    def __init__( self, urlWriter ):
+        Sheet.__init__( self, urlWriter, "Setup Kernel Image", 1 )
+# For now we don't need to select a builder...
+#        self.addControl( ListControl( 'builder', [('linux', 'Linux'), 
('netbsd', 'NetBSD')], 'Kernel Type:' ) )
+        self.addControl( FileControl( 'kernel', '/boot/vmlinuz-2.6.9-xenU', 
'Kernel Image:' ) )
+        self.addControl( InputControl( 'extra', '', 'Kernel Command Line 
Parameters:' ) )
+
+class CreatePage2( Sheet ):
+
+    def __init__( self, urlWriter ):
+       Sheet.__init__( self, urlWriter, "Setup Virtual Block Device", 2 )
+        self.addControl( InputControl( 'num_vbds', '1', 'Number of VBDs:', 
'[\\d]+', "You must enter a number in this field" ) )
+
+class CreatePage3( Sheet ):
+
+    def __init__( self, urlWriter ):
+        Sheet.__init__( self, urlWriter, "Setup Virtual Block Device", 3 )
+        
+    def write_BODY( self, request, err ):
+        if not self.passback: self.parseForm( request )
+    
+       previous_values = sxp2hash( string2sxp( self.passback ) ) #get the hash 
for quick reference
+        
+        num_vbds = previous_values.get( 'num_vbds' )
+        
+        for i in range( int( num_vbds ) ):
+            self.addControl( InputControl( 'vbd%s_dom0' % i, 'phy:sda%s' % 
str(i + 1), 'Device %s name:' % i  ) )
+            self.addControl( InputControl( 'vbd%s_domU' % i, 'sda%s' % str(i + 
1), 'Virtualized device %s:' % i ) )
+            self.addControl( ListControl( 'vbd%s_mode' % i, [('w', 'Read + 
Write'), ('r', 'Read Only')], 'Device %s mode:' % i ) )
+            
+        self.addControl( InputControl( 'root', '/dev/sda1', 'Root device (in 
VM):' ) )
+        
+        Sheet.write_BODY( self, request, err )
+                
+class CreatePage4( Sheet ):
+
+    def __init__( self, urlWriter ):        
+        Sheet.__init__( self, urlWriter, "Network settings", 4 )
+        self.addControl( ListControl( 'dhcp', [('off', 'No'), ('dhcp', 
'Yes')], 'Use DHCP:' ) )
+        self.addControl( InputControl( 'hostname', 'hostname', 'VM Hostname:' 
) )
+        self.addControl( InputControl( 'ip_addr', '1.2.3.4', 'VM IP Address:' 
) )
+        self.addControl( InputControl( 'ip_subnet', '255.255.255.0', 'VM 
Subnet Mask:' ) ) 
+        self.addControl( InputControl( 'ip_gateway', '1.2.3.4', 'VM Gateway:' 
) )           
+        self.addControl( InputControl( 'ip_nfs', '1.2.3.4', 'NFS Server:' ) )  
+                 
+class CreateFinish( Sheet ):
+
+    def __init__( self, urlWriter ):
+        Sheet.__init__( self, urlWriter, "All Done", 5 )
+        
+    def write_BODY( self, request, err ):
+    
+        if not self.passback: self.parseForm( request )
+        
+        xend_sxp = self.translate_sxp( string2sxp( self.passback ) )
+        
+        try:
+            dom_sxp = server.xend_domain_create( xend_sxp )
+            success = "Your domain was successfully created.\n"
+        except:
+            success = "There was an error creating your domain.\nThe 
configuration used is as follows:\n"
+            dom_sxp = xend_sxp
+            
+            
+        
+        pt = PreTab( success + sxp2prettystring( dom_sxp ) )
+        pt.write_BODY( request )
+
+        request.write( "<input type='hidden' name='passback' 
value=\"%s\"></p>" % self.passback )
+        request.write( "<input type='hidden' name='sheet' value='%s'></p>" % 
self.location )
+    
+    def translate_sxp( self, fin_sxp ):
+       fin_hash = ssxp2hash( fin_sxp )
+    
+        def get( key ):
+            ret = fin_hash.get( key )
+            if ret:
+                return ret
+            else:
+                return ""
+        
+       vals = OptVals()
+        
+        vals.name =    get( 'name' )
+        vals.memory =  get( 'memory' )
+        vals.maxmem =   get( 'maxmem' )
+        vals.cpu =     get( 'cpu' )
+        vals.cpu_weight = get( 'cpu_weight' )
+        
+        vals.builder =  get( 'builder' )       
+        vals.kernel =   get( 'kernel' )
+       vals.root =     get( 'root' )
+        vals.extra =   get( 'extra' )
+        
+        #setup vbds
+        
+        vbds = []
+        
+        for i in range( int( get( 'num_vbds' ) ) ):
+            vbds.append( ( get( 'vbd%s_dom0' % i ), get('vbd%s_domU' % i ), 
get( 'vbd%s_mode' % i ) ) )
+        
+        vals.disk = vbds    
+            
+        #misc
+        
+        vals.pci = []
+        
+        vals.blkif = None
+        vals.netif = None
+        vals.restart = None
+        vals.console = None
+        vals.ramdisk = None
+        
+        #setup vifs
+        
+        vals.vif = []
+        vals.nics = 1
+                
+        ip =   get( 'ip_addr' )
+        nfs =  get( 'ip_nfs' )
+        gate = get( 'ip_gateway' )
+        mask = get( 'ip_subnet' )
+        host = get( 'hostname' )
+        dhcp = get( 'dhcp' )
+        
+        vals.cmdline_ip = "%s:%s:%s:%s:%s:eth0:%s" % (ip, nfs, gate, mask, 
host, dhcp)
+        
+        try:
+            return make_config( vals )
+        except:
+            return [["Error creating domain config."]]    
+        
diff -r d63b100b327a -r 6c24d2b4f3ea tools/python/xen/sv/Daemon.py
--- /dev/null   Tue Jul 26 10:09:06 2005
+++ b/tools/python/xen/sv/Daemon.py     Tue Jul 26 15:16:12 2005
@@ -0,0 +1,110 @@
+###########################################################
+## XenSV Web Control Interface Daemon
+## Copyright (C) 2004, K A Fraser (University of Cambridge)
+## Copyright (C) 2004, Mike Wray <mike.wray@xxxxxx>
+## Copyright (C) 2004, Tom Wilkie <tw275@xxxxxxxxx>
+###########################################################
+
+import os
+import os.path
+import sys
+import re
+
+from xen.sv.params import *
+
+from twisted.internet import reactor
+from twisted.web import static, server, script
+
+from xen.util.ip import _readline, _readlines
+
+class Daemon:
+    """The xend daemon.
+    """
+    def __init__(self):
+        self.shutdown = 0
+        self.traceon = 0
+
+    def daemon_pids(self):
+        pids = []
+        pidex = '(?P<pid>\d+)'
+        pythonex = '(?P<python>\S*python\S*)'
+        cmdex = '(?P<cmd>.*)'
+        procre = re.compile('^\s*' + pidex + '\s*' + pythonex + '\s*' + cmdex 
+ '$')
+        xendre = re.compile('^/usr/sbin/xend\s*(start|restart)\s*.*$')
+        procs = os.popen('ps -e -o pid,args 2>/dev/null')
+        for proc in procs:
+            pm = procre.match(proc)
+            if not pm: continue
+            xm = xendre.match(pm.group('cmd'))
+            if not xm: continue
+            #print 'pid=', pm.group('pid'), 'cmd=', pm.group('cmd')
+            pids.append(int(pm.group('pid')))
+        return pids
+
+    def new_cleanup(self, kill=0):
+        err = 0
+        pids = self.daemon_pids()
+        if kill:
+            for pid in pids:
+                print "Killing daemon pid=%d" % pid
+                os.kill(pid, signal.SIGHUP)
+        elif pids:
+            err = 1
+            print "Daemon already running: ", pids
+        return err
+            
+    def cleanup(self, kill=False):
+        # No cleanup to do if PID_FILE is empty.
+        if not os.path.isfile(PID_FILE) or not os.path.getsize(PID_FILE):
+            return 0
+        # Read the pid of the previous invocation and search active process 
list.
+        pid = open(PID_FILE, 'r').read()
+        lines = _readlines(os.popen('ps ' + pid + ' 2>/dev/null'))
+        for line in lines:
+            if re.search('^ *' + pid + '.+xensv', line):
+                if not kill:
+                    print "Daemon is already running (pid %d)" % int(pid)
+                    return 1
+                # Old daemon is still active: terminate it.
+                os.kill(int(pid), 1)
+        # Delete the stale PID_FILE.
+        os.remove(PID_FILE)
+        return 0
+
+    def start(self, trace=0):
+        if self.cleanup(kill=False):
+            return 1
+   
+        # Fork -- parent writes PID_FILE and exits.
+        pid = os.fork()
+        if pid:
+            # Parent
+            pidfile = open(PID_FILE, 'w')
+            pidfile.write(str(pid))
+            pidfile.close()
+            return 0
+        # Child
+        self.run()
+        return 0
+
+    def stop(self):
+        return self.cleanup(kill=True)
+
+    def run(self):
+       root = static.File( SV_ROOT )
+        root.indexNames = [ 'Main.rpy' ]
+        root.processors = { '.rpy': script.ResourceScript }
+        reactor.listenTCP( SV_PORT, server.Site( root ) )
+        reactor.run()
+
+    def exit(self):
+        reactor.disconnectAll()
+        sys.exit(0)
+
+def instance():
+    global inst
+    try:
+        inst
+    except:
+        inst = Daemon()
+    return inst
diff -r d63b100b327a -r 6c24d2b4f3ea tools/python/xen/sv/DomInfo.py
--- /dev/null   Tue Jul 26 10:09:06 2005
+++ b/tools/python/xen/sv/DomInfo.py    Tue Jul 26 15:16:12 2005
@@ -0,0 +1,148 @@
+from xen.xend.XendClient import server
+from xen.xend import PrettyPrint
+
+from xen.sv.HTMLBase import HTMLBase
+from xen.sv.util import *
+from xen.sv.GenTabbed import *
+
+DEBUG=1
+
+class DomInfo( GenTabbed ):
+
+    def __init__( self, urlWriter ):
+        
+        self.dom = 0;
+    
+        def tabUrlWriter( tab ):
+            return urlWriter( "&dom=%s%s" % ( self.dom, tab ) )
+        
+        GenTabbed.__init__( self, "Domain Info", tabUrlWriter, [ 'General', 
'SXP', 'Devices' ], [ DomGeneralTab, DomSXPTab, NullTab ]  )
+
+    def write_BODY( self, request ):
+        dom = request.args.get('dom')
+        
+        if dom is None or len(dom) != 1:
+            request.write( "<p>Please Select a Domain</p>" )
+            return None
+        else:
+            self.dom = dom[0]
+        
+        GenTabbed.write_BODY( self, request )
+        
+    def write_MENU( self, request ):
+        pass
+
+class DomGeneralTab( CompositeTab ):
+    def __init__( self ):
+       CompositeTab.__init__( self, [ DomGenTab, DomActionTab ] )        
+        
+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, {}, titles )
+        
+    def write_BODY( self, request ):
+    
+        self.dom = getVar('dom', request)
+        
+        if self.dom is None:
+            request.write( "<p>Please Select a Domain</p>" )
+            return None
+            
+        self.dict = getDomInfoHash( self.dom )
+        
+        GeneralTab.write_BODY( self, request )
+            
+class DomSXPTab( PreTab ):
+
+    def __init__( self ):
+        self.dom = 0
+        PreTab.__init__( self, "" )
+
+
+    def write_BODY( self, request ):
+        self.dom = getVar('dom', request)
+        
+        if self.dom is None:
+            request.write( "<p>Please Select a Domain</p>" )
+            return None
+
+        try:
+            domInfo = server.xend_domain( self.dom )
+        except:
+            domInfo = [["Error getting domain details."]]
+            
+        self.source = sxp2prettystring( domInfo )
+        
+        PreTab.write_BODY( self, request )
+        
+class DomActionTab( ActionTab ):
+
+    def __init__( self ):
+       actions = { "shutdown" : "shutdown",
+                   "reboot" : "reboot",
+                    "pause" : "pause",
+                    "unpause" : "unpause",
+                    "destroy" : "destroy" }
+        ActionTab.__init__( self, actions )    
+        
+    def op_shutdown( self, request ):
+       dom = getVar( 'dom', request )
+        if not dom is None and dom != '0':
+          if DEBUG: print ">DomShutDown %s" % dom
+           try:
+               server.xend_domain_shutdown( int( dom ), "halt" )
+           except:
+               pass
+    
+    def op_reboot( self, request ):
+               dom = getVar( 'dom', request )
+        if not dom is None and dom != '0':
+           if DEBUG: print ">DomReboot %s" % dom
+            try:
+               server.xend_domain_shutdown( int( dom ), "reboot" )
+            except:
+               pass
+                
+    def op_pause( self, request ):
+               dom = getVar( 'dom', request )
+        if not dom is None and dom != '0':
+           if DEBUG: print ">DomPause %s" % dom
+            try:
+                server.xend_domain_pause( int( dom ) )
+            except:
+               pass
+               
+    def op_unpause( self, request ):
+               dom = getVar( 'dom', request )
+        if not dom is None and dom != '0':
+          if DEBUG: print ">DomUnpause %s" % dom
+           try:
+               server.xend_domain_unpause( int( dom ) )
+          except:
+               pass
+               
+    def op_destroy( self, request ):
+       dom = getVar( 'dom', request )
+        if not dom is None and dom != '0':
+          if DEBUG: print ">DomDestroy %s" % dom
+           try:
+               server.xend_domain_destroy( int( dom ), "halt" )
+           except:
+               pass
+        
+    
+    
+        
+
diff -r d63b100b327a -r 6c24d2b4f3ea tools/python/xen/sv/DomList.py
--- /dev/null   Tue Jul 26 10:09:06 2005
+++ b/tools/python/xen/sv/DomList.py    Tue Jul 26 15:16:12 2005
@@ -0,0 +1,81 @@
+from xen.xend.XendClient import server
+from xen.xend import sxp
+
+from xen.sv.HTMLBase import HTMLBase
+from xen.sv.util import *
+
+class DomList( HTMLBase ):
+    
+    isLeaf = True
+
+    def __init__( self, urlWriter ):
+        HTMLBase.__init__(self)
+        self.urlWriter = urlWriter
+        
+    def write_MENU( self, request ):
+       return self.write_BODY( request, head=True, long=False ) 
+
+    def write_BODY( self, request, head=True, long=True ):
+        
+       domains = []
+    
+        try:
+            domains = server.xend_domains()
+            domains.sort()
+       except:
+            pass
+                
+        request.write( "\n<table style='border:0px solid white' 
cellspacing='0' cellpadding='0' border='0' width='100%'>\n" )
+        
+        if head:
+            request.write( "<tr class='domainInfoHead'>" )
+            self.write_DOMAIN_HEAD( request, long )
+            request.write( "</tr>" )
+        
+        odd = True
+        
+        if not domains is None:
+            for domain in domains:
+                if odd:
+                    request.write( "<tr class='domainInfoOdd'>\n" )
+                    odd = False
+                else:
+                    request.write( "<tr class='domainInfoEven'>\n" )
+                    odd = True
+                self.write_DOMAIN( request, getDomInfoHash( domain ), long )
+                request.write( "</tr>\n" )
+        else:
+               request.write( "<tr colspan='10'><p class='small'>Error getting 
domain list<br/>Perhaps XenD not running?</p></tr>")
+                
+        request.write( "</table>\n" )
+            
+    def write_DOMAIN( self, request, domInfoHash, long=True ):   
+        request.write( "<td class='domainInfo' align='center'>%(id)s</td>\n" % 
domInfoHash )
+
+        url = self.urlWriter( "&mod=info&dom=%(id)s" % 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'>%(memory)5s</td>\n" % domInfoHash )
+            request.write( "<td class='domainInfo' 
align='center'>%(cpu)2s</td>\n" % domInfoHash )
+        request.write( "<td class='domainInfo' 
align='center'>%(state)5s</td>\n" % domInfoHash )
+        if domInfoHash[ 'id' ] != "0":
+            request.write( "<td class='domainInfo' align='center'>" )
+            
+            if domInfoHash[ 'state' ][ 2 ] == "-":
+                request.write( "<img src='images/small-pause.png' 
onclick='doOp2( \"pause\", \"%(dom)-4s\" )'>" % domInfoHash )
+            else:
+                request.write( "<img src='images/small-unpause.png' 
onclick='doOp2( \"unpause\", \"%(dom)-4s\" )'>" % domInfoHash )              
+            
+            request.write( "<img src='images/small-destroy.png' 
onclick='doOp2( \"destroy\", \"%(dom)-4s\" )'></td>" % domInfoHash)
+        else:
+            request.write( "<td> </td>" )
+
+    def write_DOMAIN_HEAD( self, request, long=True ):
+        request.write( "<td class='domainInfoHead' 
align='center'>Domain</td>\n" )      
+        request.write( "<td class='domainInfoHead' align='center'>Name</td>\n" 
)      
+        if long:
+            request.write( "<td class='domainInfoHead' align='center'>Memory / 
Mb</td>\n" )      
+            request.write( "<td class='domainInfoHead' 
align='center'>CPU</td>\n" )      
+        request.write( "<td class='domainInfoHead' 
align='center'>State</td>\n" )      
+        request.write( "<td class='domainInfoHead' align='center'></td>\n" )
diff -r d63b100b327a -r 6c24d2b4f3ea tools/python/xen/sv/GenTabbed.py
--- /dev/null   Tue Jul 26 10:09:06 2005
+++ b/tools/python/xen/sv/GenTabbed.py  Tue Jul 26 15:16:12 2005
@@ -0,0 +1,135 @@
+import types
+
+from xen.sv.HTMLBase import HTMLBase
+from xen.sv.TabView import TabView
+from xen.sv.util import getVar
+
+class GenTabbed( HTMLBase ):
+
+    def __init__( self, title, urlWriter, tabStrings, tabObjects ):
+        HTMLBase.__init__(self)
+        self.tabStrings = tabStrings
+        self.tabObjects = tabObjects
+        self.urlWriter = urlWriter
+        self.title = title
+
+    def write_BODY( self, request, urlWriter = None ):
+        try:
+            tab = int( getVar( 'tab', request, 0 ) )
+        except:
+            tab = 0
+            
+        request.write( "<table style='' width='100%' border='0' 
cellspacing='0' cellpadding='0'>" )
+        request.write( "<tr><td>" )
+        request.write( "<p align='center'><u>%s</u></p>" % self.title )
+        
+        TabView( tab, self.tabStrings, self.urlWriter ).write_BODY( request )
+        
+        request.write( "</td></tr><tr><td>" )
+
+        try:
+            render_tab = self.tabObjects[ tab ]
+            render_tab().write_BODY( request )
+        except:
+            request.write( "<p>Error Rendering Tab</p>" )
+       
+        request.write( "</td></tr></table>" )
+       
+    def perform( self, request ):
+        try:
+            tab = int( getVar( 'tab', request, 0 ) )
+        except:
+            tab = 0;
+            
+        op_tab = self.tabObjects[ tab ]
+        
+        if op_tab:
+            op_tab().perform( request )
+        
+class PreTab( HTMLBase ):
+
+    def __init__( self, source ):
+        HTMLBase.__init__( self )
+        self.source = source
+    
+    def write_BODY( self, request ):
+        
+        request.write( "<div style='display: block; overflow: auto; border: 
0px solid black; width: 540px; padding: 5px; z-index:0; align: center'><pre>" )
+        
+        request.write( self.source )
+        
+        request.write( "</pre></div>" )
+
+class GeneralTab( HTMLBase ):
+                        
+    def __init__( self, dict, titles ):
+        HTMLBase.__init__( self )
+        self.dict = dict
+        self.titles = titles
+                        
+    def write_BODY( self, request ): 
+        
+        request.write( "<table width='100%' cellspacing='0' cellpadding='0' 
border='0'>" )
+        
+        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( "<tr><td width='50%%'><p>%s:</p></td><td 
width='50%%'><p>%s</p></td></tr>" % ( niceName, temp ) )
+        
+        for niceName, attr in self.titles.items():
+            writeAttr( niceName, attr )
+                            
+        request.write( "</table>" )
+
+class NullTab( HTMLBase ):
+    
+    def __init__( self ):
+        HTMLBase.__init__( self )
+        self.title = "Null Tab"
+
+    def __init__( self, title ):
+        HTMLBase.__init__( self )
+        self.title = title
+        
+    def write_BODY( self, request ):
+        request.write( "<p>%s</p>" % self.title )
+
+class ActionTab( HTMLBase ):
+
+    def __init__( self, actions ):
+        self.actions = actions
+        HTMLBase.__init__( self )
+        
+    def write_BODY( self, request ):
+        request.write( "<p align='center'><table cellspacing='3' 
cellpadding='2' border='0'><tr>" )
+    
+        for ( command, text ) in self.actions.items():
+            request.write( "<td style='border: 1px solid black; 
background-color: grey' onmouseover='buttonMouseOver( this )' 
onmouseout='buttonMouseOut( this )'>" )
+            request.write( "<p><a href='javascript: doOp( \"%s\" 
);'>%s</a></p></td>" % (command, text) )
+ 
+        request.write("</table></p>")        
+        
+class CompositeTab( HTMLBase ):
+
+    def __init__( self, tabs ):
+       HTMLBase.__init__( self )
+        self.tabs = tabs
+        
+    def write_BODY( self, request ):
+       for tab in self.tabs:
+            request.write( "<br/>" )
+            tab().write_BODY( request )
+            
+    def perform( self, request ):
+       for tab in self.tabs:
+            tab().perform( request )
+    
+    
+       
+        
diff -r d63b100b327a -r 6c24d2b4f3ea tools/python/xen/sv/HTMLBase.py
--- /dev/null   Tue Jul 26 10:09:06 2005
+++ b/tools/python/xen/sv/HTMLBase.py   Tue Jul 26 15:16:12 2005
@@ -0,0 +1,62 @@
+from xen.sv.util import *
+
+class HTMLBase:
+
+    isLeaf = True
+ 
+    def __init__( self ):
+        pass
+
+    def render_POST( self, request ):
+        self.perform( request )
+        return self.render_GET( request )
+        
+    def render_GET( self, request ):
+        self.write_TOP( request )
+        self.write_BODY( request )
+        self.write_BOTTOM( request )
+        return ''
+                
+    def write_BODY( self, request ):
+        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( '<script src="inc/script.js"></script>' )
+        request.write( '</head><body>' )
+        request.write('<form method="post" action="%s">' % request.uri)
+
+    def write_BOTTOM( self, request ):
+        request.write('<input type="hidden" name="op" value="">')
+        request.write('<input type="hidden" name="args" value="">')
+        request.write('</form>')
+        request.write( "</body></html>" )
+
+    def get_op_method(self, op):
+        """Get the method for an operation.
+        For operation 'foo' looks for 'op_foo'.
+
+        op     operation name
+        returns method or None
+        """
+        op_method_name = 'op_' + op
+        return getattr(self, op_method_name, None)
+        
+    def perform(self, req):
+        """General operation handler for posted operations.
+        For operation 'foo' looks for a method op_foo and calls
+        it with op_foo(req). Replies with code 500 if op_foo
+        is not found.
+
+        The method must return a list when req.use_sxp is true
+        and an HTML string otherwise (or list).
+        Methods may also return a Deferred (for incomplete processing).
+
+        req    request
+        """
+        op = req.args.get('op')
+        if not op is None and len(op) == 1:
+            op = op[0]
+            op_method = self.get_op_method(op)
+            if op_method:
+                op_method( req )   
diff -r d63b100b327a -r 6c24d2b4f3ea tools/python/xen/sv/Main.py
--- /dev/null   Tue Jul 26 10:09:06 2005
+++ b/tools/python/xen/sv/Main.py       Tue Jul 26 15:16:12 2005
@@ -0,0 +1,113 @@
+from xen.sv.HTMLBase import HTMLBase
+from xen.sv.DomList  import DomList
+from xen.sv.NodeInfo import NodeInfo
+from xen.sv.DomInfo  import DomInfo
+from xen.sv.CreateDomain import CreateDomain
+from xen.sv.MigrateDomain import MigrateDomain
+from xen.sv.SaveDomain import SaveDomain
+from xen.sv.RestoreDomain import RestoreDomain
+
+from xen.xend.XendClient import server
+
+from xen.sv.util import getVar
+
+class Main( HTMLBase ):
+    
+    isLeaf = True
+
+    def __init__( self, urlWriter = None ):
+        self.modules = { "node": NodeInfo, 
+                         "list": DomList, 
+                         "info": DomInfo,
+                         "create": CreateDomain,
+                         "migrate" : MigrateDomain,
+                         "save" : SaveDomain,
+                         "restore" : RestoreDomain }
+
+        # ordered list of module menus to display
+        self.module_menus = [ "node", "create", "migrate", "save",
+                              "restore", "list" ]
+        HTMLBase.__init__(self)
+        
+    def render_POST( self, request ):
+    
+       #decide what module post'd the action
+                
+       args = getVar( 'args', request )
+
+        mod = getVar( 'mod', request )
+                
+        if not mod is None and args is None:
+            module = self.modules[ mod ]
+            #check module exists
+            if module:
+               module( self.mainUrlWriter ).perform( request )
+        else:
+            self.perform( request )     
+    
+        return self.render_GET( request )
+
+    def mainUrlWriter( self, module ):
+       def fun( f ):
+            return "Main.rpy?mod=%s%s" % ( module, f )
+        return fun    
+        
+    def write_BODY( self, request ):
+    
+        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'> </td>" )
+        request.write( " <td width='175px' align='center' valign'center'>" )
+        request.write( "  <table cellspacing='0' cellpadding='0' border='0' 
width='100%' height='100%'>" )
+        request.write( "   <tr><td height='140px' align='center' 
valign='bottom'><a href='http://www.cl.cam.ac.uk/Research/SRG/netos/xen/'>" )
+        request.write( "   <img src='images/xen.png' width='150' height='75' 
border='0'/></a><br/></td></tr>" )
+        request.write( "   <tr><td height='60px' align='center'><p 
class='small'>SV Web Interface<br/>(C) <a href='mailto:tw275@xxxxxxxxx'>Tom 
Wilkie</a> 2004</p></td></tr>")
+        request.write( "   <tr><td align='center' valign='top'>" )
+
+        for modName in self.module_menus:
+            self.modules[modName]( self.mainUrlWriter( modName ) ).write_MENU( 
request )
+        
+        request.write( "   </td></tr>" )
+        request.write( "  </table>" )
+        request.write( "  " )
+        request.write( " </td>\n" )
+        request.write( " <td width='15px'> </td>" )
+        request.write( " <td width='558px' align='left' valign='top'>" )
+        request.write( "  <table cellspacing='0' cellpadding='0' border='0' 
width='100%' height='100%'>" )
+        request.write( "   <tr><td height='20px'></td></tr>" )
+        request.write( "   <tr><td align='center' valign='top'>" )
+        
+        modName = getVar('mod', request)
+        
+        if modName is None:
+            request.write( '<p>Please select a module</p>' )
+        else:
+            module = self.modules[ modName ]
+            if module:
+               module( self.mainUrlWriter( modName ) ).write_BODY( request )  
+            else:
+               request.write( '<p>Invalid module. Please select another</p>' )
+    
+        request.write( "   </td></tr>" )
+        request.write( "  </table>" )
+        request.write( " </td>\n" )
+        request.write( " <td width='17px'> </td>" )
+        request.write( "</tr>\n" )
+        
+        request.write( "</table>\n" )
+        
+                
+    def op_destroy( self, request ):
+       dom = getVar( 'dom', request )
+        if not dom is None and dom != "0":
+            server.xend_domain_destroy( int( dom ), "halt" ) 
+                 
+    def op_pause( self, request ):
+       dom = getVar( 'dom', request )
+        if not dom is None and dom != "0":
+            server.xend_domain_pause( int( dom ) )      
+    
+    def op_unpause( self, request ):
+       dom = getVar( 'dom', request )
+        if not dom is None and dom != "0":
+            server.xend_domain_unpause( int( dom ) )      
diff -r d63b100b327a -r 6c24d2b4f3ea tools/python/xen/sv/MigrateDomain.py
--- /dev/null   Tue Jul 26 10:09:06 2005
+++ b/tools/python/xen/sv/MigrateDomain.py      Tue Jul 26 15:16:12 2005
@@ -0,0 +1,74 @@
+from xen.sv.Wizard import *
+from xen.sv.util import *
+from xen.sv.GenTabbed import PreTab
+
+from xen.xm.create import make_config, OptVals
+
+from xen.xend.XendClient import server
+
+class MigrateDomain( Wizard ):
+    def __init__( self, urlWriter ):
+
+        sheets = [ ChooseMigrateDomain,
+                   DoMigrate ]
+
+        Wizard.__init__( self, urlWriter, "Migrate Domain", sheets )
+
+
+class ChooseMigrateDomain( Sheet ):
+    def __init__( self, urlWriter ):
+        Sheet.__init__( self, urlWriter, "Configure Migration", 0)
+       domains = []
+       domnames = []
+
+        try:
+            domains = server.xend_domains()
+            domains.sort()
+        except:
+            pass
+
+        for i in domains:
+            if i != 'Domain-0': domnames.append((i,i))
+        
+        self.addControl( ListControl('domid',
+                                     domnames,
+                                     'Domain ID:') )
+        self.addControl( TickControl('live',
+                                     'True',
+                                     'Live migrate:') )
+        self.addControl( InputControl('rate',
+                                      '0',
+                                      'Rate limit:') )
+        self.addControl( InputControl( 'dest', 'myhost.mydomain',
+                                       'Name or IP address:',
+                                       ".*") )
+
+class DoMigrate( Sheet ):
+    def __init__(self, urlWriter ):
+        Sheet.__init__(self, urlWriter, "Migration Done", 1)
+
+    def write_BODY( self, request, err ):
+
+        if not self.passback: self.parseForm( request )
+
+#        print string2sxp(self.passback)
+        
+        config = ssxp2hash ( string2sxp( self.passback ) )
+      
+        try:
+            print config
+            print config['domid'], config['dest']
+            dom_sxp = server.xend_domain_migrate( config['domid'],
+                                                  config['dest'],
+                                                  config.get('live') == 'True',
+                                                  config['rate'] )
+            success = "Your domain was successfully Migrated.\n"
+        except Exception, e:
+            success = "There was an error migrating your domain\n"
+            dom_sxp = str(e)
+        
+        pt = PreTab( success + dom_sxp ) # sxp2prettystring( dom_sxp ) )
+        pt.write_BODY( request )
+
+        request.write( "<input type='hidden' name='passback' 
value=\"%s\"></p>" % self.passback )
+        request.write( "<input type='hidden' name='sheet' value='%s'></p>" % 
self.location )
diff -r d63b100b327a -r 6c24d2b4f3ea tools/python/xen/sv/NodeInfo.py
--- /dev/null   Tue Jul 26 10:09:06 2005
+++ b/tools/python/xen/sv/NodeInfo.py   Tue Jul 26 15:16:12 2005
@@ -0,0 +1,63 @@
+from xen.xend.XendClient import server
+
+from xen.sv.util import *
+from xen.sv.GenTabbed import *
+
+class NodeInfo( GenTabbed ):
+
+    def __init__( self, urlWriter ):  
+        GenTabbed.__init__( self, "Node Details", urlWriter, [ 'General', 
'Dmesg', ], [ NodeGeneralTab, NodeDmesgTab ] )
+    
+    def write_MENU( self, request ):
+        request.write( "<p class='small'><a href='%s'>Node details</a></p>" % 
self.urlWriter( '' ) )
+
+class NodeGeneralTab( CompositeTab ):
+    def __init__( self ):
+       CompositeTab.__init__( self, [ NodeInfoTab, NodeActionTab ] )        
+        
+class NodeInfoTab( GeneralTab ):
+                        
+    def __init__( self ):
+         
+       nodeInfo = {}
+        try:
+            nodeInfo = sxp2hash( server.xend_node() )
+       except:
+            nodeInfo[ 'system' ] = 'Error getting node info'
+             
+        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, dict=nodeInfo, titles=dictTitles )
+
+class NodeDmesgTab( PreTab ):
+
+    def __init__( self ):
+       try:
+            dmesg = server.xend_node_get_dmesg()
+        except:
+            dmesg = "Error getting node information: XenD not running?"
+        PreTab.__init__( self, dmesg )
+  
+class NodeActionTab( ActionTab ):
+
+    def __init__( self ):
+        ActionTab.__init__( self, { "shutdown" : "shutdown",
+               "reboot" : "reboot" } )    
+        
+    def op_shutdown( self, request ):
+        if debug: print ">NodeShutDown"
+       server.xend_node_shutdown()
+    
+    def op_reboot( self, request ):
+        if debug: print ">NodeReboot"
+        server.xend_node_reboot()
diff -r d63b100b327a -r 6c24d2b4f3ea tools/python/xen/sv/RestoreDomain.py
--- /dev/null   Tue Jul 26 10:09:06 2005
+++ b/tools/python/xen/sv/RestoreDomain.py      Tue Jul 26 15:16:12 2005
@@ -0,0 +1,46 @@
+from xen.sv.Wizard import *
+from xen.sv.util import *
+from xen.sv.GenTabbed import PreTab
+
+from xen.xm.create import make_config, OptVals
+
+from xen.xend.XendClient import server
+
+class RestoreDomain( Wizard ):
+    def __init__( self, urlWriter ):
+
+        sheets = [ ChooseRestoreDomain,
+                   DoRestore ]
+
+        Wizard.__init__( self, urlWriter, "Restore Domain", sheets )
+
+
+class ChooseRestoreDomain( Sheet ):
+    def __init__( self, urlWriter ):
+        Sheet.__init__( self, urlWriter, "Configure Restore", 0)
+        
+        self.addControl( InputControl( 'file', '',
+                                       'Suspend file name:',
+                                       ".*") )
+
+class DoRestore( Sheet ):
+    def __init__(self, urlWriter ):
+        Sheet.__init__(self, urlWriter, "Restore Done", 1)
+
+    def write_BODY( self, request, err ):
+
+        if not self.passback: self.parseForm( request )
+        config = ssxp2hash ( string2sxp( self.passback ) )
+      
+        try:
+            dom_sxp = server.xend_domain_restore( config['file'] )
+            success = "Your domain was successfully restored.\n"
+        except Exception, e:
+            success = "There was an error restoring your domain\n"
+            dom_sxp = str(e)
+        
+        pt = PreTab( success + sxp2prettystring( dom_sxp ) )
+        pt.write_BODY( request )
+
+        request.write( "<input type='hidden' name='passback' 
value=\"%s\"></p>" % self.passback )
+        request.write( "<input type='hidden' name='sheet' value='%s'></p>" % 
self.location )
diff -r d63b100b327a -r 6c24d2b4f3ea tools/python/xen/sv/SaveDomain.py
--- /dev/null   Tue Jul 26 10:09:06 2005
+++ b/tools/python/xen/sv/SaveDomain.py Tue Jul 26 15:16:12 2005
@@ -0,0 +1,62 @@
+from xen.sv.Wizard import *
+from xen.sv.util import *
+from xen.sv.GenTabbed import PreTab
+
+from xen.xm.create import make_config, OptVals
+
+from xen.xend.XendClient import server
+
+class SaveDomain( Wizard ):
+    def __init__( self, urlWriter ):
+
+        sheets = [ ChooseSaveDomain,
+                   DoSave ]
+
+        Wizard.__init__( self, urlWriter, "Save Domain", sheets )
+
+
+class ChooseSaveDomain( Sheet ):
+    def __init__( self, urlWriter ):
+        Sheet.__init__( self, urlWriter, "Configure Save", 0)
+        
+       domains = []
+       domnames = []
+
+       try:
+            domains = server.xend_domains()
+            domains.sort()
+        except:
+            pass
+
+        for i in domains:
+            if i != 'Domain-0': domnames.append((i,i))
+        
+        self.addControl( ListControl('domid',
+                                     domnames,
+                                     'Domain ID:') )
+        self.addControl( InputControl( 'file', '',
+                                       'Suspend file name:',
+                                       ".*") )
+
+class DoSave( Sheet ):
+    def __init__(self, urlWriter ):
+        Sheet.__init__(self, urlWriter, "Save Done", 1)
+
+    def write_BODY( self, request, err ):
+
+        if not self.passback: self.parseForm( request )
+        config = ssxp2hash ( string2sxp( self.passback ) )
+      
+        try:
+            dom_sxp = server.xend_domain_save( config['domid'],
+                                                  config['file'] )
+            success = "Your domain was successfully saved.\n"
+        except Exception, e:
+            success = "There was an error saving your domain\n"
+            dom_sxp = str(e)
+        
+        pt = PreTab( success + dom_sxp ) # sxp2prettystring( dom_sxp ) )
+        pt.write_BODY( request )
+
+        request.write( "<input type='hidden' name='passback' 
value=\"%s\"></p>" % self.passback )
+        request.write( "<input type='hidden' name='sheet' value='%s'></p>" % 
self.location )
diff -r d63b100b327a -r 6c24d2b4f3ea tools/python/xen/sv/TabView.py
--- /dev/null   Tue Jul 26 10:09:06 2005
+++ b/tools/python/xen/sv/TabView.py    Tue Jul 26 15:16:12 2005
@@ -0,0 +1,26 @@
+from xen.sv.HTMLBase import HTMLBase
+
+class TabView( HTMLBase ):
+
+    # tab - int, id into tabs of selected tab
+    # tabs - list of strings, tab names
+    # urlWriter - 
+    def __init__( self, tab, tabs, urlWriter ):
+        HTMLBase.__init__(self)
+        self.tab = tab
+        self.tabs = tabs
+        self.urlWriter = urlWriter
+
+    def write_BODY( self, request ):
+        request.write( "<table style='' border='0' cellspacing='3' 
cellpadding='2' align='center'>" )
+        request.write( "<tr height='22'>" )                  
+    
+        for i in range( len( self.tabs ) ):
+            if self.tab == i:
+                backgroundColor = "white"
+            else:
+                backgroundColor = "grey"
+        
+            request.write( "<td style='border:1px solid black; 
background-color: %s'><p align='center'><a href='%s'>%s</a></p></td>" % ( 
backgroundColor, self.urlWriter( "&tab=%s" % i ), self.tabs[ i ] ) )
+  
+        request.write( "</tr></table>" )
diff -r d63b100b327a -r 6c24d2b4f3ea tools/python/xen/sv/Wizard.py
--- /dev/null   Tue Jul 26 10:09:06 2005
+++ b/tools/python/xen/sv/Wizard.py     Tue Jul 26 15:16:12 2005
@@ -0,0 +1,269 @@
+from xen.sv.util import *
+from xen.sv.HTMLBase import HTMLBase
+from xen.xend import sxp
+
+import re
+
+DEBUG = 0
+
+class Wizard( HTMLBase ):
+
+    def __init__( self, urlWriter, title, sheets ):
+        HTMLBase.__init__( self )
+        self.title = title
+        self.sheets = sheets
+        self.urlWriter = urlWriter
+        
+    def write_MENU( self, request ):
+       request.write( "<p class='small'><a href='%s'>%s</a></p>" % 
(self.urlWriter( '' ), self.title) ) 
+    
+    def write_BODY( self, request ):
+        
+       request.write( "<table width='100%' border='0' cellspacing='0' 
cellpadding='0'><tr><td>" )
+        request.write( "<p align='center'><u>%s</u></p></td></tr><tr><td>" % 
self.title )
+        
+        currSheet = getVar( 'sheet', request )
+    
+        if not currSheet is None:
+            currSheet = int( currSheet )
+        else:
+            currSheet = 0
+            
+        sheet = self.sheets[ currSheet ]( self.urlWriter )
+        
+        err = not sheet.validate( request )
+        
+        if not err:    
+            op = getVar( 'op', request )
+        
+            if op == 'next':
+               currSheet += 1
+            elif op == 'prev':
+               currSheet -= 1
+             
+            sheet = self.sheets[ currSheet ]( self.urlWriter )
+        
+        if getVar( 'visited-sheet%s' % currSheet, request ):
+            sheet.write_BODY( request, err )
+        else:
+            sheet.write_BODY( request, False )
+
+        
+        request.write( "</td></tr><tr><td><table width='100%' border='0' 
cellspacing='0' cellpadding='0'><tr>" )
+        request.write( "<td width='80%'></td><td width='20%' align='center'><p 
align='center'>" )
+       if currSheet > 0:
+                   request.write( "<img src='images/previous.png' 
onclick='doOp( \"prev\" )' onmouseover='update( \"wizText\", \"Previous\" )' 
onmouseout='update( \"wizText\", \" \" )'> " )
+        if currSheet < ( len( self.sheets ) - 2 ):        
+            request.write( "<img src='images/next.png' onclick='doOp( \"next\" 
)' onmouseover='update( \"wizText\", \"Next\" )' onmouseout='update( 
\"wizText\", \" \" )'>" )
+        elif currSheet == ( len( self.sheets ) - 2 ):
+            request.write( "<img src='images/finish.png' onclick='doOp( 
\"next\" )' onmouseover='update( \"wizText\", \"Finish\" )' onmouseout='update( 
\"wizText\", \" \" )'>" )
+        request.write( "</p><p align='center'><span 
id='wizText'></span></p></td></tr></table>" )
+        request.write( "</td></tr></table>" )
+        
+    def op_next( self, request ):
+       pass
+        
+    def op_prev( self, request ):
+       pass
+        
+    def op_finish( self, request ):
+       pass  
+        
+class Sheet( HTMLBase ):
+
+    def __init__( self, urlWriter, title, location ):
+        HTMLBase.__init__( self )
+        self.urlWriter = urlWriter
+        self.feilds = []
+        self.title = title
+        self.location = location
+        self.passback = None
+        
+    def parseForm( self, request ):
+       do_not_parse = [ 'mod', 'op', 'sheet', 'passback' ] 
+    
+       passed_back = request.args
+        
+        temp_passback = passed_back.get( "passback" )
+        
+        if temp_passback is not None and len( temp_passback ) > 0:
+            temp_passback = temp_passback[ len( temp_passback )-1 ]
+        else:
+            temp_passback = "( )"        
+        
+        last_passback = ssxp2hash( string2sxp( temp_passback ) ) #use special 
function - will work with no head on sxp
+        
+        if DEBUG: print last_passback
+        
+        for (key, value) in passed_back.items():
+            if key not in do_not_parse:
+                last_passback[ key ] = value[ len( value ) - 1 ]
+                
+        self.passback = sxp2string( hash2sxp( last_passback ) ) #store the sxp
+        
+        if DEBUG: print self.passback
+        
+    def write_BODY( self, request, err ):
+    
+       if not self.passback: self.parseForm( request )
+        
+       request.write( "<p>%s</p>" % self.title )
+    
+       previous_values = ssxp2hash( string2sxp( self.passback ) ) #get the 
hash for quick reference
+        
+        request.write( "<table width='100%' cellpadding='0' cellspacing='1' 
border='0'>" )
+        
+       for (feild, control) in self.feilds:
+            control.write_Control( request, previous_values.get( feild ) )
+            if err and not control.validate( previous_values.get( feild ) ):
+               control.write_Help( request )
+            
+        request.write( "</table>" )
+            
+        request.write( "<input type='hidden' name='passback' 
value=\"%s\"></p>" % self.passback )
+        request.write( "<input type='hidden' name='sheet' value='%s'></p>" % 
self.location )
+        request.write( "<input type='hidden' name='visited-sheet%s' 
value='True'></p>" % self.location )
+                
+    def addControl( self, control ):
+       self.feilds.append( [ control.getName(), control ] )
+        
+    def validate( self, request ):
+    
+        if not self.passback: self.parseForm( request )
+            
+       check = True
+        
+        previous_values = ssxp2hash( string2sxp( self.passback ) ) #get the 
hash for quick reference
+       if DEBUG: print previous_values
+      
+       for (feild, control) in self.feilds:
+            if not control.validate( previous_values.get( feild ) ):
+                check = False
+                if DEBUG: print "> %s = %s" % (feild, previous_values.get( 
feild ))
+
+        return check
+        
+class SheetControl( HTMLBase ):
+
+    def __init__( self, reg_exp = ".*" ):
+        HTMLBase.__init__( self )
+        self.name = ""
+        self.reg_exp = reg_exp 
+        
+    def write_Control( self, request, persistedValue ):
+        request.write( "<tr colspan='2'><td>%s</td></tr>" % persistedValue )
+        
+    def write_Help( self, request ):
+        request.write( "<tr><td align='right' colspan='2'><p 
class='small'>Text must match pattern:" )
+        request.write( " %s</p></td></tr>" % self.reg_exp )
+        
+    def validate( self, persistedValue ):
+       if persistedValue is None:
+            persistedValue = ""
+            
+        return not re.compile( self.reg_exp ).match( persistedValue ) is None
+
+    def getName( self ):
+       return self.name
+        
+    def setName( self, name ):
+       self.name = name
+        
+class InputControl( SheetControl ):
+
+    def __init__( self, name, defaultValue, humanText,  reg_exp = ".*", 
help_text = "You must enter the appropriate details in this feild." ):
+        SheetControl.__init__( self, reg_exp )
+        self.setName( name )
+        
+        self.defaultValue = defaultValue
+        self.humanText = humanText
+        self.help_text = help_text
+        
+    def write_Control( self, request, persistedValue ):
+       if persistedValue is None:
+            persistedValue = self.defaultValue
+        
+        request.write( "<tr><td width='50%%'><p>%s</p></td><td 
width='50%%'><input size='40'type='text' name='%s' value=\"%s\"></td></tr>" % 
(self.humanText, self.getName(), persistedValue) )
+
+    def write_Help( self, request ):
+        request.write( "<tr><td align='right' colspan='2'><p class='small'>" )
+        request.write( " %s</p></td></tr>" % self.help_text )         
+        
+class TextControl( SheetControl ):
+
+    def __init__( self, text ):
+       SheetControl.__init__( self )
+        self.text = text
+        
+    def write_Control( self, request, persistedValue ):
+       request.write( "<tr><td colspan='2'><p>%s</p></td></tr>" % self.text )
+
+class SmallTextControl( SheetControl ):
+
+    def __init__( self, text ):
+       SheetControl.__init__( self )
+        self.text = text
+        
+    def write_Control( self, request, persistedValue ):
+       request.write( "<tr><td colspan='2'><p class='small'>%s</p></tr></td>" 
% self.text )
+        
+class ListControl( SheetControl ):
+
+    def __init__( self, name, options, humanText ):
+       SheetControl.__init__( self )
+        self.setName( name )
+        self.options = options
+        self.humanText = humanText
+        
+    def write_Control( self, request, persistedValue ):
+        request.write( "<tr><td width='50%%'><p>%s</p></td><td width='50%%'>" 
% self.humanText )
+       request.write( "<select name='%s'>" % self.getName() )
+        for (value, text) in self.options:
+            if value == persistedValue:
+               request.write( "<option value='%s' selected>%s\n" % (value, 
text) )
+            else:
+                request.write( "<option value='%s'>%s\n" % (value, text) )
+        request.write( "</select></td></tr>" )
+
+    def validate( self, persistedValue ):
+        for (value, text) in self.options:
+            if value == persistedValue:
+                return True
+                
+        return False
+        
+class FileControl( InputControl ):
+
+    def __init__( self, name, defaultValue, humanText,  reg_exp = ".*", 
help_text = "You must enter the appropriate details in this feild." ):
+       InputControl.__init__( self, name, defaultValue, humanText )
+        
+    def validate( self, persistedValue ):
+        if persistedValue is None: return False
+        try:
+            open( persistedValue )
+            return True
+        except IOError, TypeError:
+            return False
+    
+    def write_Help( self, request ):
+        request.write( "<tr><td colspan='2' align='right'><p 
class='small'>File does not exist: you must enter a valid, absolute file 
path.</p></td></tr>" )
+
+class TickControl( SheetControl ):
+
+    def __init__( self, name, defaultValue, humanText ):
+        SheetControl.__init__( self )
+        self.setName( name )
+        self.defaultValue = defaultValue
+        self.humanText = humanText
+        
+    def write_Control( self, request, persistedValue ):
+        request.write( "<tr><td width='50%%'><p>%s</p></td><td width='50%%'>" 
% self.humanText )
+        
+        if persistedValue == 'True':
+           request.write( "<input type='checkbox' name='%s' value='True' 
checked>" % self.getName() )
+        else:
+           request.write( "<input type='checkbox' name='%s' value='True'>" % 
self.getName() )
+            
+        request.write( "</select></td></tr>" )
+
+      
diff -r d63b100b327a -r 6c24d2b4f3ea tools/python/xen/sv/__init__.py
--- /dev/null   Tue Jul 26 10:09:06 2005
+++ b/tools/python/xen/sv/__init__.py   Tue Jul 26 15:16:12 2005
@@ -0,0 +1,1 @@
+ 
diff -r d63b100b327a -r 6c24d2b4f3ea tools/python/xen/sv/params.py
--- /dev/null   Tue Jul 26 10:09:06 2005
+++ b/tools/python/xen/sv/params.py     Tue Jul 26 15:16:12 2005
@@ -0,0 +1,3 @@
+SV_PORT = 8080
+SV_ROOT = "/var/lib/xen/sv/"
+PID_FILE = "/var/run/xen-sv.pid"
diff -r d63b100b327a -r 6c24d2b4f3ea tools/python/xen/sv/util.py
--- /dev/null   Tue Jul 26 10:09:06 2005
+++ b/tools/python/xen/sv/util.py       Tue Jul 26 15:16:12 2005
@@ -0,0 +1,126 @@
+from xen.xend.XendClient import server
+from xen.xend import sxp
+from xen.xend import PrettyPrint
+
+import types
+
+def getDomInfoHash( domain ):
+    domInfoHash = {}
+    try:
+        domInfoHash = sxp2hash( server.xend_domain( domain ) )
+        domInfoHash['dom'] = domain
+    except:
+       domInfoHash['name'] = "Error getting domain details"
+    return domInfoHash
+
+def sxp2hash( s ):
+    sxphash = {}
+        
+    for child in sxp.children( s ):
+       if isinstance( child, types.ListType ) and len( child ) > 1:
+            if isinstance( child[1], types.ListType ) and len( child ) > 1:
+                sxphash[ child[0] ] = sxp2hash( child[1] )
+            else:
+                sxphash[ child[0] ] = child[1]
+        
+    return sxphash  
+    
+def ssxp2hash( s ):
+    sxphash = {}
+    
+    for i in s:
+       if isinstance( i, types.ListType ) and len( i ) > 1:
+          sxphash[ i[0] ] = i[1]
+    
+    return sxphash 
+    
+def hash2sxp( h ):
+    hashsxp = []
+    
+    for (key, item) in h.items():
+       hashsxp.append( [key, item] )
+        
+    return hashsxp    
+    
+def string2sxp( string ):
+    pin = sxp.Parser()
+    pin.input( string )
+    return pin.get_val()    
+
+def sxp2string( sexp ):
+    return sxp.to_string( sexp )    
+    
+def sxp2prettystring( 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 getVar( var, request, default=None ):
+   
+    arg = request.args.get( var )
+
+    if arg is None:
+        return default
+    else:
+        return arg[ len( arg )-1 ]
+
+def bigTimeFormatter( time ):
+    time = float( 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 ):
+    time = float( 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' ]
+    
+    stateStr = ""
+    
+    for i in range( len( state ) ):
+        if state[i] != "-":
+            stateStr += "%s, " % states[ i ] 
+           
+    return stateStr + " (%s)" % state
+
+def memoryFormatter( mem ):
+    mem = int( mem )
+    if mem >= 1024:
+        mem = float( mem ) / 1024
+        return "%3.2fGb" % mem
+    else:    
+        return "%7dMb" % mem
+
+def cpuFormatter( mhz ):
+    mhz = int( mhz )
+    if mhz > 1000:
+        ghz = float( mhz ) / 1000.0
+        return "%4.2fGHz" % ghz
+    else:
+        return "%4dMHz" % mhz
+        
+def hyperthreadFormatter( threads ):
+    try:
+        if int( threads ) > 1:
+            return "Yes"
+        else:
+            return "No"
+    except:
+        return "No"
diff -r d63b100b327a -r 6c24d2b4f3ea tools/sv/Makefile
--- /dev/null   Tue Jul 26 10:09:06 2005
+++ b/tools/sv/Makefile Tue Jul 26 15:16:12 2005
@@ -0,0 +1,2 @@
+
+all:
diff -r d63b100b327a -r 6c24d2b4f3ea tools/sv/images/destroy.png
--- /dev/null   Tue Jul 26 10:09:06 2005
+++ b/tools/sv/images/destroy.png       Tue Jul 26 15:16:12 2005
@@ -0,0 +1,23 @@
+?PNG
+
+   
\ No newline at end of file
+IHDR   6   6   ?EjÝ |