Index: trunk/web/templates/command.tmpl
===================================================================
--- trunk/web/templates/command.tmpl	(revision 140)
+++ trunk/web/templates/command.tmpl	(revision 144)
@@ -8,7 +8,7 @@
 
 #def body
-<h1>Command succesful</h1>
+<h1>Command successful</h1>
 <p>$command ${machine.name} was successful.</p>
-#if $command == "Delete VM"
+#if $command == "Delete VM" or True
 <p><a href="list">Return</a></p>
 #else
Index: trunk/web/templates/info.tmpl
===================================================================
--- trunk/web/templates/info.tmpl	(revision 140)
+++ trunk/web/templates/info.tmpl	(revision 144)
@@ -69,6 +69,6 @@
 #end if
 #if not $on
-    <tr><td>Ram:</td><td><input type="text" size=3 value="$machine.memory"/>MB (max $maxmem)</td></tr>
-    <tr><td>Disk:</td><td><input type="text" size=3 value="${machine.disks[0].size/1024.}"/>GB (max $maxdisk)</td></tr>
+    <tr><td>Ram:</td><td><input type="text" size=3 value="$machine.memory"/>MB (max $max_mem)</td></tr>
+    <tr><td>Disk:</td><td><input type="text" size=3 value="${machine.disks[0].size/1024.}"/>GB (max $max_disk)</td></tr>
 #end if
     <tr><td><input type="submit" class="button" name="action" value="Change"/></td></tr>
Index: trunk/web/templates/list.tmpl
===================================================================
--- trunk/web/templates/list.tmpl	(revision 140)
+++ trunk/web/templates/list.tmpl	(revision 144)
@@ -21,5 +21,5 @@
 	<td>Uptime</td>
 	<td>VNC</td>
-	<td>Restart?</td>
+	<td></td>
       #for $machine in $machines:
       <tr> 
@@ -38,6 +38,6 @@
 #end if
 <td>#slurp
-#if $uptimes.get($machine.name)
-$uptimes[$machine.name]#slurp
+#if $uptimes[$machine]
+$uptimes[$machine]#slurp
 #else
 Off#slurp
@@ -45,8 +45,8 @@
 </td>
 	<td>#slurp
-#if $has_vnc.get($machine.name) == True
+#if $has_vnc[$machine] == True
 <a href="vnc?machine_id=$machine.machine_id">Console</a>#slurp
 #else
-$has_vnc.get($machine.name)
+$has_vnc[$machine]
 #end if
 </td>
@@ -55,6 +55,9 @@
 	    <input type="hidden" name="machine_id"
 		   value="$machine.machine_id"/>
-	    <input type="submit" class="button"
-		   value="Reboot"/>
+#if $uptimes[$machine]
+	    <input type="submit" class="button" name="action" value="Shutdown"/>
+#else
+	    <input type="submit" class="button" name="action" value="Power on"/>
+#end if
 	  </form>
 	</td>
@@ -63,5 +66,5 @@
     </table>
 #end if
-
+#if $can_add_vm
     <p>Create a new VM:</p>
     <form action="create" method="POST">
@@ -73,9 +76,9 @@
 	<tr>
 	  <td>Memory</td>
-	  <td><input type="text" name="memory" value="$maxmem" size=3/> megabytes ($maxmem max)</td>
+	  <td><input type="text" name="memory" value="$default_mem" size=3/> megabytes ($max_mem max)</td>
 	</tr>
 	<tr>
 	  <td>Disk</td>
-	  <td><input type="text" name="disk" value="$maxdisk" size=3/> gigabytes ($maxdisk max)</td>
+	  <td><input type="text" name="disk" value="$default_disk" size=3/> gigabytes (${"%0.1f" % ($max_disk-0.05)} max)</td>
 	</tr>
 	<tr>
@@ -102,4 +105,6 @@
       <input type="submit" class="button" value="Create it!"/>
     </form>
-
+#else
+<p>You are at the maximum number of VMs.</p>
+#end if
 #end def
Index: trunk/web/templates/main.py
===================================================================
--- trunk/web/templates/main.py	(revision 140)
+++ trunk/web/templates/main.py	(revision 144)
@@ -42,9 +42,37 @@
                      "%02x" * 6]) % tuple(u)
 
-def maxMemory(user, machine=None):
-    return 256
+MAX_MEMORY_TOTAL = 512
+MAX_MEMORY_SINGLE = 256
+MIN_MEMORY_SINGLE = 16
+MAX_DISK_TOTAL = 50
+MAX_DISK_SINGLE = 50
+MIN_DISK_SINGLE = 0.1
+MAX_VMS_TOTAL = 10
+MAX_VMS_ACTIVE = 4
+
+def getMachinesOwner(owner):
+    return Machine.select_by(owner=owner)
+
+def maxMemory(user, machine=None, on=None):
+    machines = getMachinesOwner(user.username)
+    if on is None:
+        on = getUptimes(machines)
+    active_machines = [x for x in machines if on[x]]
+    mem_usage = sum([x.memory for x in active_machines if x != machine])
+    return min(MAX_MEMORY_SINGLE, MAX_MEMORY_TOTAL-mem_usage)
 
 def maxDisk(user, machine=None):
