More updates.
authorEric Price <ecprice@mit.edu>
Mon, 8 Oct 2007 08:44:14 +0000 (04:44 -0400)
committerEric Price <ecprice@mit.edu>
Mon, 8 Oct 2007 08:44:14 +0000 (04:44 -0400)
svn path=/trunk/web/; revision=144

templates/VncViewer.jar [deleted file]
templates/command.tmpl
templates/info.tmpl
templates/list.tmpl
templates/main.py

diff --git a/templates/VncViewer.jar b/templates/VncViewer.jar
deleted file mode 100644 (file)
index af710dc..0000000
Binary files a/templates/VncViewer.jar and /dev/null differ
index d7a6890..4ea55a5 100644 (file)
@@ -7,9 +7,9 @@ $command $machine.name
 
 
 #def body
 
 
 #def body
-<h1>Command succesful</h1>
+<h1>Command successful</h1>
 <p>$command ${machine.name} was successful.</p>
 <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
 <p><a href="info?machine_id=${machine.machine_id}">Return</a></p>
 <p><a href="list">Return</a></p>
 #else
 <p><a href="info?machine_id=${machine.machine_id}">Return</a></p>
index 9f014f2..f537dd2 100644 (file)
@@ -68,8 +68,8 @@ Info on $machine.name
     <tr><td>Hostname:</td><td><input type="text" value="$machine.nics[0].hostname"/>.servers.csail.mit.edu</td></tr>
 #end if
 #if not $on
     <tr><td>Hostname:</td><td><input type="text" value="$machine.nics[0].hostname"/>.servers.csail.mit.edu</td></tr>
 #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>
   </table>
 #end if
     <tr><td><input type="submit" class="button" name="action" value="Change"/></td></tr>
   </table>
index 19b108e..a27fe0b 100644 (file)
@@ -20,7 +20,7 @@ List of your VMs
        <td>Hostname</td>
        <td>Uptime</td>
        <td>VNC</td>
        <td>Hostname</td>
        <td>Uptime</td>
        <td>VNC</td>
-       <td>Restart?</td>
+       <td></td>
       #for $machine in $machines:
       <tr> 
        <td><a href="info?machine_id=$machine.machine_id">$machine.name</a></td>
       #for $machine in $machines:
       <tr> 
        <td><a href="info?machine_id=$machine.machine_id">$machine.name</a></td>
@@ -37,32 +37,35 @@ List of your VMs
        <td></td>
 #end if
 <td>#slurp
        <td></td>
 #end if
 <td>#slurp
-#if $uptimes.get($machine.name)
-$uptimes[$machine.name]#slurp
+#if $uptimes[$machine]
+$uptimes[$machine]#slurp
 #else
 Off#slurp
 #end if
 </td>
        <td>#slurp
 #else
 Off#slurp
 #end if
 </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
 <a href="vnc?machine_id=$machine.machine_id">Console</a>#slurp
 #else
-$has_vnc.get($machine.name)
+$has_vnc[$machine]
 #end if
 </td>
        <td>
          <form action="command">
            <input type="hidden" name="machine_id"
                   value="$machine.machine_id"/>
 #end if
 </td>
        <td>
          <form action="command">
            <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>
       </tr>
       #end for
     </table>
 #end if
          </form>
        </td>
       </tr>
       #end for
     </table>
 #end if
-
+#if $can_add_vm
     <p>Create a new VM:</p>
     <form action="create" method="POST">
       <table>
     <p>Create a new VM:</p>
     <form action="create" method="POST">
       <table>
@@ -72,11 +75,11 @@ $has_vnc.get($machine.name)
        </tr>
        <tr>
          <td>Memory</td>
        </tr>
        <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>
        </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>
          <td>HVM/ParaVM$helppopup('hvm_paravm')</td>
        </tr>
        <tr>
          <td>HVM/ParaVM$helppopup('hvm_paravm')</td>
@@ -101,5 +104,7 @@ $has_vnc.get($machine.name)
       </table>
       <input type="submit" class="button" value="Create it!"/>
     </form>
       </table>
       <input type="submit" class="button" value="Create it!"/>
     </form>
-
+#else
+<p>You are at the maximum number of VMs.</p>
+#end if
 #end def
 #end def
index 642490f..c997710 100755 (executable)
@@ -41,11 +41,39 @@ def uuidToString(u):
     return "-".join(["%02x" * 4, "%02x" * 2, "%02x" * 2, "%02x" * 2,
                      "%02x" * 6]) % tuple(u)
 
     return "-".join(["%02x" * 4, "%02x" * 2, "%02x" * 2, "%02x" * 2,
                      "%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):
 
 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):
     if user.username == 'moo':
 
 def haveAccess(user, machine):
     if user.username == 'moo':
@@ -94,10 +122,11 @@ def remctl(*args, **kws):
                          stdout=subprocess.PIPE,
                          stderr=subprocess.PIPE)
     if kws.get('err'):
                          stdout=subprocess.PIPE,
                          stderr=subprocess.PIPE)
     if kws.get('err'):
