qvm-ls 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. #!/usr/bin/python2
  2. # -*- encoding: utf8 -*-
  3. #
  4. # The Qubes OS Project, http://www.qubes-os.org
  5. #
  6. # Copyright (C) 2010 Joanna Rutkowska <joanna@invisiblethingslab.com>
  7. #
  8. # This program is free software; you can redistribute it and/or
  9. # modify it under the terms of the GNU General Public License
  10. # as published by the Free Software Foundation; either version 2
  11. # of the License, or (at your option) any later version.
  12. #
  13. # This program is distributed in the hope that it will be useful,
  14. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. # GNU General Public License for more details.
  17. #
  18. # You should have received a copy of the GNU General Public License
  19. # along with this program; if not, write to the Free Software
  20. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  21. #
  22. #
  23. from qubes.qubes import QubesVmCollection
  24. from qubes.qubes import QubesHost
  25. from qubes.qubes import QubesException
  26. from optparse import OptionParser
  27. import sys
  28. fields = {
  29. "qid": {"func": "vm.qid"},
  30. "name": {"func": "('=>' if qvm_collection.get_default_template() is not None\
  31. and vm.qid == qvm_collection.get_default_template().qid else '')\
  32. + ('[' if vm.is_template() else '')\
  33. + ('<' if vm.is_disposablevm() else '')\
  34. + ('{' if vm.is_netvm() else '')\
  35. + vm.name \
  36. + (']' if vm.is_template() else '')\
  37. + ('>' if vm.is_disposablevm() else '')\
  38. + ('}' if vm.is_netvm() else '')"},
  39. "type": {"func": "'HVM' if vm.type == 'HVM' else \
  40. ('Tpl' if vm.is_template() else \
  41. ('' if vm.type in ['AppVM', 'DisposableVM'] else \
  42. vm.type.replace('VM','')))"},
  43. "updbl" : {"func": "'Yes' if vm.updateable else ''"},
  44. "template": {"func": "'n/a' if vm.is_template() else\
  45. ('None' if vm.template is None else\
  46. vm.template.name)"},
  47. "netvm": {"func": "'n/a' if vm.is_netvm() and not vm.is_proxyvm() else\
  48. ('*' if vm.uses_default_netvm else '') +\
  49. qvm_collection[vm.netvm.qid].name\
  50. if vm.netvm is not None else '-'"},
  51. "ip" : {"func": "vm.ip"},
  52. "ip back" : {"func": "vm.gateway if vm.is_netvm() else 'n/a'"},
  53. "gateway/DNS" : {"func": "vm.netvm.gateway if vm.netvm else 'n/a'"},
  54. "xid" : {"func" : "vm.get_xid() if vm.is_running() else '-'"},
  55. "mem" : {"func" : "(str(vm.get_mem()/1024) + ' MB') if vm.is_running() else '-'"},
  56. "cpu" : {"func" : "round (cpu_usages[vm.get_xid()]['cpu_usage'], 1) if vm.is_running() else '-'"},
  57. "disk": {"func" : "str(vm.get_disk_utilization()/(1024*1024)) + ' MB'"},
  58. "state": {"func" : "vm.get_power_state()"},
  59. "priv-curr": {"func" : "str(vm.get_disk_utilization_private_img()/(1024*1024)) + ' MB'"},
  60. "priv-max": {"func" : "str(vm.get_private_img_sz()/(1024*1024)) + ' MB'"},
  61. "priv-util": {"func" : "str(vm.get_disk_utilization_private_img()*100/vm.get_private_img_sz()) + '%' if vm.get_private_img_sz() != 0 else '-'"},
  62. "root-curr": {"func" : "str(vm.get_disk_utilization_root_img()/(1024*1024)) + ' MB'"},
  63. "root-max": {"func" : "str(vm.get_root_img_sz()/(1024*1024)) + ' MB'"},
  64. "root-util": {"func" : "str(vm.get_disk_utilization_root_img()*100/vm.get_root_img_sz()) + '%' if vm.get_root_img_sz() != 0 else '-'"},
  65. "label" : {"func" : "vm.label.name"},
  66. "kernel" : {"func" : "('*' if vm.uses_default_kernel else '') + str(vm.kernel) if hasattr(vm, 'kernel') else 'n/a'"},
  67. "kernelopts" : {"func" : "('*' if vm.uses_default_kernelopts else '') + str(vm.kernelopts) if hasattr(vm, 'kernelopts') else 'n/a'"},
  68. "on" : {"func" : "'*' if vm.is_running() else ''"},
  69. "last backup" : {"func": "str(vm.backup_timestamp.date()) if "
  70. "vm.backup_timestamp else '-'"},
  71. }
  72. def main():
  73. usage = "usage: %prog [options] <vm-name>"
  74. parser = OptionParser (usage)
  75. parser.add_option ("-n", "--network", dest="network",
  76. action="store_true", default=False,
  77. help="Show network addresses assigned to VMs")
  78. parser.add_option ("-c", "--cpu", dest="cpu",
  79. action="store_true", default=False,
  80. help="Show CPU load")
  81. parser.add_option ("-m", "--mem", dest="mem",
  82. action="store_true", default=False,
  83. help="Show memory usage")
  84. parser.add_option ("-d", "--disk", dest="disk",
  85. action="store_true", default=False,
  86. help="Show VM disk utilization statistics")
  87. parser.add_option ("-k", "--kernel", dest="kernel",
  88. action="store_true", default=False,
  89. help="Show VM kernel options")
  90. parser.add_option ("-i", "--ids", dest="ids",
  91. action="store_true", default=False,
  92. help="Show Qubes and Xen id#s")
  93. parser.add_option("-b", "--last-backup", dest="backup",
  94. action="store_true", default=False,
  95. help="Show date of last VM backup")
  96. parser.add_option("--raw-list", dest="raw_list",
  97. action="store_true", default=False,
  98. help="List only VM names one per line")
  99. (options, args) = parser.parse_args ()
  100. qvm_collection = QubesVmCollection()
  101. qvm_collection.lock_db_for_reading()
  102. qvm_collection.load()
  103. qvm_collection.unlock_db()
  104. if options.raw_list:
  105. for vm in qvm_collection.values():
  106. print vm.name
  107. return
  108. fields_to_display = ["name", "on", "state", "updbl", "type", "template", "netvm", "label" ]
  109. cpu_usages = None
  110. if (options.ids):
  111. fields_to_display += ["qid", "xid"]
  112. if (options.cpu):
  113. qhost = QubesHost()
  114. (measure_time, cpu_usages) = qhost.measure_cpu_usage()
  115. fields_to_display += ["cpu"]
  116. if (options.mem):
  117. fields_to_display += ["mem"]
  118. if options.backup:
  119. fields_to_display += ["last backup"]
  120. if (options.network):
  121. if 'template' in fields_to_display:
  122. fields_to_display.remove ("template")
  123. fields_to_display += ["ip", "ip back", "gateway/DNS"]
  124. if (options.disk):
  125. if 'template' in fields_to_display:
  126. fields_to_display.remove ("template")
  127. if 'netvm' in fields_to_display:
  128. fields_to_display.remove ("netvm")
  129. fields_to_display += ["priv-curr", "priv-max", "root-curr", "root-max", "disk" ]
  130. if (options.kernel):
  131. fields_to_display += ["kernel", "kernelopts" ]
  132. vms_list = [vm for vm in qvm_collection.values()]
  133. if len(args) > 0:
  134. vms_list = [vm for vm in vms_list if vm.name in args]
  135. no_vms = len (vms_list)
  136. vms_to_display = []
  137. # Frist, the NetVMs...
  138. for netvm in vms_list:
  139. if netvm.is_netvm():
  140. vms_to_display.append (netvm)
  141. # Now, the AppVMs without template (or with template not included in the list)...
  142. for appvm in vms_list:
  143. if appvm.is_appvm() and not appvm.is_template() and \
  144. (appvm.template is None or appvm.template not in vms_list):
  145. vms_to_display.append (appvm)
  146. # Now, the template, and all its AppVMs...
  147. for tvm in vms_list:
  148. if tvm.is_template():
  149. vms_to_display.append (tvm)
  150. for vm in vms_list:
  151. if (vm.is_appvm() or vm.is_disposablevm()) and \
  152. vm.template and vm.template.qid == tvm.qid:
  153. vms_to_display.append(vm)
  154. assert len(vms_to_display) == no_vms
  155. # First calculate the maximum width of each field we want to display
  156. # also collect data to display
  157. for f in fields_to_display:
  158. fields[f]["max_width"] = len(f)
  159. data_to_display = []
  160. for vm in vms_to_display:
  161. data_row = {}
  162. for f in fields_to_display:
  163. if vm.qid == 0 and (f.startswith('priv-') or f.startswith('root-') or f == 'disk'):
  164. data_row[f] = 'n/a'
  165. else:
  166. data_row[f] = str(eval(fields[f]["func"]))
  167. l = len(data_row[f])
  168. if l > fields[f]["max_width"]:
  169. fields[f]["max_width"] = l
  170. data_to_display.append(data_row)
  171. try:
  172. vm.verify_files()
  173. except QubesException as err:
  174. print >> sys.stderr, "WARNING: VM '{0}' has corrupted files!".format(vm.name)
  175. # XXX: For what?
  176. total_width = 0;
  177. for f in fields_to_display:
  178. total_width += fields[f]["max_width"]
  179. # Display the header
  180. s = ""
  181. for f in fields_to_display:
  182. fmt="{{0:-^{0}}}-+".format(fields[f]["max_width"] + 1)
  183. s += fmt.format('-')
  184. print s
  185. s = ""
  186. for f in fields_to_display:
  187. fmt="{{0:>{0}}} |".format(fields[f]["max_width"] + 1)
  188. s += fmt.format(f)
  189. print s
  190. s = ""
  191. for f in fields_to_display:
  192. fmt="{{0:-^{0}}}-+".format(fields[f]["max_width"] + 1)
  193. s += fmt.format('-')
  194. print s
  195. # ... and the actual data
  196. for row in data_to_display:
  197. s = ""
  198. for f in fields_to_display:
  199. fmt="{{0:>{0}}} |".format(fields[f]["max_width"] + 1)
  200. s += fmt.format(row[f])
  201. print s
  202. main()