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

Last change on this file since 220 was 211, checked in by andersk, 17 years ago

Use standard units.

File size: 6.8 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.username
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.username == 'moo':
72        return True
73    if user.username in (machine.administrator, machine.owner):
74        return True
75    if getafsgroups.checkAfsGroup(user.username, machine.administrator, 
76                                  'athena.mit.edu'): #XXX Cell?
77        return True
78    if getafsgroups.checkLockerOwner(user.username, 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.username == 'moo':
85        return True
86    return getafsgroups.checkLockerOwner(user.username, 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' % maxMemory(user, machine))
116    return memory
117
118def validDisk(user, disk, machine=None):
119    """Parse and validate limits for disk for a given user and machine."""
120    try:
121        disk = float(disk)
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:
127            raise ValueError
128    except ValueError:
129        raise InvalidInput('disk', disk,
130                           "Minimum %s GiB" % MIN_DISK_SINGLE)
131    return disk
132           
133def testMachineId(user, machine_id, exists=True):
134    """Parse, validate and check authorization for a given user and machine.
135
136    If exists is False, don't check that it exists.
137    """
138    if machine_id is None:
139        raise InvalidInput('machine_id', machine_id, 
140                           "Must specify a machine ID.")
141    try:
142        machine_id = int(machine_id)
143    except ValueError:
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.")
151    return machine
152
153def testAdmin(user, admin, machine):
154    if admin in (None, machine.administrator):
155        return None
156    if admin == user.username:
157        return admin
158    if getafsgroups.checkAfsGroup(user.username, admin, 'athena.mit.edu'):
159        return admin
160    if getafsgroups.checkAfsGroup(user.username, 'system:'+admin,
161                                  'athena.mit.edu'):
162        return 'system:'+admin
163    return admin
164   
165def testOwner(user, owner, machine):
166    if owner in (None, machine.owner):
167        return None
168    value = getafsgroups.checkLockerOwner(user.username, owner, verbose=True)
169    if not value:
170        return owner
171    raise InvalidInput('owner', owner, value)
172
173def testContact(user, contact, machine=None):
174    if contact in (None, machine.contact):
175        return None
176    if not re.match("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$", contact, re.I):
177        raise InvalidInput('contact', contact, "Not a valid email.")
178    return contact
179
180def testDisk(user, disksize, machine=None):
181    return disksize
182
183def testName(user, name, machine=None):
184    if name in (None, machine.name):
185        return None
186    if not Machine.select_by(name=name):
187        return name
188    raise InvalidInput('name', name, "Name is already taken.")
189
190def testHostname(user, hostname, machine):
191    for nic in machine.nics:
192        if hostname == nic.hostname:
193            return hostname
194    # check if doesn't already exist
195    if NIC.select_by(hostname=hostname):
196        raise InvalidInput('hostname', hostname,
197                           "Already exists")
198    if not re.match("^[A-Z0-9-]{1,22}$", hostname, re.I):
199        raise InvalidInput('hostname', hostname, "Not a valid hostname; "
200                           "must only use number, letters, and dashes.")
201    return hostname
Note: See TracBrowser for help on using the repository browser.