Implement administrator mode
[invirt/packages/invirt-web.git] / code / main.py
index ba892bf..5de084e 100755 (executable)
@@ -55,6 +55,15 @@ class InvirtWeb(View):
         self._cp_config['tools.mako.imports'] = ['from invirt.config import structs as config',
                                                  'from invirt import database']
 
+    def __getattr__(self, name):
+        if name in ("admin", "overlord"):
+            if not cherrypy.request.login in getAfsGroupMembers(config.adminacl, config.authz[0].cell):
+                raise InvalidInput('username', cherrypy.request.login,
+                                   'Not in admin group %s.' % config.adminacl)
+            cherrypy.request.state = State(cherrypy.request.login, isadmin=True)
+            return self
+        else:
+            return super(InvirtWeb, self).__getattr__(name)
 
     @cherrypy.expose
     @cherrypy.tools.mako(filename="/list.mako")
@@ -132,7 +141,7 @@ console will suffer artifacts.
 """,
             'Windows': """
 <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.
+<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.
 """
             }
 
@@ -146,12 +155,47 @@ console will suffer artifacts.
                     mapping=help_mapping)
     help._cp_config['tools.require_login.on'] = False
 
+    def parseCreate(self, fields):
+        kws = dict([(kw, fields.get(kw)) for kw in 'name description owner memory disksize vmtype cdrom autoinstall'.split() if fields.get(kw)])
+        validate = validation.Validate(cherrypy.request.login, cherrypy.request.state, strict=True, **kws)
+        return dict(contact=cherrypy.request.login, name=validate.name, description=validate.description, memory=validate.memory,
+                    disksize=validate.disksize, owner=validate.owner, machine_type=getattr(validate, 'vmtype', Defaults.type),
+                    cdrom=getattr(validate, 'cdrom', None),
+                    autoinstall=getattr(validate, 'autoinstall', None))
+
+    @cherrypy.expose
+    @cherrypy.tools.mako(filename="/list.mako")
+    @cherrypy.tools.require_POST()
+    def create(self, **fields):
+        """Handler for create requests."""
+        try:
+            parsed_fields = self.parseCreate(fields)
+            machine = controls.createVm(cherrypy.request.login, cherrypy.request.state, **parsed_fields)
+        except InvalidInput, err:
+            pass
+        else:
+            err = None
+        cherrypy.request.state.clear() #Changed global state
+        d = getListDict(cherrypy.request.login, cherrypy.request.state)
+        d['err'] = err
+        if err:
+            for field in fields.keys():
+                setattr(d['defaults'], field, fields.get(field))
+        else:
+            d['new_machine'] = parsed_fields['name']
+        return d
+
     @cherrypy.expose
     @cherrypy.tools.mako(filename="/helloworld.mako")
     def helloworld(self, **kwargs):
         return {'request': cherrypy.request, 'kwargs': kwargs}
     helloworld._cp_config['tools.require_login.on'] = False
 
+    @cherrypy.expose
+    def errortest(self):
+        """Throw an error, to test the error-tracing mechanisms."""
+        raise RuntimeError("test of the emergency broadcast system")
+
     class MachineView(View):
         # This is hairy. Fix when CherryPy 3.2 is out. (rename to
         # _cp_dispatch, and parse the argument as a list instead of
@@ -218,10 +262,9 @@ console will suffer artifacts.
             return d
         @cherrypy.expose
         @cherrypy.tools.mako(filename="/command.mako")
+        @cherrypy.tools.require_POST()
         def command(self, command_name, machine_id, **kwargs):
             """Handler for running commands like boot and delete on a VM."""
-            if cherrypy.request.method != "POST":
-                raise InvalidInput("request.method", command_name, "You must execute commands via POST")
             back = kwargs.get('back', None)
             try:
                 d = controls.commandResult(cherrypy.request.login, cherrypy.request.state, command_name, machine_id, kwargs)
@@ -337,33 +380,6 @@ def hasVnc(status):
             return 'location' in d
     return False
 
-def parseCreate(username, state, fields):
-    kws = dict([(kw, fields.getfirst(kw)) for kw in 'name description owner memory disksize vmtype cdrom autoinstall'.split()])
-    validate = validation.Validate(username, state, strict=True, **kws)
-    return dict(contact=username, name=validate.name, description=validate.description, memory=validate.memory,
-                disksize=validate.disksize, owner=validate.owner, machine_type=getattr(validate, 'vmtype', Defaults.type),
-                cdrom=getattr(validate, 'cdrom', None),
-                autoinstall=getattr(validate, 'autoinstall', None))
-
-def create(username, state, path, fields):
-    """Handler for create requests."""
-    try:
-        parsed_fields = parseCreate(username, state, fields)
-        machine = controls.createVm(username, state, **parsed_fields)
-    except InvalidInput, err:
-        pass
-    else:
-        err = None
-    state.clear() #Changed global state
-    d = getListDict(username, state)
-    d['err'] = err
-    if err:
-        for field in fields.keys():
-            setattr(d['defaults'], field, fields.getfirst(field))
-    else:
-        d['new_machine'] = parsed_fields['name']
-    return templates.list(searchList=[d])
-
 
 def getListDict(username, state):
     """Gets the list of local variables used by list.tmpl."""
@@ -372,9 +388,9 @@ def getListDict(username, state):
     checkpoint.checkpoint('Got my machines')
     on = {}
     has_vnc = {}
+    installing = {}
     xmlist = state.xmlist
     checkpoint.checkpoint('Got uptimes')
-    can_clone = 'ice3' not in state.xmlist_raw
     for m in machines:
         if m not in xmlist:
             has_vnc[m] = 'Off'
@@ -387,6 +403,10 @@ def getListDict(username, state):
                 has_vnc[m] = "WTF?"
             else:
                 has_vnc[m] = "ParaVM"
+            if xmlist[m].get('autoinstall'):
+                installing[m] = True
+            else:
+                installing[m] = False
     max_memory = validation.maxMemory(username, state)
     max_disk = validation.maxDisk(username)
     checkpoint.checkpoint('Got max mem/disk')
@@ -404,7 +424,7 @@ def getListDict(username, state):
              defaults=defaults,
              machines=machines,
              has_vnc=has_vnc,
-             can_clone=can_clone)
+             installing=installing)
     return d
 
 def getHostname(nic):
@@ -634,29 +654,9 @@ def unauthFront(_, _2, _3, fields):
     return templates.unauth(searchList=[{'simple' : True, 
             'hostname' : socket.getfqdn()}])
 
-def admin(username, state, path, fields):
-    if path == '':
-        return ({'Status': '303 See Other',
-                 'Location': 'admin/'},
-                "You shouldn't see this message.")
-    if not username in getAfsGroupMembers(config.adminacl, 'athena.mit.edu'):
-        raise InvalidInput('username', username,
-                           'Not in admin group %s.' % config.adminacl)
-    newstate = State(username, isadmin=True)
-    newstate.environ = state.environ
-    return handler(username, newstate, path, fields)
-
-def throwError(_, __, ___, ____):
-    """Throw an error, to test the error-tracing mechanisms."""
-    raise RuntimeError("test of the emergency broadcast system")
-
 mapping = dict(
                modify=modify,
-               create=create,
-               unauth=unauthFront,
-               admin=admin,
-               overlord=admin,
-               errortest=throwError)
+               unauth=unauthFront)
 
 def printHeaders(headers):
     """Print a dictionary as HTTP headers."""