+def getNicInfo(data_dict, machine):
+ """Helper function for info, get data on nics for a machine.
+
+ Modifies data_dict to include the relevant data, and returns a list
+ of (key, name) pairs to display "name: data_dict[key]" to the user.
+ """
+ data_dict['num_nics'] = len(machine.nics)
+ nic_fields_template = [('nic%s_hostname', 'NIC %s Hostname'),
+ ('nic%s_mac', 'NIC %s MAC Addr'),
+ ('nic%s_ip', 'NIC %s IP'),
+ ]
+ nic_fields = []
+ for i in range(len(machine.nics)):
+ nic_fields.extend([(x % i, y % i) for x, y in nic_fields_template])
+ if not i:
+ data_dict['nic%s_hostname' % i] = (machine.name +
+ '.servers.csail.mit.edu')
+ data_dict['nic%s_mac' % i] = machine.nics[i].mac_addr
+ data_dict['nic%s_ip' % i] = machine.nics[i].ip
+ if len(machine.nics) == 1:
+ nic_fields = [(x, y.replace('NIC 0 ', '')) for x, y in nic_fields]
+ return nic_fields
+
+def getDiskInfo(data_dict, machine):
+ """Helper function for info, get data on disks for a machine.
+
+ Modifies data_dict to include the relevant data, and returns a list
+ of (key, name) pairs to display "name: data_dict[key]" to the user.
+ """
+ data_dict['num_disks'] = len(machine.disks)
+ disk_fields_template = [('%s_size', '%s size')]
+ disk_fields = []
+ for disk in machine.disks:
+ name = disk.guest_device_name
+ disk_fields.extend([(x % name, y % name) for x, y in
+ disk_fields_template])
+ data_dict['%s_size' % name] = "%0.1f GiB" % (disk.size / 1024.)
+ return disk_fields
+
+def command(user, fields):
+ """Handler for running commands like boot and delete on a VM."""
+ back = fields.getfirst('back')
+ try:
+ d = controls.commandResult(user, fields)
+ if d['command'] == 'Delete VM':
+ back = 'list'
+ except InvalidInput, err:
+ if not back:
+ raise
+ print >> sys.stderr, err
+ result = None
+ else:
+ result = 'Success!'
+ if not back:
+ return Template(file='command.tmpl', searchList=[d])
+ if back == 'list':
+ g.clear() #Changed global state
+ d = getListDict(user)
+ d['result'] = result
+ return Template(file='list.tmpl', searchList=[d])
+ elif back == 'info':
+ machine = validation.testMachineId(user, fields.getfirst('machine_id'))
+ d = infoDict(user, machine)
+ d['result'] = result
+ return Template(file='info.tmpl', searchList=[d])
+ else:
+ raise InvalidInput('back', back, 'Not a known back page.')
+
+def modifyDict(user, fields):
+ olddisk = {}
+ transaction = ctx.current.create_transaction()
+ try:
+ machine = validation.testMachineId(user, fields.getfirst('machine_id'))
+ owner = validation.testOwner(user, fields.getfirst('owner'), machine)
+ admin = validation.testAdmin(user, fields.getfirst('administrator'),
+ machine)
+ contact = validation.testContact(user, fields.getfirst('contact'),
+ machine)
+ name = validation.testName(user, fields.getfirst('name'), machine)
+ oldname = machine.name
+ command = "modify"
+
+ memory = fields.getfirst('memory')
+ if memory is not None:
+ memory = validation.validMemory(user, memory, machine, on=False)
+ machine.memory = memory
+
+ disksize = validation.testDisk(user, fields.getfirst('disk'))
+ if disksize is not None:
+ disksize = validation.validDisk(user, disksize, machine)
+ disk = machine.disks[0]
+ if disk.size != disksize:
+ olddisk[disk.guest_device_name] = disksize
+ disk.size = disksize
+ ctx.current.save(disk)
+
+ if owner is not None:
+ machine.owner = owner
+ if name is not None:
+ machine.name = name
+ if admin is not None:
+ machine.administrator = admin
+ if contact is not None:
+ machine.contact = contact
+
+ ctx.current.save(machine)
+ transaction.commit()
+ except:
+ transaction.rollback()
+ raise
+ for diskname in olddisk:
+ controls.resizeDisk(oldname, diskname, str(olddisk[diskname]))
+ if name is not None:
+ controls.renameMachine(machine, oldname, name)
+ return dict(user=user,
+ command=command,
+ machine=machine)
+
+def modify(user, fields):
+ """Handler for modifying attributes of a machine."""
+ try:
+ modify_dict = modifyDict(user, fields)
+ except InvalidInput, err:
+ result = None
+ machine = validation.testMachineId(user, fields.getfirst('machine_id'))
+ else:
+ machine = modify_dict['machine']
+ result = 'Success!'
+ err = None
+ info_dict = infoDict(user, machine)
+ info_dict['err'] = err
+ if err:
+ for field in fields.keys():
+ setattr(info_dict['defaults'], field, fields.getfirst(field))
+ info_dict['result'] = result
+ return Template(file='info.tmpl', searchList=[info_dict])
+
+
+def helpHandler(user, fields):
+ """Handler for help messages."""
+ simple = fields.getfirst('simple')
+ subjects = fields.getlist('subject')
+
+ help_mapping = dict(paravm_console="""
+ParaVM machines do not support console access over VNC. To access
+these machines, you either need to boot with a liveCD and ssh in or
+hope that the sipb-xen maintainers add support for serial consoles.""",
+ hvm_paravm="""
+HVM machines use the virtualization features of the processor, while
+ParaVM machines use Xen's emulation of virtualization features. You
+want an HVM virtualized machine.""",
+ 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
+locker that you are an AFS administrator of. In particular, you or an
+AFS group you are a member of must have AFS rlidwka bits on the
+locker. You can check see who administers the LOCKER locker using the
+command 'fs la /mit/LOCKER' on Athena.) See also <a
+href="help?subject=administrator">administrator</a>.""",
+ administrator="""
+The administrator field determines who can access the console and
+power on and off the machine. This can be either a user or a moira
+group.""",
+ quotas="""
+Quotas are determined on a per-locker basis. Each quota may have a
+maximum of 512 megabytes of active ram, 50 gigabytes of disk, and 4
+active machines."""
+ )
+
+ if not subjects:
+ subjects = sorted(help_mapping.keys())
+
+ d = dict(user=user,
+ simple=simple,
+ subjects=subjects,
+ mapping=help_mapping)
+
+ return Template(file="help.tmpl", searchList=[d])