Use the compiled Cheetah templates.
[invirt/packages/invirt-web.git] / templates / main.py
index ab70cdd..e7412ba 100755 (executable)
@@ -35,24 +35,35 @@ if __name__ == '__main__':
 
 sys.path.append('/home/ecprice/.local/lib/python2.5/site-packages')
 
+import templates
 from Cheetah.Template import Template
 from sipb_xen_database import Machine, CDROM, ctx, connect
 import validation
 from webcommon import InvalidInput, CodeError, g
 import controls
 
+class Checkpoint:
+    def __init__(self):
+        self.start_time = time.time()
+        self.checkpoints = []
+
+    def checkpoint(self, s):
+        self.checkpoints.append((s, time.time()))
+
+    def __str__(self):
+        return ('Timing info:\n%s\n' %
+                '\n'.join(['%s: %s' % (d, t - self.start_time) for
+                           (d, t) in self.checkpoints]))
+
+checkpoint = Checkpoint()
+
+
 def helppopup(subj):
     """Return HTML code for a (?) link to a specified help topic"""
     return ('<span class="helplink"><a href="help?subject=' + subj + 
             '&amp;simple=true" target="_blank" ' + 
             'onclick="return helppopup(\'' + subj + '\')">(?)</a></span>')
 
-class User:
-    """User class (sort of useless, I admit)"""
-    def __init__(self, username, email):
-        self.username = username
-        self.email = email
-
 def makeErrorPre(old, addition):
     if addition is None:
         return
@@ -104,14 +115,14 @@ def error(op, user, fields, err, emsg):
     """Print an error page when a CodeError occurs"""
     d = dict(op=op, user=user, errorMessage=str(err),
              stderr=emsg)
-    return Template(file='error.tmpl', searchList=[d])
+    return templates.error(searchList=[d])
 
 def invalidInput(op, user, fields, err, emsg):
     """Print an error page when an InvalidInput exception occurs"""
     d = dict(op=op, user=user, err_field=err.err_field,
              err_value=str(err.err_value), stderr=emsg,
              errorMessage=str(err))
-    return Template(file='invalid.tmpl', searchList=[d])
+    return templates.invalid(searchList=[d])
 
 def hasVnc(status):
     """Does the machine with a given status list support VNC?"""
@@ -133,6 +144,8 @@ def parseCreate(user, fields):
         raise InvalidInput('name', name,
                            "Name already exists.")
     
+    owner = validation.testOwner(user, fields.getfirst('owner'))
+
     memory = fields.getfirst('memory')
     memory = validation.validMemory(user, memory, on=True)
     
@@ -147,8 +160,8 @@ def parseCreate(user, fields):
     cdrom = fields.getfirst('cdrom')
     if cdrom is not None and not CDROM.get(cdrom):
         raise CodeError("Invalid cdrom type '%s'" % cdrom)
-    return dict(user=user, name=name, memory=memory, disk=disk,
-                is_hvm=is_hvm, cdrom=cdrom)
+    return dict(contact=user, name=name, memory=memory, disk=disk,
+                owner=owner, is_hvm=is_hvm, cdrom=cdrom)
 
 def create(user, fields):
     """Handler for create requests."""
@@ -167,15 +180,17 @@ def create(user, fields):
             setattr(d['defaults'], field, fields.getfirst(field))
     else:
         d['new_machine'] = parsed_fields['name']
-    return Template(file='list.tmpl', searchList=[d])
+    return templates.list(searchList=[d])
 
 
 def getListDict(user):
     machines = [m for m in Machine.select() 
                 if validation.haveAccess(user, m)]    
+    checkpoint.checkpoint('Got my machines')
     on = {}
     has_vnc = {}
     on = g.uptimes
+    checkpoint.checkpoint('Got uptimes')
     for m in machines:
         m.uptime = g.uptimes.get(m)
         if not on[m]:
@@ -186,9 +201,12 @@ def getListDict(user):
             has_vnc[m] = "ParaVM"+helppopup("paravm_console")
     max_memory = validation.maxMemory(user)
     max_disk = validation.maxDisk(user)
+    checkpoint.checkpoint('Got max mem/disk')
     defaults = Defaults(max_memory=max_memory,
                         max_disk=max_disk,
+                        owner=user,
                         cdrom='gutsy-i386')
