278 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			278 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
| #!/usr/bin/python2
 | |
| # -*- encoding: utf8 -*-
 | |
| #
 | |
| # The Qubes OS Project, http://www.qubes-os.org
 | |
| #
 | |
| # Copyright (C) 2010  Joanna Rutkowska <joanna@invisiblethingslab.com>
 | |
| #
 | |
| # 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 argparse import ArgumentParser
 | |
| 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": "'HVM' if vm.type == 'HVM' else \
 | |
|              ('Tpl' if vm.is_template() else \
 | |
|              ('' if vm.type in ['AppVM', 'DisposableVM'] else \
 | |
|              vm.type.replace('VM','')))"},
 | |
| 
 | |
|     "updbl" : {"func": "'Yes' if vm.updateable else ''"},
 | |
| 
 | |
|     "template": {"func": "'n/a' if vm.is_template() else\
 | |
|                  ('None' if vm.template is None else\
 | |
|                  vm.template.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 ''"},
 | |
| 
 | |
|     "last backup" : {"func": "str(vm.backup_timestamp.date()) if "
 | |
|                              "vm.backup_timestamp else '-'"},
 | |
| 
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| def main():
 | |
|     usage = "%(prog)s [options]"
 | |
|     parser = ArgumentParser ()
 | |
| 
 | |
|     parser.add_argument ("VMs", action="store", nargs="*",
 | |
|                         help="Specify VMs to be queried")
 | |
| 
 | |
|     parser.add_argument ("-n", "--network", dest="network",
 | |
|                        action="store_true", default=False,
 | |
|                        help="Show network addresses assigned to VMs")
 | |
| 
 | |
|     parser.add_argument ("-c", "--cpu", dest="cpu",
 | |
|                        action="store_true", default=False,
 | |
|                        help="Show CPU load")
 | |
| 
 | |
|     parser.add_argument ("-m", "--mem", dest="mem",
 | |
|                        action="store_true", default=False,
 | |
|                        help="Show memory usage")
 | |
| 
 | |
|     parser.add_argument ("-d", "--disk", dest="disk",
 | |
|                        action="store_true", default=False,
 | |
|                        help="Show VM disk utilization statistics")
 | |
| 
 | |
|     parser.add_argument ("-k", "--kernel", dest="kernel",
 | |
|                        action="store_true", default=False,
 | |
|                        help="Show VM kernel arguments")
 | |
| 
 | |
|     parser.add_argument ("-i", "--ids", dest="ids",
 | |
|                        action="store_true", default=False,
 | |
|                        help="Show Qubes and Xen id#s")
 | |
| 
 | |
|     parser.add_argument("-b", "--last-backup", dest="backup",
 | |
|                       action="store_true", default=False,
 | |
|                       help="Show date of last VM backup")
 | |
| 
 | |
|     parser.add_argument("--raw-list", dest="raw_list",
 | |
|                       action="store_true", default=False,
 | |
|                       help="List only VM names one per line")
 | |
| 
 | |
|     parser.add_argument("--raw-data", dest="raw_data",
 | |
|                         action="store", nargs="+",
 | |
|                         help="Display specify data of specified VMs.\
 | |
|                               Intended for bash-parsing.")
 | |
| 
 | |
| 
 | |
|     arguments = parser.parse_args ()
 | |
| 
 | |
|     qvm_collection = QubesVmCollection()
 | |
|     qvm_collection.lock_db_for_reading()
 | |
|     qvm_collection.load()
 | |
|     qvm_collection.unlock_db()
 | |
| 
 | |
|     if arguments.raw_list:
 | |
|         for vm in qvm_collection.values():
 | |
|             print vm.name
 | |
|         return
 | |
| 
 | |
|     cpu_usages = None
 | |
| 
 | |
|     if arguments.raw_data:
 | |
|         fields_to_display = arguments.raw_data
 | |
|         if 'cpu' in arguments.raw_data:
 | |
|             qhost = QubesHost()
 | |
|             (measure_time, cpu_usages) = qhost.measure_cpu_usage(qvm_collection)
 | |
|     else:
 | |
|         fields_to_display = ["name", "on", "state", "updbl", "type", "template", "netvm", "label" ]
 | |
| 
 | |
|         if (arguments.ids):
 | |
|             fields_to_display += ["qid", "xid"]
 | |
| 
 | |
|         if (arguments.cpu):
 | |
|             qhost = QubesHost()
 | |
|             (measure_time, cpu_usages) = qhost.measure_cpu_usage(qvm_collection)
 | |
|             fields_to_display += ["cpu"]
 | |
| 
 | |
|         if (arguments.mem):
 | |
|             fields_to_display += ["mem"]
 | |
| 
 | |
|         if arguments.backup:
 | |
|             fields_to_display += ["last backup"]
 | |
| 
 | |
|         if (arguments.network):
 | |
|             if 'template' in fields_to_display:
 | |
|                 fields_to_display.remove ("template")
 | |
|             fields_to_display += ["ip", "ip back", "gateway/DNS"]
 | |
| 
 | |
|         if (arguments.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 (arguments.kernel):
 | |
|             fields_to_display += ["kernel", "kernelopts" ]
 | |
| 
 | |
|     
 | |
|     vms_list = [vm for vm in qvm_collection.values()]
 | |
|     #assume VMs are presented in desired order:
 | |
|     if len(arguments.VMs) > 0:
 | |
|         vms_to_display = [vm for vm in vms_list if vm.name in arguments.VMs]
 | |
|     #otherwise, format them accordingly:
 | |
|     else:
 | |
|         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 (or with template not included in the list)...
 | |
|         for appvm in vms_list:
 | |
|             if appvm.is_appvm() and not appvm.is_template() and \
 | |
|                 (appvm.template is None or appvm.template not in vms_list):
 | |
|                 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
 | |
| 
 | |
|     #We DON'T NEED a max_width if we devide output by pipes!
 | |
| 
 | |
|     # 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 'max_width' in fields[f] and 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)
 | |
| 
 | |
|     #Nicely formatted header only needed for humans
 | |
|     if not arguments.raw_data:
 | |
|         # 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
 | |
| 
 | |
|     #won't look pretty, but is easy to parse!
 | |
|     else:
 | |
|         for row in data_to_display:
 | |
|             print '|'.join([row[f] for f in fields_to_display])
 | |
| 
 | |
| main()
 | 
