import cgi
import datetime
import hmac
+import os
import random
import sha
import sys
from view import View, revertStandardError
+
+static_dir = os.path.join(os.path.dirname(__file__), 'static')
+InvirtStatic = cherrypy.tools.staticdir.handler(
+ root=static_dir,
+ dir=static_dir,
+ section='/static')
+
class InvirtUnauthWeb(View):
+ static = InvirtStatic
+
@cherrypy.expose
@cherrypy.tools.mako(filename="/unauth.mako")
def index(self):
- return {'simple': True}
+ return dict(simple=True)
class InvirtWeb(View):
def __init__(self):
'from invirt import database']
self._cp_config['request.error_response'] = self.handle_error
+ static = InvirtStatic
+
@cherrypy.expose
@cherrypy.tools.mako(filename="/invalid.mako")
def invalidInput(self):
@cherrypy.expose
@cherrypy.tools.mako(filename="/error.mako")
def error(self):
- #op, username, fields, err, emsg, traceback):
"""Print an error page when an exception occurs"""
op = cherrypy.request.prev.path_info
username = cherrypy.request.login
err = cherrypy.request.prev.params["err"]
emsg = cherrypy.request.prev.params["emsg"]
traceback = cherrypy.request.prev.params["traceback"]
- d = dict(op = op, user=username, fields=cherrypy.request.prev.params,
+ d = dict(op=op, user=username, fields=cherrypy.request.prev.params,
errorMessage=str(err), stderr=emsg, traceback=traceback)
error_raw = cherrypy.request.lookup.get_template("/error_raw.mako")
details = error_raw.render(**d)
return d
def __getattr__(self, name):
+ # At the point __getattr__ is called, tools haven't been run. Make sure the user is logged in.
+ cherrypy.tools.remote_user_login.callable()
+
if name in ("admin", "overlord"):
- if not cherrypy.request.login in getAfsGroupMembers(config.adminacl, config.authz[0].cell):
+ if not cherrypy.request.login in getAfsGroupMembers(config.adminacl, config.authz.afs.cells[0].cell):
raise InvalidInput('username', cherrypy.request.login,
'Not in admin group %s.' % config.adminacl)
cherrypy.request.state = State(cherrypy.request.login, isadmin=True)
def handle_error(self):
err = sys.exc_info()[1]
if isinstance(err, InvalidInput):
- e = revertStandardError()
cherrypy.request.params['err'] = err
- cherrypy.request.params['emsg'] = e
+ cherrypy.request.params['emsg'] = revertStandardError()
raise cherrypy.InternalRedirect('/invalidInput')
if not cherrypy.request.prev or 'err' not in cherrypy.request.prev.params:
- e = revertStandardError()
cherrypy.request.params['err'] = err
- cherrypy.request.params['emsg'] = e
+ cherrypy.request.params['emsg'] = revertStandardError()
cherrypy.request.params['traceback'] = _cperror.format_exc()
raise cherrypy.InternalRedirect('/error')
# fall back to cherrypy default error page
@cherrypy.tools.mako(filename="/list.mako")
def list(self, result=None):
"""Handler for list requests."""
- checkpoint.checkpoint('Getting list dict')
d = getListDict(cherrypy.request.login, cherrypy.request.state)
if result is not None:
d['result'] = result
- checkpoint.checkpoint('Got list dict')
return d
index=list
<p>We recommend using a ParaVM when possible and an HVM when necessary.
""",
- 'CPU Weight': """
-Don't ask us! We're as mystified as you are.""",
'Owner': """
The owner field is used to determine <a
href="help?subject=Quotas">quotas</a>. It must be the name of a
console will suffer artifacts.
""",
'Windows': """
+<strong>Windows 7:</strong> The Windows 7 image is licensed for all MIT students and will automatically activate off the network. The installer requires 512 MiB RAM and at least 15 GiB disk space (20 GiB or more recommended).<br>
<strong>Windows Vista:</strong> The Vista image is licensed for all MIT students and will automatically activate off the network; see <a href="/static/msca-email.txt">the licensing confirmation e-mail</a> for details. The installer requires 512 MiB RAM and at least 7.5 GiB disk space (15 GiB or more recommended).<br>
-<strong>Windows XP:</strong> This is the volume license CD image. You will need your own volume license key to complete the install. We do not have these available for the general MIT community; ask your department if they have one, or visit <a href="http://msca.mit.edu/">http://msca.mit.edu/</a> if you are staff/faculty to request one.
+<strong>Windows XP:</strong> This is the volume license CD image. You will need your own volume license key to complete the install. We do not have these available for the general MIT community; ask your department if they have one, or visit <a href="http://msca.mit.edu/">http://msca.mit.edu/</a> if you are staff/faculty to request one.
"""
}
help._cp_config['tools.require_login.on'] = False
def parseCreate(self, fields):
- kws = dict([(kw, fields.get(kw)) for kw in 'name description owner memory disksize vmtype cdrom autoinstall'.split() if fields.get(kw)])
- validate = validation.Validate(cherrypy.request.login, cherrypy.request.state, strict=True, **kws)
- return dict(contact=cherrypy.request.login, name=validate.name, description=validate.description, memory=validate.memory,
- disksize=validate.disksize, owner=validate.owner, machine_type=getattr(validate, 'vmtype', Defaults.type),
+ kws = dict([(kw, fields[kw]) for kw in
+ 'name description owner memory disksize vmtype cdrom autoinstall'.split()
+ if fields[kw]])
+ validate = validation.Validate(cherrypy.request.login,
+ cherrypy.request.state,
+ strict=True, **kws)
+ return dict(contact=cherrypy.request.login, name=validate.name,
+ description=validate.description, memory=validate.memory,
+ disksize=validate.disksize, owner=validate.owner,
+ machine_type=getattr(validate, 'vmtype', Defaults.type),
cdrom=getattr(validate, 'cdrom', None),
autoinstall=getattr(validate, 'autoinstall', None))
"""Handler for create requests."""
try:
parsed_fields = self.parseCreate(fields)
- machine = controls.createVm(cherrypy.request.login, cherrypy.request.state, **parsed_fields)
+ machine = controls.createVm(cherrypy.request.login,
+ cherrypy.request.state, **parsed_fields)
except InvalidInput, err:
pass
else:
d = getListDict(cherrypy.request.login, cherrypy.request.state)
d['err'] = err
if err:
- for field in fields.keys():
- setattr(d['defaults'], field, fields.get(field))
+ for field, value in fields.items():
+ setattr(d['defaults'], field, value)
else:
d['new_machine'] = parsed_fields['name']
return d
raise RuntimeError("test of the emergency broadcast system")
class MachineView(View):
- # This is hairy. Fix when CherryPy 3.2 is out. (rename to
- # _cp_dispatch, and parse the argument as a list instead of
- # string
-
def __getattr__(self, name):
+ """Synthesize attributes to allow RESTful URLs like
+ /machine/13/info. This is hairy. CherryPy 3.2 adds a
+ method called _cp_dispatch that allows you to explicitly
+ handle URLs that can't be mapped, and it allows you to
+ rewrite the path components and continue processing.
+
+ This function gets the next path component being resolved
+ as a string. _cp_dispatch will get an array of strings
+ representing any subsequent path components as well."""
+
try:
- machine_id = int(name)
- cherrypy.request.params['machine_id'] = machine_id
+ cherrypy.request.params['machine_id'] = int(name)
return self
except ValueError:
return None
@cherrypy.tools.mako(filename="/info.mako")
def info(self, machine_id):
"""Handler for info on a single VM."""
- machine = validation.Validate(cherrypy.request.login, cherrypy.request.state, machine_id=machine_id).machine
+ machine = validation.Validate(cherrypy.request.login,
+ cherrypy.request.state,
+ machine_id=machine_id).machine
d = infoDict(cherrypy.request.login, cherrypy.request.state, machine)
- checkpoint.checkpoint('Got infodict')
return d
index = info
def modify(self, machine_id, **fields):
"""Handler for modifying attributes of a machine."""
try:
- modify_dict = modifyDict(cherrypy.request.login, cherrypy.request.state, machine_id, fields)
+ modify_dict = modifyDict(cherrypy.request.login,
+ cherrypy.request.state,
+ machine_id, fields)
except InvalidInput, err:
result = None
- machine = validation.Validate(cherrypy.request.login, cherrypy.request.state, machine_id=machine_id).machine
+ machine = validation.Validate(cherrypy.request.login,
+ cherrypy.request.state,
+ machine_id=machine_id).machine
else:
machine = modify_dict['machine']
result = 'Success!'
err = None
- info_dict = infoDict(cherrypy.request.login, cherrypy.request.state, machine)
+ info_dict = infoDict(cherrypy.request.login,
+ cherrypy.request.state, machine)
info_dict['err'] = err
if err:
- for field in fields.keys():
- setattr(info_dict['defaults'], field, fields.get(field))
+ for field, value in fields.items():
+ setattr(info_dict['defaults'], field, value)
info_dict['result'] = result
return info_dict
Remember to enable iptables!
echo 1 > /proc/sys/net/ipv4/ip_forward
"""
- machine = validation.Validate(cherrypy.request.login, cherrypy.request.state, machine_id=machine_id).machine
-
+ machine = validation.Validate(cherrypy.request.login,
+ cherrypy.request.state,
+ machine_id=machine_id).machine
token = controls.vnctoken(machine)
host = controls.listHost(machine)
if host:
port=port,
authtoken=token)
return d
+
@cherrypy.expose
@cherrypy.tools.mako(filename="/command.mako")
@cherrypy.tools.require_POST()
def command(self, command_name, machine_id, **kwargs):
"""Handler for running commands like boot and delete on a VM."""
- back = kwargs.get('back', None)
+ back = kwargs.get('back')
+ if command_name == 'delete':
+ back = 'list'
try:
- d = controls.commandResult(cherrypy.request.login, cherrypy.request.state, command_name, machine_id, kwargs)
- if d['command'] == 'Delete VM':
- back = 'list'
+ d = controls.commandResult(cherrypy.request.login,
+ cherrypy.request.state,
+ command_name, machine_id, kwargs)
except InvalidInput, err:
if not back:
raise
return d
if back == 'list':
cherrypy.request.state.clear() #Changed global state
- raise cherrypy.InternalRedirect('/list?result=%s' % urllib.quote(result))
+ raise cherrypy.InternalRedirect('/list?result=%s'
+ % urllib.quote(result))
elif back == 'info':
- raise cherrypy.HTTPRedirect(cherrypy.request.base + '/machine/%d/' % machine_id, status=303)
+ raise cherrypy.HTTPRedirect(cherrypy.request.base
+ + '/machine/%d/' % machine_id,
+ status=303)
else:
raise InvalidInput('back', back, 'Not a known back page.')
machine = MachineView()
-class Checkpoint:
- def __init__(self):
- self.start_time = time.time()
- self.checkpoints = []
-
- def checkpoint(self, s):
- self.checkpoints.append((s, time.time()))
-
- def __str__(self):
- return ('Timing info:\n%s\n' %
- '\n'.join(['%s: %s' % (d, t - self.start_time) for
- (d, t) in self.checkpoints]))
-
-checkpoint = Checkpoint()
class Defaults:
"""Class to store default values for fields."""
def getListDict(username, state):
"""Gets the list of local variables used by list.tmpl."""
- checkpoint.checkpoint('Starting')
machines = state.machines
- checkpoint.checkpoint('Got my machines')
on = {}
has_vnc = {}
installing = {}
xmlist = state.xmlist
- checkpoint.checkpoint('Got uptimes')
for m in machines:
if m not in xmlist:
has_vnc[m] = 'Off'
m.uptime = None
else:
m.uptime = xmlist[m]['uptime']
+ installing[m] = bool(xmlist[m].get('autoinstall'))
if xmlist[m]['console']:
has_vnc[m] = True
elif m.type.hvm:
has_vnc[m] = "WTF?"
else:
has_vnc[m] = "ParaVM"
- if xmlist[m].get('autoinstall'):
- installing[m] = True
- else:
- installing[m] = False
max_memory = validation.maxMemory(username, state)
max_disk = validation.maxDisk(username)
- checkpoint.checkpoint('Got max mem/disk')
defaults = Defaults(max_memory=max_memory,
max_disk=max_disk,
owner=username)
- checkpoint.checkpoint('Got defaults')
def sortkey(machine):
return (machine.owner != username, machine.owner, machine.name)
machines = sorted(machines, key=sortkey)
defaults=defaults,
machines=machines,
has_vnc=has_vnc,
- installing=installing)
+ installing=installing,
+ disable_creation=False)
return d
def getHostname(nic):
olddisk = {}
session.begin()
try:
- kws = dict([(kw, fields.get(kw)) for kw in 'owner admin contact name description memory vmtype disksize'.split() if fields.get(kw)])
+ kws = dict((kw, fields[kw]) for kw in
+ 'owner admin contact name description memory vmtype disksize'.split()
+ if fields.get(kw))
kws['machine_id'] = machine_id
validate = validation.Validate(username, state, **kws)
machine = validate.machine
if hasattr(validate, 'vmtype'):
machine.type = validate.vmtype
+ update_acl = False
+ if hasattr(validate, 'owner') and validate.owner != machine.owner:
+ machine.owner = validate.owner
+ update_acl = True
+ if hasattr(validate, 'description'):
+ machine.description = validate.description
+ if hasattr(validate, 'admin') and validate.admin != machine.administrator:
+ machine.administrator = validate.admin
+ update_acl = True
+ if hasattr(validate, 'contact'):
+ machine.contact = validate.contact
+
+ session.save_or_update(machine)
+ session.commit()
+ except:
+ session.rollback()
+ raise
+
+ session.begin()
+ try:
if hasattr(validate, 'disksize'):
disksize = validate.disksize
disk = machine.disks[0]
olddisk[disk.guest_device_name] = disksize
disk.size = disksize
session.save_or_update(disk)
+ for diskname in olddisk:
+ controls.resizeDisk(oldname, diskname, str(olddisk[diskname]))
+ session.save_or_update(machine)
+ session.commit()
+ except:
+ session.rollback()
+ raise
- update_acl = False
- if hasattr(validate, 'owner') and validate.owner != machine.owner:
- machine.owner = validate.owner
- update_acl = True
+ session.begin()
+ try:
if hasattr(validate, 'name'):
machine.name = validate.name
for n in machine.nics:
if n.hostname == oldname:
n.hostname = validate.name
- if hasattr(validate, 'description'):
- machine.description = validate.description
- if hasattr(validate, 'admin') and validate.admin != machine.administrator:
- machine.administrator = validate.admin
- update_acl = True
- if hasattr(validate, 'contact'):
- machine.contact = validate.contact
-
+ if hasattr(validate, 'name'):
+ controls.renameMachine(machine, oldname, validate.name)
session.save_or_update(machine)
- if update_acl:
- cache_acls.refreshMachine(machine)
session.commit()
except:
session.rollback()
raise
- for diskname in olddisk:
- controls.resizeDisk(oldname, diskname, str(olddisk[diskname]))
- if hasattr(validate, 'name'):
- controls.renameMachine(machine, oldname, validate.name)
+
+ if update_acl:
+ cache_acls.refreshMachine(machine)
+
return dict(machine=machine)
def infoDict(username, state, machine):
"""Get the variables used by info.tmpl."""
status = controls.statusInfo(machine)
- checkpoint.checkpoint('Getting status info')
has_vnc = hasVnc(status)
if status is None:
main_status = dict(name=machine.name,
else:
main_status = dict(status[1:])
main_status['host'] = controls.listHost(machine)
- start_time = float(main_status.get('start_time', 0))
- uptime = datetime.timedelta(seconds=int(time.time()-start_time))
+ start_time = main_status.get('start_time')
+ if start_time is None:
+ uptime = "Still booting?"
+ else:
+ start_time = float(start_time)
+ uptime = datetime.timedelta(seconds=int(time.time()-start_time))
cpu_time_float = float(main_status.get('cpu_time', 0))
cputime = datetime.timedelta(seconds=int(cpu_time_float))
- checkpoint.checkpoint('Status')
display_fields = [('name', 'Name'),
('description', 'Description'),
('owner', 'Owner'),
pass
#fields.append((disp, None))
- checkpoint.checkpoint('Got fields')
-
-
max_mem = validation.maxMemory(machine.owner, state, machine, False)
- checkpoint.checkpoint('Got mem')
max_disk = validation.maxDisk(machine.owner, machine)
defaults = Defaults()
for name in 'machine_id name description administrator owner memory contact'.split():
setattr(defaults, name, getattr(machine, name))
defaults.type = machine.type.type_id
defaults.disk = "%0.2f" % (machine.disks[0].size/1024.)
- checkpoint.checkpoint('Got defaults')
d = dict(user=username,
on=status is not None,
machine=machine,
p.stdin.close()
p.wait()
-random.seed()
+random.seed() #sigh