Index: trunk/web/controls.py
===================================================================
--- trunk/web/controls.py	(revision 260)
+++ trunk/web/controls.py	(revision 261)
@@ -75,8 +75,18 @@
     """
     if cdtype is not None:
-        remctl('control', machine.name, 'create', 
-               cdtype)
+        out, err = remctl('control', machine.name, 'create', 
+                          cdtype, err=True)
     else:
-        remctl('control', machine.name, 'create')
+        out, err = remctl('control', machine.name, 'create',
+                          err=True)
+    if 'already exists' in out:
+        raise InvalidInput('action', 'create',
+                           'VM %s is already on' % machine.name)
+    elif err:
+        raise CodeError('"%s" on "control %s create %s' 
+                        % (err, machine.name, cdtype))
+    else:
+        raise CodeError('"%s" on "control %s create %s' 
+                        % (err, machine.name, cdtype))
 
 def registerMachine(machine):
@@ -215,9 +225,7 @@
 def commandResult(user, fields):
     start_time = 0
-    print >> sys.stderr, time.time()-start_time
     machine = validation.testMachineId(user, fields.getfirst('machine_id'))
     action = fields.getfirst('action')
     cdrom = fields.getfirst('cdrom')
-    print >> sys.stderr, time.time()-start_time
     if cdrom is not None and not CDROM.get(cdrom):
         raise CodeError("Invalid cdrom type '%s'" % cdrom)    
@@ -269,5 +277,4 @@
     elif action == 'Delete VM':
         deleteVM(machine)
-    print >> sys.stderr, time.time()-start_time
 
     d = dict(user=user,
Index: trunk/web/main.py
===================================================================
--- trunk/web/main.py	(revision 260)
+++ trunk/web/main.py	(revision 261)
@@ -37,5 +37,5 @@
 import templates
 from Cheetah.Template import Template
-from sipb_xen_database import Machine, CDROM, ctx, connect
+from sipb_xen_database import Machine, CDROM, ctx, connect, MachineAccess
 import validation
 from webcommon import InvalidInput, CodeError, g
@@ -184,6 +184,5 @@
 
 def getListDict(user):
-    machines = [m for m in Machine.select()
-                if validation.haveAccess(user, m)]
+    machines = g.machines
     checkpoint.checkpoint('Got my machines')
     on = {}
@@ -328,6 +327,6 @@
         if not back:
             raise
-        print >> sys.stderr, err
-        result = None
+        #print >> sys.stderr, err
+        result = err
     else:
         result = 'Success!'
@@ -345,6 +344,5 @@
         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):
Index: trunk/web/webcommon.py
===================================================================
--- trunk/web/webcommon.py	(revision 260)
+++ trunk/web/webcommon.py	(revision 261)
@@ -1,5 +1,5 @@
 """Exceptions for the web interface."""
 
-from sipb_xen_database import Machine
+from sipb_xen_database import Machine, MachineAccess
 
 class MyException(Exception):
@@ -25,19 +25,30 @@
 import controls
 
+def cachedproperty(func):
+    name = '__cache_' + func.__name__ + '_' + str(id(func))
+    def getter(self):
+        try:
+            return getattr(self, name)
+        except AttributeError:
+            value = func(self)
+            setattr(self, name, value)
+            return value
+    return property(getter)
+
 class Global(object):
     """Global state of the system, to avoid duplicate remctls to get state"""
     def __init__(self, user):
         self.user = user
-
-    def __get_uptimes(self):
-        if not hasattr(self, '_uptimes'):
-            self._uptimes = controls.getUptimes(Machine.select())
-        return self._uptimes
-    uptimes = property(__get_uptimes)
+    
+    machines = cachedproperty(lambda self: 
+                             [ma.machine for ma in 
+                              MachineAccess.select_by(user=self.user)])
+    uptimes = cachedproperty(lambda self: 
+                             controls.getUptimes(self.machines))
 
     def clear(self):
         """Clear the state so future accesses reload it."""
-        for attr in ('_uptimes', ):
-            if hasattr(self, attr):
+        for attr in self.__dict__:
+            if attr.startswith('__cache_'):
                 delattr(self, attr)
 