+    checkpoint.checkpoint('Got defaults')
     d = dict(user=user,
              cant_add_vm=validation.cantAddVm(user),
              max_memory=max_memory,
@@ -202,8 +220,10 @@ def getListDict(user):
 
 def listVms(user, fields):
     """Handler for list requests."""
+    checkpoint.checkpoint('Getting list dict')
     d = getListDict(user)
-    return Template(file='list.tmpl', searchList=[d])
+    checkpoint.checkpoint('Got list dict')
+    return templates.list(searchList=[d])
             
 def vnc(user, fields):
     """VNC applet page.
@@ -230,7 +250,7 @@ def vnc(user, fields):
     TOKEN_KEY = "0M6W0U1IXexThi5idy8mnkqPKEq1LtEnlK/pZSn0cDrN"
 
     data = {}
-    data["user"] = user.username
+    data["user"] = user
     data["machine"] = machine.name
     data["expires"] = time.time()+(5*60)
     pickled_data = cPickle.dumps(data)
@@ -249,7 +269,7 @@ def vnc(user, fields):
              machine=machine,
              hostname=os.environ.get('SERVER_NAME', 'localhost'),
              authtoken=token)
-    return Template(file='vnc.tmpl', searchList=[d])
+    return templates.vnc(searchList=[d])
 
 def getNicInfo(data_dict, machine):
     """Helper function for info, get data on nics for a machine.
@@ -258,15 +278,16 @@ def getNicInfo(data_dict, machine):
     of (key, name) pairs to display "name: data_dict[key]" to the user.
     """
     data_dict['num_nics'] = len(machine.nics)
-    nic_fields_template = [('nic%s_hostname', 'NIC %s hostname'),
+    nic_fields_template = [('nic%s_hostname', 'NIC %s Hostname'),
                            ('nic%s_mac', 'NIC %s MAC Addr'),
                            ('nic%s_ip', 'NIC %s IP'),
                            ]
     nic_fields = []
     for i in range(len(machine.nics)):
         nic_fields.extend([(x % i, y % i) for x, y in nic_fields_template])
-        data_dict['nic%s_hostname' % i] = (machine.nics[i].hostname + 
-                                           '.servers.csail.mit.edu')
+        if not i:
+            data_dict['nic%s_hostname' % i] = (machine.name + 
+                                               '.servers.csail.mit.edu')
         data_dict['nic%s_mac' % i] = machine.nics[i].mac_addr
         data_dict['nic%s_ip' % i] = machine.nics[i].ip
     if len(machine.nics) == 1:
@@ -286,7 +307,7 @@ def getDiskInfo(data_dict, machine):
         name = disk.guest_device_name
         disk_fields.extend([(x % name, y % name) for x, y in 
                             disk_fields_template])
-        data_dict['%s_size' % name] = "%0.1f GB" % (disk.size / 1024.)
+        data_dict['%s_size' % name] = "%0.1f GiB" % (disk.size / 1024.)
     return disk_fields
 
 def command(user, fields):
@@ -304,19 +325,20 @@ def command(user, fields):
     else:
         result = 'Success!'
         if not back:
-            return Template(file='command.tmpl', searchList=[d])
+            return templates.command(searchList=[d])
     if back == 'list':
         g.clear() #Changed global state
         d = getListDict(user)
         d['result'] = result
-        return Template(file='list.tmpl', searchList=[d])
+        return templates.list(searchList=[d])
     elif back == 'info':
         machine = validation.testMachineId(user, fields.getfirst('machine_id'))
         d = infoDict(user, machine)
         d['result'] = result
-        return Template(file='info.tmpl', searchList=[d])
+        return templates.info(searchList=[d])
     else:
-        raise InvalidInput('back', back, 'Not a known back page.')
+        raise InvalidInput
+    ('back', back, 'Not a known back page.')
 
 def modifyDict(user, fields):
     olddisk = {}
@@ -328,8 +350,6 @@ def modifyDict(user, fields):
                                      machine)
         contact = validation.testContact(user, fields.getfirst('contact'),
                                          machine)
-        hostname = validation.testHostname(owner, fields.getfirst('hostname'),
-                                           machine)
         name = validation.testName(user, fields.getfirst('name'), machine)
         oldname = machine.name
         command = "modify"
@@ -348,12 +368,6 @@ def modifyDict(user, fields):
                 disk.size = disksize
                 ctx.current.save(disk)
         
-        # XXX first NIC gets hostname on change?  
-        # Interface doesn't support more.
-        for nic in machine.nics[:1]:
-            nic.hostname = hostname
-            ctx.current.save(nic)
-
         if owner is not None:
             machine.owner = owner
         if name is not None:
@@ -393,7 +407,7 @@ def modify(user, fields):
         for field in fields.keys():
             setattr(info_dict['defaults'], field, fields.getfirst(field))
     info_dict['result'] = result
-    return Template(file='info.tmpl', searchList=[info_dict])
+    return templates.info(searchList=[info_dict])
     
 
 def helpHandler(user, fields):
@@ -437,7 +451,7 @@ active machines."""
              subjects=subjects,
              mapping=help_mapping)
     
