source: trunk/web/templates/main.py @ 118

Last change on this file since 118 was 118, checked in by quentin, 17 years ago

Generate real authentication tokens

  • Property svn:executable set to *
File size: 7.5 KB
Line 
1#!/usr/bin/python
2
3import sys
4import cgi
5import os
6import string
7import subprocess
8import time
9import cPickle
10import base64
11
12print 'Content-Type: text/html\n'
13sys.stderr = sys.stdout
14sys.path.append('/home/ecprice/.local/lib/python2.5/site-packages')
15
16from Cheetah.Template import Template
17from sipb_xen_database import *
18import random
19
20# ... and stolen from xend/uuid.py
21def randomUUID():
22    """Generate a random UUID."""
23
24    return [ random.randint(0, 255) for _ in range(0, 16) ]
25
26def uuidToString(u):
27    return "-".join(["%02x" * 4, "%02x" * 2, "%02x" * 2, "%02x" * 2,
28                     "%02x" * 6]) % tuple(u)
29
30
31def maxMemory(user):
32    return 256
33
34def haveAccess(user, machine):
35    return True
36
37
38def error(op, user, fields, errorMessage):
39    d = dict(op=op,
40             user=user,
41             errorMessage=errorMessage)
42    print Template(file='error.tmpl',
43                   searchList=d);
44
45def validMachineName(name):
46    if not name:
47        return False
48    charset = string.ascii_letters + string.digits + '-'
49    if name[0] == '-' or len(name) > 22:
50        return False
51    return all(x in charset for x in name)
52
53def kinit():
54    keytab = '/etc/tabbott.keytab'
55    username = 'tabbott/extra'
56    p = subprocess.Popen(['kinit', "-k", "-t", keytab, 
57                          username])
58    p.wait()
59
60def checkKinit():
61    p = subprocess.Popen(['klist', '-s'])
62    if p.wait():
63        kinit()
64
65def remctl(*args):
66    checkKinit()
67    p = subprocess.Popen(['remctl', 'black-mesa.mit.edu']
68                         + list(args),
69                         stdout=subprocess.PIPE,
70                         stderr=subprocess.PIPE)
71    if p.wait():
72        print >> sys.stderr, 'ERROR on remctl ', args
73        print >> sys.stderr, p.stderr.read()
74
75def makeDisks():
76    remctl('lvcreate','all')
77
78def bootMachine(machine, cdtype):
79    if cdtype is not None:
80        remctl('vmboot', 'cdrom', str(machine.name),
81               cdtype)
82    else:
83        remctl('vmboot', 'cdrom', str(machine.name))
84
85def createVm(user, name, memory, disk, is_hvm, cdrom):
86    # put stuff in the table
87    transaction = ctx.current.create_transaction()
88    try:
89        res = meta.engine.execute('select nextval(\'"machines_machine_id_seq"\')')
90        id = res.fetchone()[0]
91        machine = Machine()
92        machine.machine_id = id
93        machine.name = name
94        machine.memory = memory
95        machine.owner = user.username
96        machine.contact = user.email
97        machine.uuid = uuidToString(randomUUID())
98        machine.boot_off_cd = True
99        machine_type = Type.get_by(hvm=is_hvm)
100        machine.type_id = machine_type.type_id
101        ctx.current.save(machine)
102        disk = Disk(machine.machine_id, 
103                    'hda', disk)
104        open = NIC.select_by(machine_id=None)
105        if not open: #No IPs left!
106            return "No IP addresses left!  Contact sipb-xen-dev@mit.edu"
107        nic = open[0]
108        nic.machine_id = machine.machine_id
109        nic.hostname = name
110        ctx.current.save(nic)   
111        ctx.current.save(disk)
112        transaction.commit()
113    except:
114        transaction.rollback()
115        raise
116    makeDisks()
117    # tell it to boot with cdrom
118    bootMachine(machine, cdrom)
119
120    return machine
121
122def create(user, fields):
123    name = fields.getfirst('name')
124    if not validMachineName(name):
125        return error('create', user, fields,
126                     "Invalid name '%s'" % name)
127    name = name.lower()
128
129    if Machine.get_by(name=name):
130        return error('create', user, fields,
131                     "A machine named '%s' already exists" % name)
132   
133    memory = fields.getfirst('memory')
134    try:
135        memory = int(memory)
136        if memory <= 0:
137            raise ValueError
138    except ValueError:
139        return error('create', user, fields,
140                     "Invalid memory amount")
141    if memory > maxMemory(user):
142        return error('create', user, fields,
143                     "Too much memory requested")
144   
145    disk = fields.getfirst('disk')
146    try:
147        disk = float(disk)
148        disk = int(disk * 1024)
149        if disk <= 0:
150            raise ValueError
151    except ValueError:
152        return error('create', user, fields,
153                     "Invalid disk amount")
154   
155    vm_type = fields.getfirst('vmtype')
156    if vm_type not in ('hvm', 'paravm'):
157        return error('create', user, fields,
158                     "Invalid vm type '%s'"  % vm_type)   
159    is_hvm = (vm_type == 'hvm')
160
161    cdrom = fields.getfirst('cdrom')
162    if cdrom is not None and not CDROM.get(cdrom):
163        return error('create', user, fields,
164                     "Invalid cdrom type '%s'" % cdrom)   
165   
166    machine = createVm(user, name, memory, disk, is_hvm, cdrom)
167    if isinstance(machine, basestring):
168        return error('create', user, fields,
169                     machine)
170    d = dict(user=user,
171             machine=machine)
172    print Template(file='create.tmpl',
173                   searchList=d);
174
175def listVms(user, fields):
176    machines = Machine.select()
177    d = dict(user=user,
178             machines=machines,
179             cdroms=CDROM.select())
180
181    print Template(file='list.tmpl', searchList=d)
182
183def testMachineId(user, machineId, exists=True):
184    if machineId is None:
185        error('vnc', user, fields,
186              "No machine ID specified")
187        return False
188    try:
189        machineId = int(machineId)
190    except ValueError:
191        error('vnc', user, fields,
192              "Invalid machine ID '%s'" 
193              % machineId)
194        return False
195    machine = Machine.get(machineId)
196    if exists and machine is None:
197        error('vnc', user, fields,
198              "No such machine ID '%s'" 
199              % machineId)
200        return False
201    if not haveAccess(user, machine):
202        error('vnc', user, fields,
203              "No access to machine ID '%s'" 
204              % machineId)
205        return False
206    return machine
207
208def vnc(user, fields):
209    machine = testMachineId(user, fields.getfirst('machine_id'))
210    if machine is None: #gave error page already
211        return
212   
213    TOKEN_KEY = "0M6W0U1IXexThi5idy8mnkqPKEq1LtEnlK/pZSn0cDrN"
214
215    data = {}
216    data["user"] = user
217    data["machine"]=machine
218    data["expires"]=time.time()+(5*60)
219    pickledData = cPickle.dumps(data)
220    m = hmac.new(TOKEN_KEY, digestmod=sha)
221    m.update(pickledData)
222    token = {'data': pickledData, 'digest': m.digest()}
223    token = cPickle.dumps(token)
224    token = base64.urlsafe_b64encode(token)
225   
226    d = dict(user=user,
227             machine=machine,
228             hostname='localhost',
229             authtoken=token)
230    print Template(file='vnc.tmpl',
231                   searchList=d)
232
233def info(user, fields):
234    machine = testMachineId(user, fields.getfirst('machine_id'))
235    if machine is None: #gave error page already
236        return
237   
238    d = dict(user=user,
239             machine=machine)
240    print Template(file='info.tmpl',
241                   searchList=d)
242
243mapping = dict(list=listVms,
244               vnc=vnc,
245               info=info,
246               create=create)
247
248if __name__ == '__main__':
249    fields = cgi.FieldStorage()
250    class C:
251        username = "moo"
252        email = 'moo@cow.com'
253    u = C()
254    connect('postgres://sipb-xen@sipb-xen-dev/sipb_xen')
255    operation = os.environ.get('PATH_INFO', '')
256    if operation.startswith('/'):
257        operation = operation[1:]
258    if not operation:
259        operation = 'list'
260   
261    fun = mapping.get(operation, 
262                      lambda u, e:
263                          error(operation, u, e,
264                                "Invalid operation '%'" % operation))
265    fun(u, fields)
Note: See TracBrowser for help on using the repository browser.