#!/usr/bin/python2 # # The Qubes OS Project, http://www.qubes-os.org # # Copyright (C) 2010 Joanna Rutkowska # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # # from qubes.qubes import QubesVmCollection from qubes.qubes import QubesHost from qubes.qubes import QubesException from optparse import OptionParser import sys fields = { "qid": {"func": "vm.qid"}, "name": {"func": "('=>' if qvm_collection.get_default_template() is not None\ and vm.qid == qvm_collection.get_default_template().qid else '')\ + ('[' if vm.is_template() else '')\ + ('<' if vm.is_disposablevm() else '')\ + ('{' if vm.is_netvm() else '')\ + vm.name \ + (']' if vm.is_template() else '')\ + ('>' if vm.is_disposablevm() else '')\ + ('}' if vm.is_netvm() else '')"}, "type": {"func": "'Tpl' if vm.is_template() else \ ('Proxy' if vm.is_proxyvm() else \ (' Net' if vm.is_netvm() else \ ('HVM' if vm.type == 'HVM' else '')))"}, "updbl" : {"func": "'Yes' if vm.updateable else ''"}, "template": {"func": "'n/a' if vm.is_template() else\ ('None' if vm.template is None else\ qvm_collection[vm.template.qid].name)"}, "netvm": {"func": "'n/a' if vm.is_netvm() and not vm.is_proxyvm() else\ ('*' if vm.uses_default_netvm else '') +\ qvm_collection[vm.netvm.qid].name\ if vm.netvm is not None else '-'"}, "ip" : {"func": "vm.ip"}, "ip back" : {"func": "vm.gateway if vm.is_netvm() else 'n/a'"}, "gateway/DNS" : {"func": "vm.netvm.gateway if vm.netvm else 'n/a'"}, "xid" : {"func" : "vm.get_xid() if vm.is_running() else '-'"}, "mem" : {"func" : "(str(vm.get_mem()/1024) + ' MB') if vm.is_running() else '-'"}, "cpu" : {"func" : "round (cpu_usages[vm.get_xid()]['cpu_usage'], 1) if vm.is_running() else '-'"}, "disk": {"func" : "str(vm.get_disk_utilization()/(1024*1024)) + ' MB'"}, "state": {"func" : "vm.get_power_state()"}, "priv-curr": {"func" : "str(vm.get_disk_utilization_private_img()/(1024*1024)) + ' MB'"}, "priv-max": {"func" : "str(vm.get_private_img_sz()/(1024*1024)) + ' MB'"}, "priv-util": {"func" : "str(vm.get_disk_utilization_private_img()*100/vm.get_private_img_sz()) + '%' if vm.get_private_img_sz() != 0 else '-'"}, "root-curr": {"func" : "str(vm.get_disk_utilization_root_img()/(1024*1024)) + ' MB'"}, "root-max": {"func" : "str(vm.get_root_img_sz()/(1024*1024)) + ' MB'"}, "root-util": {"func" : "str(vm.get_disk_utilization_root_img()*100/vm.get_root_img_sz()) + '%' if vm.get_root_img_sz() != 0 else '-'"}, "label" : {"func" : "vm.label.name"}, "kernel" : {"func" : "('*' if vm.uses_default_kernel else '') + str(vm.kernel) if hasattr(vm, 'kernel') else 'n/a'"}, "kernelopts" : {"func" : "('*' if vm.uses_default_kernelopts else '') + str(vm.kernelopts) if hasattr(vm, 'kernelopts') else 'n/a'"}, "on" : {"func" : "'*' if vm.is_running() else ''"} } def main(): usage = "usage: %prog [options] " parser = OptionParser (usage) parser.add_option ("-n", "--network", dest="network", action="store_true", default=False, help="Show network addresses assigned to VMs") parser.add_option ("-c", "--cpu", dest="cpu", action="store_true", default=False, help="Show CPU load") parser.add_option ("-m", "--mem", dest="mem", action="store_true", default=False, help="Show memory usage") parser.add_option ("-d", "--disk", dest="disk", action="store_true", default=False, help="Show VM disk utilization statistics") parser.add_option ("-k", "--kernel", dest="kernel", action="store_true", default=False, help="Show VM kernel options") parser.add_option ("-i", "--ids", dest="ids", action="store_true", default=False, help="Show Qubes and Xen id#s") (options, args) = parser.parse_args () qvm_collection = QubesVmCollection() qvm_collection.lock_db_for_reading() qvm_collection.load() qvm_collection.unlock_db() fields_to_display = ["name", "on", "state", "updbl", "type", "template", "netvm", "label" ] cpu_usages = None if (options.ids): fields_to_display += ["qid", "xid"] if (options.cpu): qhost = QubesHost() (measure_time, cpu_usages) = qhost.measure_cpu_usage() fields_to_display += ["cpu"] if (options.mem): fields_to_display += ["mem"] if (options.network): if 'template' in fields_to_display: fields_to_display.remove ("template") fields_to_display += ["ip", "ip back", "gateway/DNS"] if (options.disk): if 'template' in fields_to_display: fields_to_display.remove ("template") if 'netvm' in fields_to_display: fields_to_display.remove ("netvm") fields_to_display += ["priv-curr", "priv-max", "root-curr", "root-max", "disk" ] if (options.kernel): fields_to_display += ["kernel", "kernelopts" ] vms_list = [vm for vm in qvm_collection.values()] no_vms = len (vms_list) vms_to_display = [] # Frist, the NetVMs... for netvm in vms_list: if netvm.is_netvm(): vms_to_display.append (netvm) # Now, the AppVMs without template... for appvm in vms_list: if appvm.is_appvm() and appvm.template is None: vms_to_display.append (appvm) # Now, the template, and all its AppVMs... for tvm in vms_list: if tvm.is_template(): vms_to_display.append (tvm) for vm in vms_list: if (vm.is_appvm() or vm.is_disposablevm()) and \ vm.template and vm.template.qid == tvm.qid: vms_to_display.append(vm) assert len(vms_to_display) == no_vms # First calculate the maximum width of each field we want to display # also collect data to display for f in fields_to_display: fields[f]["max_width"] = len(f) data_to_display = [] for vm in vms_to_display: data_row = {} for f in fields_to_display: if vm.qid == 0 and (f.startswith('priv-') or f.startswith('root-') or f == 'disk'): data_row[f] = 'n/a' else: data_row[f] = str(eval(fields[f]["func"])) l = len(data_row[f]) if l > fields[f]["max_width"]: fields[f]["max_width"] = l data_to_display.append(data_row) try: vm.verify_files() except QubesException as err: print >> sys.stderr, "WARNING: VM '{0}' has corrupted files!".format(vm.name) # XXX: For what? total_width = 0; for f in fields_to_display: total_width += fields[f]["max_width"] # Display the header s = "" for f in fields_to_display: fmt="{{0:-^{0}}}-+".format(fields[f]["max_width"] + 1) s += fmt.format('-') print s s = "" for f in fields_to_display: fmt="{{0:>{0}}} |".format(fields[f]["max_width"] + 1) s += fmt.format(f) print s s = "" for f in fields_to_display: fmt="{{0:-^{0}}}-+".format(fields[f]["max_width"] + 1) s += fmt.format('-') print s # ... and the actual data for row in data_to_display: s = "" for f in fields_to_display: fmt="{{0:>{0}}} |".format(fields[f]["max_width"] + 1) s += fmt.format(row[f]) print s main()