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

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

Remove the useless User class (now user is a string)
Allow creation under another owner.

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
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' % 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:
157        return admin
158    if getafsgroups.checkAfsGroup(user, admin, 'athena.mit.edu'):
159        return admin
160    if getafsgroups.checkAfsGroup(user, 'system:'+admin,
161                                  'athena.mit.edu'):
162        return 'system:'+admin
163    return admin
164   
165def testOwner(user, owner, machine=None):
166    if owner == user or machine is not None and owner == machine.owner:
167        return owner
168    if owner is None:
169        raise InvalidInput('owner', owner, "Owner must be specified")
170    value = getafsgroups.checkLockerOwner(user, owner, verbose=True)
171    if not value:
172        return owner
173    raise InvalidInput('owner', owner, value)
174
175def testContact(user, contact, machine=None):
176    if contact in (None, machine.contact):
177        return None
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.")
180    return contact
181
182def testDisk(user, disksize, machine=None):
183    return disksize
184
185def testName(user, name, machine=None):
186    if name in (None, machine.name):
187        return None
188    if not Machine.select_by(name=name):
189        return name
190    raise InvalidInput('name', name, "Name is already taken.")
191
192def testHostname(user, hostname, machine):
193    for nic in machine.nics:
194        if hostname == nic.hostname:
195            return hostname
196    # check if doesn't already exist
197    if NIC.select_by(hostname=hostname):
198        raise InvalidInput('hostname', hostname,
199                           "Already exists")
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.")
203    return hostname
Note: See TracBrowser for help on using the repository browser.