6 from sipb_xen_database import Machine, NIC
7 from webcommon import InvalidInput, g
10 MAX_MEMORY_SINGLE = 256
11 MIN_MEMORY_SINGLE = 16
18 def getMachinesByOwner(user, machine=None):
19 """Return the machines owned by the same as a machine.
21 If the machine is None, return the machines owned by the same
28 return Machine.select_by(owner=owner)
30 def maxMemory(user, machine=None, on=True):
31 """Return the maximum memory for a machine or a user.
33 If machine is None, return the memory available for a new
34 machine. Else, return the maximum that machine can have.
36 on is whether the machine should be turned on. If false, the max
37 memory for the machine to change to, if it is left off, is
41 return MAX_MEMORY_SINGLE
42 if machine.memory > MAX_MEMORY_SINGLE:
43 # If they've been blessed, let them have it
45 machines = getMachinesByOwner(user, machine)
46 active_machines = [x for x in machines if g.uptimes[x]]
47 mem_usage = sum([x.memory for x in active_machines if x != machine])
48 return min(MAX_MEMORY_SINGLE, MAX_MEMORY_TOTAL-mem_usage)
50 def maxDisk(user, machine=None):
51 machines = getMachinesByOwner(user, machine)
52 disk_usage = sum([sum([y.size for y in x.disks])
53 for x in machines if x != machine])
54 return min(MAX_DISK_SINGLE, MAX_DISK_TOTAL-disk_usage/1024.)
57 machines = getMachinesByOwner(user)
58 active_machines = [x for x in machines if g.uptimes[x]]
59 if len(machines) >= MAX_VMS_TOTAL:
60 return 'You have too many VMs to create a new one.'
61 if len(active_machines) >= MAX_VMS_ACTIVE:
62 return ('You already have the maximum number of VMs turned on. '
63 'To create more, turn one off.')
67 reason = cantAddVm(user)
69 raise InvalidInput('create', True, reason)
72 def haveAccess(user, machine):
73 """Return whether a user has administrative access to a machine"""
76 if user in (machine.administrator, machine.owner):
78 if getafsgroups.checkAfsGroup(user, machine.administrator,
79 'athena.mit.edu'): #XXX Cell?
81 if not getafsgroups.notLockerOwner(user, machine.owner):
83 return owns(user, machine)
85 def owns(user, machine):
86 """Return whether a user owns a machine"""
89 return not getafsgroups.notLockerOwner(user, machine.owner)
91 def validMachineName(name):
92 """Check that name is valid for a machine name"""
95 charset = string.ascii_letters + string.digits + '-_'
96 if name[0] in '-_' or len(name) > 22:
103 def validMemory(user, memory, machine=None, on=True):
104 """Parse and validate limits for memory for a given user and machine.
106 on is whether the memory must be valid after the machine is
111 if memory < MIN_MEMORY_SINGLE:
114 raise InvalidInput('memory', memory,
115 "Minimum %s MiB" % MIN_MEMORY_SINGLE)
116 if memory > maxMemory(user, machine, on):
117 raise InvalidInput('memory', memory,
118 'Maximum %s MiB for %s' % (maxMemory(user, machine),
122 def validDisk(user, disk, machine=None):
123 """Parse and validate limits for disk for a given user and machine."""
126 if disk > maxDisk(user, machine):
127 raise InvalidInput('disk', disk,
128 "Maximum %s G" % maxDisk(user, machine))
129 disk = int(disk * 1024)
130 if disk < MIN_DISK_SINGLE * 1024:
133 raise InvalidInput('disk', disk,
134 "Minimum %s GiB" % MIN_DISK_SINGLE)
137 def testMachineId(user, machine_id, exists=True):
138 """Parse, validate and check authorization for a given user and machine.
140 If exists is False, don't check that it exists.
142 if machine_id is None:
143 raise InvalidInput('machine_id', machine_id,
144 "Must specify a machine ID.")
146 machine_id = int(machine_id)
148 raise InvalidInput('machine_id', machine_id, "Must be an integer.")
149 machine = Machine.get(machine_id)
150 if exists and machine is None:
151 raise InvalidInput('machine_id', machine_id, "Does not exist.")
152 if machine is not None and not haveAccess(user, machine):
153 raise InvalidInput('machine_id', machine_id,
154 "You do not have access to this machine.")
157 def testAdmin(user, admin, machine):
158 if admin in (None, machine.administrator):
162 if getafsgroups.checkAfsGroup(user, admin, 'athena.mit.edu'):
164 if getafsgroups.checkAfsGroup(user, 'system:'+admin,
166 return 'system:'+admin
169 def testOwner(user, owner, machine=None):
170 if owner == user or machine is not None and owner == machine.owner:
173 raise InvalidInput('owner', owner, "Owner must be specified")
174 value = getafsgroups.notLockerOwner(user, owner)
177 raise InvalidInput('owner', owner, value)
179 def testContact(user, contact, machine=None):
180 if contact in (None, machine.contact):
182 if not re.match("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$", contact, re.I):
183 raise InvalidInput('contact', contact, "Not a valid email.")
186 def testDisk(user, disksize, machine=None):
189 def testName(user, name, machine=None):
190 if name in (None, machine.name):
192 if not Machine.select_by(name=name):
194 raise InvalidInput('name', name, "Name is already taken.")
196 def testHostname(user, hostname, machine):
197 for nic in machine.nics:
198 if hostname == nic.hostname:
200 # check if doesn't already exist
201 if NIC.select_by(hostname=hostname):
202 raise InvalidInput('hostname', hostname,
204 if not re.match("^[A-Z0-9-]{1,22}$", hostname, re.I):
205 raise InvalidInput('hostname', hostname, "Not a valid hostname; "
206 "must only use number, letters, and dashes.")