Removed outdated CPU weight and added Windows 7 help.
[invirt/packages/invirt-web.git] / code / main.py
index 3be15a6..cf0aca2 100755 (executable)
@@ -6,6 +6,7 @@ import cPickle
 import cgi
 import datetime
 import hmac
 import cgi
 import datetime
 import hmac
+import os
 import random
 import sha
 import sys
 import random
 import sha
 import sys
@@ -37,11 +38,20 @@ from invirt.common import InvalidInput, CodeError
 
 from view import View, revertStandardError
 
 
 from view import View, revertStandardError
 
+
+static_dir = os.path.join(os.path.dirname(__file__), 'static')
+InvirtStatic = cherrypy.tools.staticdir.handler(
+    root=static_dir,
+    dir=static_dir,
+    section='/static')
+
 class InvirtUnauthWeb(View):
 class InvirtUnauthWeb(View):
+    static = InvirtStatic
+
     @cherrypy.expose
     @cherrypy.tools.mako(filename="/unauth.mako")
     def index(self):
     @cherrypy.expose
     @cherrypy.tools.mako(filename="/unauth.mako")
     def index(self):
-        return {'simple': True}
+        return dict(simple=True)
 
 class InvirtWeb(View):
     def __init__(self):
 
 class InvirtWeb(View):
     def __init__(self):
@@ -53,6 +63,8 @@ class InvirtWeb(View):
                                                  'from invirt import database']
         self._cp_config['request.error_response'] = self.handle_error
 
                                                  'from invirt import database']
         self._cp_config['request.error_response'] = self.handle_error
 
+    static = InvirtStatic
+
     @cherrypy.expose
     @cherrypy.tools.mako(filename="/invalid.mako")
     def invalidInput(self):
     @cherrypy.expose
     @cherrypy.tools.mako(filename="/invalid.mako")
     def invalidInput(self):
@@ -85,6 +97,9 @@ class InvirtWeb(View):
         return d
 
     def __getattr__(self, name):
         return d
 
     def __getattr__(self, name):
+        # At the point __getattr__ is called, tools haven't been run. Make sure the user is logged in.
+        cherrypy.tools.remote_user_login.callable()
+
         if name in ("admin", "overlord"):
             if not cherrypy.request.login in getAfsGroupMembers(config.adminacl, config.authz.afs.cells[0].cell):
                 raise InvalidInput('username', cherrypy.request.login,
         if name in ("admin", "overlord"):
             if not cherrypy.request.login in getAfsGroupMembers(config.adminacl, config.authz.afs.cells[0].cell):
                 raise InvalidInput('username', cherrypy.request.login,
@@ -112,11 +127,9 @@ class InvirtWeb(View):
     @cherrypy.tools.mako(filename="/list.mako")
     def list(self, result=None):
         """Handler for list requests."""
     @cherrypy.tools.mako(filename="/list.mako")
     def list(self, result=None):
         """Handler for list requests."""
-        checkpoint.checkpoint('Getting list dict')
         d = getListDict(cherrypy.request.login, cherrypy.request.state)
         if result is not None:
             d['result'] = result
         d = getListDict(cherrypy.request.login, cherrypy.request.state)
         if result is not None:
             d['result'] = result
-        checkpoint.checkpoint('Got list dict')
         return d
     index=list
 
         return d
     index=list
 
@@ -158,8 +171,6 @@ wiki</a>, including steps to prepare an HVM guest to boot as a ParaVM
 
 <p>We recommend using a ParaVM when possible and an HVM when necessary.
 """,
 
 <p>We recommend using a ParaVM when possible and an HVM when necessary.
 """,
-            'CPU Weight': """
-Don't ask us!  We're as mystified as you are.""",
             'Owner': """
 The owner field is used to determine <a
 href="help?subject=Quotas">quotas</a>.  It must be the name of a
             'Owner': """
 The owner field is used to determine <a
 href="help?subject=Quotas">quotas</a>.  It must be the name of a
@@ -183,8 +194,9 @@ your machine will run just fine, but the applet's display of the
 console will suffer artifacts.
 """,
             'Windows': """
 console will suffer artifacts.
 """,
             'Windows': """
+<strong>Windows 7:</strong> The Windows 7 image is licensed for all MIT students and will automatically activate off the network. The installer requires 512 MiB RAM and at least 15 GiB disk space (20 GiB or more recommended).<br>
 <strong>Windows Vista:</strong> The Vista image is licensed for all MIT students and will automatically activate off the network; see <a href="/static/msca-email.txt">the licensing confirmation e-mail</a> for details. The installer requires 512 MiB RAM and at least 7.5 GiB disk space (15 GiB or more recommended).<br>
 <strong>Windows Vista:</strong> The Vista image is licensed for all MIT students and will automatically activate off the network; see <a href="/static/msca-email.txt">the licensing confirmation e-mail</a> for details. The installer requires 512 MiB RAM and at least 7.5 GiB disk space (15 GiB or more recommended).<br>
-<strong>Windows XP:</strong> This is the volume license CD image. You will need your own volume license key to complete the install. We do not have these available for the general MIT community; ask your department if they have one, or visit <a href="http://msca.mit.edu/">http://msca.mit.edu/</a> if you are staff/faculty to request one.
+<strong>Windows XP:</strong> This is the volume license CD image. You will need your own volume license key to complete the install. We do not have these available for the general MIT community; ask your department if they have one, or visit <a href="http://msca.mit.edu/">http://msca.mit.edu/</a> if you are staff/faculty to request one. 
 """
             }
 
 """
             }
 
@@ -273,7 +285,6 @@ console will suffer artifacts.
                                           cherrypy.request.state,
                                           machine_id=machine_id).machine
             d = infoDict(cherrypy.request.login, cherrypy.request.state, machine)
                                           cherrypy.request.state,
                                           machine_id=machine_id).machine
             d = infoDict(cherrypy.request.login, cherrypy.request.state, machine)
