7 from sipb_xen_database import Machine, NIC, Type
8 from webcommon import InvalidInput, g
10 MAX_MEMORY_TOTAL = 512
11 MAX_MEMORY_SINGLE = 256
12 MIN_MEMORY_SINGLE = 16
19 def getMachinesByOwner(user, machine=None):
20 """Return the machines owned by the same as a machine.
22 If the machine is None, return the machines owned by the same
29 return Machine.select_by(owner=owner)
31 def maxMemory(user, machine=None, on=True):
32 """Return the maximum memory for a machine or a user.
34 If machine is None, return the memory available for a new
35 machine. Else, return the maximum that machine can have.
37 on is whether the machine should be turned on. If false, the max
38 memory for the machine to change to, if it is left off, is
41 if machine is not None and machine.memory > MAX_MEMORY_SINGLE:
42 # If they've been blessed, let them have it
45 return MAX_MEMORY_SINGLE
46 machines = getMachinesByOwner(user, machine)
47 active_machines = [x for x in machines if g.uptimes.get(x)]
48 mem_usage = sum([x.memory for x in active_machines if x != machine])
49 return min(MAX_MEMORY_SINGLE, MAX_MEMORY_TOTAL-mem_usage)
51 def maxDisk(user, machine=None):
52 machines = getMachinesByOwner(user, machine)
53 disk_usage = sum([sum([y.size for y in x.disks])
54 for x in machines if x != machine])
55 return min(MAX_DISK_SINGLE, MAX_DISK_TOTAL-disk_usage/1024.)
58 machines = getMachinesByOwner(user)
59 active_machines = [x for x in machines if g.uptimes.get(x)]
60 if len(machines) >= MAX_VMS_TOTAL:
61 return 'You have too many VMs to create a new one.'
62 if len(active_machines) >= MAX_VMS_ACTIVE:
63 return ('You already have the maximum number of VMs turned on. '
64 'To create more, turn one off.')
68 reason = cantAddVm(user)
70 raise InvalidInput('create', True, reason)
73 def haveAccess(user, machine):
74 """Return whether a user has administrative access to a machine"""
75 return user in cache_acls.accessList(machine)
77 def owns(user, machine):
78 """Return whether a user owns a machine"""
79 return user in expandLocker(machine.owner)
81 def validMachineName(name):
82 """Check that name is valid for a machine name"""
85 charset = string.ascii_letters + string.digits + '-_'
86 if name[0] in '-_' or len(name) > 22:
93 def validMemory(user, memory, machine=None, on=True):
94 """Parse and validate limits for memory for a given user and machine.
96 on is whether the memory must be valid after the machine is
101 if memory < MIN_MEMORY_SINGLE:
104 raise InvalidInput('memory', memory,
105 "Minimum %s MiB" % MIN_MEMORY_SINGLE)
106 if memory > maxMemory(user, machine, on):
107 raise InvalidInput('memory', memory,
108 'Maximum %s MiB for %s' % (maxMemory(user, machine),
112 def validDisk(user, disk, machine=None):
113 """Parse and validate limits for disk for a given user and machine."""
116 if disk > maxDisk(user, machine):
117 raise InvalidInput('disk', disk,
118 "Maximum %s G" % maxDisk(user, machine))
119 disk = int(disk * 1024)
120 if disk < MIN_DISK_SINGLE * 1024:
123 raise InvalidInput('disk', disk,
124 "Minimum %s GiB" % MIN_DISK_SINGLE)
127 def validVmType(vm_type):
129 return Type.get('linux-hvm')
130 elif vm_type == 'paravm':
131 return Type.get('linux')
133 raise CodeError("Invalid vm type '%s'" % vm_type)
135 def testMachineId(user, machine_id, exists=True):
136 """Parse, validate and check authorization for a given user and machine.
138 If exists is False, don't check that it exists.
140 if machine_id is None:
141 raise InvalidInput('machine_id', machine_id,
142 "Must specify a machine ID.")
144 machine_id = int(machine_id)
146 raise InvalidInput('machine_id', machine_id, "Must be an integer.")
147 machine = Machine.get(machine_id)
148 if exists and machine is None:
149 raise InvalidInput('machine_id', machine_id, "Does not exist.")
150 if machine is not None and not haveAccess(user, machine):
151 raise InvalidInput('machine_id', machine_id,
152 "You do not have access to this machine.")
155 def testAdmin(user, admin, machine):
156 """Determine whether a user can set the admin of a machine to this value.
158 Return the value to set the admin field to (possibly 'system:' +
159 admin). XXX is modifying this a good idea?
161 if admin in (None, machine.administrator):
166 if cache_acls.isUser(admin):
168 admin = 'system:' + admin
170 if user in getafsgroups.getAfsGroupMembers(admin, 'athena.mit.edu'):
172 except getafsgroups.AfsProcessError, e:
174 if errmsg.startswith("pts: User or group doesn't exist"):
175 errmsg = 'The group "%s" does not exist.' % admin
176 raise InvalidInput('administrator', admin, errmsg)
177 #XXX Should we require that user is in the admin group?
180 def testOwner(user, owner, machine=None):
181 """Determine whether a user can set the owner of a machine to this value.
183 If machine is None, this is the owner of a new machine.
185 if owner == user or machine is not None and owner == machine.owner:
188 raise InvalidInput('owner', owner, "Owner must be specified")
190 if user not in cache_acls.expandLocker(owner):
191 raise InvalidInput('owner', owner, 'You do not have access to the '
193 except getafsgroups.AfsProcessError, e:
194 raise InvalidInput('owner', owner, str(e))
197 def testContact(user, contact, machine=None):
198 if contact in (None, machine.contact):
200 if not re.match("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$", contact, re.I):
201 raise InvalidInput('contact', contact, "Not a valid email.")
204 def testDisk(user, disksize, machine=None):
207 def testName(user, name, machine=None):
208 if name in (None, machine.name):
210 if not Machine.select_by(name=name):
212 raise InvalidInput('name', name, "Name is already taken.")
214 def testHostname(user, hostname, machine):
215 for nic in machine.nics:
216 if hostname == nic.hostname:
218 # check if doesn't already exist
219 if NIC.select_by(hostname=hostname):
220 raise InvalidInput('hostname', hostname,
222 if not re.match("^[A-Z0-9-]{1,22}$", hostname, re.I):
223 raise InvalidInput('hostname', hostname, "Not a valid hostname; "
224 "must only use number, letters, and dashes.")