-    return 10.0
+    machines = getMachinesOwner(user.username)
+    disk_usage = sum([sum([y.size for y in x.disks])
+                      for x in machines if x != machine])
+    return min(MAX_DISK_SINGLE, MAX_DISK_TOTAL-disk_usage/1024.)
+
+def canAddVm(user, on=None):
+    machines = getMachinesOwner(user.username)
+    if on is None:
+        on = getUptimes(machines)
+    active_machines = [x for x in machines if on[x]]
+    return (len(machines) < MAX_VMS_TOTAL and
+            len(active_machines) < MAX_VMS_ACTIVE)
 
 def haveAccess(user, machine):
@@ -95,8 +123,9 @@
                          stderr=subprocess.PIPE)
     if kws.get('err'):
+        p.wait()
         return p.stdout.read(), p.stderr.read()
     if p.wait():
-        print >> sys.stderr, 'ERROR on remctl ', args
-        print >> sys.stderr, p.stderr.read()
+        raise MyException('ERROR on remctl %s: %s' %
+                          (args, p.stderr.read()))
     return p.stdout.read()
 
@@ -159,5 +188,8 @@
         uptime = ' '.join(lst[2:])
         d[name] = uptime
-    return d
+    ans = {}
+    for m in machines:
+        ans[m] = d.get(m.name)
+    return ans
 
 def statusInfo(machine):
@@ -191,4 +223,10 @@
     transaction = ctx.current.create_transaction()
     try:
+        if memory > maxMemory(user):
+            raise MyException("Too much memory requested")
+        if disk > maxDisk(user) * 1024:
+            raise MyException("Too much disk requested")
+        if not canAddVm(user):
+            raise MyException("Too many VMs requested")
         res = meta.engine.execute('select nextval(\'"machines_machine_id_seq"\')')
         id = res.fetchone()[0]
@@ -218,6 +256,6 @@
         transaction.rollback()
         raise
+    registerMachine(machine)
     makeDisks()
-    registerMachine(machine)
     # tell it to boot with cdrom
     bootMachine(machine, cdrom)
@@ -228,8 +266,9 @@
     try:
         memory = int(memory)
-        if memory <= 0:
+        if memory < MIN_MEMORY_SINGLE:
             raise ValueError
     except ValueError:
-        raise MyException("Invalid memory amount")
+        raise MyException("Invalid memory amount; must be at least %s MB" %
+                          MIN_MEMORY_SINGLE)
     if memory > maxMemory(user, machine):
         raise MyException("Too much memory requested")
@@ -242,8 +281,9 @@
             raise MyException("Too much disk requested")
         disk = int(disk * 1024)
-        if disk <= 0:
+        if disk < MIN_DISK_SINGLE * 1024:
             raise ValueError
     except ValueError:
-        raise MyException("Invalid disk amount")
+        raise MyException("Invalid disk amount; minimum is %s GB" %
+                          MIN_DISK_SINGLE)
     return disk
 
@@ -287,17 +327,22 @@
     on = uptimes
     for m in machines:
-        if not on.get(m.name):
-            has_vnc[m.name] = 'Off'
+        if not on[m]:
+            has_vnc[m] = 'Off'
         elif m.type.hvm:
-            has_vnc[m.name] = True
+            has_vnc[m] = True
         else:
-            has_vnc[m.name] = "ParaVM"+helppopup("paravm_console")
+            has_vnc[m] = "ParaVM"+helppopup("paravm_console")
     #     for m in machines:
     #         status = statusInfo(m)
     #         on[m.name] = status is not None
     #         has_vnc[m.name] = hasVnc(status)
+    max_mem=maxMemory(user, on=on)
+    max_disk=maxDisk(user)
     d = dict(user=user,
-             maxmem=maxMemory(user),
-             maxdisk=maxDisk(user),
+             can_add_vm=canAddVm(user, on=on),
+             max_mem=max_mem,
+             max_disk=max_disk,
+             default_mem=max_mem,
+             default_disk=min(4.0, max_disk),
              machines=machines,
              has_vnc=has_vnc,
@@ -418,4 +463,6 @@
             remctl('reboot', machine.name)
     elif action == 'Power on':
+        if maxMemory(user) < machine.memory:
+            raise MyException("You don't have enough free RAM quota")
         bootMachine(machine, cdrom)
     elif action == 'Power off':
@@ -515,5 +562,6 @@
             pass
             #fields.append((disp, None))
-
+    max_mem = maxMemory(user, machine)
+    max_disk = maxDisk(user, machine)
     d = dict(user=user,
              cdroms=CDROM.select(),
@@ -523,6 +571,6 @@
              uptime=str(uptime),
              ram=machine.memory,
-             maxmem=maxMemory(user, machine),
-             maxdisk=maxDisk(user, machine),
+             max_mem=max_mem,
+             max_disk=max_disk,
              fields = fields)
     print Template(file='info.tmpl',
@@ -549,6 +597,6 @@
         u.email = os.environ[ 'SSL_CLIENT_S_DN_Email']
     else:
-        u.username = 'nobody'
-        u.email = None
+        u.username = 'moo'
+        u.email = 'nobody'
     connect('postgres://sipb-xen@sipb-xen-dev/sipb_xen')
     operation = os.environ.get('PATH_INFO', '')