-            checkpoint.checkpoint('Got infodict')
             return d
         index = info
 
             return d
         index = info
 
@@ -381,20 +392,6 @@ console will suffer artifacts.
 
     machine = MachineView()
 
 
     machine = MachineView()
 
-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()
 
 class Defaults:
     """Class to store default values for fields."""
 
 class Defaults:
     """Class to store default values for fields."""
@@ -428,14 +425,11 @@ def hasVnc(status):
 
 def getListDict(username, state):
     """Gets the list of local variables used by list.tmpl."""
 
 def getListDict(username, state):
     """Gets the list of local variables used by list.tmpl."""
-    checkpoint.checkpoint('Starting')
     machines = state.machines
     machines = state.machines
-    checkpoint.checkpoint('Got my machines')
     on = {}
     has_vnc = {}
     installing = {}
     xmlist = state.xmlist
     on = {}
     has_vnc = {}
     installing = {}
     xmlist = state.xmlist
-    checkpoint.checkpoint('Got uptimes')
     for m in machines:
         if m not in xmlist:
             has_vnc[m] = 'Off'
     for m in machines:
         if m not in xmlist:
             has_vnc[m] = 'Off'
@@ -451,11 +445,9 @@ def getListDict(username, state):
                 has_vnc[m] = "ParaVM"
     max_memory = validation.maxMemory(username, state)
     max_disk = validation.maxDisk(username)
                 has_vnc[m] = "ParaVM"
     max_memory = validation.maxMemory(username, state)
     max_disk = validation.maxDisk(username)
-    checkpoint.checkpoint('Got max mem/disk')
     defaults = Defaults(max_memory=max_memory,
                         max_disk=max_disk,
                         owner=username)
     defaults = Defaults(max_memory=max_memory,
                         max_disk=max_disk,
                         owner=username)
-    checkpoint.checkpoint('Got defaults')
     def sortkey(machine):
         return (machine.owner != username, machine.owner, machine.name)
     machines = sorted(machines, key=sortkey)
     def sortkey(machine):
         return (machine.owner != username, machine.owner, machine.name)
     machines = sorted(machines, key=sortkey)
@@ -466,7 +458,8 @@ def getListDict(username, state):
              defaults=defaults,
              machines=machines,
              has_vnc=has_vnc,
              defaults=defaults,
              machines=machines,
              has_vnc=has_vnc,
-             installing=installing)
+             installing=installing,
+             disable_creation=False)
     return d
 
 def getHostname(nic):
     return d
 
 def getHostname(nic):
@@ -530,9 +523,9 @@ def modifyDict(username, state, machine_id, fields):
     olddisk = {}
     session.begin()
     try:
     olddisk = {}
     session.begin()
     try:
-        kws = dict([(kw, fields[kw]) for kw in
+        kws = dict((kw, fields[kw]) for kw in
          'owner admin contact name description memory vmtype disksize'.split()
          'owner admin contact name description memory vmtype disksize'.split()
-                    if fields[kw]])
+                    if fields.get(kw))
         kws['machine_id'] = machine_id
         validate = validation.Validate(username, state, **kws)
         machine = validate.machine
         kws['machine_id'] = machine_id
         validate = validation.Validate(username, state, **kws)
         machine = validate.machine
@@ -544,6 +537,26 @@ def modifyDict(username, state, machine_id, fields):
         if hasattr(validate, 'vmtype'):
             machine.type = validate.vmtype
 
         if hasattr(validate, 'vmtype'):
             machine.type = validate.vmtype
 
+        update_acl = False
+        if hasattr(validate, 'owner') and validate.owner != machine.owner:
+            machine.owner = validate.owner
+            update_acl = True
+        if hasattr(validate, 'description'):
+            machine.description = validate.description
+        if hasattr(validate, 'admin') and validate.admin != machine.administrator:
+            machine.administrator = validate.admin
+            update_acl = True
+        if hasattr(validate, 'contact'):
+            machine.contact = validate.contact
+
+        session.save_or_update(machine)
+        session.commit()
+    except:
+        session.rollback()
+        raise
+
+    session.begin()
+    try:
         if hasattr(validate, 'disksize'):
             disksize = validate.disksize
             disk = machine.disks[0]
         if hasattr(validate, 'disksize'):
             disksize = validate.disksize
             disk = machine.disks[0]