+        p.wait()
         return p.stdout.read(), p.stderr.read()
     if 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()
 
 def makeDisks():
     return p.stdout.read()
 
 def makeDisks():
@@ -158,7 +187,10 @@ def getUptimes(machines):
         name, id = lst[:2]
         uptime = ' '.join(lst[2:])
         d[name] = uptime
         name, id = lst[:2]
         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):
     """Return the status list for a given machine.
 
 def statusInfo(machine):
     """Return the status list for a given machine.
@@ -190,6 +222,12 @@ def createVm(user, name, memory, disk, is_hvm, cdrom):
     # put stuff in the table
     transaction = ctx.current.create_transaction()
     try:
     # put stuff in the table
     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]
         machine = Machine()
         res = meta.engine.execute('select nextval(\'"machines_machine_id_seq"\')')
         id = res.fetchone()[0]
         machine = Machine()
@@ -217,8 +255,8 @@ def createVm(user, name, memory, disk, is_hvm, cdrom):
     except:
         transaction.rollback()
         raise
     except:
         transaction.rollback()
         raise
-    makeDisks()
     registerMachine(machine)
     registerMachine(machine)
+    makeDisks()
     # tell it to boot with cdrom
     bootMachine(machine, cdrom)
 
     # tell it to boot with cdrom
     bootMachine(machine, cdrom)
 
@@ -227,10 +265,11 @@ def createVm(user, name, memory, disk, is_hvm, cdrom):
 def validMemory(user, memory, machine=None):
     try:
         memory = int(memory)
 def validMemory(user, memory, machine=None):
     try:
         memory = int(memory)
-        if memory <= 0:
+        if memory < MIN_MEMORY_SINGLE:
             raise ValueError
     except ValueError:
             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")
     return memory
     if memory > maxMemory(user, machine):
         raise MyException("Too much memory requested")
     return memory
@@ -241,10 +280,11 @@ def validDisk(user, disk, machine=None):
         if disk > maxDisk(user, machine):
             raise MyException("Too much disk requested")
         disk = int(disk * 1024)
         if disk > maxDisk(user, machine):
             raise MyException("Too much disk requested")
         disk = int(disk * 1024)
-        if disk <= 0:
+        if disk < MIN_DISK_SINGLE * 1024:
             raise ValueError
     except ValueError:
             raise ValueError
     except ValueError:
-        raise MyException("Invalid disk amount")
+        raise MyException("Invalid disk amount; minimum is %s GB" %
+                          MIN_DISK_SINGLE)
     return disk
 
 def create(user, fields):
     return disk
 
 def create(user, fields):
@@ -286,19 +326,24 @@ def listVms(user, fields):
     uptimes = getUptimes(machines)
     on = uptimes
     for m in machines:
     uptimes = getUptimes(machines)
     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:
         elif m.type.hvm:
-            has_vnc[m.name] = True
+            has_vnc[m] = True
         else:
         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)
     #     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,
     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,
              uptimes=uptimes,
              machines=machines,
              has_vnc=has_vnc,
              uptimes=uptimes,
@@ -417,6 +462,8 @@ def command(user, fields):
         else:
             remctl('reboot', machine.name)
     elif action == 'Power on':
         else:
             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':
         remctl('destroy', machine.name)
         bootMachine(machine, cdrom)
     elif action == 'Power off':
         remctl('destroy', machine.name)
@@ -514,7 +561,8 @@ def info(user, fields):
         else:
             pass
             #fields.append((disp, None))
         else:
             pass
             #fields.append((disp, None))
-
+    max_mem = maxMemory(user, machine)
+    max_disk = maxDisk(user, machine)
     d = dict(user=user,
              cdroms=CDROM.select(),
              on=status is not None,
     d = dict(user=user,
              cdroms=CDROM.select(),
              on=status is not None,
@@ -522,8 +570,8 @@ def info(user, fields):
              has_vnc=has_vnc,
              uptime=str(uptime),
              ram=machine.memory,
              has_vnc=has_vnc,
              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',
                    searchList=[d, global_dict])
              fields = fields)
     print Template(file='info.tmpl',
                    searchList=[d, global_dict])
@@ -548,8 +596,8 @@ if __name__ == '__main__':
         u.username = username
         u.email = os.environ[ 'SSL_CLIENT_S_DN_Email']
     else:
         u.username = username
         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', '')
     #print 'Content-Type: text/plain\n'
     connect('postgres://sipb-xen@sipb-xen-dev/sipb_xen')
     operation = os.environ.get('PATH_INFO', '')
     #print 'Content-Type: text/plain\n'