ait/poc/scanner/create_dvm.py
changeset 1 446a7ba98309
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/ait/poc/scanner/create_dvm.py	Sat May 04 12:17:31 2013 -0400
     1.3 @@ -0,0 +1,280 @@
     1.4 +#!/bin/python
     1.5 +import os
     1.6 +import time
     1.7 +import dbus
     1.8 +import sys
     1.9 +import subprocess
    1.10 +from qubes.qubes import QubesVmCollection
    1.11 +from qubes.qubes import QubesDispVmLabels
    1.12 +from qubes.qubes import QubesException
    1.13 +from qubes.qubes import QubesVmLabels
    1.14 +from qubes.qmemman_client import QMemmanClient
    1.15 +from qubes.qubesutils import block_list,block_attach,block_detach,block_detach_all,block_check_attached
    1.16 +from qubes.qubesutils import kbytes_to_kmg, bytes_to_kmg
    1.17 +
    1.18 +
    1.19 +notify_object = None
    1.20 +current_savefile = '/var/run/qubes/current_savefile'
    1.21 +current_dvm_conf = '/var/run/qubes/current_dvm.conf'
    1.22 +avir_appvm_template = 'avir-template'
    1.23 +avir_dvm_template = 'avir-template-dvm'
    1.24 +
    1.25 +def get_vm_collection():
    1.26 +	vm_collection = QubesVmCollection()
    1.27 +	vm_collection.lock_db_for_reading()
    1.28 +	vm_collection.load()
    1.29 +	vm_collection.unlock_db()
    1.30 +	return vm_collection
    1.31 +
    1.32 +def get_vm_by_name(vmname):
    1.33 +	return get_vm_collection().get_vm_by_name(vmname)
    1.34 +
    1.35 +def gen_scanner_name():
    1.36 +	vm_collection = get_vm_collection()
    1.37 +	vms = [vm for vm in vm_collection.values()]
    1.38 +	vm_names = []
    1.39 +	for vm in vms:
    1.40 +		if vm.is_appvm() and vm.template.name == avir_appvm_template:
    1.41 +			vm_names.append (vm.name)
    1.42 +	print vm_names
    1.43 +
    1.44 +	ids = range(100)
    1.45 +	for id in ids:
    1.46 +		if "scanner"+str(id) not in vm_names:
    1.47 +			return "scanner"+str(id)
    1.48 +	print >> sys.stderr, "Unable to generate new scanner vm name"
    1.49 +	exit(1)
    1.50 +
    1.51 +class VMFactory:
    1.52 +	def __init__(self):
    1.53 +		self.tray_notify(str="Initialized")
    1.54 +
    1.55 +	def tray_notify(self, str, timeout = 3000):
    1.56 +		notify_object.Notify("Qubes", 0, "red", "Qubes", str, [], [], timeout, dbus_interface="org.freedesktop.Notifications")
    1.57 +
    1.58 +	def tray_notify_error(self, str, timeout = 3000):
    1.59 +		notify_object.Notify("Qubes", 0, "dialog-error", "Qubes", str, [], [], timeout, dbus_interface="org.freedesktop.Notifications")
    1.60 +
    1.61 +	def create_appvm(self):
    1.62 +		#generate new avir-scanner name
    1.63 +		scanner_vmname = gen_scanner_name()
    1.64 +		print "Generating new scanner vm %s " % scanner_vmname
    1.65 +
    1.66 +		#create new vscanner virtual machine from template "avir-template"
    1.67 +		qvm_collection = QubesVmCollection()
    1.68 +		qvm_collection.lock_db_for_writing()
    1.69 +		qvm_collection.load()
    1.70 +		avir_template = qvm_collection.get_vm_by_name(avir_appvm_template)
    1.71 +		if not avir_template.is_template():
    1.72 +			print >> sys.stderr, "VM '{0}' is not a TemplateVM".format(avir_template)
    1.73 +			exit (1)
    1.74 +		vmtype = "QubesAppVm"
    1.75 +
    1.76 +		try:
    1.77 +			scanner_vm = qvm_collection.add_new_vm(vmtype, name=scanner_vmname, template=avir_template, label = QubesVmLabels["orange"])
    1.78 +		except QubesException as err:
    1.79 +			print >> sys.stderr, "ERROR: {0}".format(err)
    1.80 +			exit (1)
    1.81 +
    1.82 +		scanner_vm.memory = 512
    1.83 +		scanner_vm.vcpus = 2
    1.84 +		try:
    1.85 +			scanner_vm.create_on_disk(verbose=True, source_template=avir_template)
    1.86 +			#if options.root:
    1.87 +			#       os.unlink(vm.root_img)
    1.88 +			#       os.rename(options.root, vm.root_img)
    1.89 +		except (IOError, OSError) as err:
    1.90 +			print >> sys.stderr, "ERROR: {0}".format(err)
    1.91 +			exit (1)
    1.92 +
    1.93 +		qvm_collection.save()
    1.94 +		qvm_collection.unlock_db()
    1.95 +		return scanner_vmname
    1.96 +
    1.97 +	def start_vm(self, vmname):
    1.98 +		vm = get_vm_by_name(vmname)
    1.99 +		if vm is None or vm.qid not in get_vm_collection():
   1.100 +			print >> sys.stderr, "A VM with the name '{0}' does not exist in the system.".format(vmname)
   1.101 +			exit(1)
   1.102 +		try:
   1.103 +			vm.verify_files()
   1.104 +			xid = vm.start(verbose=True, preparing_dvm=False, start_guid=True, notify_function=None)
   1.105 +		except (IOError, OSError, QubesException, MemoryError) as err:
   1.106 +			#if options.tray:
   1.107 +			#	tray_notify_error(str(err))
   1.108 +			#else:
   1.109 +			print >> sys.stderr, "ERROR: {0}".format(err)
   1.110 +			exit (1)
   1.111 +
   1.112 +	def create_dvm(self):
   1.113 +		qmemman_client = QMemmanClient()
   1.114 +		if not qmemman_client.request_memory(400*1024*1024):
   1.115 +			qmemman_client.close()
   1.116 +			errmsg = 'Not enough memory to create DVM. '
   1.117 +			errmsg +='Terminate some appVM and retry.'
   1.118 +			if os.path.exists('/usr/bin/kdialog'):
   1.119 +				subprocess.call(['/usr/bin/kdialog', '--sorry', errmsg])
   1.120 +			else:
   1.121 +				subprocess.call(['/usr/bin/zenity', '--warning', errmsg])
   1.122 +			return None
   1.123 +		self.tray_notify("Starting new DispVM...")
   1.124 +
   1.125 +		qvm_collection = QubesVmCollection()
   1.126 +		qvm_collection.lock_db_for_writing()
   1.127 +		qvm_collection.load()
   1.128 +		avir_template = qvm_collection.get_vm_by_name(avir_dvm_template)
   1.129 +		if avir_template is None:
   1.130 +			sys.stderr.write( 'Domain ' + avir_dvm_template + ' does not exist ?')
   1.131 +			qvm_collection.unlock_db()
   1.132 +			qmemman_client.close()
   1.133 +			return None
   1.134 +		label = avir_template.label
   1.135 +		retcode = subprocess.call(['/usr/lib/qubes/qubes_restore',
   1.136 +			current_savefile,
   1.137 +			current_dvm_conf,
   1.138 +			'-u', str(avir_template.default_user),
   1.139 +			'-c', label.color,
   1.140 +			'-i', label.icon_path,
   1.141 +			'-l', str(label.index)])
   1.142 +		qmemman_client.close()
   1.143 +		if retcode != 0:
   1.144 +			if os.path.exists('/usr/bin/kdialog'):
   1.145 +				subprocess.call(['/usr/bin/kdialog', '--sorry', 'DisposableVM creation failed, see qubes_restore.log'])
   1.146 +			else:
   1.147 +				subprocess.call(['/usr/bin/zenity', '--warning', 'DisposableVM creation failed, see qubes_restore.log'])
   1.148 +			qvm_collection.unlock_db()
   1.149 +			return None
   1.150 +
   1.151 +		f = open('/var/run/qubes/dispVM_xid', 'r');
   1.152 +		disp_xid = f.readline().rstrip('\n')
   1.153 +		disp_name = f.readline().rstrip('\n')
   1.154 +		disptempl = f.readline().rstrip('\n')
   1.155 +		f.close()
   1.156 +		
   1.157 +		print >>sys.stderr, "getting vm %s" % disptempl	
   1.158 +		avir_disptempl = qvm_collection.get_vm_by_name(disptempl);
   1.159 +		if avir_disptempl is None:
   1.160 +			sys.stderr.write( 'Domain ' + disptempl + ' does not exist ?')
   1.161 +			qvm_collection.unlock_db()
   1.162 +			return None
   1.163 +
   1.164 +		dispid = int(disp_name[4:])
   1.165 +		dispvm = qvm_collection.add_new_disposablevm(disp_name, avir_disptempl.template, label=label, dispid=dispid, netvm=avir_disptempl.netvm)
   1.166 +		print >> sys.stderr, "Waiting for the VM %s to startup...", dispvm.name
   1.167 +		startup_counter = 0
   1.168 +		startup_counter_max = 60
   1.169 +		while startup_counter < startup_counter_max:
   1.170 +			if dispvm.is_running():
   1.171 +				break
   1.172 +			shutdown_counter += 1
   1.173 +			time.sleep (1)
   1.174 +
   1.175 +		qvm_collection.save()
   1.176 +		qvm_collection.unlock_db()
   1.177 +		return dispvm.name
   1.178 +
   1.179 +	def stop_vm(self, vmname):
   1.180 +		vm = get_vm_by_name(vmname)
   1.181 +		if vm is None or vm.qid not in get_vm_collection():
   1.182 +			print >> sys.stderr, "A VM with the name '{0}' does not exist in the system.".format(vmname)
   1.183 +			exit(1)
   1.184 +		vm.shutdown(force=True)
   1.185 +		print >> sys.stderr, "Waiting for the VM %s to shutdown...", vmname
   1.186 +		shutdown_counter = 0
   1.187 +		shutdown_counter_max = 60
   1.188 +		while shutdown_counter < shutdown_counter_max:
   1.189 +			if not vm.is_running():
   1.190 +				return
   1.191 +			shutdown_counter += 1
   1.192 +			time.sleep (1)
   1.193 +
   1.194 +	def remove_vm(self, vmname):
   1.195 +		qvm_collection = QubesVmCollection()
   1.196 +		qvm_collection.lock_db_for_writing()
   1.197 +		qvm_collection.load()
   1.198 +		vm = qvm_collection.get_vm_by_name(vmname)
   1.199 +
   1.200 +		if vm is None or vm.qid not in qvm_collection:
   1.201 +			print >> sys.stderr, "A VM with the name '{0}' does not exist in the system.".format(vmname)
   1.202 +			exit(1)
   1.203 +
   1.204 +		if vm.is_running():
   1.205 +			print >> sys.stderr, "Cannot remove a running VM, stop it first"
   1.206 +			exit (1)
   1.207 +
   1.208 +		if vm.is_template():
   1.209 +			dependent_vms = qvm_collection.get_vms_based_on(vm.qid)
   1.210 +			if len(dependent_vms) > 0:
   1.211 +				print >> sys.stderr, "The following AppVMs use '{0}' as a template:".format(vmname)
   1.212 +				for vm in dependent_vms:
   1.213 +					print >> sys.stderr, "{name:<12} (qid={qid})".format(qid=vm.qid, name=vm.name)
   1.214 +				print >> sys.stderr, "Please remove those VMs first."
   1.215 +				exit (1)
   1.216 +			if qvm_collection.default_template_qid == vm.qid:
   1.217 +				qvm_collection.default_template_qid = None
   1.218 +
   1.219 +		try:
   1.220 +			vm.remove_from_disk()
   1.221 +		except (IOError, OSError) as err:
   1.222 +			print >> sys.stderr, "Warning: {0}".format(err)
   1.223 +
   1.224 +		# Do not exit, perhaps the VM files were somehow removed
   1.225 +		# so just remove it from Qubes DB
   1.226 +		qvm_collection.pop(vm.qid)
   1.227 +		qvm_collection.save()
   1.228 +		qvm_collection.unlock_db()
   1.229 +
   1.230 +	def attach_dev(self, vmname, devname):
   1.231 +		vm = get_vm_by_name(vmname)
   1.232 +		if vm is None or vm.qid not in get_vm_collection():
   1.233 +			print >> sys.stderr, "A VM with the name '{0}' does not exist in the system.".format(vmname)
   1.234 +			exit(1)
   1.235 +		print "Attaching %s to vm - %s" % (devname, vm.name)
   1.236 +		kwargs = {}
   1.237 +		kwargs['auto_detach'] = True
   1.238 +		try:
   1.239 +			backend_vm = get_vm_by_name("dom0")
   1.240 +			block_attach(vm, backend_vm, devname, **kwargs)
   1.241 +		except QubesException as e:
   1.242 +			print >> sys.stderr, "ERROR: %s" % str(e)
   1.243 +			exit(1)
   1.244 +
   1.245 +	def detach_dev(self, vmname, devname):
   1.246 +		vm = get_vm_by_name(vmname)
   1.247 +		if vm is None or vm.qid not in get_vm_collection():
   1.248 +			print >> sys.stderr, "A VM with the name '{0}' does not exist in the system.".format(vmname)
   1.249 +			exit(1)
   1.250 +		print "Detaching %s from vm - %s" % (devname, vmname)
   1.251 +		kwargs = {}
   1.252 +		#kwargs['frontend'] = "to_scan"
   1.253 +		try:
   1.254 +			block_detach(vm, **kwargs)
   1.255 +		except QubesException as e:
   1.256 +			print >> sys.stderr, "ERROR: %s" % str(e)
   1.257 +			sys.exit(1)
   1.258 +
   1.259 +	def scan(self, vmname):
   1.260 +		vm = get_vm_by_name(vmname)
   1.261 +		if vm is None or vm.qid not in get_vm_collection():
   1.262 +			print >> sys.stderr, "A VM with the name '{0}' does not exist in the system.".format(vmname)
   1.263 +			exit(1)
   1.264 +		subprocess.call(['/usr/lib/qubes/qrexec_client', '-d', vmname, 'root:mount /dev/xvdi /mnt/removable'])
   1.265 +		#subprocess.call(['/usr/lib/qubes/qrexec_client', '-d', vmname, 'root:clamscan /mnt/removable'])
   1.266 +		subprocess.call(['/usr/lib/qubes/qrexec_client', '-d', vmname, 'root:umount /mnt/removable'])
   1.267 +
   1.268 +
   1.269 +def main():
   1.270 +	global notify_object
   1.271 +	print >>sys.stderr, "time=%s, qfile-daemon-dvm init" % (str(time.time()))
   1.272 +	notify_object = dbus.SessionBus().get_object("org.freedesktop.Notifications", "/org/freedesktop/Notifications")
   1.273 +	vm_factory = VMFactory()
   1.274 +	#vmname = vm_factory.create_dvm()
   1.275 +	vmname = vm_factory.create_appvm()
   1.276 +	vm_factory.start_vm(vmname)
   1.277 +	vm_factory.attach_dev(vmname, "sdb")
   1.278 +	vm_factory.scan(vmname)
   1.279 +	vm_factory.detach_dev(vmname, "sdb")
   1.280 +	#vm_factory.stop_vm(vmname)
   1.281 +	#vm_factory.remove_vm(vmname) 
   1.282 +
   1.283 +main()