@@ -551,41 +564,37 @@ def modifyDict(username, state, machine_id, fields):
                 olddisk[disk.guest_device_name] = disksize
                 disk.size = disksize
                 session.save_or_update(disk)
                 olddisk[disk.guest_device_name] = disksize
                 disk.size = disksize
                 session.save_or_update(disk)
+        for diskname in olddisk:
+            controls.resizeDisk(oldname, diskname, str(olddisk[diskname]))
+        session.save_or_update(machine)
+        session.commit()
+    except:
+        session.rollback()
+        raise
 
 
-        update_acl = False
-        if hasattr(validate, 'owner') and validate.owner != machine.owner:
-            machine.owner = validate.owner
-            update_acl = True
+    session.begin()
+    try:
         if hasattr(validate, 'name'):
             machine.name = validate.name
             for n in machine.nics:
                 if n.hostname == oldname:
                     n.hostname = validate.name
         if hasattr(validate, 'name'):
             machine.name = validate.name
             for n in machine.nics:
                 if n.hostname == oldname:
                     n.hostname = validate.name
-        if hasattr(validate, 'description'):
-            machine.description = validate.description
-        if hasattr(validate, 'admin') and validate.admin != machine.administrator:
-            machine.administrator = validate.admin
-            update_acl = True
-        if hasattr(validate, 'contact'):
-            machine.contact = validate.contact
-
+        if hasattr(validate, 'name'):
+            controls.renameMachine(machine, oldname, validate.name)
         session.save_or_update(machine)
         session.save_or_update(machine)
-        if update_acl:
-            cache_acls.refreshMachine(machine)
         session.commit()
     except:
         session.rollback()
         raise
         session.commit()
     except:
         session.rollback()
         raise
-    for diskname in olddisk:
-        controls.resizeDisk(oldname, diskname, str(olddisk[diskname]))
-    if hasattr(validate, 'name'):
-        controls.renameMachine(machine, oldname, validate.name)
+
+    if update_acl:
+        cache_acls.refreshMachine(machine)
+
     return dict(machine=machine)
 
 def infoDict(username, state, machine):
     """Get the variables used by info.tmpl."""
     status = controls.statusInfo(machine)
     return dict(machine=machine)
 
 def infoDict(username, state, machine):
     """Get the variables used by info.tmpl."""
     status = controls.statusInfo(machine)
-    checkpoint.checkpoint('Getting status info')
     has_vnc = hasVnc(status)
     if status is None:
         main_status = dict(name=machine.name,
     has_vnc = hasVnc(status)
     if status is None:
         main_status = dict(name=machine.name,
@@ -595,11 +604,14 @@ def infoDict(username, state, machine):
     else:
         main_status = dict(status[1:])
         main_status['host'] = controls.listHost(machine)
     else:
         main_status = dict(status[1:])
         main_status['host'] = controls.listHost(machine)
-        start_time = float(main_status.get('start_time', 0))
-        uptime = datetime.timedelta(seconds=int(time.time()-start_time))
+        start_time = main_status.get('start_time')
+        if start_time is None:
+            uptime = "Still booting?"
+        else:
+            start_time = float(start_time)
+            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))
         cpu_time_float = float(main_status.get('cpu_time', 0))
         cputime = datetime.timedelta(seconds=int(cpu_time_float))
-    checkpoint.checkpoint('Status')
     display_fields = [('name', 'Name'),
                       ('description', 'Description'),
                       ('owner', 'Owner'),
     display_fields = [('name', 'Name'),
                       ('description', 'Description'),
                       ('owner', 'Owner'),
@@ -645,11 +657,7 @@ def infoDict(username, state, machine):
             pass
             #fields.append((disp, None))
 
             pass
             #fields.append((disp, None))
 
-    checkpoint.checkpoint('Got fields')
-
-
     max_mem = validation.maxMemory(machine.owner, state, machine, False)
     max_mem = validation.maxMemory(machine.owner, state, machine, False)
-    checkpoint.checkpoint('Got mem')
     max_disk = validation.maxDisk(machine.owner, machine)
     defaults = Defaults()
     for name in 'machine_id name description administrator owner memory contact'.split():
     max_disk = validation.maxDisk(machine.owner, machine)
     defaults = Defaults()
     for name in 'machine_id name description administrator owner memory contact'.split():
@@ -657,7 +665,6 @@ def infoDict(username, state, machine):
             setattr(defaults, name, getattr(machine, name))
     defaults.type = machine.type.type_id
     defaults.disk = "%0.2f" % (machine.disks[0].size/1024.)
             setattr(defaults, name, getattr(machine, name))
     defaults.type = machine.type.type_id
     defaults.disk = "%0.2f" % (machine.disks[0].size/1024.)
-    checkpoint.checkpoint('Got defaults')
     d = dict(user=username,
              on=status is not None,
              machine=machine,
     d = dict(user=username,
              on=status is not None,
              machine=machine,