OpenSecurity/bin/vmmanager.pyw
changeset 212 59ebaa44c12c
parent 193 8d5b7c9ff783
child 213 2e0b94e12bfc
     1.1 --- a/OpenSecurity/bin/vmmanager.pyw	Thu Jun 12 14:08:36 2014 +0200
     1.2 +++ b/OpenSecurity/bin/vmmanager.pyw	Thu Jul 17 10:20:10 2014 +0100
     1.3 @@ -1,8 +1,37 @@
     1.4 -'''
     1.5 -Created on Nov 19, 2013
     1.6 +#!/bin/env python
     1.7 +# -*- coding: utf-8 -*-
     1.8  
     1.9 -@author: BarthaM
    1.10 -'''
    1.11 +# ------------------------------------------------------------
    1.12 +# opensecurityd
    1.13 +#   
    1.14 +# the opensecurityd as RESTful server
    1.15 +#
    1.16 +# Autor: Mihai Bartha, <mihai.bartha@ait.ac.at>
    1.17 +#
    1.18 +# Copyright (C) 2013 AIT Austrian Institute of Technology
    1.19 +# AIT Austrian Institute of Technology GmbH
    1.20 +# Donau-City-Strasse 1 | 1220 Vienna | Austria
    1.21 +# http://www.ait.ac.at
    1.22 +#
    1.23 +# This program is free software; you can redistribute it and/or
    1.24 +# modify it under the terms of the GNU General Public License
    1.25 +# as published by the Free Software Foundation version 2.
    1.26 +# 
    1.27 +# This program is distributed in the hope that it will be useful,
    1.28 +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    1.29 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    1.30 +# GNU General Public License for more details.
    1.31 +# 
    1.32 +# You should have received a copy of the GNU General Public License
    1.33 +# along with this program; if not, write to the Free Software
    1.34 +# Foundation, Inc., 51 Franklin Street, Fifth Floor, 
    1.35 +# Boston, MA  02110-1301, USA.
    1.36 +# ------------------------------------------------------------
    1.37 +
    1.38 +
    1.39 +# ------------------------------------------------------------
    1.40 +# imports
    1.41 +
    1.42  import os
    1.43  import os.path
    1.44  from subprocess import Popen, PIPE, call, STARTUPINFO, _subprocess
    1.45 @@ -27,6 +56,7 @@
    1.46  import win32wnet
    1.47  import urllib
    1.48  import urllib2
    1.49 +import unittest
    1.50  DEBUG = True
    1.51  
    1.52  
    1.53 @@ -64,7 +94,14 @@
    1.54      
    1.55      #def __getitem__(self, item):
    1.56      #    return self.coords[item]
    1.57 - 
    1.58 +def once(theClass):
    1.59 +    theClass.systemProperties = theClass.getSystemProperties()
    1.60 +    theClass.machineFolder =    theClass.systemProperties["Default machine folder"]
    1.61 +    theClass.hostonlyIFs =      theClass.getHostOnlyIFs()
    1.62 +    theClass.blacklistedRSD =   theClass.loadRSDBlacklist()
    1.63 +    return theClass
    1.64 +    
    1.65 +@once
    1.66  class VMManager(object):
    1.67      vmRootName = "SecurityDVM"
    1.68      systemProperties = None
    1.69 @@ -78,14 +115,9 @@
    1.70  
    1.71   
    1.72      def __init__(self):
    1.73 -        self.systemProperties = self.getSystemProperties()
    1.74 -        self.machineFolder = self.systemProperties["Default machine folder"]
    1.75 -        self.hostonlyIFs = self.getHostOnlyIFs()
    1.76 -        VMManager.blacklistedRSD = self.loadRSDBlacklist()
    1.77          # only proceed if we have a working background environment
    1.78          if self.backend_ok():
    1.79              self.cleanup()
    1.80 -            self.start()
    1.81          else:
    1.82              logger.critical(self.status_message)
    1.83      
    1.84 @@ -116,24 +148,24 @@
    1.85      
    1.86      # return the folder containing the guest VMs     
    1.87      def getMachineFolder(self):
    1.88 -        return self.machineFolder
    1.89 +        return VMManager.machineFolder
    1.90  
    1.91      def backend_ok(self):
    1.92  
    1.93          """check if the backend (VirtualBox) is sufficient for our task"""
    1.94  
    1.95          # ensure we have our system props
    1.96 -        if self.systemProperties == None:
    1.97 -            self.systemProperties = self.getSystemProperties()
    1.98 -        if self.systemProperties == None:
    1.99 +        if VMManager.systemProperties == None:
   1.100 +            VMManager.systemProperties = self.getSystemProperties()
   1.101 +        if VMManager.systemProperties == None:
   1.102              self.status_message = 'Failed to get backend system properties. Is Backend (VirtualBox?) installed?'
   1.103              return False
   1.104  
   1.105          # check for existing Extension pack
   1.106 -        if not 'Remote desktop ExtPack' in self.systemProperties:
   1.107 +        if not 'Remote desktop ExtPack' in VMManager.systemProperties:
   1.108              self.status_message = 'No remote desktop extension pack found. Please install the "Oracle VM VirtualBox Extension Pack" from https://www.virtualbox.org/wiki/Downloads.'
   1.109              return False
   1.110 -        if self.systemProperties['Remote desktop ExtPack'] == 'Oracle VM VirtualBox Extension Pack ':
   1.111 +        if VMManager.systemProperties['Remote desktop ExtPack'] == 'Oracle VM VirtualBox Extension Pack ':
   1.112              self.status_message = 'Unsure if suitable extension pack is installed. Please install the "Oracle VM VirtualBox Extension Pack" from https://www.virtualbox.org/wiki/Downloads.'
   1.113              return False
   1.114  
   1.115 @@ -336,11 +368,11 @@
   1.116          if self.isSDVMExisting(vm_name):
   1.117              return
   1.118          #remove eventually existing SDVM folder
   1.119 -        machineFolder = Cygwin.cygPath(self.machineFolder)
   1.120 +        machineFolder = Cygwin.cygPath(VMManager.machineFolder)
   1.121          Cygwin.checkResult(Cygwin.bashExecute('/usr/bin/rm -rf \\\"' + machineFolder + '/' + vm_name + '\\\"'))
   1.122          hostonly_if = self.getHostOnlyIFs()
   1.123          Cygwin.checkResult(Cygwin.vboxExecute('createvm --name ' + vm_name + ' --ostype Debian --register'))
   1.124 -        Cygwin.checkResult(Cygwin.vboxExecute('modifyvm ' + vm_name + ' --memory 512 --vram 10 --cpus 1 --usb on --usbehci on --nic1 hostonly --hostonlyadapter1 \"' + hostonly_if['Name'] + '\" --nic2 nat'))
   1.125 +        Cygwin.checkResult(Cygwin.vboxExecute('modifyvm ' + vm_name + ' --memory 768 --vram 10 --cpus 1 --usb on --usbehci on --nic1 hostonly --hostonlyadapter1 \"' + hostonly_if['Name'] + '\" --nic2 nat'))
   1.126          Cygwin.checkResult(Cygwin.vboxExecute('storagectl ' + vm_name + ' --name SATA --add sata --portcount 2'))
   1.127  
   1.128      #create new SecurityDVM with automatically generated name from template (thread safe)        
   1.129 @@ -354,7 +386,7 @@
   1.130      def storageAttach(self, vm_name):
   1.131          if self.isStorageAttached(vm_name):
   1.132              self.storageDetach(vm_name)
   1.133 -        Cygwin.checkResult(Cygwin.vboxExecute('storageattach ' + vm_name + ' --storagectl SATA --port 0 --device 0 --type hdd --medium \"'+ self.machineFolder + '\SecurityDVM\SecurityDVM.vmdk\"'))
   1.134 +        Cygwin.checkResult(Cygwin.vboxExecute('storageattach ' + vm_name + ' --storagectl SATA --port 0 --device 0 --type hdd --medium \"'+ VMManager.machineFolder + '\SecurityDVM\SecurityDVM.vmdk\"'))
   1.135      
   1.136      # return true if storage is attached 
   1.137      def isStorageAttached(self, vm_name):
   1.138 @@ -379,19 +411,22 @@
   1.139          # check for updates
   1.140          self.genCertificateISO(self.vmRootName)
   1.141          self.attachCertificateISO(self.vmRootName)
   1.142 -        imageUUID = self.getVMInfo(self.vmRootName)["SATA-ImageUUID-0-0"] #TODO: // verify value
   1.143 +        
   1.144 +        #templateUUID = self.getVMInfo(self.vmRootName)["SATA-ImageUUID-0-0"] #TODO: // verify value
   1.145 +        templateUUID = self.getTemplateUUID()
   1.146 +        
   1.147          self.storageDetach(self.vmRootName)
   1.148 -        self.removeSnapshots(imageUUID)
   1.149 +        self.removeSnapshots(templateUUID)
   1.150          
   1.151 -        template_storage = self.machineFolder + '\\' + self.vmRootName + '\\' + self.vmRootName + '.vmdk'
   1.152 +        template_storage = VMManager.machineFolder + '\\' + self.vmRootName + '\\' + self.vmRootName + '.vmdk'
   1.153          #TODO:// modify to take vm name as argument
   1.154          self.changeStorageType(template_storage,'normal')
   1.155          self.storageAttach(self.vmRootName)
   1.156          self.startVM(self.vmRootName)
   1.157 -        self.waitStartup(self.vmRootName)
   1.158 +        self.waitStartup(self.vmRootName, timeout_ms = 30000)
   1.159          
   1.160          tmp_ip = self.getHostOnlyIP(self.vmRootName)
   1.161 -        tmp_machine_folder = Cygwin.cygPath(self.machineFolder)
   1.162 +        tmp_machine_folder = Cygwin.cygPath(VMManager.machineFolder)
   1.163          Cygwin.checkResult(Cygwin.sshExecute('"sudo apt-get -y update"', tmp_ip, 'osecuser', tmp_machine_folder + '/' + self.vmRootName + '/dvm_key'))
   1.164          Cygwin.checkResult(Cygwin.sshExecute('"sudo apt-get -y upgrade"', tmp_ip, 'osecuser', tmp_machine_folder + '/' + self.vmRootName + '/dvm_key'))
   1.165          
   1.166 @@ -403,17 +438,19 @@
   1.167              self.startVM(self.vmRootName)
   1.168              self.waitStartup(self.vmRootName)
   1.169          
   1.170 -        self.hibernateVM(self.vmRootName)
   1.171 +        #self.hibernateVM(self.vmRootName)
   1.172 +        self.stopVM(self.vmRootName)
   1.173          self.waitShutdown(self.vmRootName)
   1.174          self.storageDetach(self.vmRootName)
   1.175          self.changeStorageType(template_storage,'immutable')
   1.176          self.storageAttach(self.vmRootName)
   1.177          
   1.178 -        self.start()
   1.179 +        #self.start()
   1.180  
   1.181      #"SATA-0-0"="C:\Users\BarthaM\VirtualBox VMs\SecurityDVM\Snapshots\{d0af827d-f13a-49be-8ac1-df20b13bda83}.vmdk"
   1.182 -    #"SATA-ImageUUID-0-0"="d0af827d-f13a-49be-8ac1-df20b13bda83"    
   1.183 -    def getDiskImages(self):
   1.184 +    #"SATA-ImageUUID-0-0"="d0af827d-f13a-49be-8ac1-df20b13bda83"
   1.185 +    @staticmethod    
   1.186 +    def getDiskImages():
   1.187          results = Cygwin.checkResult(Cygwin.vboxExecute('list hdds'))[1]
   1.188          results = results.replace('Parent UUID', 'Parent')
   1.189          items = list( "UUID:"+result for result in results.split('UUID:') if result != '')
   1.190 @@ -428,9 +465,10 @@
   1.191              snaps[props['UUID']] = props
   1.192          return snaps
   1.193      
   1.194 -    def getTemplateUUID(self):
   1.195 -        images = self.getDiskImages()
   1.196 -        template_storage = self.machineFolder + '\\' + self.vmRootName + '/' +self.vmRootName + '.vmdk'
   1.197 +    @staticmethod 
   1.198 +    def getTemplateUUID():
   1.199 +        images = VMManager.getDiskImages()
   1.200 +        template_storage = VMManager.machineFolder + '\\' + VMManager.vmRootName + '\\' + VMManager.vmRootName + '.vmdk'
   1.201          # find template uuid
   1.202          template_uuid = None
   1.203          for hdd in images.values():
   1.204 @@ -462,18 +500,19 @@
   1.205          self.removeVMFolder(vm_name)
   1.206      
   1.207      def removeVMFolder(self, vm_name):
   1.208 -        machineFolder = Cygwin.cygPath(self.machineFolder)
   1.209 +        machineFolder = Cygwin.cygPath(VMManager.machineFolder)
   1.210          Cygwin.checkResult(Cygwin.bashExecute('/usr/bin/rm -rf \\\"' + machineFolder + '/' + vm_name + '\\\"'))
   1.211      
   1.212      # start VM
   1.213      def startVM(self, vm_name):
   1.214          logger.info('Starting ' +  vm_name)
   1.215 -        result = Cygwin.checkResult(Cygwin.vboxExecute('startvm ' + vm_name + ' --type headless' ))
   1.216 +        #TODO: modify to use Cygwin.checkResult() of make it retry 3 times
   1.217 +        result = Cygwin.vboxExecute('startvm ' + vm_name + ' --type headless' )
   1.218          while 'successfully started' not in result[1]:
   1.219              logger.error("Failed to start SDVM: " + vm_name + " retrying")
   1.220              logger.error("Command returned:\n" + result[2])
   1.221              time.sleep(1)
   1.222 -            result = Cygwin.checkResult(Cygwin.vboxExecute('startvm ' + vm_name + ' --type headless'))
   1.223 +            result = Cygwin.vboxExecute('startvm ' + vm_name + ' --type headless')
   1.224          return result[0]
   1.225      
   1.226      # return wether VM is running or not
   1.227 @@ -483,12 +522,12 @@
   1.228      # stop VM
   1.229      def stopVM(self, vm_name):
   1.230          logger.info('Sending shutdown signal to ' + vm_name)
   1.231 -        Cygwin.checkResult(Cygwin.sshExecute( '"sudo shutdown -h now"', self.getHostOnlyIP(vm_name), 'osecuser', Cygwin.cygPath(self.machineFolder) + '/' + vm_name + '/dvm_key' ))
   1.232 +        Cygwin.checkResult(Cygwin.sshExecute( '"sudo shutdown -h now"', self.getHostOnlyIP(vm_name), 'osecuser', Cygwin.cygPath(VMManager.machineFolder) + '/' + vm_name + '/dvm_key' ))
   1.233      
   1.234      # stop VM
   1.235      def hibernateVM(self, vm_name):
   1.236          logger.info('Sending hibernate-disk signal to ' + vm_name)
   1.237 -        Cygwin.checkResult(Cygwin.sshBackgroundExecute( '"sudo hibernate-disk"', self.getHostOnlyIP(vm_name), 'osecuser', Cygwin.cygPath(self.machineFolder) + '/' + vm_name + '/dvm_key', wait_return=False))
   1.238 +        Cygwin.checkResult(Cygwin.sshBackgroundExecute( '"sudo hibernate-disk"', self.getHostOnlyIP(vm_name), 'osecuser', Cygwin.cygPath(VMManager.machineFolder) + '/' + vm_name + '/dvm_key', wait_return=False))
   1.239              
   1.240      # poweroff VM
   1.241      def poweroffVM(self, vm_name):
   1.242 @@ -502,7 +541,7 @@
   1.243          if vm_name == None:
   1.244              logger.info('Getting hostOnly IP address for Host')
   1.245              #TODO:// optimise to store on init local variable and return that value (avoid calling list hostonlyifs)
   1.246 -            return self.hostonlyIFs['IPAddress']
   1.247 +            return VMManager.hostonlyIFs['IPAddress']
   1.248          else:
   1.249              logger.info('Getting hostOnly IP address ' + vm_name)
   1.250              result = Cygwin.checkResult(Cygwin.vboxExecute('guestproperty get ' + vm_name + ' /VirtualBox/GuestInfo/Net/0/V4/IP'))
   1.251 @@ -521,7 +560,7 @@
   1.252      
   1.253      #generates ISO containing authorized_keys for use with guest VM
   1.254      def genCertificateISO(self, vm_name):
   1.255 -        machineFolder = Cygwin.cygPath(self.machineFolder)
   1.256 +        machineFolder = Cygwin.cygPath(VMManager.machineFolder)
   1.257          # remove .ssh folder if exists
   1.258          Cygwin.checkResult(Cygwin.bashExecute('/usr/bin/rm -rf \\\"' + machineFolder + '/' + vm_name + '/.ssh\\\"'))
   1.259          # remove .ssh folder if exists
   1.260 @@ -543,12 +582,12 @@
   1.261      
   1.262      # attaches generated ssh public cert to guest vm
   1.263      def attachCertificateISO(self, vm_name):
   1.264 -        result = Cygwin.checkResult(Cygwin.vboxExecute('storageattach ' + vm_name + ' --storagectl SATA --port 1 --device 0 --type dvddrive --mtype readonly --medium \"' + self.machineFolder + '\\' + vm_name + '\\'+ vm_name + '.iso\"'))
   1.265 +        result = Cygwin.checkResult(Cygwin.vboxExecute('storageattach ' + vm_name + ' --storagectl SATA --port 1 --device 0 --type dvddrive --mtype readonly --medium \"' + VMManager.machineFolder + '\\' + vm_name + '\\'+ vm_name + '.iso\"'))
   1.266          return result
   1.267      
   1.268      # wait for machine to come up
   1.269 -    def waitStartup(self, vm_name, timeout_ms = 30000):
   1.270 -        Cygwin.checkResult(Cygwin.vboxExecute('guestproperty wait ' + vm_name + ' SDVMStarted --timeout ' + str(timeout_ms) + ' --fail-on-timeout'))
   1.271 +    def waitStartup(self, vm_name, timeout_ms = 1000):
   1.272 +        Cygwin.checkResult(Cygwin.vboxExecute('guestproperty wait ' + vm_name + ' SDVMStarted --timeout ' + str(timeout_ms) + ' --fail-on-timeout', try_count = 60))
   1.273          return self.getHostOnlyIP(vm_name)
   1.274      
   1.275      # wait for machine to shutdown
   1.276 @@ -681,7 +720,6 @@
   1.277          command = '-r -o StrictHostKeyChecking=no -i "' + certificate + '" "' + src + '" "osecuser@' + self.browsingManager.ip_addr + ':' + dest + '"'
   1.278          return Cygwin.execute(Cygwin.cygwin_scp, command, wait_return=True, window=False)    
   1.279  
   1.280 -
   1.281  #handles browsing session creation 
   1.282  class BrowsingHandler(threading.Thread):
   1.283      vmm = None
   1.284 @@ -748,8 +786,10 @@
   1.285                  self.vmm.storageAttach(self.vm_name)
   1.286                  self.vmm.genCertificateISO(self.vm_name)
   1.287                  self.vmm.attachCertificateISO(self.vm_name)
   1.288 +                
   1.289                  self.vmm.startVM(self.vm_name)
   1.290 -                self.ip_addr = self.vmm.waitStartup(self.vm_name)
   1.291 +                
   1.292 +                self.ip_addr = self.vmm.waitStartup(self.vm_name, timeout_ms=30000)
   1.293                  if self.ip_addr == None:
   1.294                      logger.error("Failed to get ip address")
   1.295                      continue
   1.296 @@ -797,8 +837,12 @@
   1.297                  self.started.set()
   1.298                  logger.info("Browsing SDVM running.")
   1.299                  self.restart.wait()
   1.300 +            except OpenSecurityException, e:
   1.301 +                logger.error(''.join(e))
   1.302              except:
   1.303 +                logger.error("Unexpected error: " + sys.exc_info()[0])
   1.304                  logger.error("BrowsingHandler failed. Cleaning up")
   1.305 +                #self.running= False
   1.306                  
   1.307  class DeviceHandler(threading.Thread): 
   1.308      vmm = None
   1.309 @@ -881,82 +925,3 @@
   1.310                          continue
   1.311                      
   1.312              self.existingRSDs = tmp_rsds
   1.313 -                        
   1.314 -
   1.315 -if __name__ == '__main__':
   1.316 -    #man = VMManager.getInstance()
   1.317 -    #man.listVM()
   1.318 -    #print man.getConnectedRSDs()
   1.319 -    #print man.getNetworkDrives()
   1.320 -    #man.genNetworkDrive()
   1.321 -    #drive_bitmask = ctypes.cdll.kernel32.GetLogicalDrives()
   1.322 -    #print list(itertools.compress(string.ascii_uppercase,  map(lambda x:ord(x) - ord('0'), bin(drive_bitmask)[:1:-1])))
   1.323 -    #print list(map(chr, range(68, 91))) 
   1.324 -    #print Cygwin.getRegEntry('SYSTEM\CurrentControlSet\Enum\USB', 'VID_1058&PID_0704')[0]
   1.325 -    #devices = VMManager.getConnectedRSDS()
   1.326 -    #print devices
   1.327 -    
   1.328 -    drives = VMManager.getLogicalDrives()
   1.329 -    print drives
   1.330 -    print VMManager.getDriveType("E")
   1.331 -    print VMManager.getVolumeInfo("E")
   1.332 -    print VMManager.getNetworkPath("E")
   1.333 -    
   1.334 -    #vmm.backupFile()
   1.335 -    #for device in devices.values():
   1.336 -    #    #print device
   1.337 -    #    if VMManager.isMassStorageDevice(device):
   1.338 -    #        print device
   1.339 -        
   1.340 -    
   1.341 -    
   1.342 -    #time.sleep(-1)
   1.343 -    #man.listVM()
   1.344 -    #man.listVM()
   1.345 -    #man.listVM()
   1.346 -    #man.listVM()
   1.347 -    #man.genCertificateISO('SecurityDVM0')
   1.348 -    #man.guestExecute('SecurityDVM0', '/bin/ls -la')
   1.349 -    #logger = setupLogger('VMManager')
   1.350 -    #c = Cygwin()
   1.351 -    
   1.352 -    #man.sshExecute('/bin/ls -la', 'SecurityDVM0')
   1.353 -    #man.sshExecuteX11('/usr/bin/iceweasel', 'SecurityDVM0')
   1.354 -    #man.removeVM('SecurityDVM0')
   1.355 -    #man.netUse('192.168.56.134', 'USB\\')
   1.356 -    #ip = '192.168.56.139'
   1.357 -    
   1.358 -    #man.cygwin_path = 'c:\\cygwin64\\bin\\'
   1.359 -    #man.handleDeviceChange()
   1.360 -    #print man.listSDVM()
   1.361 -    #man.configureHostNetworking()
   1.362 -    #new_vm = man.generateSDVMName()
   1.363 -    #man.createVM(new_vm)
   1.364 -    
   1.365 -    #print Cygwin.cmd()
   1.366 -    #man.isAvailable('c:')
   1.367 -    #ip = man.getHostOnlyIP('SecurityDVM0')
   1.368 -    #man.mapNetworkDrive('h:', '\\\\' + ip + '\Download', None, None)
   1.369 -    
   1.370 -    #man.genCertificateISO(new_vm)
   1.371 -    #man.attachCertificateISO(new_vm)
   1.372 -    
   1.373 -    #man.attachCertificateISO(vm_name)
   1.374 -    #man.guestExecute(vm_name, "ls")
   1.375 -    #man.sshGuestX11Execute('SecurityDVM1', '/usr/bin/iceweasel')
   1.376 -    #time.sleep(60)
   1.377 -    #print man.cygwinPath("C:\Users\BarthaM\VirtualBox VMs\SecurityDVM\.ssh\*")
   1.378 -    #man.genCertificateISO('SecurityDVM')
   1.379 -    #man.attachCertificateISO('SecurityDVM')
   1.380 -    #man.isStorageAttached('SecurityDVM')
   1.381 -    #man.guestExecute('SecurityDVM', 'sudo apt-get -y update')
   1.382 -    #man.guestExecute('SecurityDVM', 'sudo apt-get -y upgrade' )
   1.383 -    
   1.384 -    #man.stopVM('SecurityDVM')
   1.385 -    #man.storageDetach('SecurityDVM')
   1.386 -    #man.changeStorageType('C:\Users\BarthaM\VirtualBox VMs\SecurityDVM\SecurityDVM.vmdk','immutable')
   1.387 -    #man.storageAttach('SecurityDVM')
   1.388 -    
   1.389 -    
   1.390 -    #cmd = "c:\\cygwin64\\bin\\bash.exe --login -c \"/bin/ls\""
   1.391 -    #man.execute(cmd)