#!/usr/bin/python import sys import cgi import os import string import subprocess import time import cPickle import base64 print 'Content-Type: text/html\n' sys.stderr = sys.stdout sys.path.append('/home/ecprice/.local/lib/python2.5/site-packages') from Cheetah.Template import Template from sipb_xen_database import * import random # ... and stolen from xend/uuid.py def randomUUID(): """Generate a random UUID.""" return [ random.randint(0, 255) for _ in range(0, 16) ] def uuidToString(u): return "-".join(["%02x" * 4, "%02x" * 2, "%02x" * 2, "%02x" * 2, "%02x" * 6]) % tuple(u) def maxMemory(user): return 256 def haveAccess(user, machine): return True def error(op, user, fields, errorMessage): d = dict(op=op, user=user, errorMessage=errorMessage) print Template(file='error.tmpl', searchList=d); def validMachineName(name): if not name: return False charset = string.ascii_letters + string.digits + '-' if name[0] == '-' or len(name) > 22: return False return all(x in charset for x in name) def kinit(): keytab = '/etc/tabbott.keytab' username = 'tabbott/extra' p = subprocess.Popen(['kinit', "-k", "-t", keytab, username]) p.wait() def checkKinit(): p = subprocess.Popen(['klist', '-s']) if p.wait(): kinit() def remctl(*args): checkKinit() p = subprocess.Popen(['remctl', 'black-mesa.mit.edu'] + list(args), stdout=subprocess.PIPE, stderr=subprocess.PIPE) if p.wait(): print >> sys.stderr, 'ERROR on remctl ', args print >> sys.stderr, p.stderr.read() def makeDisks(): remctl('lvcreate','all') def bootMachine(machine, cdtype): if cdtype is not None: remctl('vmboot', 'cdrom', str(machine.name), cdtype) else: remctl('vmboot', 'cdrom', str(machine.name)) def createVm(user, name, memory, disk, is_hvm, cdrom): # put stuff in the table transaction = ctx.current.create_transaction() try: res = meta.engine.execute('select nextval(\'"machines_machine_id_seq"\')') id = res.fetchone()[0] machine = Machine() machine.machine_id = id machine.name = name machine.memory = memory machine.owner = user.username machine.contact = user.email machine.uuid = uuidToString(randomUUID()) machine.boot_off_cd = True machine_type = Type.get_by(hvm=is_hvm) machine.type_id = machine_type.type_id ctx.current.save(machine) disk = Disk(machine.machine_id, 'hda', disk) open = NIC.select_by(machine_id=None) if not open: #No IPs left! return "No IP addresses left! Contact sipb-xen-dev@mit.edu" nic = open[0] nic.machine_id = machine.machine_id nic.hostname = name ctx.current.save(nic) ctx.current.save(disk) transaction.commit() except: transaction.rollback() raise makeDisks() # tell it to boot with cdrom bootMachine(machine, cdrom) return machine def create(user, fields): name = fields.getfirst('name') if not validMachineName(name): return error('create', user, fields, "Invalid name '%s'" % name) name = name.lower() if Machine.get_by(name=name): return error('create', user, fields, "A machine named '%s' already exists" % name) memory = fields.getfirst('memory') try: memory = int(memory) if memory <= 0: raise ValueError except ValueError: return error('create', user, fields, "Invalid memory amount") if memory > maxMemory(user): return error('create', user, fields, "Too much memory requested") disk = fields.getfirst('disk') try: disk = float(disk) disk = int(disk * 1024) if disk <= 0: raise ValueError except ValueError: return error('create', user, fields, "Invalid disk amount") vm_type = fields.getfirst('vmtype') if vm_type not in ('hvm', 'paravm'): return error('create', user, fields, "Invalid vm type '%s'" % vm_type) is_hvm = (vm_type == 'hvm') cdrom = fields.getfirst('cdrom') if cdrom is not None and not CDROM.get(cdrom): return error('create', user, fields, "Invalid cdrom type '%s'" % cdrom) machine = createVm(user, name, memory, disk, is_hvm, cdrom) if isinstance(machine, basestring): return error('create', user, fields, machine) d = dict(user=user, machine=machine) print Template(file='create.tmpl', searchList=d); def listVms(user, fields): machines = Machine.select() d = dict(user=user, machines=machines, cdroms=CDROM.select()) print Template(file='list.tmpl', searchList=d) def testMachineId(user, machineId, exists=True): if machineId is None: error('vnc', user, fields, "No machine ID specified") return False try: machineId = int(machineId) except ValueError: error('vnc', user, fields, "Invalid machine ID '%s'" % machineId) return False machine = Machine.get(machineId) if exists and machine is None: error('vnc', user, fields, "No such machine ID '%s'" % machineId) return False if not haveAccess(user, machine): error('vnc', user, fields, "No access to machine ID '%s'" % machineId) return False return machine def vnc(user, fields): machine = testMachineId(user, fields.getfirst('machine_id')) if machine is None: #gave error page already return TOKEN_KEY = "0M6W0U1IXexThi5idy8mnkqPKEq1LtEnlK/pZSn0cDrN" data = {} data["user"] = user data["machine"]=machine data["expires"]=time.time()+(5*60) pickledData = cPickle.dumps(data) m = hmac.new(TOKEN_KEY, digestmod=sha) m.update(pickledData) token = {'data': pickledData, 'digest': m.digest()} token = cPickle.dumps(token) token = base64.urlsafe_b64encode(token) d = dict(user=user, machine=machine, hostname='localhost', authtoken=token) print Template(file='vnc.tmpl', searchList=d) def info(user, fields): machine = testMachineId(user, fields.getfirst('machine_id')) if machine is None: #gave error page already return d = dict(user=user, machine=machine) print Template(file='info.tmpl', searchList=d) mapping = dict(list=listVms, vnc=vnc, info=info, create=create) if __name__ == '__main__': fields = cgi.FieldStorage() class C: username = "moo" email = 'moo@cow.com' u = C() connect('postgres://sipb-xen@sipb-xen-dev/sipb_xen') operation = os.environ.get('PATH_INFO', '') if operation.startswith('/'): operation = operation[1:] if not operation: operation = 'list' fun = mapping.get(operation, lambda u, e: error(operation, u, e, "Invalid operation '%'" % operation)) fun(u, fields)