source: trunk/packages/sipb-xen-www/code/main.py @ 518

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

Default type in info page

  • Property svn:executable set to *
File size: 23.6 KB
RevLine 
[113]1#!/usr/bin/python
[205]2"""Main CGI script for web interface"""
[113]3
[205]4import base64
5import cPickle
[113]6import cgi
[205]7import datetime
8import hmac
[113]9import os
[205]10import sha
11import simplejson
12import sys
[118]13import time
[447]14import urllib
[205]15from StringIO import StringIO
[113]16
[205]17def revertStandardError():
18    """Move stderr to stdout, and return the contents of the old stderr."""
19    errio = sys.stderr
20    if not isinstance(errio, StringIO):
21        return None
22    sys.stderr = sys.stdout
23    errio.seek(0)
24    return errio.read()
25
26def printError():
27    """Revert stderr to stdout, and print the contents of stderr"""
28    if isinstance(sys.stderr, StringIO):
29        print revertStandardError()
30
31if __name__ == '__main__':
32    import atexit
33    atexit.register(printError)
34    sys.stderr = StringIO()
35
[113]36sys.path.append('/home/ecprice/.local/lib/python2.5/site-packages')
37
[235]38import templates
[113]39from Cheetah.Template import Template
[440]40import sipb_xen_database
[443]41from sipb_xen_database import Machine, CDROM, ctx, connect, MachineAccess, Type, Autoinstall
[209]42import validation
[446]43import cache_acls
[209]44from webcommon import InvalidInput, CodeError, g
45import controls
[113]46
[235]47class Checkpoint:
48    def __init__(self):
49        self.start_time = time.time()
50        self.checkpoints = []
51
52    def checkpoint(self, s):
53        self.checkpoints.append((s, time.time()))
54
55    def __str__(self):
56        return ('Timing info:\n%s\n' %
57                '\n'.join(['%s: %s' % (d, t - self.start_time) for
58                           (d, t) in self.checkpoints]))
59
60checkpoint = Checkpoint()
61
[447]62def jquote(string):
63    return "'" + string.replace('\\', '\\\\').replace("'", "\\'").replace('\n', '\\n') + "'"
[235]64
[205]65def helppopup(subj):
66    """Return HTML code for a (?) link to a specified help topic"""
[447]67    return ('<span class="helplink"><a href="help?' +
68            cgi.escape(urllib.urlencode(dict(subject=subj, simple='true')))
69            +'" target="_blank" ' +
70            'onclick="return helppopup(' + cgi.escape(jquote(subj)) + ')">(?)</a></span>')
[205]71
72def makeErrorPre(old, addition):
73    if addition is None:
74        return
75    if old:
76        return old[:-6]  + '\n----\n' + str(addition) + '</pre>'
77    else:
78        return '<p>STDERR:</p><pre>' + str(addition) + '</pre>'
[139]79
[440]80Template.sipb_xen_database = sipb_xen_database
[205]81Template.helppopup = staticmethod(helppopup)
82Template.err = None
[139]83
[205]84class JsonDict:
85    """Class to store a dictionary that will be converted to JSON"""
86    def __init__(self, **kws):
87        self.data = kws
88        if 'err' in kws:
89            err = kws['err']
90            del kws['err']
91            self.addError(err)
[139]92
[205]93    def __str__(self):
94        return simplejson.dumps(self.data)
95
96    def addError(self, text):
97        """Add stderr text to be displayed on the website."""
98        self.data['err'] = \
99            makeErrorPre(self.data.get('err'), text)
100
101class Defaults:
102    """Class to store default values for fields."""
103    memory = 256
104    disk = 4.0
105    cdrom = ''
[443]106    autoinstall = ''
[205]107    name = ''
[515]108    type = 'linux-hvm'
109
[205]110    def __init__(self, max_memory=None, max_disk=None, **kws):
111        if max_memory is not None:
112            self.memory = min(self.memory, max_memory)
113        if max_disk is not None:
114            self.max_disk = min(self.disk, max_disk)
115        for key in kws:
116            setattr(self, key, kws[key])
117
118
119
[209]120DEFAULT_HEADERS = {'Content-Type': 'text/html'}
[205]121
[153]122def error(op, user, fields, err, emsg):
[145]123    """Print an error page when a CodeError occurs"""
[153]124    d = dict(op=op, user=user, errorMessage=str(err),
125             stderr=emsg)
[235]126    return templates.error(searchList=[d])
[113]127
[153]128def invalidInput(op, user, fields, err, emsg):
129    """Print an error page when an InvalidInput exception occurs"""
130    d = dict(op=op, user=user, err_field=err.err_field,
131             err_value=str(err.err_value), stderr=emsg,
132             errorMessage=str(err))
[235]133    return templates.invalid(searchList=[d])
[153]134
[119]135def hasVnc(status):
[133]136    """Does the machine with a given status list support VNC?"""
[119]137    if status is None:
138        return False
139    for l in status:
140        if l[0] == 'device' and l[1][0] == 'vfb':
141            d = dict(l[1][1:])
142            return 'location' in d
143    return False
144
[205]145def parseCreate(user, fields):
[134]146    name = fields.getfirst('name')
[209]147    if not validation.validMachineName(name):
[429]148        raise InvalidInput('name', name, 'You must provide a machine name.  Max 22 chars, alnum plus \'-\' and \'_\'.')
[162]149    name = name.lower()
[134]150
151    if Machine.get_by(name=name):
[153]152        raise InvalidInput('name', name,
[205]153                           "Name already exists.")
[438]154
[228]155    owner = validation.testOwner(user, fields.getfirst('owner'))
156
[134]157    memory = fields.getfirst('memory')
[266]158    memory = validation.validMemory(owner, memory, on=True)
[438]159
[243]160    disk_size = fields.getfirst('disk')
[266]161    disk_size = validation.validDisk(owner, disk_size)
[134]162
[113]163    vm_type = fields.getfirst('vmtype')
[437]164    vm_type = validation.validVmType(vm_type)
[113]165
166    cdrom = fields.getfirst('cdrom')
167    if cdrom is not None and not CDROM.get(cdrom):
[205]168        raise CodeError("Invalid cdrom type '%s'" % cdrom)
[340]169
170    clone_from = fields.getfirst('clone_from')
171    if clone_from and clone_from != 'ice3':
172        raise CodeError("Invalid clone image '%s'" % clone_from)
[438]173
[243]174    return dict(contact=user, name=name, memory=memory, disk_size=disk_size,
[437]175                owner=owner, machine_type=vm_type, cdrom=cdrom, clone_from=clone_from)
[113]176
[205]177def create(user, fields):
178    """Handler for create requests."""
179    try:
180        parsed_fields = parseCreate(user, fields)
[209]181        machine = controls.createVm(**parsed_fields)
[205]182    except InvalidInput, err:
[207]183        pass
[205]184    else:
185        err = None
186    g.clear() #Changed global state
187    d = getListDict(user)
188    d['err'] = err
189    if err:
190        for field in fields.keys():
191            setattr(d['defaults'], field, fields.getfirst(field))
192    else:
193        d['new_machine'] = parsed_fields['name']
[235]194    return templates.list(searchList=[d])
[205]195
196
197def getListDict(user):
[438]198    """Gets the list of local variables used by list.tmpl."""
[261]199    machines = g.machines
[235]200    checkpoint.checkpoint('Got my machines')
[133]201    on = {}
[119]202    has_vnc = {}
[152]203    on = g.uptimes
[235]204    checkpoint.checkpoint('Got uptimes')
[136]205    for m in machines:
[205]206        m.uptime = g.uptimes.get(m)
[144]207        if not on[m]:
208            has_vnc[m] = 'Off'
[138]209        elif m.type.hvm:
[144]210            has_vnc[m] = True
[136]211        else:
[144]212            has_vnc[m] = "ParaVM"+helppopup("paravm_console")
[209]213    max_memory = validation.maxMemory(user)
214    max_disk = validation.maxDisk(user)
[235]215    checkpoint.checkpoint('Got max mem/disk')
[205]216    defaults = Defaults(max_memory=max_memory,
217                        max_disk=max_disk,
[228]218                        owner=user,
[205]219                        cdrom='gutsy-i386')
[235]220    checkpoint.checkpoint('Got defaults')
[424]221    def sortkey(machine):
222        return (machine.owner != user, machine.owner, machine.name)
223    machines = sorted(machines, key=sortkey)
[113]224    d = dict(user=user,
[209]225             cant_add_vm=validation.cantAddVm(user),
[205]226             max_memory=max_memory,
[144]227             max_disk=max_disk,
[205]228             defaults=defaults,
[113]229             machines=machines,
[119]230             has_vnc=has_vnc,
[443]231             uptimes=g.uptimes)
[205]232    return d
[113]233
[205]234def listVms(user, fields):
235    """Handler for list requests."""
[235]236    checkpoint.checkpoint('Getting list dict')
[205]237    d = getListDict(user)
[235]238    checkpoint.checkpoint('Got list dict')
239    return templates.list(searchList=[d])
[438]240
[113]241def vnc(user, fields):
[119]242    """VNC applet page.
243
244    Note that due to same-domain restrictions, the applet connects to
245    the webserver, which needs to forward those requests to the xen
246    server.  The Xen server runs another proxy that (1) authenticates
247    and (2) finds the correct port for the VM.
248
249    You might want iptables like:
250
[205]251    -t nat -A PREROUTING -s ! 18.181.0.60 -i eth1 -p tcp -m tcp \
[438]252      --dport 10003 -j DNAT --to-destination 18.181.0.60:10003
[205]253    -t nat -A POSTROUTING -d 18.181.0.60 -o eth1 -p tcp -m tcp \
[438]254      --dport 10003 -j SNAT --to-source 18.187.7.142
[205]255    -A FORWARD -d 18.181.0.60 -i eth1 -o eth1 -p tcp -m tcp \
256      --dport 10003 -j ACCEPT
[145]257
258    Remember to enable iptables!
259    echo 1 > /proc/sys/net/ipv4/ip_forward
[119]260    """
[209]261    machine = validation.testMachineId(user, fields.getfirst('machine_id'))
[438]262
[118]263    TOKEN_KEY = "0M6W0U1IXexThi5idy8mnkqPKEq1LtEnlK/pZSn0cDrN"
264
265    data = {}
[228]266    data["user"] = user
[205]267    data["machine"] = machine.name
268    data["expires"] = time.time()+(5*60)
269    pickled_data = cPickle.dumps(data)
[118]270    m = hmac.new(TOKEN_KEY, digestmod=sha)
[205]271    m.update(pickled_data)
272    token = {'data': pickled_data, 'digest': m.digest()}
[118]273    token = cPickle.dumps(token)
274    token = base64.urlsafe_b64encode(token)
[438]275
[209]276    status = controls.statusInfo(machine)
[152]277    has_vnc = hasVnc(status)
[438]278
[113]279    d = dict(user=user,
[152]280             on=status,
281             has_vnc=has_vnc,
[113]282             machine=machine,
[119]283             hostname=os.environ.get('SERVER_NAME', 'localhost'),
[113]284             authtoken=token)
[235]285    return templates.vnc(searchList=[d])
[113]286
[252]287def getHostname(nic):
[438]288    """Find the hostname associated with a NIC.
289
290    XXX this should be merged with the similar logic in DNS and DHCP.
291    """
[252]292    if nic.hostname and '.' in nic.hostname:
293        return nic.hostname
294    elif nic.machine:
[507]295        return nic.machine.name + '.xvm.mit.edu'
[252]296    else:
297        return None
298
299
[133]300def getNicInfo(data_dict, machine):
[145]301    """Helper function for info, get data on nics for a machine.
302
303    Modifies data_dict to include the relevant data, and returns a list
304    of (key, name) pairs to display "name: data_dict[key]" to the user.
305    """
[133]306    data_dict['num_nics'] = len(machine.nics)
[227]307    nic_fields_template = [('nic%s_hostname', 'NIC %s Hostname'),
[133]308                           ('nic%s_mac', 'NIC %s MAC Addr'),
309                           ('nic%s_ip', 'NIC %s IP'),
310                           ]
311    nic_fields = []
312    for i in range(len(machine.nics)):
313        nic_fields.extend([(x % i, y % i) for x, y in nic_fields_template])
[227]314        if not i:
[252]315            data_dict['nic%s_hostname' % i] = getHostname(machine.nics[i])
[133]316        data_dict['nic%s_mac' % i] = machine.nics[i].mac_addr
317        data_dict['nic%s_ip' % i] = machine.nics[i].ip
318    if len(machine.nics) == 1:
319        nic_fields = [(x, y.replace('NIC 0 ', '')) for x, y in nic_fields]
320    return nic_fields
321
322def getDiskInfo(data_dict, machine):
[145]323    """Helper function for info, get data on disks for a machine.
324
325    Modifies data_dict to include the relevant data, and returns a list
326    of (key, name) pairs to display "name: data_dict[key]" to the user.
327    """
[133]328    data_dict['num_disks'] = len(machine.disks)
329    disk_fields_template = [('%s_size', '%s size')]
330    disk_fields = []
331    for disk in machine.disks:
332        name = disk.guest_device_name
[438]333        disk_fields.extend([(x % name, y % name) for x, y in
[205]334                            disk_fields_template])
[211]335        data_dict['%s_size' % name] = "%0.1f GiB" % (disk.size / 1024.)
[133]336    return disk_fields
337
[205]338def command(user, fields):
339    """Handler for running commands like boot and delete on a VM."""
[207]340    back = fields.getfirst('back')
[205]341    try:
[209]342        d = controls.commandResult(user, fields)
[207]343        if d['command'] == 'Delete VM':
344            back = 'list'
[205]345    except InvalidInput, err:
[207]346        if not back:
[205]347            raise
[261]348        #print >> sys.stderr, err
349        result = err
[205]350    else:
351        result = 'Success!'
[207]352        if not back:
[235]353            return templates.command(searchList=[d])
[207]354    if back == 'list':
[205]355        g.clear() #Changed global state
356        d = getListDict(user)
[207]357        d['result'] = result
[235]358        return templates.list(searchList=[d])
[207]359    elif back == 'info':
[209]360        machine = validation.testMachineId(user, fields.getfirst('machine_id'))
[407]361        return ({'Status': '302',
362                 'Location': '/info?machine_id=%d' % machine.machine_id},
363                "You shouldn't see this message.")
[205]364    else:
[261]365        raise InvalidInput('back', back, 'Not a known back page.')
[205]366
367def modifyDict(user, fields):
[438]368    """Modify a machine as specified by CGI arguments.
369
370    Return a list of local variables for modify.tmpl.
371    """
[177]372    olddisk = {}
[161]373    transaction = ctx.current.create_transaction()
374    try:
[209]375        machine = validation.testMachineId(user, fields.getfirst('machine_id'))
376        owner = validation.testOwner(user, fields.getfirst('owner'), machine)
377        admin = validation.testAdmin(user, fields.getfirst('administrator'),
378                                     machine)
379        contact = validation.testContact(user, fields.getfirst('contact'),
380                                         machine)
381        name = validation.testName(user, fields.getfirst('name'), machine)
[161]382        oldname = machine.name
[205]383        command = "modify"
[153]384
[161]385        memory = fields.getfirst('memory')
386        if memory is not None:
[209]387            memory = validation.validMemory(user, memory, machine, on=False)
[161]388            machine.memory = memory
[438]389
[440]390        vm_type = validation.validVmType(fields.getfirst('vmtype'))
391        if vm_type is not None:
392            machine.type = vm_type
393
[209]394        disksize = validation.testDisk(user, fields.getfirst('disk'))
[161]395        if disksize is not None:
[209]396            disksize = validation.validDisk(user, disksize, machine)
[177]397            disk = machine.disks[0]
398            if disk.size != disksize:
399                olddisk[disk.guest_device_name] = disksize
400                disk.size = disksize
401                ctx.current.save(disk)
[438]402
[446]403        update_acl = False
404        if owner is not None and owner != machine.owner:
[161]405            machine.owner = owner
[446]406            update_acl = True
[187]407        if name is not None:
[161]408            machine.name = name
[446]409        if admin is not None and admin != machine.administrator:
[187]410            machine.administrator = admin
[446]411            update_acl = True
[187]412        if contact is not None:
413            machine.contact = contact
[438]414
[161]415        ctx.current.save(machine)
[446]416        if update_acl:
417            cache_acls.refreshMachine(machine)
[161]418        transaction.commit()
419    except:
420        transaction.rollback()
[163]421        raise
[177]422    for diskname in olddisk:
[209]423        controls.resizeDisk(oldname, diskname, str(olddisk[diskname]))
[187]424    if name is not None:
[209]425        controls.renameMachine(machine, oldname, name)
[205]426    return dict(user=user,
427                command=command,
428                machine=machine)
[438]429
[205]430def modify(user, fields):
431    """Handler for modifying attributes of a machine."""
432    try:
433        modify_dict = modifyDict(user, fields)
434    except InvalidInput, err:
[207]435        result = None
[209]436        machine = validation.testMachineId(user, fields.getfirst('machine_id'))
[205]437    else:
438        machine = modify_dict['machine']
[209]439        result = 'Success!'
[205]440        err = None
441    info_dict = infoDict(user, machine)
442    info_dict['err'] = err
443    if err:
444        for field in fields.keys():
445            setattr(info_dict['defaults'], field, fields.getfirst(field))
[207]446    info_dict['result'] = result
[235]447    return templates.info(searchList=[info_dict])
[161]448
[438]449
[205]450def helpHandler(user, fields):
[145]451    """Handler for help messages."""
[139]452    simple = fields.getfirst('simple')
453    subjects = fields.getlist('subject')
[438]454
[205]455    help_mapping = dict(paravm_console="""
[432]456ParaVM machines do not support local console access over VNC.  To
457access the serial console of these machines, you can SSH with Kerberos
458to sipb-xen-console.mit.edu, using the name of the machine as your
459username.""",
[205]460                        hvm_paravm="""
[139]461HVM machines use the virtualization features of the processor, while
462ParaVM machines use Xen's emulation of virtualization features.  You
463want an HVM virtualized machine.""",
[205]464                        cpu_weight="""
465Don't ask us!  We're as mystified as you are.""",
466                        owner="""
467The owner field is used to determine <a
468href="help?subject=quotas">quotas</a>.  It must be the name of a
469locker that you are an AFS administrator of.  In particular, you or an
470AFS group you are a member of must have AFS rlidwka bits on the
[432]471locker.  You can check who administers the LOCKER locker using the
472commands 'attach LOCKER; fs la /mit/LOCKER' on Athena.)  See also <a
[205]473href="help?subject=administrator">administrator</a>.""",
474                        administrator="""
475The administrator field determines who can access the console and
476power on and off the machine.  This can be either a user or a moira
477group.""",
478                        quotas="""
[408]479Quotas are determined on a per-locker basis.  Each locker may have a
[205]480maximum of 512 megabytes of active ram, 50 gigabytes of disk, and 4
[309]481active machines.""",
482                        console="""
483<strong>Framebuffer:</strong> At a Linux boot prompt in your VM, try
484setting <tt>fb=false</tt> to disable the framebuffer.  If you don't,
485your machine will run just fine, but the applet's display of the
486console will suffer artifacts.
487"""
[187]488                   )
[438]489
[187]490    if not subjects:
[205]491        subjects = sorted(help_mapping.keys())
[438]492
[139]493    d = dict(user=user,
494             simple=simple,
495             subjects=subjects,
[205]496             mapping=help_mapping)
[438]497
[235]498    return templates.help(searchList=[d])
[133]499
[438]500
[205]501def badOperation(u, e):
[438]502    """Function called when accessing an unknown URI."""
[205]503    raise CodeError("Unknown operation")
504
505def infoDict(user, machine):
[438]506    """Get the variables used by info.tmpl."""
[209]507    status = controls.statusInfo(machine)
[235]508    checkpoint.checkpoint('Getting status info')
[133]509    has_vnc = hasVnc(status)
510    if status is None:
511        main_status = dict(name=machine.name,
512                           memory=str(machine.memory))
[205]513        uptime = None
514        cputime = None
[133]515    else:
516        main_status = dict(status[1:])
[167]517        start_time = float(main_status.get('start_time', 0))
518        uptime = datetime.timedelta(seconds=int(time.time()-start_time))
519        cpu_time_float = float(main_status.get('cpu_time', 0))
520        cputime = datetime.timedelta(seconds=int(cpu_time_float))
[235]521    checkpoint.checkpoint('Status')
[133]522    display_fields = """name uptime memory state cpu_weight on_reboot
523     on_poweroff on_crash on_xend_start on_xend_stop bootloader""".split()
524    display_fields = [('name', 'Name'),
525                      ('owner', 'Owner'),
[187]526                      ('administrator', 'Administrator'),
[133]527                      ('contact', 'Contact'),
[136]528                      ('type', 'Type'),
[133]529                      'NIC_INFO',
530                      ('uptime', 'uptime'),
531                      ('cputime', 'CPU usage'),
532                      ('memory', 'RAM'),
533                      'DISK_INFO',
534                      ('state', 'state (xen format)'),
[139]535                      ('cpu_weight', 'CPU weight'+helppopup('cpu_weight')),
[133]536                      ('on_reboot', 'Action on VM reboot'),
537                      ('on_poweroff', 'Action on VM poweroff'),
538                      ('on_crash', 'Action on VM crash'),
539                      ('on_xend_start', 'Action on Xen start'),
540                      ('on_xend_stop', 'Action on Xen stop'),
541                      ('bootloader', 'Bootloader options'),
542                      ]
543    fields = []
544    machine_info = {}
[147]545    machine_info['name'] = machine.name
[136]546    machine_info['type'] = machine.type.hvm and 'HVM' or 'ParaVM'
[133]547    machine_info['owner'] = machine.owner
[187]548    machine_info['administrator'] = machine.administrator
[133]549    machine_info['contact'] = machine.contact
550
551    nic_fields = getNicInfo(machine_info, machine)
552    nic_point = display_fields.index('NIC_INFO')
[438]553    display_fields = (display_fields[:nic_point] + nic_fields +
[205]554                      display_fields[nic_point+1:])
[133]555
556    disk_fields = getDiskInfo(machine_info, machine)
557    disk_point = display_fields.index('DISK_INFO')
[438]558    display_fields = (display_fields[:disk_point] + disk_fields +
[205]559                      display_fields[disk_point+1:])
[438]560
[211]561    main_status['memory'] += ' MiB'
[133]562    for field, disp in display_fields:
[167]563        if field in ('uptime', 'cputime') and locals()[field] is not None:
[133]564            fields.append((disp, locals()[field]))
[147]565        elif field in machine_info:
566            fields.append((disp, machine_info[field]))
[133]567        elif field in main_status:
568            fields.append((disp, main_status[field]))
569        else:
570            pass
571            #fields.append((disp, None))
[235]572
573    checkpoint.checkpoint('Got fields')
574
575
576    max_mem = validation.maxMemory(user, machine, False)
577    checkpoint.checkpoint('Got mem')
[209]578    max_disk = validation.maxDisk(user, machine)
579    defaults = Defaults()
[516]580    for name in 'machine_id name administrator owner memory contact'.split():
[205]581        setattr(defaults, name, getattr(machine, name))
[516]582    defaults.type = machine.type.type_id
[205]583    defaults.disk = "%0.2f" % (machine.disks[0].size/1024.)
[235]584    checkpoint.checkpoint('Got defaults')
[113]585    d = dict(user=user,
[133]586             on=status is not None,
587             machine=machine,
[205]588             defaults=defaults,
[133]589             has_vnc=has_vnc,
590             uptime=str(uptime),
591             ram=machine.memory,
[144]592             max_mem=max_mem,
593             max_disk=max_disk,
[166]594             owner_help=helppopup("owner"),
[133]595             fields = fields)
[205]596    return d
[113]597
[205]598def info(user, fields):
599    """Handler for info on a single VM."""
[209]600    machine = validation.testMachineId(user, fields.getfirst('machine_id'))
[205]601    d = infoDict(user, machine)
[235]602    checkpoint.checkpoint('Got infodict')
603    return templates.info(searchList=[d])
[205]604
[510]605def unauthFront(_, fields):
606    """Information for unauth'd users."""
607    return templates.unauth(searchList=[{'simple' : True}])
608
[113]609mapping = dict(list=listVms,
610               vnc=vnc,
[133]611               command=command,
612               modify=modify,
[113]613               info=info,
[139]614               create=create,
[510]615               help=helpHandler,
616               unauth=unauthFront)
[113]617
[205]618def printHeaders(headers):
[438]619    """Print a dictionary as HTTP headers."""
[205]620    for key, value in headers.iteritems():
621        print '%s: %s' % (key, value)
622    print
623
624
625def getUser():
626    """Return the current user based on the SSL environment variables"""
[510]627    email = os.environ.get('SSL_CLIENT_S_DN_Email', None)
628    if email is None:
629        return None
630    return email.split("@")[0]
[205]631
[438]632def main(operation, user, fields):
[235]633    start_time = time.time()
[153]634    fun = mapping.get(operation, badOperation)
[205]635
636    if fun not in (helpHandler, ):
637        connect('postgres://sipb-xen@sipb-xen-dev.mit.edu/sipb_xen')
[119]638    try:
[235]639        checkpoint.checkpoint('Before')
[153]640        output = fun(u, fields)
[235]641        checkpoint.checkpoint('After')
[205]642
[209]643        headers = dict(DEFAULT_HEADERS)
[205]644        if isinstance(output, tuple):
645            new_headers, output = output
646            headers.update(new_headers)
647        e = revertStandardError()
[153]648        if e:
[205]649            output.addError(e)
650        printHeaders(headers)
[235]651        output_string =  str(output)
652        checkpoint.checkpoint('output as a string')
653        print output_string
[421]654        print '<!-- <pre>%s</pre> -->' % checkpoint
[205]655    except Exception, err:
656        if not fields.has_key('js'):
657            if isinstance(err, CodeError):
658                print 'Content-Type: text/html\n'
659                e = revertStandardError()
660                print error(operation, u, fields, err, e)
661                sys.exit(1)
662            if isinstance(err, InvalidInput):
663                print 'Content-Type: text/html\n'
664                e = revertStandardError()
665                print invalidInput(operation, u, fields, err, e)
666                sys.exit(1)
[153]667        print 'Content-Type: text/plain\n'
[205]668        print 'Uh-oh!  We experienced an error.'
669        print 'Please email sipb-xen@mit.edu with the contents of this page.'
670        print '----'
671        e = revertStandardError()
[153]672        print e
673        print '----'
674        raise
[209]675
676if __name__ == '__main__':
677    fields = cgi.FieldStorage()
678    u = getUser()
679    g.user = u
680    operation = os.environ.get('PATH_INFO', '')
681    if not operation:
682        print "Status: 301 Moved Permanently"
683        print 'Location: ' + os.environ['SCRIPT_NAME']+'/\n'
684        sys.exit(0)
685
[510]686    if u is None:
687        operation = 'unauth'
688
[209]689    if operation.startswith('/'):
690        operation = operation[1:]
691    if not operation:
692        operation = 'list'
693
[248]694    if os.getenv("SIPB_XEN_PROFILE"):
695        import profile
696        profile.run('main(operation, u, fields)', 'log-'+operation)
697    else:
698        main(operation, u, fields)
Note: See TracBrowser for help on using the repository browser.