X-Git-Url: http://xvm.mit.edu/gitweb/invirt/packages/invirt-web.git/blobdiff_plain/e37dd15bbf8683bab8454ea0eec8e9968ce982b2..ab37513bfa791d4b4a9c24fd2c20db9d74669226:/code/validation.py diff --git a/code/validation.py b/code/validation.py index fd2b979..c0e3aeb 100644 --- a/code/validation.py +++ b/code/validation.py @@ -1,9 +1,10 @@ #!/usr/bin/python +import cache_acls import getafsgroups import re import string -from sipb_xen_database import Machine, NIC +from sipb_xen_database import Machine, NIC, Type, Disk from webcommon import InvalidInput, g MAX_MEMORY_TOTAL = 512 @@ -17,7 +18,7 @@ MAX_VMS_ACTIVE = 4 def getMachinesByOwner(user, machine=None): """Return the machines owned by the same as a machine. - + If the machine is None, return the machines owned by the same user. """ @@ -30,7 +31,7 @@ def getMachinesByOwner(user, machine=None): def maxMemory(user, machine=None, on=True): """Return the maximum memory for a machine or a user. - If machine is None, return the memory available for a new + If machine is None, return the memory available for a new machine. Else, return the maximum that machine can have. on is whether the machine should be turned on. If false, the max @@ -43,19 +44,27 @@ def maxMemory(user, machine=None, on=True): if not on: return MAX_MEMORY_SINGLE machines = getMachinesByOwner(user, machine) - active_machines = [x for x in machines if g.uptimes.get(x)] + active_machines = [x for x in machines if g.xmlist.get(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): - machines = getMachinesByOwner(user, machine) - disk_usage = sum([sum([y.size for y in x.disks]) - for x in machines if x != machine]) + """Return the maximum disk that a machine can reach. + + If machine is None, the maximum disk for a new machine. Otherwise, + return the maximum that a given machine can be changed to. + """ + if machine is not None: + machine_id = machine.machine_id + else: + machine_id = None + disk_usage = Disk.query().filter_by(Disk.c.machine_id != machine_id, + owner=user).sum(Disk.c.size) or 0 return min(MAX_DISK_SINGLE, MAX_DISK_TOTAL-disk_usage/1024.) def cantAddVm(user): machines = getMachinesByOwner(user) - active_machines = [x for x in machines if g.uptimes.get(x)] + active_machines = [x for x in machines if g.xmlist.get(x)] if len(machines) >= MAX_VMS_TOTAL: return 'You have too many VMs to create a new one.' if len(active_machines) >= MAX_VMS_ACTIVE: @@ -71,18 +80,11 @@ def validAddVm(user): def haveAccess(user, machine): """Return whether a user has administrative access to a machine""" - if user in (machine.administrator, machine.owner): - return True - if getafsgroups.checkAfsGroup(user, machine.administrator, - 'athena.mit.edu'): #XXX Cell? - return True - if not getafsgroups.notLockerOwner(user, machine.owner): - return True - return owns(user, machine) + return user in cache_acls.accessList(machine) def owns(user, machine): """Return whether a user owns a machine""" - return not getafsgroups.notLockerOwner(user, machine.owner) + return user in expandLocker(machine.owner) def validMachineName(name): """Check that name is valid for a machine name""" @@ -107,7 +109,7 @@ def validMemory(user, memory, machine=None, on=True): if memory < MIN_MEMORY_SINGLE: raise ValueError except ValueError: - raise InvalidInput('memory', memory, + raise InvalidInput('memory', memory, "Minimum %s MiB" % MIN_MEMORY_SINGLE) if memory > maxMemory(user, machine, on): raise InvalidInput('memory', memory, @@ -129,14 +131,22 @@ def validDisk(user, disk, machine=None): raise InvalidInput('disk', disk, "Minimum %s GiB" % MIN_DISK_SINGLE) return disk - + +def validVmType(vm_type): + if vm_type is None: + return None + t = Type.get(vm_type) + if t is None: + raise CodeError("Invalid vm type '%s'" % vm_type) + return t + def testMachineId(user, machine_id, exists=True): """Parse, validate and check authorization for a given user and machine. If exists is False, don't check that it exists. """ if machine_id is None: - raise InvalidInput('machine_id', machine_id, + raise InvalidInput('machine_id', machine_id, "Must specify a machine ID.") try: machine_id = int(machine_id) @@ -151,26 +161,46 @@ def testMachineId(user, machine_id, exists=True): return machine def testAdmin(user, admin, machine): + """Determine whether a user can set the admin of a machine to this value. + + Return the value to set the admin field to (possibly 'system:' + + admin). XXX is modifying this a good idea? + """ if admin in (None, machine.administrator): return None if admin == user: return admin - if getafsgroups.checkAfsGroup(user, admin, 'athena.mit.edu'): - return admin - if getafsgroups.checkAfsGroup(user, 'system:'+admin, - 'athena.mit.edu'): - return 'system:'+admin + if ':' not in admin: + if cache_acls.isUser(admin): + return admin + admin = 'system:' + admin + try: + if user in getafsgroups.getAfsGroupMembers(admin, 'athena.mit.edu'): + return admin + except getafsgroups.AfsProcessError, e: + errmsg = str(e) + if errmsg.startswith("pts: User or group doesn't exist"): + errmsg = 'The group "%s" does not exist.' % admin + raise InvalidInput('administrator', admin, errmsg) + #XXX Should we require that user is in the admin group? return admin - + def testOwner(user, owner, machine=None): + """Determine whether a user can set the owner of a machine to this value. + + If machine is None, this is the owner of a new machine. + """ if owner == user or machine is not None and owner == machine.owner: return owner if owner is None: raise InvalidInput('owner', owner, "Owner must be specified") - value = getafsgroups.notLockerOwner(user, owner) - if not value: - return owner - raise InvalidInput('owner', owner, value) + try: + if user not in cache_acls.expandLocker(owner): + raise InvalidInput('owner', owner, 'You do not have access to the ' + + owner + ' locker') + except getafsgroups.AfsProcessError, e: + raise InvalidInput('owner', owner, str(e)) + return owner def testContact(user, contact, machine=None): if contact in (None, machine.contact):