class VirtualBox(Wrapper): # Properties directly inherited from IVirtualMachine _passthruProperties = [ "homeFolder", "packageType", "revision", "settingsFilePath", "version", # Also allow direct access to these methods. These shouldn't # be used directly, buy only by other pyVBox classes. "createMachine", "findMachine", "getMachine", "openExistingSession", "openMachine", "openRemoteSession", "openSession", "registerMachine", ] def __init__(self): self._manager = VirtualBoxManager() self._wrappedInstance = self._manager.getIVirtualBox() def getGuestOSType(self, osTypeId): """Returns an object describing the specified guest OS type.""" iosType = self._wrappedInstance.getGuestOSType(osTypeId) return GuestOSType(iosType) @property def guestOSTypes(self): """Return an array of all available guest OS Types.""" return [GuestOSType(t) for t in self._getArray('guestOSTypes')] @property def machines(self): """Return array of machine objects registered within this VirtualBox instance.""" from VirtualMachine import VirtualMachine return [VirtualMachine(vm) for vm in self._getArray('machines')] def waitForEvent(self): self._manager.waitForEvents() def _getArray(self, arrayName): """Return the array identified by the given name""" return self._manager.getArray(self._wrappedInstance, arrayName)
class VirtualBoxMonitor: def __init__(self, vbox): self._vbox = vbox self._manager = VirtualBoxManager() self._isMscom = self._manager.isMSCOM() def onMachineStateChange(self, id, state): pass def onMachineDataChange(self, id): pass def onExtraDataCanChange(self, id, key, value): # Witty COM bridge thinks if someone wishes to return tuple, hresult # is one of values we want to return if self._isMscom: return "", 0, True else: return True, "" def onExtraDataChange(self, id, key, value): pass def onMediaRegistered(self, id, type, registered): pass def onMachineRegistered(self, id, registred): pass def onSessionStateChange(self, id, state): pass def onSnapshotTaken(self, mach, id): pass def onSnapshotDiscarded(self, mach, id): pass def onSnapshotChange(self, mach, id): pass def onGuestPropertyChange(self, id, name, newValue, flags): pass
class VirtualMachine(Wrapper): # Properties directly inherited from IMachine _passthruProperties = [ "accelerate2DVideoEnabled", "accelerate3DEnabled", "accessible", "CPUCount", "currentStateModified", "description", "guestPropertyNotificationPatterns", "HardwareVersion", "hardwareUUID", "id", "lastStateChange", "lockMachine", "logFolder", "memorySize", "monitorCount", "name", "OSTypeId", "sessionPid", "sessionState", "sessionType", "settingsFilePath", "settingsModified", "snapshotCount", "snapshotFolder", "state", "stateFilePath", "statisticsUpdateInterval", "teleporterAddress", "teleporterEnabled", "teleporterPassword", "teleporterPort", "unregister", "VRAMSize", ] _manager = VirtualBoxManager() _vbox = VirtualBox() def __init__(self, machine, session=None): """Return a VirtualMachine wrapper around given IMachine instance""" self._wrappedInstance = machine def __del__(self): pass def __str__(self): return self.name # # Top-level controls # def pause(self, wait=False): """Pause a running VM. If wait is True, then wait until machine is actually paused before returning.""" with self.lock() as session: with VirtualBoxException.ExceptionHandler(): session.console.pause() # XXX Note sure if we need a lock for this or not if wait: self.waitUntilPaused() def resume(self): """Resume a paused VM.""" with self.lock() as session: with VirtualBoxException.ExceptionHandler(): session.console.resume() def powerOff(self, wait=False): """Power off a running VM. If wait is True, then wait for power down and session closureto complete.""" with self.lock() as session: with VirtualBoxException.ExceptionHandler(): session.console.powerDown() # XXX Not sure we need a lock for the following if wait: self.waitUntilDown() self.waitUntilUnlocked() def powerOn(self, type="gui", env=""): """Spawns a new process that executes a virtual machine. This is spawning a "remote session" in VirtualBox terms.""" # TODO: Add a wait argument if not self.isRegistered(): raise VirtualBoxException.VirtualBoxInvalidVMStateException( "VM is not registered") with VirtualBoxException.ExceptionHandler(): iMachine = self.getIMachine() session = Session.create() iprogress = iMachine.launchVMProcess(session.getISession(), type, env) progress = Progress(iprogress) progress.waitForCompletion() session.unlockMachine() def eject(self): """Do what ever it takes to unregister the VM""" if not self.isRegistered(): # Nothing to do return if self.isRunning(): self.powerOff(wait=True) self.unregister(cleanup_mode=Constants.CleanupMode_DetachAllReturnNone) def delete(self): """Delete the VM. VM must be locked or unregistered""" with VirtualBoxException.ExceptionHandler(): iMachine = self.getIMachine() iprogress = iMachine.delete(None) progress = Progress(iprogress) progress.waitForCompletion() # # Creation methods # @classmethod def open(cls, path): """Opens a virtual machine from the existing settings file. Note that calling open() on a VM that is already registered will throw a VirtualBoxFileNotFoundException except. Throws VirtualBoxFileNotFoundException if file not found.""" with VirtualBoxException.ExceptionHandler(): path = cls._canonicalizeVMPath(path) machine = cls._vbox.openMachine(path) return VirtualMachine(machine) @classmethod def find(cls, nameOrId): """Attempts to find a virtual machine given its name or UUID.""" with VirtualBoxException.ExceptionHandler(): machine = cls._vbox.findMachine(nameOrId) return VirtualMachine(machine) @classmethod def get(cls, id): """Attempts to find a virtual machine given its UUID.""" return cls.find(id) @classmethod def create(cls, name, osTypeId, settingsFile=None, id=None, register=True, forceOverwrite=False): """Create a new virtual machine with the given name and osType. If settingsFile is not None, it should be a path to use instead of the default for the settings file. If id is not None, it will be used as the UUID of the machine. Otherwise one will be automatically generated. If register is True, register machine after creation.""" with VirtualBoxException.ExceptionHandler(): machine = cls._vbox.createMachine(settingsFile, name, osTypeId, id, forceOverwrite) vm = VirtualMachine(machine) vm.saveSettings() if register: vm.register() return vm def clone(self, name, settingsFile=None, id=None, register=True, description=None): """Clone this virtual machine as new VM with given name. Clones basic properties of machine plus any storage controllers. Does not clone any attached storage. If settingsFile is not None, it should be a path to use instead of the default for the settingsFile If id is not None, it will be used as the UUID of the new machine. Otherwise one will be automatically generated. If register is True, register new machine after creation. If description is None, copy description from source, otherwise use description.""" vm = VirtualMachine.create(name, self.OSTypeId, settingsFile=settingsFile, id=id, # Once we register, we cannot make # changes without opening a # session, so defer any # registration. register=False) if description: vm.description = description else: vm.description = self.description vm.CPUCount = self.CPUCount vm.memorySize = self.memorySize vm.VRAMSize = self.VRAMSize vm.accelerate3DEnabled = self.accelerate3DEnabled vm.accelerate2DVideoEnabled = self.accelerate2DVideoEnabled vm.monitorCount = self.monitorCount controllers = self.getStorageControllers() vm.register() for controller in controllers: vm.addStorageController(controller.bus, name = controller.name) if not register: clone.unregister() return vm @classmethod def getAll(cls): """Return an array of all known virtual machines""" return [VirtualMachine(vm) for vm in cls._vbox.machines] # # Registration methods # def register(self): """Registers the machine within this VirtualBox installation.""" with VirtualBoxException.ExceptionHandler(): self._vbox.registerMachine(self.getIMachine()) def unregister(self, cleanup_mode=Constants.CleanupMode_DetachAllReturnNone): """Unregisters the machine previously registered using register().""" with VirtualBoxException.ExceptionHandler(): machine = self.getIMachine() machine.unregister(cleanup_mode) def isRegistered(self): """Is this virtual machine registered?""" from VirtualBoxException import VirtualBoxObjectNotFoundException try: VirtualMachine.get(self.id) registered = True except VirtualBoxObjectNotFoundException, e: registered = False except Exception, e: raise
def __init__(self, vbox): self._vbox = vbox self._manager = VirtualBoxManager() self._isMscom = self._manager.isMSCOM()
def __init__(self): self._manager = VirtualBoxManager() self._wrappedInstance = self._manager.getIVirtualBox()
class Session(Wrapper): # Properties directly inherited from IMachine _passthruProperties = [ "console", "state", "type", ] _manager = VirtualBoxManager() _vbox = VirtualBox() def __init__(self, isession): self._wrappedInstance = isession self._machine = None @classmethod def create(cls): """Return a new Session instance""" return cls(cls._createSession()) @classmethod def _createSession(cls): """Create and return an ISesison object.""" return cls._manager.mgr.getSessionObject(cls._vbox) def __del__(self): self.unlockMachine(wait=False) def saveSettings(self): """Save changes to VM associated with session.""" with VirtualBoxException.ExceptionHandler(): self.getIMachine().saveSettings() def _setMachine(self, machine): """Set the machine associated with this session.""" self._machine = machine def getMachine(self): """Return the mutable machine associated with the session.""" return self._machine def unlockMachine(self, wait=True): """Close any open session, unlocking the machine.""" if self.isLocked(): with VirtualBoxException.ExceptionHandler(): self._wrappedInstance.unlockMachine() if wait: while self.isLocked(): self._vbox.waitForEvent() def getISession(self): """Return ISession instance wrapped by Session""" return self._wrappedInstance def getIMachine(self): """Return mutable IMachine object associated with session.""" return self._wrappedInstance.machine def isDirect(self): """Is this a direct session?""" return (self.type != Constants.SessionType_Remote) def isLocked(self): """Is this session locked?""" return (self.state == Constants.SessionState_Locked) def isUnlocked(self): """Is this session unlocked?""" return (self.state == Constants.SessionState_Unlocked)
class Medium(Wrapper): # Properties directly inherited from IMedium _passthruProperties = [ "autoResize", "description", "format", "hostDrive", "id", "lastAccessError", "location", "logicalSize", "name", "readOnly", "size", "state", "type" ] # These properties are converted by given function before being returned. _wrappedProperties = [ ("deviceType", Device.class_from_type), ] _manager = VirtualBoxManager() def __init__(self, imedium): """Return a Medium wrapper around given IMedium instance""" assert(imedium is not None) self._wrappedInstance = imedium # # Creation methods # @classmethod def open(cls, path, deviceType, accessMode = None, forceNewUuid=False): """Opens a medium from an existing location. Throws VirtualBoxFileError if file not found.""" with VirtualBoxException.ExceptionHandler(): if accessMode is None: accessMode = Constants.AccessMode_ReadWrite # path must be absolute path path = cls._canonicalizeMediumPath(path) medium = cls._getVBox().openMedium(path, deviceType, accessMode, forceNewUuid) return Medium(medium) @classmethod def find(cls, path, deviceType): """Returns a medium that uses the given path or UUID to store medium data.""" with VirtualBoxException.ExceptionHandler(): if not UUID.isUUID(path): path = cls._canonicalizeMediumPath(path) medium = cls._getVBox().findMedium(path, deviceType) return Medium(medium) def clone(self, path, newUUID=True, wait=True): """Create a clone of this medium at the given location. If wait is True, does not return until process completes. if newUUID is true, clone will have new UUID and will be registered, otherwise will have same UUID as source medium. Returns Progress instance.""" with VirtualBoxException.ExceptionHandler(): path = self._canonicalizeMediumPath(path) if newUUID: # If target doesn't have storage, new UUID is created. target= self.create(path) else: # If target does have storage, UUID is copied. target = self.createWithStorage(path, self.logicalSize) progress = self.cloneTo(target, wait=wait) if wait: progress.waitForCompletion() return progress @classmethod def create(cls, path, format=None): """Create a new hard disk at the given location.""" with VirtualBoxException.ExceptionHandler(): path = cls._canonicalizeMediumPath(path) if os.path.exists(path): # Todo: Better exception here raise VirtualBoxException.VirtualBoxException( "Cannot create %s - file already exists." % path) with VirtualBoxException.ExceptionHandler(): # Despire the name of this method it returns an IMedium # instance imedium = cls._getVBox().createHardDisk(format, path) return cls(imedium) @classmethod def createWithStorage(cls, path, size, format=None, variant=None, wait=True): """Create a new hard disk at given location with given size (in MB). This is a wrapper around the create() and createBaseStorage() methods.""" disk = cls.create(path, format) disk.createBaseStorage(size, variant, wait) return disk def getIMedium(self): """Return IMedium object.""" return self._wrappedInstance def close(self): """Closes this medium.""" self._wrappedInstance.close() def basename(self): """Return the basename of the location of the storage unit holding medium data.""" return os.path.basename(self.location) def dirname(self): """Return the dirname of the location of the storage unit holding medium data.""" return os.path.dirname(self.location) # # Internal string representations # def __str__(self): return self.name # IMedium apparently defines this and its method will sometimes # be called in preference to our __str__() method. def __unicode__(self): return self.name # # Instantiation of other methods # def cloneTo(self, target, variant=None, parent=None, wait=True): """Clone to the target hard drive. Returns Progress instance. If wait is True, does not return until process completes.""" if variant is None: variant = Constants.MediumVariant_Standard with VirtualBoxException.ExceptionHandler(): progress = self.getIMedium().cloneTo(target.getIMedium(), variant, parent) progress = Progress(progress) if wait: progress.waitForCompletion() return progress def createBaseStorage(self, size, variant=None, wait=True): """Create storage for the drive of the given size (in MB). Returns Progress instance. If wait is True, does not return until process completes.""" if variant is None: variant = Constants.MediumVariant_Standard with VirtualBoxException.ExceptionHandler(): progress = self.getIMedium().createBaseStorage(size, variant) progress = Progress(progress) if wait: progress.waitForCompletion() return progress # # Internal methods # @classmethod def _canonicalizeMediumPath(cls, path): """Given a path to a hard drive (or other medium) do any needed clean up.""" # path must be absolute path return os.path.abspath(path) @classmethod def _getVBox(cls): """Return the VirtualBox object associated with this VirtualMachine.""" return cls._manager.getIVirtualBox()