ait/poc/scanner/create_dvm.py
author mb
Sat, 04 May 2013 12:17:31 -0400
changeset 1 446a7ba98309
permissions -rw-r--r--
added scanner scripts
     1 #!/bin/python
     2 import os
     3 import time
     4 import dbus
     5 import sys
     6 import subprocess
     7 from qubes.qubes import QubesVmCollection
     8 from qubes.qubes import QubesDispVmLabels
     9 from qubes.qubes import QubesException
    10 from qubes.qubes import QubesVmLabels
    11 from qubes.qmemman_client import QMemmanClient
    12 from qubes.qubesutils import block_list,block_attach,block_detach,block_detach_all,block_check_attached
    13 from qubes.qubesutils import kbytes_to_kmg, bytes_to_kmg
    14 
    15 
    16 notify_object = None
    17 current_savefile = '/var/run/qubes/current_savefile'
    18 current_dvm_conf = '/var/run/qubes/current_dvm.conf'
    19 avir_appvm_template = 'avir-template'
    20 avir_dvm_template = 'avir-template-dvm'
    21 
    22 def get_vm_collection():
    23 	vm_collection = QubesVmCollection()
    24 	vm_collection.lock_db_for_reading()
    25 	vm_collection.load()
    26 	vm_collection.unlock_db()
    27 	return vm_collection
    28 
    29 def get_vm_by_name(vmname):
    30 	return get_vm_collection().get_vm_by_name(vmname)
    31 
    32 def gen_scanner_name():
    33 	vm_collection = get_vm_collection()
    34 	vms = [vm for vm in vm_collection.values()]
    35 	vm_names = []
    36 	for vm in vms:
    37 		if vm.is_appvm() and vm.template.name == avir_appvm_template:
    38 			vm_names.append (vm.name)
    39 	print vm_names
    40 
    41 	ids = range(100)
    42 	for id in ids:
    43 		if "scanner"+str(id) not in vm_names:
    44 			return "scanner"+str(id)
    45 	print >> sys.stderr, "Unable to generate new scanner vm name"
    46 	exit(1)
    47 
    48 class VMFactory:
    49 	def __init__(self):
    50 		self.tray_notify(str="Initialized")
    51 
    52 	def tray_notify(self, str, timeout = 3000):
    53 		notify_object.Notify("Qubes", 0, "red", "Qubes", str, [], [], timeout, dbus_interface="org.freedesktop.Notifications")
    54 
    55 	def tray_notify_error(self, str, timeout = 3000):
    56 		notify_object.Notify("Qubes", 0, "dialog-error", "Qubes", str, [], [], timeout, dbus_interface="org.freedesktop.Notifications")
    57 
    58 	def create_appvm(self):
    59 		#generate new avir-scanner name
    60 		scanner_vmname = gen_scanner_name()
    61 		print "Generating new scanner vm %s " % scanner_vmname
    62 
    63 		#create new vscanner virtual machine from template "avir-template"
    64 		qvm_collection = QubesVmCollection()
    65 		qvm_collection.lock_db_for_writing()
    66 		qvm_collection.load()
    67 		avir_template = qvm_collection.get_vm_by_name(avir_appvm_template)
    68 		if not avir_template.is_template():
    69 			print >> sys.stderr, "VM '{0}' is not a TemplateVM".format(avir_template)
    70 			exit (1)
    71 		vmtype = "QubesAppVm"
    72 
    73 		try:
    74 			scanner_vm = qvm_collection.add_new_vm(vmtype, name=scanner_vmname, template=avir_template, label = QubesVmLabels["orange"])
    75 		except QubesException as err:
    76 			print >> sys.stderr, "ERROR: {0}".format(err)
    77 			exit (1)
    78 
    79 		scanner_vm.memory = 512
    80 		scanner_vm.vcpus = 2
    81 		try:
    82 			scanner_vm.create_on_disk(verbose=True, source_template=avir_template)
    83 			#if options.root:
    84 			#       os.unlink(vm.root_img)
    85 			#       os.rename(options.root, vm.root_img)
    86 		except (IOError, OSError) as err:
    87 			print >> sys.stderr, "ERROR: {0}".format(err)
    88 			exit (1)
    89 
    90 		qvm_collection.save()
    91 		qvm_collection.unlock_db()
    92 		return scanner_vmname
    93 
    94 	def start_vm(self, vmname):
    95 		vm = get_vm_by_name(vmname)
    96 		if vm is None or vm.qid not in get_vm_collection():
    97 			print >> sys.stderr, "A VM with the name '{0}' does not exist in the system.".format(vmname)
    98 			exit(1)
    99 		try:
   100 			vm.verify_files()
   101 			xid = vm.start(verbose=True, preparing_dvm=False, start_guid=True, notify_function=None)
   102 		except (IOError, OSError, QubesException, MemoryError) as err:
   103 			#if options.tray:
   104 			#	tray_notify_error(str(err))
   105 			#else:
   106 			print >> sys.stderr, "ERROR: {0}".format(err)
   107 			exit (1)
   108 
   109 	def create_dvm(self):
   110 		qmemman_client = QMemmanClient()
   111 		if not qmemman_client.request_memory(400*1024*1024):
   112 			qmemman_client.close()
   113 			errmsg = 'Not enough memory to create DVM. '
   114 			errmsg +='Terminate some appVM and retry.'
   115 			if os.path.exists('/usr/bin/kdialog'):
   116 				subprocess.call(['/usr/bin/kdialog', '--sorry', errmsg])
   117 			else:
   118 				subprocess.call(['/usr/bin/zenity', '--warning', errmsg])
   119 			return None
   120 		self.tray_notify("Starting new DispVM...")
   121 
   122 		qvm_collection = QubesVmCollection()
   123 		qvm_collection.lock_db_for_writing()
   124 		qvm_collection.load()
   125 		avir_template = qvm_collection.get_vm_by_name(avir_dvm_template)
   126 		if avir_template is None:
   127 			sys.stderr.write( 'Domain ' + avir_dvm_template + ' does not exist ?')
   128 			qvm_collection.unlock_db()
   129 			qmemman_client.close()
   130 			return None
   131 		label = avir_template.label
   132 		retcode = subprocess.call(['/usr/lib/qubes/qubes_restore',
   133 			current_savefile,
   134 			current_dvm_conf,
   135 			'-u', str(avir_template.default_user),
   136 			'-c', label.color,
   137 			'-i', label.icon_path,
   138 			'-l', str(label.index)])
   139 		qmemman_client.close()
   140 		if retcode != 0:
   141 			if os.path.exists('/usr/bin/kdialog'):
   142 				subprocess.call(['/usr/bin/kdialog', '--sorry', 'DisposableVM creation failed, see qubes_restore.log'])
   143 			else:
   144 				subprocess.call(['/usr/bin/zenity', '--warning', 'DisposableVM creation failed, see qubes_restore.log'])
   145 			qvm_collection.unlock_db()
   146 			return None
   147 
   148 		f = open('/var/run/qubes/dispVM_xid', 'r');
   149 		disp_xid = f.readline().rstrip('\n')
   150 		disp_name = f.readline().rstrip('\n')
   151 		disptempl = f.readline().rstrip('\n')
   152 		f.close()
   153 		
   154 		print >>sys.stderr, "getting vm %s" % disptempl	
   155 		avir_disptempl = qvm_collection.get_vm_by_name(disptempl);
   156 		if avir_disptempl is None:
   157 			sys.stderr.write( 'Domain ' + disptempl + ' does not exist ?')
   158 			qvm_collection.unlock_db()
   159 			return None
   160 
   161 		dispid = int(disp_name[4:])
   162 		dispvm = qvm_collection.add_new_disposablevm(disp_name, avir_disptempl.template, label=label, dispid=dispid, netvm=avir_disptempl.netvm)
   163 		print >> sys.stderr, "Waiting for the VM %s to startup...", dispvm.name
   164 		startup_counter = 0
   165 		startup_counter_max = 60
   166 		while startup_counter < startup_counter_max:
   167 			if dispvm.is_running():
   168 				break
   169 			shutdown_counter += 1
   170 			time.sleep (1)
   171 
   172 		qvm_collection.save()
   173 		qvm_collection.unlock_db()
   174 		return dispvm.name
   175 
   176 	def stop_vm(self, vmname):
   177 		vm = get_vm_by_name(vmname)
   178 		if vm is None or vm.qid not in get_vm_collection():
   179 			print >> sys.stderr, "A VM with the name '{0}' does not exist in the system.".format(vmname)
   180 			exit(1)
   181 		vm.shutdown(force=True)
   182 		print >> sys.stderr, "Waiting for the VM %s to shutdown...", vmname
   183 		shutdown_counter = 0
   184 		shutdown_counter_max = 60
   185 		while shutdown_counter < shutdown_counter_max:
   186 			if not vm.is_running():
   187 				return
   188 			shutdown_counter += 1
   189 			time.sleep (1)
   190 
   191 	def remove_vm(self, vmname):
   192 		qvm_collection = QubesVmCollection()
   193 		qvm_collection.lock_db_for_writing()
   194 		qvm_collection.load()
   195 		vm = qvm_collection.get_vm_by_name(vmname)
   196 
   197 		if vm is None or vm.qid not in qvm_collection:
   198 			print >> sys.stderr, "A VM with the name '{0}' does not exist in the system.".format(vmname)
   199 			exit(1)
   200 
   201 		if vm.is_running():
   202 			print >> sys.stderr, "Cannot remove a running VM, stop it first"
   203 			exit (1)
   204 
   205 		if vm.is_template():
   206 			dependent_vms = qvm_collection.get_vms_based_on(vm.qid)
   207 			if len(dependent_vms) > 0:
   208 				print >> sys.stderr, "The following AppVMs use '{0}' as a template:".format(vmname)
   209 				for vm in dependent_vms:
   210 					print >> sys.stderr, "{name:<12} (qid={qid})".format(qid=vm.qid, name=vm.name)
   211 				print >> sys.stderr, "Please remove those VMs first."
   212 				exit (1)
   213 			if qvm_collection.default_template_qid == vm.qid:
   214 				qvm_collection.default_template_qid = None
   215 
   216 		try:
   217 			vm.remove_from_disk()
   218 		except (IOError, OSError) as err:
   219 			print >> sys.stderr, "Warning: {0}".format(err)
   220 
   221 		# Do not exit, perhaps the VM files were somehow removed
   222 		# so just remove it from Qubes DB
   223 		qvm_collection.pop(vm.qid)
   224 		qvm_collection.save()
   225 		qvm_collection.unlock_db()
   226 
   227 	def attach_dev(self, vmname, devname):
   228 		vm = get_vm_by_name(vmname)
   229 		if vm is None or vm.qid not in get_vm_collection():
   230 			print >> sys.stderr, "A VM with the name '{0}' does not exist in the system.".format(vmname)
   231 			exit(1)
   232 		print "Attaching %s to vm - %s" % (devname, vm.name)
   233 		kwargs = {}
   234 		kwargs['auto_detach'] = True
   235 		try:
   236 			backend_vm = get_vm_by_name("dom0")
   237 			block_attach(vm, backend_vm, devname, **kwargs)
   238 		except QubesException as e:
   239 			print >> sys.stderr, "ERROR: %s" % str(e)
   240 			exit(1)
   241 
   242 	def detach_dev(self, vmname, devname):
   243 		vm = get_vm_by_name(vmname)
   244 		if vm is None or vm.qid not in get_vm_collection():
   245 			print >> sys.stderr, "A VM with the name '{0}' does not exist in the system.".format(vmname)
   246 			exit(1)
   247 		print "Detaching %s from vm - %s" % (devname, vmname)
   248 		kwargs = {}
   249 		#kwargs['frontend'] = "to_scan"
   250 		try:
   251 			block_detach(vm, **kwargs)
   252 		except QubesException as e:
   253 			print >> sys.stderr, "ERROR: %s" % str(e)
   254 			sys.exit(1)
   255 
   256 	def scan(self, vmname):
   257 		vm = get_vm_by_name(vmname)
   258 		if vm is None or vm.qid not in get_vm_collection():
   259 			print >> sys.stderr, "A VM with the name '{0}' does not exist in the system.".format(vmname)
   260 			exit(1)
   261 		subprocess.call(['/usr/lib/qubes/qrexec_client', '-d', vmname, 'root:mount /dev/xvdi /mnt/removable'])
   262 		#subprocess.call(['/usr/lib/qubes/qrexec_client', '-d', vmname, 'root:clamscan /mnt/removable'])
   263 		subprocess.call(['/usr/lib/qubes/qrexec_client', '-d', vmname, 'root:umount /mnt/removable'])
   264 
   265 
   266 def main():
   267 	global notify_object
   268 	print >>sys.stderr, "time=%s, qfile-daemon-dvm init" % (str(time.time()))
   269 	notify_object = dbus.SessionBus().get_object("org.freedesktop.Notifications", "/org/freedesktop/Notifications")
   270 	vm_factory = VMFactory()
   271 	#vmname = vm_factory.create_dvm()
   272 	vmname = vm_factory.create_appvm()
   273 	vm_factory.start_vm(vmname)
   274 	vm_factory.attach_dev(vmname, "sdb")
   275 	vm_factory.scan(vmname)
   276 	vm_factory.detach_dev(vmname, "sdb")
   277 	#vm_factory.stop_vm(vmname)
   278 	#vm_factory.remove_vm(vmname) 
   279 
   280 main()