Changeset 119


Ignore:
Timestamp:
Oct 7, 2007, 5:32:53 PM (17 years ago)
Author:
ecprice
Message:

More work.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/web/templates/main.py

    r118 r119  
    66import string
    77import subprocess
     8import re
    89import time
    910import cPickle
    1011import base64
     12import sha
     13import hmac
    1114
    1215print 'Content-Type: text/html\n'
     
    1821import random
    1922
     23class MyException(Exception):
     24    pass
     25
    2026# ... and stolen from xend/uuid.py
    2127def randomUUID():
     
    2834                     "%02x" * 6]) % tuple(u)
    2935
    30 
    3136def maxMemory(user):
    3237    return 256
    3338
     39def maxDisk(user):
     40    return 10.0
     41
    3442def haveAccess(user, machine):
    3543    return True
    3644
    37 
    38 def 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);
     45def error(op, user, fields, err):
     46    d = dict(op=op, user=user, errorMessage=str(err))
     47    print Template(file='error.tmpl', searchList=d);
    4448
    4549def validMachineName(name):
     50    """Check that name is valid for a machine name"""
    4651    if not name:
    4752        return False
    48     charset = string.ascii_letters + string.digits + '-'
    49     if name[0] == '-' or len(name) > 22:
     53    charset = string.ascii_letters + string.digits + '-_'
     54    if name[0] in '-_' or len(name) > 22:
    5055        return False
    5156    return all(x in charset for x in name)
    5257
    53 def kinit():
    54     keytab = '/etc/tabbott.keytab'
    55     username = 'tabbott/extra'
    56     p = subprocess.Popen(['kinit', "-k", "-t", keytab,
    57                           username])
    58     p.wait()
     58def kinit(username = 'tabbott/extra', keytab = '/etc/tabbott.keytab'):
     59    """Kinit with a given username and keytab"""
     60
     61    p = subprocess.Popen(['kinit', "-k", "-t", keytab, username])
     62    e = p.wait()
     63    if e:
     64        raise MyException("Error %s in kinit" % e)
    5965
    6066def checkKinit():
     67    """If we lack tickets, kinit."""
    6168    p = subprocess.Popen(['klist', '-s'])
    6269    if p.wait():
    6370        kinit()
    6471
    65 def remctl(*args):
     72def remctl(*args, **kws):
     73    """Perform a remctl and return the output.
     74
     75    kinits if necessary, and outputs errors to stderr.
     76    """
    6677    checkKinit()
    6778    p = subprocess.Popen(['remctl', 'black-mesa.mit.edu']
     
    6980                         stdout=subprocess.PIPE,
    7081                         stderr=subprocess.PIPE)
     82    if kws.get('err'):
     83        return p.stdout.read(), p.stderr.read()
    7184    if p.wait():
    7285        print >> sys.stderr, 'ERROR on remctl ', args
    7386        print >> sys.stderr, p.stderr.read()
     87    return p.stdout.read()
    7488
    7589def makeDisks():
    76     remctl('lvcreate','all')
     90    """Update the lvm partitions to include all disks in the database."""
     91    remctl('web', 'lvcreate')
    7792
    7893def bootMachine(machine, cdtype):
     94    """Boot a machine with a given boot CD.
     95
     96    If cdtype is None, give no boot cd.  Otherwise, it is the string
     97    id of the CD (e.g. 'gutsy_i386')
     98    """
    7999    if cdtype is not None:
    80         remctl('vmboot', 'cdrom', str(machine.name),
     100        remctl('web', 'vmboot', machine.name,
    81101               cdtype)
    82102    else:
    83         remctl('vmboot', 'cdrom', str(machine.name))
     103        remctl('web', 'vmboot', machine.name)
     104
     105def registerMachine(machine):
     106    """Register a machine to be controlled by the web interface"""
     107    remctl('web', 'register', machine.name)
     108
     109def parseStatus(s):
     110    """Parse a status string into nested tuples of strings.
     111
     112    s = output of xm list --long <machine_name>
     113    """
     114    values = re.split('([()])', s)
     115    stack = [[]]
     116    for v in values[2:-2]: #remove initial and final '()'
     117        if not v:
     118            continue
     119        v = v.strip()
     120        if v == '(':
     121            stack.append([])
     122        elif v == ')':
     123            stack[-2].append(stack[-1])
     124            stack.pop()
     125        else:
     126            if not v:
     127                continue
     128            stack[-1].extend(v.split())
     129    return stack[-1]
     130
     131def statusInfo(machine):
     132    value_string, err_string = remctl('list-long', machine.name, err=True)
     133    if 'Unknown command' in err_string:
     134        raise MyException("ERROR in remctl list-long %s is not registered" % (machine.name,))
     135    elif 'does not exist' in err_string:
     136        return None
     137    elif err_string:
     138        raise MyException("ERROR in remctl list-long %s:  %s" % (machine.name, err_string))
     139    status = parseStatus(value_string)
     140    return status
     141
     142def hasVnc(status):
     143    if status is None:
     144        return False
     145    for l in status:
     146        if l[0] == 'device' and l[1][0] == 'vfb':
     147            d = dict(l[1][1:])
     148            return 'location' in d
     149    return False
    84150
    85151def createVm(user, name, memory, disk, is_hvm, cdrom):
     
    115181        raise
    116182    makeDisks()
     183    registerMachine(machine)
    117184    # tell it to boot with cdrom
    118185    bootMachine(machine, cdrom)
     
    123190    name = fields.getfirst('name')
    124191    if not validMachineName(name):
    125         return error('create', user, fields,
    126                      "Invalid name '%s'" % name)
     192        raise MyException("Invalid name '%s'" % name)
    127193    name = name.lower()
    128194
    129195    if Machine.get_by(name=name):
    130         return error('create', user, fields,
    131                      "A machine named '%s' already exists" % name)
     196        raise MyException("A machine named '%s' already exists" % name)
    132197   
    133198    memory = fields.getfirst('memory')
     
    137202            raise ValueError
    138203    except ValueError:
    139         return error('create', user, fields,
    140                      "Invalid memory amount")
     204        raise MyException("Invalid memory amount")
    141205    if memory > maxMemory(user):
    142         return error('create', user, fields,
    143                      "Too much memory requested")
     206        raise MyException("Too much memory requested")
    144207   
    145208    disk = fields.getfirst('disk')
     
    150213            raise ValueError
    151214    except ValueError:
    152         return error('create', user, fields,
    153                      "Invalid disk amount")
     215        raise MyException("Invalid disk amount")
     216    if disk > maxDisk(user):
     217        raise MyException("Too much disk requested")
    154218   
    155219    vm_type = fields.getfirst('vmtype')
    156220    if vm_type not in ('hvm', 'paravm'):
    157         return error('create', user, fields,
    158                      "Invalid vm type '%s'"  % vm_type)   
     221        raise MyException("Invalid vm type '%s'"  % vm_type)   
    159222    is_hvm = (vm_type == 'hvm')
    160223
    161224    cdrom = fields.getfirst('cdrom')
    162225    if cdrom is not None and not CDROM.get(cdrom):
    163         return error('create', user, fields,
    164                      "Invalid cdrom type '%s'" % cdrom)   
     226        raise MyException("Invalid cdrom type '%s'" % cdrom)   
    165227   
    166228    machine = createVm(user, name, memory, disk, is_hvm, cdrom)
    167229    if isinstance(machine, basestring):
    168         return error('create', user, fields,
    169                      machine)
     230        raise MyException(machine)
    170231    d = dict(user=user,
    171232             machine=machine)
     
    175236def listVms(user, fields):
    176237    machines = Machine.select()
     238    status = statusInfo(machines)
     239    has_vnc = {}
     240    for m in machines:
     241        on[m.name] = status[m.name] is not None
     242        has_vnc[m.name] = hasVnc(status[m.name])
    177243    d = dict(user=user,
     244             maxmem=maxMemory(user),
     245             maxdisk=maxDisk(user),
    178246             machines=machines,
     247             status=status,
     248             has_vnc=has_vnc,
    179249             cdroms=CDROM.select())
    180 
    181250    print Template(file='list.tmpl', searchList=d)
    182251
    183252def testMachineId(user, machineId, exists=True):
    184253    if machineId is None:
    185         error('vnc', user, fields,
    186               "No machine ID specified")
    187         return False
     254        raise MyException("No machine ID specified")
    188255    try:
    189256        machineId = int(machineId)
    190257    except ValueError:
    191         error('vnc', user, fields,
    192               "Invalid machine ID '%s'"
    193               % machineId)
    194         return False
     258        raise MyException("Invalid machine ID '%s'" % machineId)
    195259    machine = Machine.get(machineId)
    196260    if exists and machine is None:
    197         error('vnc', user, fields,
    198               "No such machine ID '%s'"
    199               % machineId)
    200         return False
     261        raise MyException("No such machine ID '%s'" % machineId)
    201262    if not haveAccess(user, machine):
    202         error('vnc', user, fields,
    203               "No access to machine ID '%s'"
    204               % machineId)
    205         return False
     263        raise MyException("No access to machine ID '%s'" % machineId)
    206264    return machine
    207265
    208266def vnc(user, fields):
     267    """VNC applet page.
     268
     269    Note that due to same-domain restrictions, the applet connects to
     270    the webserver, which needs to forward those requests to the xen
     271    server.  The Xen server runs another proxy that (1) authenticates
     272    and (2) finds the correct port for the VM.
     273
     274    You might want iptables like:
     275
     276    -t nat -A PREROUTING -s ! 18.181.0.60 -i eth1 -p tcp -m tcp --dport 10003 -j DNAT --to-destination 18.181.0.60:10003
     277    -t nat -A POSTROUTING -d 18.181.0.60 -o eth1 -p tcp -m tcp --dport 10003 -j SNAT --to-source 18.187.7.142
     278    -A FORWARD -d 18.181.0.60 -i eth1 -o eth1 -p tcp -m tcp --dport 10003 -j ACCEPT
     279    """
    209280    machine = testMachineId(user, fields.getfirst('machine_id'))
    210     if machine is None: #gave error page already
    211         return
     281    #XXX fix
    212282   
    213283    TOKEN_KEY = "0M6W0U1IXexThi5idy8mnkqPKEq1LtEnlK/pZSn0cDrN"
     
    226296    d = dict(user=user,
    227297             machine=machine,
    228              hostname='localhost',
     298             hostname=os.environ.get('SERVER_NAME', 'localhost'),
    229299             authtoken=token)
    230300    print Template(file='vnc.tmpl',
     
    233303def info(user, fields):
    234304    machine = testMachineId(user, fields.getfirst('machine_id'))
    235     if machine is None: #gave error page already
    236         return
    237    
    238305    d = dict(user=user,
    239306             machine=machine)
     
    254321    connect('postgres://sipb-xen@sipb-xen-dev/sipb_xen')
    255322    operation = os.environ.get('PATH_INFO', '')
     323    if not operation:
     324        pass
     325        #XXX do redirect
     326
    256327    if operation.startswith('/'):
    257328        operation = operation[1:]
     
    263334                          error(operation, u, e,
    264335                                "Invalid operation '%'" % operation))
    265     fun(u, fields)
     336    try:
     337        fun(u, fields)
     338    except MyException, err:
     339        error(operation, u, fields, err)
Note: See TracChangeset for help on using the changeset viewer.