source: trunk/web/templates/validation.py @ 233

Last change on this file since 233 was 229, checked in by ecprice, 17 years ago

Replace 'megabyte' with 'MiB' to please Anders.

File size: 6.9 KB
Line 
1#!/usr/bin/python
2
3import getafsgroups
4import re
5import string
6from sipb_xen_database import Machine, NIC
7from webcommon import InvalidInput, g
8
9MAX_MEMORY_TOTAL = 512
10MAX_MEMORY_SINGLE = 256
11MIN_MEMORY_SINGLE = 16
12MAX_DISK_TOTAL = 50
13MAX_DISK_SINGLE = 50
14MIN_DISK_SINGLE = 0.1
15MAX_VMS_TOTAL = 10
16MAX_VMS_ACTIVE = 4
17
18def getMachinesByOwner(user, machine=None):
19    """Return the machines owned by the same as a machine.
20   
21    If the machine is None, return the machines owned by the same
22    user.
23    """
24    if machine:
25        owner = machine.owner
26    else:
27        owner = user
28    return Machine.select_by(owner=owner)
29
30def maxMemory(user, machine=None, on=True):
31    """Return the maximum memory for a machine or a user.
32
33    If machine is None, return the memory available for a new
34    machine.  Else, return the maximum that machine can have.
35
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
38    returned.
39    """
40    if not on:
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)
46
47def 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.)
52
53def cantAddVm(user):
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.')
61    return False
62
63def validAddVm(user):
64    reason = cantAddVm(user)
65    if reason:
66        raise InvalidInput('create', True, reason)
67    return True
68
69def haveAccess(user, machine):
70    """Return whether a user has adminstrative access to a machine"""
71    if user == 'moo':
72        return True
73    if user in (machine.administrator, machine.owner):
74        return True
75    if getafsgroups.checkAfsGroup(user, machine.administrator, 
76                                  'athena.mit.edu'): #XXX Cell?
77        return True
78    if getafsgroups.checkLockerOwner(user, machine.owner):
79        return True
80    return owns(user, machine)
81
82def owns(user, machine):
83    """Return whether a user owns a machine"""
84    if user == 'moo':
85        return True
86    return getafsgroups.checkLockerOwner(user, machine.owner)
87
88def validMachineName(name):
89    """Check that name is valid for a machine name"""
90    if not name:
91        return False
92    charset = string.ascii_letters + string.digits + '-_'
93    if name[0] in '-_' or len(name) > 22:
94        return False
95    for x in name:
96        if x not in charset:
97            return False
98    return True
99
100def validMemory(user, memory, machine=None, on=True):
101    """Parse and validate limits for memory for a given user and machine.
102
103    on is whether the memory must be valid after the machine is
104    switched on.
105    """
106    try:
107        memory = int(memory)
108        if memory < MIN_MEMORY_SINGLE:
109            raise ValueError
110    except ValueError:
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),
116                                                      user))
117    return memory
118
119def validDisk(user, disk, machine=None):
120    """Parse and validate limits for disk for a given user and machine."""
121    try:
122        disk = float(disk)
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:
128            raise ValueError
129    except ValueError:
130        raise InvalidInput('disk', disk,
131                           "Minimum %s GiB" % MIN_DISK_SINGLE)
132    return disk
133           
134def testMachineId(user, machine_id, exists=True):
135    """Parse, validate and check authorization for a given user and machine.
136
137    If exists is False, don't check that it exists.
138    """
139    if machine_id is None:
140        raise InvalidInput('machine_id', machine_id, 
141                           "Must specify a machine ID.")
142    try:
143        machine_id = int(machine_id)
144    except ValueError:
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.")
152    return machine
153
154def testAdmin(user, admin, machine):
155    if admin in (None, machine.administrator):
156        return None
157    if admin == user:
158        return admin
159    if getafsgroups.checkAfsGroup(user, admin, 'athena.mit.edu'):
160        return admin
161    if getafsgroups.checkAfsGroup(user, 'system:'+admin,
162                                  'athena.mit.edu'):
163        return 'system:'+admin
164    return admin
165   
166def testOwner(user, owner, machine=None):
167    if owner == user or machine is not None and owner == machine.owner:
168        return owner
169    if owner is None:
170        raise InvalidInput('owner', owner, "Owner must be specified")
171    value = getafsgroups.checkLockerOwner(user, owner, verbose=True)
172    if not value:
173        return owner
174    raise InvalidInput('owner', owner, value)
175
176def testContact(user, contact, machine=None):
177    if contact in (None, machine.contact):
178        return None
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.")
181    return contact
182
183def testDisk(user, disksize, machine=None):
184    return disksize
185
186def testName(user, name, machine=None):
187    if name in (None, machine.name):
188        return None
189    if not Machine.select_by(name=name):
190        return name
191    raise InvalidInput('name', name, "Name is already taken.")
192
193def testHostname(user, hostname, machine):
194    for nic in machine.nics:
195        if hostname == nic.hostname:
196            return hostname
197    # check if doesn't already exist
198    if NIC.select_by(hostname=hostname):
199        raise InvalidInput('hostname', hostname,
200                           "Already exists")
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.")
204    return hostname
Note: See TracBrowser for help on using the repository browser.