Changeset 205
- Timestamp:
- Oct 20, 2007, 8:28:32 AM (17 years ago)
- Location:
- trunk/web/templates
- Files:
-
- 4 added
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/web/templates/info.tmpl
r187 r205 6 6 #end def 7 7 8 9 #def body 10 <h1>Info</h1> 8 #def infoTable() 11 9 <p>Info on ${machine.name}:</p> 12 10 <table> … … 15 13 #end for 16 14 </table> 15 #end def 17 16 18 <p>Commands:</p> 17 #def commands() 18 <script> 19 function commandButton(elt, action){ 20 form = elt.up('', 4); 21 cdrom = Form.serialize(form, true).cdrom; 22 new Ajax.Request('command', {method: 'post', 23 parameters: 'machine_id=$machine.machine_id&js=info&cdrom='+cdrom+'&action='+action, 24 onSuccess: replaceFunc 25 }); 26 return false; 27 } 28 </script> 19 29 <form action="command" action="POST"> 20 30 <input type="hidden" name="machine_id" value="$machine.machine_id"/> … … 34 44 <tr> 35 45 #if $on 36 <td><input type="submit" class="button" name="action" value="Power off" /></td>37 <td><input type="submit" class="button" name="action" value="Shutdown" /></td>38 <td><input type="submit" class="button" name="action" value="Reboot" /></td>46 <td><input type="submit" class="button" name="action" value="Power off" onclick="return commandButton(this, 'Power off');"/></td> 47 <td><input type="submit" class="button" name="action" value="Shutdown" onclick="return commandButton(this, 'Shutdown');"/></td> 48 <td><input type="submit" class="button" name="action" value="Reboot" onclick="return commandButton(this, 'Reboot');"/></td> 39 49 #else 40 <td><input type="submit" class="button" name="action" value="Power on" /></td>50 <td><input type="submit" class="button" name="action" value="Power on" onclick="return commandButton(this, 'Power on');"/></td> 41 51 #end if 42 52 <td>Boot CD:</td> 43 <td><select name="cdrom"> 44 <option selected value="">None</option> 45 #for $cdrom in $cdroms 46 <option value="$cdrom.cdrom_id"> 47 $cdrom.description 48 </option> 49 #end for 50 </select></td> 53 <td>$cdromList($cdroms)</td> 51 54 </tr> 52 55 <tr> 53 <td><input type="submit" class="button" name="action" value="Delete VM" /></td>56 <td><input type="submit" class="button" name="action" value="Delete VM" onclick="return confirm('Are you sure that you want to delete this VM?');"/></td> 54 57 </tr> 55 58 </table> 56 59 </form> 57 <p>Change settings: 60 #end def 61 62 #def modifyForm() 63 #if $err 64 <p class="error">We had a problem with your request:</p> 65 #else if $varExists('new_machine') 66 <p>Successfully modified.</p> 67 #end if 58 68 #if $on 59 69 (To edit ram, disk size, or machine name, turn off the machine first.) 60 70 #end if 61 71 </p> 62 <form action="modify" method="POST" >63 <input type="hidden" name="machine_id" value="$ machine.machine_id"/>72 <form action="modify" method="POST" onsubmit="return jsFormSubmit('modify', this);"> 73 <input type="hidden" name="machine_id" value="$defaults.machine_id"/> 64 74 <table> 65 <tr><td>Owner${helppopup("owner")}:</td><td><input type="text" name="owner", value="$machine.owner"/></td></tr> 66 <tr><td>Administrator${helppopup("administrator")}:</td><td><input type="text" name="administrator", value="$machine.administrator"/></td></tr> 67 <tr><td>Contact email:</td><td><input type="text" name="contact" value="$machine.contact"/></td></tr> 75 <tr><td>Owner${helppopup("owner")}:</td><td><input type="text" name="owner", value="$defaults.owner"/></td></tr> 76 $errorRow('owner', $err) 77 <tr><td>Administrator${helppopup("administrator")}:</td><td><input type="text" name="administrator", value="$defaults.administrator"/></td></tr> 78 $errorRow('administrator', $err) 79 <tr><td>Contact email:</td><td><input type="text" name="contact" value="$defaults.contact"/></td></tr> 80 $errorRow('contact', $err) 68 81 #if $machine.nics 69 <tr><td>Hostname:</td><td><input type="text" name="hostname" value="$ machine.nics[0].hostname"/>.servers.csail.mit.edu</td></tr>82 <tr><td>Hostname:</td><td><input type="text" name="hostname" value="$defaults.hostname"/>.servers.csail.mit.edu</td></tr> 70 83 #end if 84 $errorRow('hostname', $err) 71 85 #if not $on 72 <tr><td>Machine Name:</td><td><input type="text" name="name" value="$machine.name"/></td></tr> 73 <tr><td>Ram:</td><td><input type="text" size=3 name="memory" value="$machine.memory"/>MB (max $max_mem)</td></tr> 74 <tr><td>Disk:</td><td><input type="text" size=3 name="disk" value="${machine.disks[0].size/1024.}"/>GB (max $max_disk)</td><td>WARNING: Modifying disk size may corrupt your data.</td></tr> 86 <tr><td>Machine Name:</td><td><input type="text" name="name" value="$defaults.name"/></td></tr> 87 $errorRow('name', $err) 88 <tr><td>Ram:</td><td><input type="text" size=3 name="memory" value="$defaults.memory"/>MB (max $max_mem)</td></tr> 89 $errorRow('memory', $err) 90 <tr><td>Disk:</td><td><input type="text" size=3 name="disk" value="$defaults.disk"/>GB (max $max_disk)</td><td>WARNING: Modifying disk size may corrupt your data.</td></tr> 91 $errorRow('disk', $err) 92 #else 93 $errorRow('name', $err) 94 $errorRow('memory', $err) 95 $errorRow('disk', $err) 75 96 #end if 76 97 <tr><td><input type="submit" class="button" name="action" value="Change"/></td></tr> 77 98 </table> 78 99 </form> 100 #end def 79 101 102 #def body 103 <h1>Info</h1> 104 <div id="info"> 105 $infoTable() 106 </div> 107 108 <p>Commands:</p> 109 <div id="commands"> 110 $commands() 111 </div> 112 <p>Change settings: 113 <div id="modify"> 114 $modifyForm() 115 </div> 80 116 #end def -
trunk/web/templates/list.tmpl
r186 r205 1 1 #from skeleton import skeleton 2 2 #extends skeleton 3 3 4 4 5 #def title … … 6 7 #end def 7 8 8 #def body9 #if not $machines10 9 #def createTable() 10 #if $cant_add_vm 11 <p>$cant_add_vm</p> 11 12 #else 12 <p>You have the following VMs:</p> 13 <table> 14 <tr> 15 <td>Name</td> 16 <td>Memory</td> 17 <td>owner</td> 18 <td>IP</td> 19 <td>Hostname</td> 20 <td>Uptime</td> 21 <td>VNC</td> 22 <td></td> 23 #for $machine in $machines: 13 <p>Create a new VM:</p> 14 #if $err 15 <p class="error">We had a problem with your request:</p> 16 #else if $varExists('new_machine') 17 <p>Congratulations! You successfully created a new VM called $new_machine.</p> 18 #end if 19 <form action="create" method="POST" onsubmit="return jsFormSubmit('create', this);"> 20 <table> 21 $errorRow('create', $err) 22 <tr> 23 <td>Name</td> 24 <td><input type="text" name="name" value="$defaults.name"/></td> 25 </tr> 26 $errorRow('name', $err) 27 <tr> 28 <td>Memory</td> 29 <td><input type="text" name="memory" value="$defaults.memory" size=3/> megabytes ($max_memory max)</td> 30 </tr> 31 $errorRow('memory', $err) 32 <tr> 33 <td>Disk</td> 34 <td><input type="text" name="disk" value="$defaults.disk" size=3/> gigabytes (${"%0.1f" % ($max_disk-0.05)} max)</td> 35 </tr> 36 $errorRow('disk', $err) 37 <tr> 38 <td>HVM/ParaVM$helppopup('hvm_paravm')</td> 39 <td> 40 #for $value, $name in (('hvm', 'HVM'), ('paravm', 'ParaVM')) 41 <input #slurp 42 #if $defaults.vmtype == $value then 'checked' else '' 43 type="radio" name="vmtype" value="$value">$name</input> 44 #end for 45 </td> 46 </tr> 47 $errorRow('vmtype', $err) 48 <tr> 49 <td>Boot CD</td> 50 <td>$cdromList($cdroms, $defaults.cdrom)</td> 51 </tr> 52 $errorRow('cdrom', $err) 53 </table> 54 <input type="submit" class="button" value="Create it!"/> 55 </form> 56 #end if 57 #end def 58 59 #def machineRow($machine) 24 60 <tr> 25 61 <td><a href="info?machine_id=$machine.machine_id">$machine.name</a></td> … … 35 71 #end if 36 72 <td>#slurp 37 #if $ uptimes[$machine]38 $ uptimes[$machine]#slurp73 #if $machine.uptime 74 $machine.uptime#slurp 39 75 #else 40 76 Off#slurp … … 49 85 </td> 50 86 <td> 51 <form action="command" >87 <form action="command" method="post" onsubmit="return rowFormSubmit(this, 'list');"> 52 88 <input type="hidden" name="machine_id" 53 89 value="$machine.machine_id"/> 54 #if $uptimes[$machine] 55 <input type="submit" class="button" name="action" value="Shutdown"/> 56 #else 57 <input type="submit" class="button" name="action" value="Power on"/> 58 #end if 90 <input type="submit" class="button" name="action" value="#slurp 91 #if $machine.uptime then 'Shutdown' else 'Power on' 92 "/> 59 93 </form> 60 94 </td> 61 95 </tr> 96 #end def 97 98 #def machineList($machines) 99 <table> 100 <tr> 101 <td>Name</td> 102 <td>Memory</td> 103 <td>owner</td> 104 <td>IP</td> 105 <td>Hostname</td> 106 <td>Uptime</td> 107 <td>VNC</td> 108 <td></td> 109 #for $machine in $machines: 110 $machineRow($machine) 62 111 #end for 63 112 </table> 113 #end def 114 115 116 #def body 117 #if not $machines 118 <p>You don't currently control any VMs.</p> 119 #else 120 <p>You have the following VMs:</p> 64 121 #end if 65 #if $can_add_vm 66 <p>Create a new VM:</p> 67 <form action="create" method="POST"> 68 <table> 69 <tr> 70 <td>Name</td> 71 <td><input type="text" name="name" value=""/></td> 72 </tr> 73 <tr> 74 <td>Memory</td> 75 <td><input type="text" name="memory" value="$default_mem" size=3/> megabytes ($max_mem max)</td> 76 </tr> 77 <tr> 78 <td>Disk</td> 79 <td><input type="text" name="disk" value="$default_disk" size=3/> gigabytes (${"%0.1f" % ($max_disk-0.05)} max)</td> 80 </tr> 81 <tr> 82 <td>HVM/ParaVM$helppopup('hvm_paravm')</td> 83 <td> 84 <input checked type="radio" name="vmtype" value="hvm">HVM</input> 85 <input type="radio" name="vmtype" value="paravm">ParaVM</input> 86 </td> 87 </tr> 88 <tr> 89 <td>Boot CD</td> 90 <td> 91 <select name="cdrom"> 92 <option selected value="">None</option> 93 #for $cdrom in $cdroms 94 <option value="$cdrom.cdrom_id"> 95 $cdrom.description 96 </option> 97 #end for 98 </select> 99 </td> 100 </tr> 101 </table> 102 <input type="submit" class="button" value="Create it!"/> 103 </form> 104 #else 105 <p>You are at the maximum number of VMs.</p> 106 #end if 122 <p><a href="list" onclick="new Ajax.Updater('machinelist', 'list?js=machinelist', {method: 'get' });return false">refresh</a></p> 123 <div id="machinelist"> 124 $machineList($machines) 125 </div> 126 <div id="createtable"> 127 $createTable() 128 </div> 107 129 #end def -
trunk/web/templates/main.py
r203 r205 1 1 #!/usr/bin/python 2 3 import sys 2 """Main CGI script for web interface""" 3 4 import base64 5 import cPickle 4 6 import cgi 7 import datetime 8 import getafsgroups 9 import hmac 5 10 import os 11 import random 12 import re 13 import sha 14 import simplejson 6 15 import string 7 16 import subprocess 8 import re17 import sys 9 18 import time 10 import cPickle 11 import base64 12 import sha 13 import hmac 14 import datetime 15 import StringIO 16 import getafsgroups 17 18 errio = StringIO.StringIO() 19 sys.stderr = errio 19 from StringIO import StringIO 20 21 22 def revertStandardError(): 23 """Move stderr to stdout, and return the contents of the old stderr.""" 24 errio = sys.stderr 25 if not isinstance(errio, StringIO): 26 return None 27 sys.stderr = sys.stdout 28 errio.seek(0) 29 return errio.read() 30 31 def printError(): 32 """Revert stderr to stdout, and print the contents of stderr""" 33 if isinstance(sys.stderr, StringIO): 34 print revertStandardError() 35 36 if __name__ == '__main__': 37 import atexit 38 atexit.register(printError) 39 sys.stderr = StringIO() 40 20 41 sys.path.append('/home/ecprice/.local/lib/python2.5/site-packages') 21 42 22 43 from Cheetah.Template import Template 23 44 from sipb_xen_database import * 24 import random25 45 26 46 class MyException(Exception): … … 44 64 pass 45 65 66 def helppopup(subj): 67 """Return HTML code for a (?) link to a specified help topic""" 68 return ('<span class="helplink"><a href="help?subject=' + subj + 69 '&simple=true" target="_blank" ' + 70 'onclick="return helppopup(\'' + subj + '\')">(?)</a></span>') 71 46 72 class Global(object): 73 """Global state of the system, to avoid duplicate remctls to get state""" 47 74 def __init__(self, user): 48 75 self.user = user … … 54 81 uptimes = property(__get_uptimes) 55 82 83 def clear(self): 84 """Clear the state so future accesses reload it.""" 85 for attr in ('_uptimes', ): 86 if hasattr(self, attr): 87 delattr(self, attr) 88 56 89 g = None 57 90 58 def helppopup(subj): 59 """Return HTML code for a (?) link to a specified help topic""" 60 return '<span class="helplink"><a href="help?subject='+subj+'&simple=true" target="_blank" onclick="return helppopup(\''+subj+'\')">(?)</a></span>' 61 62 63 global_dict = {} 64 global_dict['helppopup'] = helppopup 65 91 class User: 92 """User class (sort of useless, I admit)""" 93 def __init__(self, username, email): 94 self.username = username 95 self.email = email 96 97 def makeErrorPre(old, addition): 98 if addition is None: 99 return 100 if old: 101 return old[:-6] + '\n----\n' + str(addition) + '</pre>' 102 else: 103 return '<p>STDERR:</p><pre>' + str(addition) + '</pre>' 104 105 Template.helppopup = staticmethod(helppopup) 106 Template.err = None 107 108 class JsonDict: 109 """Class to store a dictionary that will be converted to JSON""" 110 def __init__(self, **kws): 111 self.data = kws 112 if 'err' in kws: 113 err = kws['err'] 114 del kws['err'] 115 self.addError(err) 116 117 def __str__(self): 118 return simplejson.dumps(self.data) 119 120 def addError(self, text): 121 """Add stderr text to be displayed on the website.""" 122 self.data['err'] = \ 123 makeErrorPre(self.data.get('err'), text) 124 125 class Defaults: 126 """Class to store default values for fields.""" 127 memory = 256 128 disk = 4.0 129 cdrom = '' 130 name = '' 131 vmtype = 'hvm' 132 def __init__(self, max_memory=None, max_disk=None, **kws): 133 if max_memory is not None: 134 self.memory = min(self.memory, max_memory) 135 if max_disk is not None: 136 self.max_disk = min(self.disk, max_disk) 137 for key in kws: 138 setattr(self, key, kws[key]) 139 140 141 142 default_headers = {'Content-Type': 'text/html'} 66 143 67 144 # ... and stolen from xend/uuid.py … … 120 197 return min(MAX_DISK_SINGLE, MAX_DISK_TOTAL-disk_usage/1024.) 121 198 122 def can AddVm(user):199 def cantAddVm(user): 123 200 machines = getMachinesByOwner(user) 124 201 active_machines = [x for x in machines if g.uptimes[x]] 125 return (len(machines) < MAX_VMS_TOTAL and 126 len(active_machines) < MAX_VMS_ACTIVE) 202 if len(machines) >= MAX_VMS_TOTAL: 203 return 'You have too many VMs to create a new one.' 204 if len(active_machines) >= MAX_VMS_ACTIVE: 205 return ('You already have the maximum number of VMs turned on. ' 206 'To create more, turn one off.') 207 return False 127 208 128 209 def haveAccess(user, machine): … … 132 213 if user.username in (machine.administrator, machine.owner): 133 214 return True 134 if getafsgroups.checkAfsGroup(user.username, machine.administrator, 'athena.mit.edu'): #XXX Cell? 215 if getafsgroups.checkAfsGroup(user.username, machine.administrator, 216 'athena.mit.edu'): #XXX Cell? 135 217 return True 136 218 if getafsgroups.checkLockerOwner(user.username, machine.owner): … … 148 230 d = dict(op=op, user=user, errorMessage=str(err), 149 231 stderr=emsg) 150 return Template(file='error.tmpl', searchList=[d , global_dict]);232 return Template(file='error.tmpl', searchList=[d]); 151 233 152 234 def invalidInput(op, user, fields, err, emsg): … … 155 237 err_value=str(err.err_value), stderr=emsg, 156 238 errorMessage=str(err)) 157 return Template(file='invalid.tmpl', searchList=[d , global_dict]);239 return Template(file='invalid.tmpl', searchList=[d]); 158 240 159 241 def validMachineName(name): … … 194 276 stdout=subprocess.PIPE, 195 277 stderr=subprocess.PIPE) 278 v = p.wait() 196 279 if kws.get('err'): 197 p.wait()198 280 return p.stdout.read(), p.stderr.read() 199 if p.wait():200 print >> sys.stderr, 'Error 281 if v: 282 print >> sys.stderr, 'Error', v, 'on remctl', args, ':' 201 283 print >> sys.stderr, p.stderr.read() 202 284 raise CodeError('ERROR on remctl') … … 277 359 Gets and parses xm list --long 278 360 """ 279 value_string, err_string = remctl('control', machine.name, 'list-long', err=True) 361 value_string, err_string = remctl('control', machine.name, 'list-long', 362 err=True) 280 363 if 'Unknown command' in err_string: 281 raise CodeError("ERROR in remctl list-long %s is not registered" % (machine.name,)) 364 raise CodeError("ERROR in remctl list-long %s is not registered" % 365 (machine.name,)) 282 366 elif 'does not exist' in err_string: 283 367 return None 284 368 elif err_string: 285 raise CodeError("ERROR in remctl list-long %s: %s" % (machine.name, err_string)) 369 raise CodeError("ERROR in remctl list-long %s: %s" % 370 (machine.name, err_string)) 286 371 status = parseStatus(value_string) 287 372 return status … … 308 393 raise InvalidInput('disk', disk, 309 394 "Max %s" % maxDisk(user)) 310 if not canAddVm(user): 311 raise InvalidInput('create', True, 'Unable to create more VMs') 312 res = meta.engine.execute('select nextval(\'"machines_machine_id_seq"\')') 395 reason = cantAddVm(user) 396 if reason: 397 raise InvalidInput('create', True, reason) 398 res = meta.engine.execute('select nextval(' 399 '\'"machines_machine_id_seq"\')') 313 400 id = res.fetchone()[0] 314 401 machine = Machine() … … 326 413 disk = Disk(machine.machine_id, 327 414 'hda', disk) 328 open = NIC.select_by(machine_id=None) 329 if not open: #No IPs left! 330 raise CodeError("No IP addresses left! Contact sipb-xen-dev@mit.edu") 331 nic = open[0] 415 open_nics = NIC.select_by(machine_id=None) 416 if not open_nics: #No IPs left! 417 raise CodeError("No IP addresses left! " 418 "Contact sipb-xen-dev@mit.edu") 419 nic = open_nics[0] 332 420 nic.machine_id = machine.machine_id 333 421 nic.hostname = name … … 378 466 return disk 379 467 380 def create(user, fields): 381 """Handler for create requests.""" 468 def parseCreate(user, fields): 382 469 name = fields.getfirst('name') 383 470 if not validMachineName(name): 384 raise InvalidInput('name', name )471 raise InvalidInput('name', name, 'You must provide a machine name.') 385 472 name = name.lower() 386 473 387 474 if Machine.get_by(name=name): 388 475 raise InvalidInput('name', name, 389 " Already exists")476 "Name already exists.") 390 477 391 478 memory = fields.getfirst('memory') … … 402 489 cdrom = fields.getfirst('cdrom') 403 490 if cdrom is not None and not CDROM.get(cdrom): 404 raise CodeError("Invalid cdrom type '%s'" % cdrom) 405 406 machine = createVm(user, name, memory, disk, is_hvm, cdrom) 407 d = dict(user=user, 408 machine=machine) 409 return Template(file='create.tmpl', 410 searchList=[d, global_dict]); 411 412 def listVms(user, fields): 413 """Handler for list requests.""" 491 raise CodeError("Invalid cdrom type '%s'" % cdrom) 492 return dict(user=user, name=name, memory=memory, disk=disk, 493 is_hvm=is_hvm, cdrom=cdrom) 494 495 def create(user, fields): 496 """Handler for create requests.""" 497 js = fields.getfirst('js') 498 try: 499 parsed_fields = parseCreate(user, fields) 500 machine = createVm(**parsed_fields) 501 except InvalidInput, err: 502 if not js: 503 raise 504 else: 505 err = None 506 if not js: 507 d = dict(user=user, 508 machine=machine) 509 return Template(file='create.tmpl', searchList=[d]) 510 g.clear() #Changed global state 511 d = getListDict(user) 512 d['err'] = err 513 if err: 514 for field in fields.keys(): 515 setattr(d['defaults'], field, fields.getfirst(field)) 516 else: 517 d['new_machine'] = parsed_fields['name'] 518 t = Template(file='list.tmpl', searchList=[d]) 519 return JsonDict(createtable=t.createTable(), 520 machinelist=t.machineList(d['machines'])) 521 522 523 def getListDict(user): 414 524 machines = [m for m in Machine.select() if haveAccess(user, m)] 415 525 on = {} … … 417 527 on = g.uptimes 418 528 for m in machines: 529 m.uptime = g.uptimes.get(m) 419 530 if not on[m]: 420 531 has_vnc[m] = 'Off' … … 427 538 # on[m.name] = status is not None 428 539 # has_vnc[m.name] = hasVnc(status) 429 max_mem=maxMemory(user) 430 max_disk=maxDisk(user) 540 max_memory = maxMemory(user) 541 max_disk = maxDisk(user) 542 defaults = Defaults(max_memory=max_memory, 543 max_disk=max_disk, 544 cdrom='gutsy-i386') 431 545 d = dict(user=user, 432 can _add_vm=canAddVm(user),433 max_mem =max_mem,546 cant_add_vm=cantAddVm(user), 547 max_memory=max_memory, 434 548 max_disk=max_disk, 435 default_mem=max_mem, 436 default_disk=min(4.0, max_disk), 549 defaults=defaults, 437 550 machines=machines, 438 551 has_vnc=has_vnc, 439 552 uptimes=g.uptimes, 440 553 cdroms=CDROM.select()) 441 return Template(file='list.tmpl', searchList=[d, global_dict]) 442 554 return d 555 556 def listVms(user, fields): 557 """Handler for list requests.""" 558 d = getListDict(user) 559 t = Template(file='list.tmpl', searchList=[d]) 560 js = fields.getfirst('js') 561 if not js: 562 return t 563 if js == 'machinelist': 564 return t.machineList(d['machines']) 565 elif js.startswith('machinerow-'): 566 request_machine_id = int(js.split('-')[1]) 567 m = [x for x in d['machines'] if x.id == request_machine_id] 568 return t.machineRow(m) 569 elif js == 'createtable': 570 return t.createTable() 571 443 572 def testMachineId(user, machineId, exists=True): 444 573 """Parse, validate and check authorization for a given machineId. … … 469 598 You might want iptables like: 470 599 471 -t nat -A PREROUTING -s ! 18.181.0.60 -i eth1 -p tcp -m tcp --dport 10003 -j DNAT --to-destination 18.181.0.60:10003 472 -t nat -A POSTROUTING -d 18.181.0.60 -o eth1 -p tcp -m tcp --dport 10003 -j SNAT --to-source 18.187.7.142 473 -A FORWARD -d 18.181.0.60 -i eth1 -o eth1 -p tcp -m tcp --dport 10003 -j ACCEPT 600 -t nat -A PREROUTING -s ! 18.181.0.60 -i eth1 -p tcp -m tcp \ 601 --dport 10003 -j DNAT --to-destination 18.181.0.60:10003 602 -t nat -A POSTROUTING -d 18.181.0.60 -o eth1 -p tcp -m tcp \ 603 --dport 10003 -j SNAT --to-source 18.187.7.142 604 -A FORWARD -d 18.181.0.60 -i eth1 -o eth1 -p tcp -m tcp \ 605 --dport 10003 -j ACCEPT 474 606 475 607 Remember to enable iptables! … … 482 614 data = {} 483 615 data["user"] = user.username 484 data["machine"] =machine.name485 data["expires"] =time.time()+(5*60)486 pickled Data = cPickle.dumps(data)616 data["machine"] = machine.name 617 data["expires"] = time.time()+(5*60) 618 pickled_data = cPickle.dumps(data) 487 619 m = hmac.new(TOKEN_KEY, digestmod=sha) 488 m.update(pickled Data)489 token = {'data': pickled Data, 'digest': m.digest()}620 m.update(pickled_data) 621 token = {'data': pickled_data, 'digest': m.digest()} 490 622 token = cPickle.dumps(token) 491 623 token = base64.urlsafe_b64encode(token) … … 500 632 hostname=os.environ.get('SERVER_NAME', 'localhost'), 501 633 authtoken=token) 502 return Template(file='vnc.tmpl', 503 searchList=[d, global_dict]) 634 return Template(file='vnc.tmpl', searchList=[d]) 504 635 505 636 def getNicInfo(data_dict, machine): … … 517 648 for i in range(len(machine.nics)): 518 649 nic_fields.extend([(x % i, y % i) for x, y in nic_fields_template]) 519 data_dict['nic%s_hostname' % i] = machine.nics[i].hostname + '.servers.csail.mit.edu' 650 data_dict['nic%s_hostname' % i] = (machine.nics[i].hostname + 651 '.servers.csail.mit.edu') 520 652 data_dict['nic%s_mac' % i] = machine.nics[i].mac_addr 521 653 data_dict['nic%s_ip' % i] = machine.nics[i].ip … … 535 667 for disk in machine.disks: 536 668 name = disk.guest_device_name 537 disk_fields.extend([(x % name, y % name) for x, y in disk_fields_template]) 669 disk_fields.extend([(x % name, y % name) for x, y in 670 disk_fields_template]) 538 671 data_dict['%s_size' % name] = "%0.1f GB" % (disk.size / 1024.) 539 672 return disk_fields … … 543 676 remctl('control', machine.name, 'destroy', err=True) 544 677 transaction = ctx.current.create_transaction() 545 delete_disk_pairs = [(machine.name, d.guest_device_name) for d in machine.disks] 678 delete_disk_pairs = [(machine.name, d.guest_device_name) 679 for d in machine.disks] 546 680 try: 547 681 for nic in machine.nics: … … 560 694 unregisterMachine(machine) 561 695 562 def command(user, fields): 563 """Handler for running commands like boot and delete on a VM.""" 696 def commandResult(user, fields): 564 697 print >> sys.stderr, time.time()-start_time 565 698 machine = testMachineId(user, fields.getfirst('machine_id')) … … 569 702 if cdrom is not None and not CDROM.get(cdrom): 570 703 raise CodeError("Invalid cdrom type '%s'" % cdrom) 571 if action not in ('Reboot', 'Power on', 'Power off', 'Shutdown', 'Delete VM'): 704 if action not in ('Reboot', 'Power on', 'Power off', 'Shutdown', 705 'Delete VM'): 572 706 raise CodeError("Invalid action '%s'" % action) 573 707 if action == 'Reboot': 574 708 if cdrom is not None: 575 remctl('control', machine.name, 'reboot', cdrom) 709 out, err = remctl('control', machine.name, 'reboot', cdrom, 710 err=True) 576 711 else: 577 remctl('control', machine.name, 'reboot') 712 out, err = remctl('control', machine.name, 'reboot', 713 err=True) 714 if err: 715 if re.match("Error: Domain '.*' does not exist.", err): 716 raise InvalidInput("action", "reboot", 717 "Machine is not on") 718 else: 719 print >> sys.stderr, 'Error on reboot:' 720 print >> sys.stderr, err 721 raise CodeError('ERROR on remctl') 722 578 723 elif action == 'Power on': 579 724 if maxMemory(user) < machine.memory: 580 725 raise InvalidInput('action', 'Power on', 581 "You don't have enough free RAM quota to turn on this machine") 726 "You don't have enough free RAM quota " 727 "to turn on this machine.") 582 728 bootMachine(machine, cdrom) 583 729 elif action == 'Power off': 584 remctl('control', machine.name, 'destroy') 730 out, err = remctl('control', machine.name, 'destroy', err=True) 731 if err: 732 if re.match("Error: Domain '.*' does not exist.", err): 733 raise InvalidInput("action", "Power off", 734 "Machine is not on.") 735 else: 736 print >> sys.stderr, 'Error on power off:' 737 print >> sys.stderr, err 738 raise CodeError('ERROR on remctl') 585 739 elif action == 'Shutdown': 586 remctl('control', machine.name, 'shutdown') 740 out, err = remctl('control', machine.name, 'shutdown', err=True) 741 if err: 742 if re.match("Error: Domain '.*' does not exist.", err): 743 raise InvalidInput("action", "Shutdown", 744 "Machine is not on.") 745 else: 746 print >> sys.stderr, 'Error on Shutdown:' 747 print >> sys.stderr, err 748 raise CodeError('ERROR on remctl') 587 749 elif action == 'Delete VM': 588 750 deleteVM(machine) … … 592 754 command=action, 593 755 machine=machine) 594 return Template(file="command.tmpl", searchList=[d, global_dict]) 756 return d 757 758 def command(user, fields): 759 """Handler for running commands like boot and delete on a VM.""" 760 js = fields.getfirst('js') 761 try: 762 d = commandResult(user, fields) 763 except InvalidInput, err: 764 if not js: 765 raise 766 result = None 767 else: 768 err = None 769 result = 'Success!' 770 if not js: 771 return Template(file='command.tmpl', searchList=[d]) 772 if js == 'list': 773 g.clear() #Changed global state 774 d = getListDict(user) 775 t = Template(file='list.tmpl', searchList=[d]) 776 return JsonDict(createtable=t.createTable(), 777 machinelist=t.machineList(d['machines']), 778 result=result, 779 err=err) 780 elif js == 'info': 781 machine = testMachineId(user, fields.getfirst('machine_id')) 782 d = infoDict(user, machine) 783 t = Template(file='info.tmpl', searchList=[d]) 784 return JsonDict(info=t.infoTable(), 785 commands=t.commands(), 786 modify=t.modifyForm(), 787 result=result, 788 err=err) 789 else: 790 raise InvalidInput('js', js, 'Not a known js type.') 595 791 596 792 def testAdmin(user, admin, machine): … … 601 797 if getafsgroups.checkAfsGroup(user.username, admin, 'athena.mit.edu'): 602 798 return admin 603 if getafsgroups.checkAfsGroup(user.username, 'system:'+admin, 'athena.mit.edu'): 799 if getafsgroups.checkAfsGroup(user.username, 'system:'+admin, 800 'athena.mit.edu'): 604 801 return 'system:'+admin 605 raise InvalidInput('admin ', admin,606 'You must control the group you move it to ')802 raise InvalidInput('administrator', admin, 803 'You must control the group you move it to.') 607 804 608 805 def testOwner(user, owner, machine): 609 806 if owner in (None, machine.owner): 610 807 return None 611 #XXX should you be able to transfer ownership if you don't already own it?612 #if not owns(user, machine):613 # raise InvalidInput('owner', owner, "You don't own this machine, so you can't transfer ownership")614 808 value = getafsgroups.checkLockerOwner(user.username, owner, verbose=True) 615 809 if value == True: … … 621 815 return None 622 816 if not re.match("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$", contact, re.I): 623 raise InvalidInput('contact', contact, "Not a valid email ")817 raise InvalidInput('contact', contact, "Not a valid email.") 624 818 return contact 625 819 … … 632 826 if not Machine.select_by(name=name): 633 827 return name 634 raise InvalidInput('name', name, " Already taken")828 raise InvalidInput('name', name, "Name is already taken.") 635 829 636 830 def testHostname(user, hostname, machine): … … 643 837 "Already exists") 644 838 if not re.match("^[A-Z0-9-]{1,22}$", hostname, re.I): 645 raise InvalidInput('hostname', hostname, "Not a valid hostname; must only use number, letters, and dashes.") 839 raise InvalidInput('hostname', hostname, "Not a valid hostname; " 840 "must only use number, letters, and dashes.") 646 841 return hostname 647 842 648 def modify(user, fields): 649 """Handler for modifying attributes of a machine.""" 650 843 def modifyDict(user, fields): 651 844 olddisk = {} 652 845 transaction = ctx.current.create_transaction() … … 659 852 name = testName(user, fields.getfirst('name'), machine) 660 853 oldname = machine.name 661 command ="modify"854 command = "modify" 662 855 663 856 memory = fields.getfirst('memory') … … 675 868 ctx.current.save(disk) 676 869 677 # XXX first NIC gets hostname on change? Interface doesn't support more. 870 # XXX first NIC gets hostname on change? 871 # Interface doesn't support more. 678 872 for nic in machine.nics[:1]: 679 873 nic.hostname = hostname … … 700 894 remctl("web", "lvrename", oldname, disk.guest_device_name, name) 701 895 remctl("web", "moveregister", oldname, name) 702 d = dict(user=user, 703 command=command, 704 machine=machine) 705 return Template(file="command.tmpl", searchList=[d, global_dict]) 706 707 708 def help(user, fields): 896 return dict(user=user, 897 command=command, 898 machine=machine) 899 900 def modify(user, fields): 901 """Handler for modifying attributes of a machine.""" 902 js = fields.getfirst('js') 903 try: 904 modify_dict = modifyDict(user, fields) 905 except InvalidInput, err: 906 if not js: 907 raise 908 result = '' 909 machine = testMachineId(user, fields.getfirst('machine_id')) 910 else: 911 machine = modify_dict['machine'] 912 result='Success!' 913 err = None 914 if not js: 915 return Template(file='command.tmpl', searchList=[modify_dict]) 916 info_dict = infoDict(user, machine) 917 info_dict['err'] = err 918 if err: 919 for field in fields.keys(): 920 setattr(info_dict['defaults'], field, fields.getfirst(field)) 921 t = Template(file='info.tmpl', searchList=[info_dict]) 922 return JsonDict(info=t.infoTable(), 923 commands=t.commands(), 924 modify=t.modifyForm(), 925 result=result, 926 err=err) 927 928 929 def helpHandler(user, fields): 709 930 """Handler for help messages.""" 710 931 simple = fields.getfirst('simple') 711 932 subjects = fields.getlist('subject') 712 933 713 mapping = dict(paravm_console="""934 help_mapping = dict(paravm_console=""" 714 935 ParaVM machines do not support console access over VNC. To access 715 936 these machines, you either need to boot with a liveCD and ssh in or 716 937 hope that the sipb-xen maintainers add support for serial consoles.""", 717 hvm_paravm="""938 hvm_paravm=""" 718 939 HVM machines use the virtualization features of the processor, while 719 940 ParaVM machines use Xen's emulation of virtualization features. You 720 941 want an HVM virtualized machine.""", 721 cpu_weight="""Don't ask us! We're as mystified as you are.""", 722 owner="""The owner field is used to determine <a href="help?subject=quotas">quotas</a>. It must be the name 723 of a locker that you are an AFS administrator of. In particular, you 724 or an AFS group you are a member of must have AFS rlidwka bits on the 942 cpu_weight=""" 943 Don't ask us! We're as mystified as you are.""", 944 owner=""" 945 The owner field is used to determine <a 946 href="help?subject=quotas">quotas</a>. It must be the name of a 947 locker that you are an AFS administrator of. In particular, you or an 948 AFS group you are a member of must have AFS rlidwka bits on the 725 949 locker. You can check see who administers the LOCKER locker using the 726 command 'fs la /mit/LOCKER' on Athena.) See also <a href="help?subject=administrator">administrator</a>.""", 727 administrator="""The administrator field determines who can access the console and power on and off the machine. This can be either a user or a moira group.""", 728 quotas="""Quotas are determined on a per-locker basis. Each 729 quota may have a maximum of 512 megabytes of active ram, 50 gigabytes of disk, and 4 active machines.""" 730 950 command 'fs la /mit/LOCKER' on Athena.) See also <a 951 href="help?subject=administrator">administrator</a>.""", 952 administrator=""" 953 The administrator field determines who can access the console and 954 power on and off the machine. This can be either a user or a moira 955 group.""", 956 quotas=""" 957 Quotas are determined on a per-locker basis. Each quota may have a 958 maximum of 512 megabytes of active ram, 50 gigabytes of disk, and 4 959 active machines.""" 731 960 ) 732 961 733 962 if not subjects: 734 subjects = sorted( mapping.keys())963 subjects = sorted(help_mapping.keys()) 735 964 736 965 d = dict(user=user, 737 966 simple=simple, 738 967 subjects=subjects, 739 mapping=mapping) 740 741 return Template(file="help.tmpl", searchList=[d, global_dict]) 742 743 744 def info(user, fields): 745 """Handler for info on a single VM.""" 746 machine = testMachineId(user, fields.getfirst('machine_id')) 968 mapping=help_mapping) 969 970 return Template(file="help.tmpl", searchList=[d]) 971 972 973 def badOperation(u, e): 974 raise CodeError("Unknown operation") 975 976 def infoDict(user, machine): 747 977 status = statusInfo(machine) 748 978 has_vnc = hasVnc(status) … … 750 980 main_status = dict(name=machine.name, 751 981 memory=str(machine.memory)) 752 uptime =None753 cputime =None982 uptime = None 983 cputime = None 754 984 else: 755 985 main_status = dict(status[1:]) … … 789 1019 nic_fields = getNicInfo(machine_info, machine) 790 1020 nic_point = display_fields.index('NIC_INFO') 791 display_fields = display_fields[:nic_point] + nic_fields + display_fields[nic_point+1:] 1021 display_fields = (display_fields[:nic_point] + nic_fields + 1022 display_fields[nic_point+1:]) 792 1023 793 1024 disk_fields = getDiskInfo(machine_info, machine) 794 1025 disk_point = display_fields.index('DISK_INFO') 795 display_fields = display_fields[:disk_point] + disk_fields + display_fields[disk_point+1:] 1026 display_fields = (display_fields[:disk_point] + disk_fields + 1027 display_fields[disk_point+1:]) 796 1028 797 1029 main_status['memory'] += ' MB' … … 808 1040 max_mem = maxMemory(user, machine) 809 1041 max_disk = maxDisk(user, machine) 1042 defaults=Defaults() 1043 for name in 'machine_id name administrator owner memory contact'.split(): 1044 setattr(defaults, name, getattr(machine, name)) 1045 if machine.nics: 1046 defaults.hostname = machine.nics[0].hostname 1047 defaults.disk = "%0.2f" % (machine.disks[0].size/1024.) 810 1048 d = dict(user=user, 811 1049 cdroms=CDROM.select(), 812 1050 on=status is not None, 813 1051 machine=machine, 1052 defaults=defaults, 814 1053 has_vnc=has_vnc, 815 1054 uptime=str(uptime), … … 819 1058 owner_help=helppopup("owner"), 820 1059 fields = fields) 821 return Template(file='info.tmpl', 822 searchList=[d, global_dict]) 1060 return d 1061 1062 def info(user, fields): 1063 """Handler for info on a single VM.""" 1064 machine = testMachineId(user, fields.getfirst('machine_id')) 1065 d = infoDict(user, machine) 1066 return Template(file='info.tmpl', searchList=[d]) 823 1067 824 1068 mapping = dict(list=listVms, … … 828 1072 info=info, 829 1073 create=create, 830 help=help) 1074 help=helpHandler) 1075 1076 def printHeaders(headers): 1077 for key, value in headers.iteritems(): 1078 print '%s: %s' % (key, value) 1079 print 1080 1081 1082 def getUser(): 1083 """Return the current user based on the SSL environment variables""" 1084 if 'SSL_CLIENT_S_DN_Email' in os.environ: 1085 username = os.environ['SSL_CLIENT_S_DN_Email'].split("@")[0] 1086 return User(username, os.environ['SSL_CLIENT_S_DN_Email']) 1087 else: 1088 return User('moo', 'nobody') 831 1089 832 1090 if __name__ == '__main__': 833 1091 start_time = time.time() 834 1092 fields = cgi.FieldStorage() 835 class User: 836 username = "moo" 837 email = 'moo@cow.com' 838 u = User() 1093 u = getUser() 839 1094 g = Global(u) 840 if 'SSL_CLIENT_S_DN_Email' in os.environ:841 username = os.environ[ 'SSL_CLIENT_S_DN_Email'].split("@")[0]842 u.username = username843 u.email = os.environ[ 'SSL_CLIENT_S_DN_Email']844 else:845 u.username = 'moo'846 u.email = 'nobody'847 connect('postgres://sipb-xen@sipb-xen-dev/sipb_xen')848 1095 operation = os.environ.get('PATH_INFO', '') 849 1096 if not operation: … … 857 1104 operation = 'list' 858 1105 859 def badOperation(u, e): 860 raise CodeError("Unknown operation") 1106 861 1107 862 1108 fun = mapping.get(operation, badOperation) 863 if fun not in (help, ): 864 connect('postgres://sipb-xen@sipb-xen-dev/sipb_xen') 1109 1110 if fun not in (helpHandler, ): 1111 connect('postgres://sipb-xen@sipb-xen-dev.mit.edu/sipb_xen') 865 1112 try: 866 1113 output = fun(u, fields) 867 print 'Content-Type: text/html\n' 868 sys.stderr=sys.stdout 869 errio.seek(0) 870 e = errio.read() 1114 1115 headers = dict(default_headers) 1116 if isinstance(output, tuple): 1117 new_headers, output = output 1118 headers.update(new_headers) 1119 1120 e = revertStandardError() 871 1121 if e: 872 output = str(output)873 output = output.replace('<body>', '<body><p>STDERR:</p><pre>'+e+'</pre>')1122 output.addError(e) 1123 printHeaders(headers) 874 1124 print output 875 except CodeError, err: 876 print 'Content-Type: text/html\n' 877 sys.stderr=sys.stdout 878 errio.seek(0) 879 e = errio.read() 880 print error(operation, u, fields, err, e) 881 except InvalidInput, err: 882 print 'Content-Type: text/html\n' 883 sys.stderr=sys.stdout 884 errio.seek(0) 885 e = errio.read() 886 print invalidInput(operation, u, fields, err, e) 887 except: 1125 except Exception, err: 1126 if not fields.has_key('js'): 1127 if isinstance(err, CodeError): 1128 print 'Content-Type: text/html\n' 1129 e = revertStandardError() 1130 print error(operation, u, fields, err, e) 1131 sys.exit(1) 1132 if isinstance(err, InvalidInput): 1133 print 'Content-Type: text/html\n' 1134 e = revertStandardError() 1135 print invalidInput(operation, u, fields, err, e) 1136 sys.exit(1) 888 1137 print 'Content-Type: text/plain\n' 889 sys.stderr=sys.stdout 890 errio.seek(0) 891 e = errio.read() 1138 print 'Uh-oh! We experienced an error.' 1139 print 'Please email sipb-xen@mit.edu with the contents of this page.' 1140 print '----' 1141 e = revertStandardError() 892 1142 print e 893 1143 print '----' -
trunk/web/templates/skeleton.py
r187 r205 21 21 import Cheetah.Filters as Filters 22 22 import Cheetah.ErrorCatchers as ErrorCatchers 23 from functions import functions 23 24 24 25 ################################################## … … 34 35 __CHEETAH_version__ = '2.0rc8' 35 36 __CHEETAH_versionTuple__ = (2, 0, 0, 'candidate', 8) 36 __CHEETAH_genTime__ = 1192 082083.44486537 __CHEETAH_genTimestamp__ = ' Thu Oct 11 01:54:432007'37 __CHEETAH_genTime__ = 1192883107.2947011 38 __CHEETAH_genTimestamp__ = 'Sat Oct 20 08:25:07 2007' 38 39 __CHEETAH_src__ = 'skeleton.tmpl' 39 __CHEETAH_srcLastModified__ = ' Thu Oct 11 01:54:41 2007'40 __CHEETAH_srcLastModified__ = 'Sat Oct 20 08:22:11 2007' 40 41 __CHEETAH_docstring__ = 'Autogenerated by CHEETAH: The Python-Powered Template Engine' 41 42 … … 49 50 ## CLASSES 50 51 51 class skeleton( Template):52 class skeleton(functions): 52 53 53 54 ################################################## … … 57 58 def __init__(self, *args, **KWs): 58 59 59 Template.__init__(self, *args, **KWs)60 functions.__init__(self, *args, **KWs) 60 61 if not self._CHEETAH__instanceInitialized: 61 62 cheetahKWArgs = {} … … 66 67 67 68 68 def respond(self, trans=None): 69 70 71 72 ## CHEETAH: main method generated for this template 69 def full_body(self, **KWS): 70 71 72 73 ## CHEETAH: generated from #def full_body at line 4, col 1. 74 trans = KWS.get("trans") 73 75 if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)): 74 76 trans = self.transaction # is None unless self.awake() was called … … 84 86 ## START - generated method body 85 87 86 write('''<html> 88 write('''<!DOCTYPE html 89 PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 90 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 91 <html> 87 92 <head><title>''') 88 _v = VFFSL(SL,"title",True) # '$title' on line 2, col 1489 if _v is not None: write(_filter(_v, rawExpr='$title')) # from line 2, col 14.93 _v = VFFSL(SL,"title",True) # '$title' on line 9, col 14 94 if _v is not None: write(_filter(_v, rawExpr='$title')) # from line 9, col 14. 90 95 write('''</title> 91 96 <link href="static/favicon.ico" type="image/x-icon" rel="shortcut icon"> 92 97 <link rel="stylesheet" href="static/style.css" type="text/css" /> 93 98 <link rel="stylesheet" href="static/layout.css" type="text/css" media="screen" /> 99 <script type="text/javascript" src="static/prototype.js"></script> 94 100 <script type="text/javascript"> 95 101 var helpWin = null; … … 108 114 return false; 109 115 } 116 117 Ajax.Responders.register({ 118 onCreate: function(){ 119 if (Ajax.activeRequestCount > 0) { 120 document.getElementById("loadingnotice").style.display = \'block\'; 121 } 122 }, 123 onComplete: function(){ 124 if (Ajax.activeRequestCount == 0) { 125 document.getElementById("loadingnotice").style.display = \'none\'; 126 } 127 } 128 }); 129 function replaceFunc(transport) { 130 try { 131 d = transport.responseText.evalJSON(); 132 } catch (e) { 133 $(\'body\').innerHTML = \'<pre>\'+transport.responseText+\'</pre>\' 134 return; 135 } 136 for(key in d) { 137 $(key).innerHTML = d[key]; 138 } 139 } 140 141 function jsFormSubmit(location, elt){ 142 new Ajax.Request(location, {method: \'post\', 143 parameters: Form.serialize(elt)+\'&js=true\', 144 onSuccess: replaceFunc, 145 onComplete: function() {Form.enable(elt);} 146 }); 147 Form.disable(elt); 148 return false; 149 } 150 151 function rowFormSubmit(elt, retpage){ 152 new Ajax.Request(\'command\', {method: \'post\', 153 parameters: Form.serialize(elt)+\'&js=\'+retpage, 154 onSuccess: replaceFunc 155 }); 156 return false; 157 } 158 159 window.onload = { 160 //Fix bug with disabled elements 161 $''') 162 _v = 'form' # "$('form')" on line 75, col 4 163 if _v is not None: write(_filter(_v, rawExpr="$('form')")) # from line 75, col 4. 164 write('''.each(Form.enable); 165 } 166 110 167 </script> 111 168 </head> 112 <body> 113 ''') 114 if not VFFSL(SL,"varExists",False)('simple') or not VFFSL(SL,"simple",True): # generated from line 25, col 1 169 <body id="body"> 170 171 <div id="err"> 172 ''') 173 if VFFSL(SL,"varExists",False)('error_text'): # generated from line 83, col 1 174 write('''<p>STDERR:</p><pre>''') 175 _v = VFFSL(SL,"error_text",True) # '$error_text' on line 84, col 20 176 if _v is not None: write(_filter(_v, rawExpr='$error_text')) # from line 84, col 20. 177 write('''</pre> 178 ''') 179 write('''</div> 180 181 ''') 182 if not VFFSL(SL,"varExists",False)('simple') or not VFFSL(SL,"simple",True): # generated from line 88, col 1 115 183 write('''<p>[You are logged in as ''') 116 _v = VFFSL(SL,"user.username",True) # '$user.username' on line 26, col 26117 if _v is not None: write(_filter(_v, rawExpr='$user.username')) # from line 26, col 26.184 _v = VFFSL(SL,"user.username",True) # '$user.username' on line 89, col 26 185 if _v is not None: write(_filter(_v, rawExpr='$user.username')) # from line 89, col 26. 118 186 write('''.]</p> 187 188 <div class="navigation"> 119 189 <p><a href="list">List</a> 120 190 ''') 121 if VFFSL(SL,"varExists",False)('machine'): # generated from line 28, col 1191 if VFFSL(SL,"varExists",False)('machine'): # generated from line 93, col 1 122 192 write('''<a href="info?machine_id=''') 123 _v = VFFSL(SL,"machine.machine_id",True) # '$machine.machine_id' on line 29, col 26124 if _v is not None: write(_filter(_v, rawExpr='$machine.machine_id')) # from line 29, col 26.193 _v = VFFSL(SL,"machine.machine_id",True) # '$machine.machine_id' on line 94, col 26 194 if _v is not None: write(_filter(_v, rawExpr='$machine.machine_id')) # from line 94, col 26. 125 195 write('''">Info</a> 126 196 <a href="vnc?machine_id=''') 127 _v = VFFSL(SL,"machine.machine_id",True) # '$machine.machine_id' on line 30, col 25128 if _v is not None: write(_filter(_v, rawExpr='$machine.machine_id')) # from line 30, col 25.197 _v = VFFSL(SL,"machine.machine_id",True) # '$machine.machine_id' on line 95, col 25 198 if _v is not None: write(_filter(_v, rawExpr='$machine.machine_id')) # from line 95, col 25. 129 199 write('''">Console</a> 130 200 ''') 131 201 write('''<a href="help">Help</a></p> 132 202 ''') 133 _v = VFFSL(SL,"body",True) # '$body' on line 34, col 1 134 if _v is not None: write(_filter(_v, rawExpr='$body')) # from line 34, col 1. 203 write('''</div> 204 205 <div id="loadingnotice" class="loadingnotice">LOADING</div> 206 <div id="result" class="result"></div> 207 208 ''') 209 _v = VFFSL(SL,"body",True) # '$body' on line 104, col 1 210 if _v is not None: write(_filter(_v, rawExpr='$body')) # from line 104, col 1. 135 211 write(''' 136 212 ''') 137 if not VFFSL(SL,"varExists",False)('simple') or not VFFSL(SL,"simple",True): # generated from line 35, col 1213 if not VFFSL(SL,"varExists",False)('simple') or not VFFSL(SL,"simple",True): # generated from line 105, col 1 138 214 write('''<hr /> 139 215 Questions? Contact <a href="mailto:sipb-xen-dev@mit.edu">sipb-xen-dev@mit.edu</a>. … … 148 224 return _dummyTrans and trans.response().getvalue() or "" 149 225 226 227 def writeBody(self, **KWS): 228 229 230 231 ## CHEETAH: main method generated for this template 232 trans = KWS.get("trans") 233 if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)): 234 trans = self.transaction # is None unless self.awake() was called 235 if not trans: 236 trans = DummyTransaction() 237 _dummyTrans = True 238 else: _dummyTrans = False 239 write = trans.response().write 240 SL = self._CHEETAH__searchList 241 _filter = self._CHEETAH__currentFilter 242 243 ######################################## 244 ## START - generated method body 245 246 write(''' 247 ''') 248 249 ######################################## 250 ## END - generated method body 251 252 return _dummyTrans and trans.response().getvalue() or "" 253 150 254 ################################################## 151 255 ## CHEETAH GENERATED ATTRIBUTES … … 166 270 _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__ 167 271 168 _mainCheetahMethod_for_skeleton= ' respond'272 _mainCheetahMethod_for_skeleton= 'writeBody' 169 273 170 274 ## END CLASS DEFINITION -
trunk/web/templates/skeleton.tmpl
r187 r205 1 #from functions import functions 2 #extends functions 3 4 #def full_body 5 <!DOCTYPE html 6 PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 7 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 1 8 <html> 2 9 <head><title>$title</title> … … 4 11 <link rel="stylesheet" href="static/style.css" type="text/css" /> 5 12 <link rel="stylesheet" href="static/layout.css" type="text/css" media="screen" /> 13 <script type="text/javascript" src="static/prototype.js"></script> 6 14 <script type="text/javascript"> 7 15 var helpWin = null; … … 20 28 return false; 21 29 } 30 31 Ajax.Responders.register({ 32 onCreate: function(){ 33 if (Ajax.activeRequestCount > 0) { 34 document.getElementById("loadingnotice").style.display = 'block'; 35 } 36 }, 37 onComplete: function(){ 38 if (Ajax.activeRequestCount == 0) { 39 document.getElementById("loadingnotice").style.display = 'none'; 40 } 41 } 42 }); 43 function replaceFunc(transport) { 44 try { 45 d = transport.responseText.evalJSON(); 46 } catch (e) { 47 \$('body').innerHTML = '<pre>'+transport.responseText+'</pre>' 48 return; 49 } 50 for(key in d) { 51 \$(key).innerHTML = d[key]; 52 } 53 } 54 55 function jsFormSubmit(location, elt){ 56 new Ajax.Request(location, {method: 'post', 57 parameters: Form.serialize(elt)+'&js=true', 58 onSuccess: replaceFunc, 59 onComplete: function() {Form.enable(elt);} 60 }); 61 Form.disable(elt); 62 return false; 63 } 64 65 function rowFormSubmit(elt, retpage){ 66 new Ajax.Request('command', {method: 'post', 67 parameters: Form.serialize(elt)+'&js='+retpage, 68 onSuccess: replaceFunc 69 }); 70 return false; 71 } 72 73 window.onload = { 74 //Fix bug with disabled elements 75 $$('form').each(Form.enable); 76 } 77 22 78 </script> 23 79 </head> 24 <body> 80 <body id="body"> 81 82 <div id="err"> 83 #if $varExists('error_text') 84 <p>STDERR:</p><pre>$error_text</pre> 85 #end if 86 </div> 87 25 88 #if not $varExists('simple') or not $simple 26 89 <p>[You are logged in as $user.username.]</p> 90 91 <div class="navigation"> 27 92 <p><a href="list">List</a> 28 93 #if $varExists('machine') … … 32 97 <a href="help">Help</a></p> 33 98 #end if 99 </div> 100 101 <div id="loadingnotice" class="loadingnotice">LOADING</div> 102 <div id="result" class="result"></div> 103 34 104 $body 35 105 #if not $varExists('simple') or not $simple … … 39 109 </body> 40 110 </html> 111 #end def -
trunk/web/templates/static/style.css
r182 r205 67 67 font-family: "Bitstream Vera Sans Mono", "Luxi Mono", "Courier New", monospace; 68 68 } 69 70 #loadingnotice { 71 padding: 2px; 72 display: none; 73 color: #FFFFFF; 74 background: #CC2200; 75 position: fixed; 76 right: 10px; 77 top: 5px; 78 } 79 80 .error { 81 color: #FF0000; 82 padding: 0.25em; 83 } 84 85 td.error { 86 border: 1px solid red; 87 }
Note: See TracChangeset
for help on using the changeset viewer.