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 machines = getMachinesByOwner(user, machine)
43 active_machines = [x for x in machines if g.uptimes[x]]
44 mem_usage = sum([x.memory for x in active_machines if x != machine])
45 return min(MAX_MEMORY_SINGLE, MAX_MEMORY_TOTAL-mem_usage)
47 def maxDisk(user, machine=None):
48 machines = getMachinesByOwner(user, machine)
49 disk_usage = sum([sum([y.size for y in x.disks])
50 for x in machines if x != machine])
51 return min(MAX_DISK_SINGLE, MAX_DISK_TOTAL-disk_usage/1024.)
54 machines = getMachinesByOwner(user)
55 active_machines = [x for x in machines if g.uptimes[x]]
56 if len(machines) >= MAX_VMS_TOTAL:
57 return 'You have too many VMs to create a new one.'
58 if len(active_machines) >= MAX_VMS_ACTIVE:
59 return ('You already have the maximum number of VMs turned on. '
60 'To create more, turn one off.')
64 reason = cantAddVm(user)
66 raise InvalidInput('create', True, reason)
69 def haveAccess(user, machine):
70 """Return whether a user has administrative access to a machine"""
73 if user in (machine.administrator, machine.owner):
75 if getafsgroups.checkAfsGroup(user, machine.administrator,
76 'athena.mit.edu'): #XXX Cell?
78 if not getafsgroups.notLockerOwner(user, machine.owner):
80 return owns(user, machine)
82 def owns(user, machine):
83 """Return whether a user owns a machine"""
86 return not getafsgroups.notLockerOwner(user, machine.owner)
88 def validMachineName(name):
89 """Check that name is valid for a machine name"""
92 charset = string.ascii_letters + string.digits + '-_'
93 if name[0] in '-_' or len(name) > 22:
100 def validMemory(user, memory, machine=None, on=True):
101 """Parse and validate limits for memory for a given user and machine.
103 on is whether the memory must be valid after the machine is
108 if memory < MIN_MEMORY_SINGLE:
111 raise InvalidInput('memory', memory,
112 "Minimum %s MiB" % MIN_MEMORY_SINGLE)
113 if memory > maxMemory(user, machine, on):
114 raise InvalidInput('memory', memory,
115 'Maximum %s MiB for %s' % (maxMemory(user, machine),
119 def validDisk(user, disk, machine=None):
120 """Parse and validate limits for disk for a given user and machine."""
123 if disk > maxDisk(user, machine):
124 raise InvalidInput('disk', disk,
125 "Maximum %s G" % maxDisk(user, machine))
126 disk = int(disk * 1024)
127 if disk < MIN_DISK_SINGLE * 1024:
130 raise InvalidInput('disk', disk,
131 "Minimum %s GiB" % MIN_DISK_SINGLE)
134 def testMachineId(user, machine_id, exists=True):
135 """Parse, validate and check authorization for a given user and machine.
137 If exists is False, don't check that it exists.
139 if machine_id is None:
140 raise InvalidInput('machine_id', machine_id,
141 "Must specify a machine ID.")
143 machine_id = int(machine_id)
145 raise InvalidInput('machine_id', machine_id, "Must be an integer.")
146 machine = Machine.get(machine_id)
147 if exists and machine is None:
148 raise InvalidInput('machine_id', machine_id, "Does not exist.")
149 if machine is not None and not haveAccess(user, machine):
150 raise InvalidInput('machine_id', machine_id,
151 "You do not have access to this machine.")
154 def testAdmin(user, admin, machine):
155 if admin in (None, machine.administrator):
159 if getafsgroups.checkAfsGroup(user, admin, 'athena.mit.edu'):
161 if getafsgroups.checkAfsGroup(user, 'system:'+admin,
163 return 'system:'+admin
166 def testOwner(user, owner, machine=None):
167 if owner == user or machine is not None and owner == machine.owner:
170 raise InvalidInput('owner', owner, "Owner must be specified")
171 value = getafsgroups.notLockerOwner(user, owner)
174 raise InvalidInput('owner', owner, value)
176 def testContact(user, contact, machine=None):
177 if contact in (None, machine.contact):
179 if not re.match("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$", contact, re.I):
180 raise InvalidInput('contact', contact, "Not a valid email.")
183 def testDisk(user, disksize, machine=None):
186 def testName(user, name, machine=None):
187 if name in (None, machine.name):
189 if not Machine.select_by(name=name):
191 raise InvalidInput('name', name, "Name is already taken.")
193 def testHostname(user, hostname, machine):
194 for nic in machine.nics:
195 if hostname == nic.hostname:
197 # check if doesn't already exist
198 if NIC.select_by(hostname=hostname):
199 raise InvalidInput('hostname', hostname,
201 if not re.match("^[A-Z0-9-]{1,22}$", hostname, re.I):
202 raise InvalidInput('hostname', hostname, "Not a valid hostname; "
203 "must only use number, letters, and dashes.")