1756ab33e9
Do not assume only predefined VMs types, do not assume only one type of template etc.
235 lines
8.5 KiB
Python
Executable File
235 lines
8.5 KiB
Python
Executable File
#!/usr/bin/python2
|
|
#
|
|
# 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 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": "'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 ''"}
|
|
|
|
}
|
|
|
|
|
|
|
|
def main():
|
|
usage = "usage: %prog [options] <vm-name>"
|
|
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()]
|
|
if len(args) > 0:
|
|
vms_list = [vm for vm in vms_list if vm.name in args]
|
|
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
|
|
|
|
# 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()
|