-    return Template(file="help.tmpl", searchList=[d])
+    return templates.help(searchList=[d])
     
 
 def badOperation(u, e):
@@ -445,6 +459,7 @@ def badOperation(u, e):
 
 def infoDict(user, machine):
     status = controls.statusInfo(machine)
+    checkpoint.checkpoint('Getting status info')
     has_vnc = hasVnc(status)
     if status is None:
         main_status = dict(name=machine.name,
@@ -457,6 +472,7 @@ def infoDict(user, machine):
         uptime = datetime.timedelta(seconds=int(time.time()-start_time))
         cpu_time_float = float(main_status.get('cpu_time', 0))
         cputime = datetime.timedelta(seconds=int(cpu_time_float))
+    checkpoint.checkpoint('Status')
     display_fields = """name uptime memory state cpu_weight on_reboot 
      on_poweroff on_crash on_xend_start on_xend_stop bootloader""".split()
     display_fields = [('name', 'Name'),
@@ -496,7 +512,7 @@ def infoDict(user, machine):
     display_fields = (display_fields[:disk_point] + disk_fields + 
                       display_fields[disk_point+1:])
     
-    main_status['memory'] += ' MB'
+    main_status['memory'] += ' MiB'
     for field, disp in display_fields:
         if field in ('uptime', 'cputime') and locals()[field] is not None:
             fields.append((disp, locals()[field]))
@@ -507,14 +523,18 @@ def infoDict(user, machine):
         else:
             pass
             #fields.append((disp, None))
-    max_mem = validation.maxMemory(user, machine)
+
+    checkpoint.checkpoint('Got fields')
+
+
+    max_mem = validation.maxMemory(user, machine, False)
+    checkpoint.checkpoint('Got mem')
     max_disk = validation.maxDisk(user, machine)
     defaults = Defaults()
     for name in 'machine_id name administrator owner memory contact'.split():
         setattr(defaults, name, getattr(machine, name))
-    if machine.nics:
-        defaults.hostname = machine.nics[0].hostname
     defaults.disk = "%0.2f" % (machine.disks[0].size/1024.)
+    checkpoint.checkpoint('Got defaults')
     d = dict(user=user,
              cdroms=CDROM.select(),
              on=status is not None,
@@ -533,7 +553,8 @@ def info(user, fields):
     """Handler for info on a single VM."""
     machine = validation.testMachineId(user, fields.getfirst('machine_id'))
     d = infoDict(user, machine)
-    return Template(file='info.tmpl', searchList=[d])
+    checkpoint.checkpoint('Got infodict')
+    return templates.info(searchList=[d])
 
 mapping = dict(list=listVms,
                vnc=vnc,
@@ -553,28 +574,33 @@ def getUser():
     """Return the current user based on the SSL environment variables"""
     if 'SSL_CLIENT_S_DN_Email' in os.environ:
         username = os.environ['SSL_CLIENT_S_DN_Email'].split("@")[0]
-        return User(username, os.environ['SSL_CLIENT_S_DN_Email'])
+        return username
     else:
-        return User('moo', 'nobody')
+        return 'moo'
 
 def main(operation, user, fields):    
+    start_time = time.time()
     fun = mapping.get(operation, badOperation)
 
     if fun not in (helpHandler, ):
         connect('postgres://sipb-xen@sipb-xen-dev.mit.edu/sipb_xen')
     try:
+        checkpoint.checkpoint('Before')
         output = fun(u, fields)
+        checkpoint.checkpoint('After')
 
         headers = dict(DEFAULT_HEADERS)
         if isinstance(output, tuple):
             new_headers, output = output
             headers.update(new_headers)
-
         e = revertStandardError()
         if e:
             output.addError(e)
         printHeaders(headers)
-        print output
+        output_string =  str(output)
+        checkpoint.checkpoint('output as a string')
+        print output_string
+        print '<pre>%s</pre>' % checkpoint
     except Exception, err:
         if not fields.has_key('js'):
             if isinstance(err, CodeError):
@@ -597,7 +623,6 @@ def main(operation, user, fields):
         raise
 
 if __name__ == '__main__':
-    start_time = time.time()
     fields = cgi.FieldStorage()
     u = getUser()
     g.user = u
@@ -612,5 +637,7 @@ if __name__ == '__main__':
     if not operation:
         operation = 'list'
 
-    main(operation, u, fields)
+    #main(operation, u, fields)
+    import profile
+    profile.run('main(operation, u, fields)', 'log-'+operation)