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