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
40 if machine is not None and machine.memory > MAX_MEMORY_SINGLE:
41 # If they've been blessed, let them have it
44 return MAX_MEMORY_SINGLE
45 machines = getMachinesByOwner(user, machine)
46 active_machines = [x for x in machines if g.uptimes.get(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.get(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"""
74 if user in (machine.administrator, machine.owner):
76 if getafsgroups.checkAfsGroup(user, machine.administrator,
77 'athena.mit.edu'): #XXX Cell?
79 if not getafsgroups.notLockerOwner(user, machine.owner):
81 return owns(user, machine)
83 def owns(user, machine):
84 """Return whether a user owns a machine"""
85 return not getafsgroups.notLockerOwner(user, machine.owner)
87 def validMachineName(name):
88 """Check that name is valid for a machine name"""
91 charset = string.ascii_letters + string.digits + '-_'
92 if name[0] in '-_' or len(name) > 22:
99 def validMemory(user, memory, machine=None, on=True):
100 """Parse and validate limits for memory for a given user and machine.
102 on is whether the memory must be valid after the machine is
107 if memory < MIN_MEMORY_SINGLE:
110 raise InvalidInput('memory', memory,
111 "Minimum %s MiB" % MIN_MEMORY_SINGLE)
112 if memory > maxMemory(user, machine, on):
113 raise InvalidInput('memory', memory,
114 'Maximum %s MiB for %s' % (maxMemory(user, machine),
118 def validDisk(user, disk, machine=None):
119 """Parse and validate limits for disk for a given user and machine."""
122 if disk > maxDisk(user, machine):
123 raise InvalidInput('disk', disk,
124 "Maximum %s G" % maxDisk(user, machine))
125 disk = int(disk * 1024)
126 if disk < MIN_DISK_SINGLE * 1024:
129 raise InvalidInput('disk', disk,
130 "Minimum %s GiB" % MIN_DISK_SINGLE)
133 def testMachineId(user, machine_id, exists=True):
134 """Parse, validate and check authorization for a given user and machine.
136 If exists is False, don't check that it exists.
138 if machine_id is None:
139 raise InvalidInput('machine_id', machine_id,
140 "Must specify a machine ID.")
142 machine_id = int(machine_id)
144 raise InvalidInput('machine_id', machine_id, "Must be an integer.")
145 machine = Machine.get(machine_id)
146 if exists and machine is None:
147 raise InvalidInput('machine_id', machine_id, "Does not exist.")
148 if machine is not None and not haveAccess(user, machine):
149 raise InvalidInput('machine_id', machine_id,
150 "You do not have access to this machine.")
153 def testAdmin(user, admin, machine):
154 if admin in (None, machine.administrator):
158 if getafsgroups.checkAfsGroup(user, admin, 'athena.mit.edu'):
160 if getafsgroups.checkAfsGroup(user, 'system:'+admin,
162 return 'system:'+admin
165 def testOwner(user, owner, machine=None):
166 if owner == user or machine is not None and owner == machine.owner:
169 raise InvalidInput('owner', owner, "Owner must be specified")
170 value = getafsgroups.notLockerOwner(user, owner)
173 raise InvalidInput('owner', owner, value)
175 def testContact(user, contact, machine=None):
176 if contact in (None, machine.contact):
178 if not re.match("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$", contact, re.I):
179 raise InvalidInput('contact', contact, "Not a valid email.")
182 def testDisk(user, disksize, machine=None):
185 def testName(user, name, machine=None):
186 if name in (None, machine.name):
188 if not Machine.select_by(name=name):
190 raise InvalidInput('name', name, "Name is already taken.")
192 def testHostname(user, hostname, machine):
193 for nic in machine.nics:
194 if hostname == nic.hostname:
196 # check if doesn't already exist
197 if NIC.select_by(hostname=hostname):
198 raise InvalidInput('hostname', hostname,
200 if not re.match("^[A-Z0-9-]{1,22}$", hostname, re.I):
201 raise InvalidInput('hostname', hostname, "Not a valid hostname; "
202 "must only use number, letters, and dashes.")