OpenSecurity/bin/vmmanager.pyw
author mb
Wed, 26 Feb 2014 17:27:07 +0100
changeset 79 617009c32da0
parent 78 23551f635ca9
child 81 84663db906d7
permissions -rwxr-xr-x
hibernate, wait_startup, and other changes
     1 '''
     2 Created on Nov 19, 2013
     3 
     4 @author: BarthaM
     5 '''
     6 import os
     7 import os.path
     8 from subprocess import Popen, PIPE, call, STARTUPINFO, _subprocess
     9 import sys
    10 import re
    11 
    12 from cygwin import Cygwin
    13 from environment import Environment
    14 import threading
    15 import time
    16 import string
    17 
    18 import shutil
    19 import stat
    20 import tempfile
    21 from opensecurity_util import logger, setupLogger, OpenSecurityException
    22 import ctypes
    23 import itertools
    24 DEBUG = True
    25 
    26 class VMManagerException(Exception):
    27     def __init__(self, value):
    28         self.value = value
    29     def __str__(self):
    30         return repr(self.value)
    31 
    32 class USBFilter:
    33     vendorid = ""
    34     productid = ""
    35     revision = ""
    36     
    37     def __init__(self, vendorid, productid, revision):
    38         self.vendorid = vendorid.lower()
    39         self.productid = productid.lower()
    40         self.revision = revision.lower()
    41         return
    42     
    43     def __eq__(self, other):
    44         return self.vendorid == other.vendorid and self.productid == other.productid and self.revision == other.revision
    45     
    46     def __hash__(self):
    47         return hash(self.vendorid) ^ hash(self.productid) ^ hash(self.revision)
    48     
    49     def __repr__(self):
    50         return "VendorId = \'" + str(self.vendorid) + "\' ProductId = \'" + str(self.productid) + "\' Revision = \'" + str(self.revision) + "\'"
    51  
    52 class VMManager(object):
    53     vmRootName = "SecurityDVM"
    54     systemProperties = None
    55     startNotifications = list()
    56     _instance = None
    57     machineFolder = ''
    58     rsdHandler = None
    59     
    60     def __init__(self):
    61         self.systemProperties = self.getSystemProperties()
    62         self.machineFolder = self.systemProperties["Default machine folder"]
    63         self.cleanup()
    64         self.rsdHandler = DeviceHandler(self)
    65         self.rsdHandler.start()
    66         return
    67     
    68     @staticmethod
    69     def getInstance():
    70         if VMManager._instance == None:
    71             VMManager._instance = VMManager()
    72         return VMManager._instance
    73     
    74     def cleanup(self):
    75         if self.rsdHandler != None:
    76             self.rsdHandler.stop()
    77             self.rsdHandler.join()
    78         drives = self.getNetworkDrives()
    79         for drive in drives.keys():
    80             self.unmapNetworkDrive(drive)
    81         for vm in self.listSDVM():
    82             self.poweroffVM(vm)
    83             self.removeVM(vm)
    84         
    85     def putStartNotification(self, ip):
    86         self.startNotifications.append(ip)
    87     
    88     def isSDVMStarted(self, ip):
    89         return ip in self.startNotifications
    90     
    91     # return hosty system properties
    92     def getSystemProperties(self):
    93         result = Cygwin.vboxExecute('list systemproperties')
    94         if result[1]=='':
    95             return None
    96         props = dict((k.strip(),v.strip().strip('"')) for k,v in (line.split(':', 1) for line in result[1].strip().splitlines()))
    97         #logger.debug(props)
    98         return props
    99     
   100     # return the folder containing the guest VMs     
   101     def getMachineFolder(self):
   102         return self.machineFolder
   103 
   104     # list all existing VMs registered with VBox
   105     def listVM(self):
   106         result = Cygwin.vboxExecute('list vms')[1]
   107         vms = list(k.strip().strip('"') for k,_ in (line.split(' ') for line in result.splitlines()))
   108         return vms
   109     
   110     # list running VMs
   111     def listRunningVMS(self):
   112         result = Cygwin.vboxExecute('list runningvms')[1]
   113         vms = list(k.strip().strip('"') for k,_ in (line.split(' ') for line in result.splitlines()))
   114         return vms
   115     
   116     # list existing SDVMs
   117     def listSDVM(self):
   118         vms = self.listVM()
   119         svdms = []
   120         for vm in vms:
   121             if vm.startswith(self.vmRootName) and vm != self.vmRootName:
   122                 svdms.append(vm)
   123         return svdms
   124     
   125     # generate valid (not already existing SDVM name). necessary for creating a new VM
   126     def generateSDVMName(self):
   127         vms = self.listVM()
   128         for i in range(0,999):
   129             if(not self.vmRootName+str(i) in vms):
   130                 return self.vmRootName+str(i)
   131         return ''
   132     
   133     # return the RSDs connected to the host
   134     def getConnectedRSDS(self):
   135         results = Cygwin.vboxExecute('list usbhost')[1]
   136         results = results.split('Host USB Devices:')[1].strip()
   137         
   138         items = list( "UUID:"+result for result in results.split('UUID:') if result != '')
   139         rsds = dict()   
   140         for item in items:
   141             props = dict()
   142             for line in item.splitlines():
   143                 if line != "":         
   144                     k,v = line[:line.index(':')].strip(), line[line.index(':')+1:].strip()
   145                     props[k] = v
   146             
   147             if 'Product' in props.keys() and props['Product'] == 'Mass Storage':
   148                 usb_filter = USBFilter( re.search(r"\((?P<vid>[0-9A-Fa-f]+)\)", props['VendorId']).groupdict()['vid'], 
   149                                         re.search(r"\((?P<pid>[0-9A-Fa-f]+)\)", props['ProductId']).groupdict()['pid'],
   150                                         re.search(r"\((?P<rev>[0-9A-Fa-f]+)\)", props['Revision']).groupdict()['rev'] )
   151                 rsds[props['UUID']] = usb_filter;
   152                 logger.debug(usb_filter)
   153         return rsds
   154     
   155     # return the RSDs attached to all existing SDVMs
   156     def getAttachedRSDs(self):
   157         vms = self.listSDVM()
   158         attached_devices = dict()
   159         for vm in vms:
   160             rsd_filter = self.getUSBFilter(vm)
   161             if rsd_filter != None:
   162                 attached_devices[vm] = rsd_filter
   163         return attached_devices
   164     
   165     # configures hostonly networking and DHCP server. requires admin rights
   166     def configureHostNetworking(self):
   167         #cmd = 'vboxmanage list hostonlyifs'
   168         #Cygwin.vboxExecute(cmd)
   169         #cmd = 'vboxmanage hostonlyif remove \"VirtualBox Host-Only Ethernet Adapter\"'
   170         #Cygwin.vboxExecute(cmd)
   171         #cmd = 'vboxmanage hostonlyif create'
   172         #Cygwin.vboxExecute(cmd)
   173         Cygwin.vboxExecute('hostonlyif ipconfig \"VirtualBox Host-Only Ethernet Adapter\" --ip 192.168.56.1 --netmask 255.255.255.0')
   174         #cmd = 'vboxmanage dhcpserver add'
   175         #Cygwin.vboxExecute(cmd)
   176         Cygwin.vboxExecute('dhcpserver modify --ifname \"VirtualBox Host-Only Ethernet Adapter\" --ip 192.168.56.100 --netmask 255.255.255.0 --lowerip 192.168.56.101 --upperip 192.168.56.200')
   177     
   178     #create new virtual machine instance based on template vm named SecurityDVM (\SecurityDVM\SecurityDVM.vmdk)
   179     def createVM(self, vm_name):
   180         hostonly_if = self.getHostOnlyIFs()
   181         Cygwin.vboxExecute('createvm --name ' + vm_name + ' --ostype Debian --register')
   182         Cygwin.vboxExecute('modifyvm ' + vm_name + ' --memory 512 --vram 10 --cpus 1 --usb on --usbehci on --nic1 hostonly --hostonlyadapter1 \"' + hostonly_if['Name'] + '\" --nic2 nat')
   183         Cygwin.vboxExecute('storagectl ' + vm_name + ' --name SATA --add sata --portcount 2')
   184         return
   185     
   186     # attach storage image to controller
   187     def storageAttach(self, vm_name):
   188         if self.isStorageAttached(vm_name):
   189             self.storageDetach(vm_name)
   190         Cygwin.vboxExecute('storageattach ' + vm_name + ' --storagectl SATA --port 0 --device 0 --type hdd --medium \"'+ self.machineFolder + '\SecurityDVM\SecurityDVM.vmdk\"')
   191         return
   192     
   193     # return true if storage is attached 
   194     def isStorageAttached(self, vm_name):
   195         info = self.getVMInfo(vm_name)
   196         return (info['SATA-0-0']!='none')
   197     
   198     # detach storage from controller
   199     def storageDetach(self, vm_name):
   200         if self.isStorageAttached(vm_name):
   201             Cygwin.vboxExecute('storageattach ' + vm_name + ' --storagectl SATA --port 0 --device 0 --type hdd --medium none')
   202         return
   203     
   204     def changeStorageType(self, filename, storage_type):
   205         Cygwin.vboxExecute('modifyhd \"' + filename + '\" --type ' + storage_type)
   206         return
   207     
   208     # list storage snaphots for VM
   209     def updateTemplate(self):
   210         self.cleanup()
   211         self.poweroffVM('SecurityDVM')
   212         self.waitShutdown('SecurityDVM')
   213         
   214         # check for updates
   215         self.genCertificateISO('SecurityDVM')
   216         self.attachCertificateISO('SecurityDVM')
   217         
   218         self.storageDetach('SecurityDVM')
   219         results = Cygwin.vboxExecute('list hdds')[1]
   220         results = results.replace('Parent UUID', 'Parent')
   221         items = list( "UUID:"+result for result in results.split('UUID:') if result != '')
   222         
   223         snaps = dict()   
   224         for item in items:
   225             props = dict()
   226             for line in item.splitlines():
   227                 if line != "":         
   228                     k,v = line[:line.index(':')].strip(), line[line.index(':')+1:].strip()
   229                     props[k] = v;
   230             snaps[props['UUID']] = props
   231         
   232         
   233         template_storage = self.machineFolder + '\SecurityDVM\SecurityDVM.vmdk'
   234         
   235         # find template uuid
   236         template_uuid = ''
   237         for hdd in snaps.values():
   238             if hdd['Location'] == template_storage:
   239                 template_uuid = hdd['UUID']
   240         logger.debug('found parent uuid ' + template_uuid)
   241         
   242         # remove snapshots 
   243         for hdd in snaps.values():
   244             if hdd['Parent'] == template_uuid:
   245                 #template_uuid = hdd['UUID']
   246                 logger.debug('removing snapshot ' + hdd['UUID'])
   247                 results = Cygwin.vboxExecute('closemedium disk {' + hdd['UUID'] + '} --delete')[1]
   248                 # parse result 0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%
   249         
   250         self.changeStorageType(template_storage,'normal')
   251         self.storageAttach('SecurityDVM')
   252         self.startVM('SecurityDVM')
   253         self.waitStartup('SecurityDVM')
   254         Cygwin.sshExecute('"sudo apt-get -y update"', VMManager.getHostOnlyIP('SecurityDVM'), 'osecuser', Cygwin.cygPath(self.machineFolder) + '/' + 'SecurityDVM' + '/dvm_key'  )
   255         Cygwin.sshExecute('"sudo apt-get -y upgrade"', VMManager.getHostOnlyIP('SecurityDVM'), 'osecuser', Cygwin.cygPath(self.machineFolder) + '/' + 'SecurityDVM' + '/dvm_key'  )
   256         #self.stopVM('SecurityDVM')
   257         self.hibernateVM('SecurityDVM')
   258         self.waitShutdown('SecurityDVM')
   259         self.storageDetach('SecurityDVM')
   260         self.changeStorageType(template_storage,'immutable')
   261         self.storageAttach('SecurityDVM')
   262         self.rsdHandler = DeviceHandler(self)
   263         self.rsdHandler.start()
   264     
   265     #remove VM from the system. should be used on VMs returned by listSDVMs    
   266     def removeVM(self, vm_name):
   267         logger.info('Removing ' + vm_name)
   268         Cygwin.vboxExecute('unregistervm ' + vm_name + ' --delete')
   269         machineFolder = Cygwin.cygPath(self.machineFolder)
   270         Cygwin.bashExecute('"/usr/bin/rm -rf ' + machineFolder + '/' + vm_name + '"')
   271     
   272     # start VM
   273     def startVM(self, vm_name):
   274         logger.info('Starting ' +  vm_name)
   275         result = Cygwin.vboxExecute('startvm ' + vm_name + ' --type headless' )
   276         while not string.find(str(result), 'successfully started',):
   277             logger.error("Failed to start SDVM: " + vm_name + " retrying")
   278             time.sleep(1)
   279             result = Cygwin.vboxExecute('startvm ' + vm_name + ' --type headless')
   280         return result[0]
   281     
   282     # return wether VM is running or not
   283     def isVMRunning(self, vm_name):
   284         return vm_name in self.listRunningVMS()    
   285     
   286     # stop VM
   287     def stopVM(self, vm_name):
   288         logger.info('Sending shutdown signal to ' + vm_name)
   289         Cygwin.sshExecute( '"sudo shutdown -h now"', VMManager.getHostOnlyIP(vm_name), 'osecuser', Cygwin.cygPath(self.machineFolder) + '/' + vm_name + '/dvm_key' )
   290     
   291     # stop VM
   292     def hibernateVM(self, vm_name):
   293         logger.info('Sending shutdown signal to ' + vm_name)
   294         Cygwin.sshExecute( '"sudo hibernate-disk&"', VMManager.getHostOnlyIP(vm_name), 'osecuser', Cygwin.cygPath(self.machineFolder) + '/' + vm_name + '/dvm_key', wait_return=False )
   295             
   296     # poweroff VM
   297     def poweroffVM(self, vm_name):
   298         if not self.isVMRunning(vm_name):
   299             return
   300         logger.info('Powering off ' + vm_name)
   301         return Cygwin.vboxExecute('controlvm ' + vm_name + ' poweroff')
   302     
   303     #list the hostonly IFs exposed by the VBox host
   304     @staticmethod    
   305     def getHostOnlyIFs():
   306         result = Cygwin.vboxExecute('list hostonlyifs')[1]
   307         if result=='':
   308             return None
   309         props = dict((k.strip(),v.strip().strip('"')) for k,v in (line.split(':', 1) for line in result.strip().splitlines()))
   310         return props
   311     
   312     # return the hostOnly IP for a running guest or the host
   313     @staticmethod    
   314     def getHostOnlyIP(vm_name):
   315         if vm_name == None:
   316             logger.info('Gettting hostOnly IP address for Host')
   317             return VMManager.getHostOnlyIFs()['IPAddress']
   318         else:
   319             logger.info('Gettting hostOnly IP address ' + vm_name)
   320             result = Cygwin.vboxExecute('guestproperty get ' + vm_name + ' /VirtualBox/GuestInfo/Net/0/V4/IP')
   321             if result=='':
   322                 return None
   323             result = result[1]
   324             if result.startswith('No value set!'):
   325                 return None
   326             return result[result.index(':')+1:].strip()
   327             
   328     # attach removable storage device to VM by provision of filter
   329     def attachRSD(self, vm_name, rsd_filter):
   330         return Cygwin.vboxExecute('usbfilter add 0 --target ' + vm_name + ' --name OpenSecurityRSD --vendorid ' + rsd_filter.vendorid + ' --productid ' + rsd_filter.productid + ' --revision ' + rsd_filter.revision)
   331     
   332     # detach removable storage from VM by 
   333     def detachRSD(self, vm_name):
   334         return Cygwin.vboxExecute('usbfilter remove 0 --target ' + vm_name )
   335         
   336     
   337     # return the description set for an existing VM
   338     def getVMInfo(self, vm_name):
   339         results = Cygwin.vboxExecute('showvminfo ' + vm_name + ' --machinereadable')[1]
   340         props = dict((k.strip().strip('"'),v.strip().strip('"')) for k,v in (line.split('=', 1) for line in results.splitlines()))
   341         #logger.debug(props)
   342         return props
   343     
   344     # return the configured USB filter for an existing VM 
   345     def getUSBFilter(self, vm_name):
   346         props = self.getVMInfo(vm_name)
   347         keys = set(['USBFilterVendorId1', 'USBFilterProductId1', 'USBFilterRevision1'])
   348         keyset = set(props.keys())
   349         usb_filter = None
   350         if keyset.issuperset(keys):
   351             usb_filter = USBFilter(props['USBFilterVendorId1'], props['USBFilterProductId1'], props['USBFilterRevision1'])
   352         return usb_filter
   353     
   354     #generates ISO containing authorized_keys for use with guest VM
   355     def genCertificateISO(self, vm_name):
   356         machineFolder = Cygwin.cygPath(self.machineFolder)
   357         # remove .ssh folder if exists
   358         cmd = '\"/usr/bin/rm -rf \\\"' + machineFolder + '/' + vm_name + '/.ssh\\\"\"'
   359         Cygwin.bashExecute(cmd)
   360         # remove .ssh folder if exists
   361         Cygwin.bashExecute('\"/usr/bin/rm -rf \\\"' + machineFolder + '/' + vm_name + '/dvm_key\\\"\"')
   362         # create .ssh folder in vm_name
   363         Cygwin.bashExecute('\"/usr/bin/mkdir -p \\\"' + machineFolder + '/' + vm_name + '/.ssh\\\"\"')
   364         # generate dvm_key pair in vm_name / .ssh     
   365         Cygwin.bashExecute('\"/usr/bin/ssh-keygen -q -t rsa -N \\"\\" -C \\\"' + vm_name + '\\\" -f \\\"' + machineFolder + '/' + vm_name + '/.ssh/dvm_key\\\"\"')
   366         # move out private key
   367         Cygwin.bashExecute('\"/usr/bin/mv \\\"' + machineFolder + '/' + vm_name + '/.ssh/dvm_key\\\" \\\"' + machineFolder + '/' + vm_name + '\\\"')
   368         # set permissions for private key
   369         Cygwin.bashExecute('\"/usr/bin/chmod 500 \\\"' + machineFolder + '/' + vm_name + '/dvm_key\\\"\"')
   370         # rename public key to authorized_keys
   371         Cygwin.bashExecute('\"/usr/bin/mv \\\"' + machineFolder + '/' + vm_name + '/.ssh/dvm_key.pub\\\" \\\"' + machineFolder + '/' + vm_name + '/.ssh/authorized_keys\\\"')
   372         # set permissions for authorized_keys
   373         Cygwin.bashExecute('\"/usr/bin/chmod 500 \\\"' + machineFolder + '/' + vm_name + '/.ssh/authorized_keys\\\"\"')
   374         # generate iso image with .ssh/authorized keys
   375         Cygwin.bashExecute('\"/usr/bin/genisoimage -J -R -o \\\"' + machineFolder + '/' + vm_name + '/'+ vm_name + '.iso\\\" \\\"' + machineFolder + '/' + vm_name + '/.ssh\\\"\"')
   376     
   377     # attaches generated ssh public cert to guest vm
   378     def attachCertificateISO(self, vm_name):
   379         result = Cygwin.vboxExecute('storageattach ' + vm_name + ' --storagectl SATA --port 1 --device 0 --type dvddrive --mtype readonly --medium \"' + self.machineFolder + '\\' + vm_name + '\\'+ vm_name + '.iso\"')
   380         return result
   381     
   382     # wait for machine to come up
   383     def waitStartup(self, vm_name, timeout_ms = 30000):
   384         #result = Cygwin.vboxExecute('guestproperty wait ' + vm_name + ' /VirtualBox/GuestInfo/Net/0/V4/IP --timeout ' + str(timeout_ms) + ' --fail-on-timeout')
   385         
   386         result = Cygwin.vboxExecute('guestproperty wait ' + vm_name + ' SDVMStarted --timeout ' + str(timeout_ms) + ' --fail-on-timeout')
   387         #new_ip = VMManager.getHostOnlyIP(vm_name)
   388         #while new_ip == None:
   389         #    time.sleep(1)
   390         #    new_ip = VMManager.getHostOnlyIP(vm_name)
   391         #while not self.isSDVMStarted(new_ip):
   392         #    time.sleep(1)
   393         return VMManager.getHostOnlyIP(vm_name)
   394     
   395     # wait for machine to shutdown
   396     def waitShutdown(self, vm_name):
   397         while vm_name in self.listRunningVMS():
   398             time.sleep(1)
   399         return
   400         
   401     # handles browsing request    
   402     def handleBrowsingRequest(self):
   403         if VMManager.handleDeviceChangeLock.acquire(True):
   404             new_sdvm = self.generateSDVMName()
   405             self.createVM(new_sdvm)
   406             self.storageAttach(new_sdvm)
   407             self.genCertificateISO(new_sdvm)
   408             self.attachCertificateISO(new_sdvm)
   409             self.startVM(new_sdvm)
   410             new_ip = self.waitStartup(new_sdvm)
   411             if new_ip != None:
   412                 self.mapNetworkDrive('g:', '\\\\' + new_ip + '\\Download', None, None)
   413             #TODO: cleanup notifications somwhere else (eg. machine shutdown)
   414             self.startNotifications.remove(new_ip)
   415             VMManager.handleDeviceChangeLock.release()
   416         return new_sdvm
   417     
   418     #Small function to check the availability of network resource.
   419     #def isAvailable(self, path):
   420         #return os.path.exists(path)
   421         #result = Cygwin.cmdExecute('IF EXIST "' + path + '" echo YES')
   422         #return string.find(result[1], 'YES',)
   423     
   424     #Small function to check if the mention location is a directory
   425     def isDirectory(self, path):
   426         result = Cygwin.cmdExecute('dir ' + path + ' | FIND ".."')
   427         return string.find(result[1], 'DIR',)
   428 
   429     def mapNetworkDrive(self, drive, networkPath, user, password):
   430         self.unmapNetworkDrive(drive)
   431         #Check for drive availability
   432         if os.path.exists(drive):
   433             logger.error("Drive letter is already in use: " + drive)
   434             return -1
   435         #Check for network resource availability
   436         while not os.path.exists(networkPath):
   437             time.sleep(1)
   438             logger.info("Path not accessible: " + networkPath + " retrying")
   439             #return -1
   440     
   441         command = 'USE ' + drive + ' ' + networkPath + ' /PERSISTENT:NO'
   442         if user != None:
   443             command += ' ' + password + ' /User' + user
   444     
   445         #TODO: Execute 'NET USE' command with authentication
   446         result = Cygwin.execute('C:\\Windows\\system32\\net.exe', command)
   447         if string.find(result[1], 'successfully',) == -1:
   448             logger.error("Failed: NET " + command)
   449             return -1
   450         return 1
   451     
   452     def unmapNetworkDrive(self, drive):
   453         drives = self.getNetworkDrives()
   454         if drive not in drives.keys():
   455             return 1 
   456         result = Cygwin.execute('C:\\Windows\\system32\\net.exe', 'USE ' + drive + ' /DELETE /YES')
   457         if string.find(str(result[1]), 'successfully',) == -1:
   458             logger.error(result[2])
   459             return -1
   460         return 1
   461     
   462     def getNetworkDrives(self):
   463         ip = VMManager.getHostOnlyIP(None)
   464         ip = ip[:ip.rindex('.')]
   465         drives = dict()    
   466         result = Cygwin.execute('C:\\Windows\\system32\\net.exe', 'USE')
   467         for line in result[1].splitlines():
   468             if ip in line:
   469                 parts = line.split()
   470                 drives[parts[1]] = parts[2]
   471         return drives
   472             
   473     def genNetworkDrive(self):
   474         network_drives = self.getNetworkDrives()
   475         logical_drives = self.getLogicalDrives()
   476         drives = list(map(chr, range(68, 91)))  
   477         for drive in drives:
   478             if drive+':' not in network_drives and drive not in logical_drives:
   479                 return drive+':'
   480 
   481     def getNetworkDrive(self, vm_name):
   482         ip = self.getHostOnlyIP(vm_name)
   483         result = Cygwin.execute('C:\\Windows\\system32\\net.exe', 'USE')
   484         for line in result[1].splitlines():
   485             if ip in line:
   486                 parts = line.split()
   487                 return parts[0]
   488     
   489     def getLogicalDrives(self):
   490         drive_bitmask = ctypes.cdll.kernel32.GetLogicalDrives()
   491         return list(itertools.compress(string.ascii_uppercase,  map(lambda x:ord(x) - ord('0'), bin(drive_bitmask)[:1:-1])))
   492                     
   493         #vms = self.listSDVM()
   494         #for vm in vms:
   495         #    ip = self.getHostOnlyIP(vm)
   496         
   497 class DeviceHandler(threading.Thread): 
   498     vmm = None
   499     #handleDeviceChangeLock = threading.Lock()
   500     attachedRSDs = None  
   501     connectedRSDs = None
   502     running = True
   503     def __init__(self, vmmanger): 
   504         threading.Thread.__init__(self)
   505         self.vmm = vmmanger
   506  
   507     def stop(self):
   508         self.running = False
   509         
   510     def run(self):
   511         self.connectedRSDs = dict()#self.vmm.getConnectedRSDS()
   512         self.attachedRSDs = self.vmm.getAttachedRSDs()
   513         while self.running:
   514             tmp_rsds = self.vmm.getConnectedRSDS()
   515             if tmp_rsds.keys() == self.connectedRSDs.keys():
   516                 logger.debug("Nothing's changed. sleep(3)")
   517                 time.sleep(3)
   518                 continue
   519             
   520             logger.info("Something's changed")          
   521             
   522             self.connectedRSDs = tmp_rsds
   523             self.attachedRSDs = self.vmm.getAttachedRSDs()
   524             
   525             
   526             for vm_name in self.attachedRSDs.keys():
   527                 if self.attachedRSDs[vm_name] not in self.connectedRSDs.values():
   528                     drive = self.vmm.getNetworkDrive(vm_name)
   529                     self.vmm.unmapNetworkDrive(drive)
   530                     #self.stopVM(vm_name)
   531                     self.vmm.detachRSD(vm_name)
   532                     self.vmm.poweroffVM(vm_name)
   533                     self.vmm.removeVM(vm_name)
   534             #create new vm for attached device if any
   535             self.attachedRSDs = self.vmm.getAttachedRSDs()
   536             self.connectedRSDs = self.vmm.getConnectedRSDS()
   537             
   538             new_ip = None
   539             for connected_device in self.connectedRSDs.values():
   540                 if (self.attachedRSDs and False) or (connected_device not in self.attachedRSDs.values()):
   541                     new_sdvm = self.vmm.generateSDVMName()
   542                     self.vmm.createVM(new_sdvm)
   543                     self.vmm.storageAttach(new_sdvm)
   544                     self.vmm.attachRSD(new_sdvm, connected_device)
   545                     self.vmm.startVM(new_sdvm)
   546                     new_ip = self.vmm.waitStartup(new_sdvm)
   547                     drive = self.vmm.genNetworkDrive()
   548                     if new_ip != None:
   549                         self.vmm.mapNetworkDrive(drive, '\\\\' + new_ip + '\\USB', None, None)
   550                     #TODO: cleanup notifications somwhere else (eg. machine shutdown)
   551                     self.vmm.startNotifications.remove(new_ip)
   552             #self.handleDeviceChangeLock.release()
   553                 
   554 
   555 if __name__ == '__main__':
   556     #man = VMManager.getInstance()
   557     #man.listVM()
   558     #print man.getConnectedRSDs()
   559     #print man.getNetworkDrives()
   560     #man.genNetworkDrive()
   561     drive_bitmask = ctypes.cdll.kernel32.GetLogicalDrives()
   562     print list(itertools.compress(string.ascii_uppercase,  map(lambda x:ord(x) - ord('0'), bin(drive_bitmask)[:1:-1])))
   563     #print list(map(chr, range(68, 91))) 
   564     
   565     #time.sleep(-1)
   566     #man.listVM()
   567     #man.listVM()
   568     #man.listVM()
   569     #man.listVM()
   570     #man.genCertificateISO('SecurityDVM0')
   571     #man.guestExecute('SecurityDVM0', '/bin/ls -la')
   572     #logger = setupLogger('VMManager')
   573     #c = Cygwin()
   574     
   575     #man.sshExecute('/bin/ls -la', 'SecurityDVM0')
   576     #man.sshExecuteX11('/usr/bin/iceweasel', 'SecurityDVM0')
   577     #man.removeVM('SecurityDVM0')
   578     #man.netUse('192.168.56.134', 'USB\\')
   579     #ip = '192.168.56.139'
   580     
   581     #man.cygwin_path = 'c:\\cygwin64\\bin\\'
   582     #man.handleDeviceChange()
   583     #print man.listSDVM()
   584     #man.configureHostNetworking()
   585     #new_vm = man.generateSDVMName()
   586     #man.createVM(new_vm)
   587     
   588     #print Cygwin.cmd()
   589     #man.isAvailable('c:')
   590     #ip = man.getHostOnlyIP('SecurityDVM0')
   591     #man.mapNetworkDrive('h:', '\\\\' + ip + '\Download', None, None)
   592     
   593     #man.genCertificateISO(new_vm)
   594     #man.attachCertificateISO(new_vm)
   595     
   596     #man.attachCertificateISO(vm_name)
   597     #man.guestExecute(vm_name, "ls")
   598     #man.sshGuestX11Execute('SecurityDVM1', '/usr/bin/iceweasel')
   599     #time.sleep(60)
   600     #print man.cygwinPath("C:\Users\BarthaM\VirtualBox VMs\SecurityDVM\.ssh\*")
   601     #man.genCertificateISO('SecurityDVM')
   602     #man.attachCertificateISO('SecurityDVM')
   603     #man.isStorageAttached('SecurityDVM')
   604     #man.guestExecute('SecurityDVM', 'sudo apt-get -y update')
   605     #man.guestExecute('SecurityDVM', 'sudo apt-get -y upgrade' )
   606     
   607     #man.stopVM('SecurityDVM')
   608     #man.storageDetach('SecurityDVM')
   609     #man.changeStorageType('C:\Users\BarthaM\VirtualBox VMs\SecurityDVM\SecurityDVM.vmdk','immutable')
   610     #man.storageAttach('SecurityDVM')
   611     
   612     
   613     #cmd = "c:\\cygwin64\\bin\\bash.exe --login -c \"/bin/ls\""
   614     #man.execute(cmd)
   615