More updates.
[invirt/packages/invirt-web.git] / templates / main.py
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)
 
-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):
     if user.username == 'moo':
@@ -94,10 +122,11 @@ def remctl(*args, **kws):
                          stdout=subprocess.PIPE,
                          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()
 
 def makeDisks():
@@ -158,7 +187,10 @@ def getUptimes(machines):
         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.
@@ -190,6 +222,12 @@ def createVm(user, name, memory, disk, is_hvm, cdrom):
     # 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()
@@ -217,8 +255,8 @@ def createVm(user, name, memory, disk, is_hvm, cdrom):
     except:
         transaction.rollback()
         raise
-    makeDisks()
     registerMachine(machine)
+    makeDisks()
     # 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)
-        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")
     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 <= 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
 
 def create(user, fields):
@@ -286,19 +326,24 @@ def listVms(user, fields):
     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:
-            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,
              uptimes=uptimes,
@@ -417,6 +462,8 @@ def command(user, fields):
         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)
@@ -514,7 +561,8 @@ def info(user, fields):
         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,
@@ -522,8 +570,8 @@ def info(user, fields):
              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])
@@ -548,8 +596,8 @@ if __name__ == '__main__':
         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'