VirtualBox

source: vbox/trunk/src/VBox/Main/glue/vboxapi.py@ 48282

Last change on this file since 48282 was 48282, checked in by vboxsync, 11 years ago

32-bit main API on 64-bit solaris.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 38.1 KB
Line 
1# -*- coding: utf-8 -*-
2# $Id: vboxapi.py 48282 2013-09-04 23:59:15Z vboxsync $
3"""
4VirtualBox Python API Glue.
5"""
6
7__copyright__ = \
8"""
9Copyright (C) 2009-2013 Oracle Corporation
10
11This file is part of VirtualBox Open Source Edition (OSE), as
12available from http://www.virtualbox.org. This file is free software;
13you can redistribute it and/or modify it under the terms of the GNU
14General Public License (GPL) as published by the Free Software
15Foundation, in version 2 as it comes in the "COPYING" file of the
16VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18"""
19__version__ = "$Revision: 48282 $"
20
21
22# Note! To set Python bitness on OSX use 'export VERSIONER_PYTHON_PREFER_32_BIT=yes'
23
24
25# Standard Python imports.
26import sys, os
27import traceback
28
29
30#
31# Globals, environment and sys.path changes.
32#
33VBoxBinDir = os.environ.get("VBOX_PROGRAM_PATH", None)
34VBoxSdkDir = os.environ.get("VBOX_SDK_PATH", None)
35
36if VBoxBinDir is None:
37 # Will be set by the installer
38 VBoxBinDir = "%VBOX_INSTALL_PATH%"
39else:
40 VBoxBinDir = os.path.abspath(VBoxBinDir);
41
42if VBoxSdkDir is None:
43 # Will be set by the installer
44 VBoxSdkDir = "%VBOX_SDK_PATH%"
45else:
46 VBoxBinDir = os.path.abspath(VBoxSdkDir);
47
48os.environ["VBOX_PROGRAM_PATH"] = VBoxBinDir
49os.environ["VBOX_SDK_PATH"] = VBoxSdkDir
50sys.path.append(VBoxBinDir)
51
52
53#
54# Import the generated VirtualBox constants.
55#
56from VirtualBox_constants import VirtualBoxReflectionInfo
57
58
59class PerfCollector(object):
60 """ This class provides a wrapper over IPerformanceCollector in order to
61 get more 'pythonic' interface.
62
63 To begin collection of metrics use setup() method.
64
65 To get collected data use query() method.
66
67 It is possible to disable metric collection without changing collection
68 parameters with disable() method. The enable() method resumes metric
69 collection.
70 """
71
72 def __init__(self, mgr, vbox):
73 """ Initializes the instance.
74
75 """
76 self.mgr = mgr
77 self.isMscom = (mgr.type == 'MSCOM')
78 self.collector = vbox.performanceCollector
79
80 def setup(self, names, objects, period, nsamples):
81 """ Discards all previously collected values for the specified
82 metrics, sets the period of collection and the number of retained
83 samples, enables collection.
84 """
85 self.collector.setupMetrics(names, objects, period, nsamples)
86
87 def enable(self, names, objects):
88 """ Resumes metric collection for the specified metrics.
89 """
90 self.collector.enableMetrics(names, objects)
91
92 def disable(self, names, objects):
93 """ Suspends metric collection for the specified metrics.
94 """
95 self.collector.disableMetrics(names, objects)
96
97 def query(self, names, objects):
98 """ Retrieves collected metric values as well as some auxiliary
99 information. Returns an array of dictionaries, one dictionary per
100 metric. Each dictionary contains the following entries:
101 'name': metric name
102 'object': managed object this metric associated with
103 'unit': unit of measurement
104 'scale': divide 'values' by this number to get float numbers
105 'values': collected data
106 'values_as_string': pre-processed values ready for 'print' statement
107 """
108 # Get around the problem with input arrays returned in output
109 # parameters (see #3953) for MSCOM.
110 if self.isMscom:
111 (values, names, objects, names_out, objects_out, units, scales, sequence_numbers,
112 indices, lengths) = self.collector.queryMetricsData(names, objects)
113 else:
114 (values, names_out, objects_out, units, scales, sequence_numbers,
115 indices, lengths) = self.collector.queryMetricsData(names, objects)
116 out = []
117 for i in xrange(0, len(names_out)):
118 scale = int(scales[i])
119 if scale != 1:
120 fmt = '%.2f%s'
121 else:
122 fmt = '%d %s'
123 out.append({
124 'name':str(names_out[i]),
125 'object':str(objects_out[i]),
126 'unit':str(units[i]),
127 'scale':scale,
128 'values':[int(values[j]) for j in xrange(int(indices[i]), int(indices[i])+int(lengths[i]))],
129 'values_as_string':'['+', '.join([fmt % (int(values[j])/scale, units[i]) for j in xrange(int(indices[i]), int(indices[i])+int(lengths[i]))])+']'
130 })
131 return out
132
133#
134# Attribute hacks.
135#
136def ComifyName(name):
137 return name[0].capitalize() + name[1:]
138
139
140## This is for saving the original DispatchBaseClass __getattr__ and __setattr__
141# method references.
142_g_dCOMForward = {
143 'getattr': None,
144 'setattr': None,
145}
146
147def _CustomGetAttr(self, sAttr):
148 """ Our getattr replacement for DispatchBaseClass. """
149 # Fastpath.
150 oRet = self.__class__.__dict__.get(sAttr);
151 if oRet != None:
152 return oRet;
153
154 # Try case-insensitivity workaround for class attributes (COM methods).
155 sAttrLower = sAttr.lower();
156 for sKey in self.__class__.__dict__.keys():
157 if sKey.lower() == sAttrLower:
158 self.__class__.__dict__[sAttr] = self.__class__.__dict__[sKey]
159 return getattr(self, sKey)
160
161 # Slow path.
162 try:
163 return _g_dCOMForward['getattr'](self, ComifyName(sAttr))
164 except AttributeError:
165 return _g_dCOMForward['getattr'](self, sAttr)
166
167def _CustomSetAttr(self, sAttr, oValue):
168 """ Our setattr replacement for DispatchBaseClass. """
169 try:
170 return _g_dCOMForward['setattr'](self, ComifyName(sAttr), oValue)
171 except AttributeError:
172 return _g_dCOMForward['setattr'](self, sAttr, oValue)
173
174
175
176class PlatformBase(object):
177 """
178 Base class for the platform specific code.
179 """
180
181 def __init__(self, aoParams):
182 _ = aoParams;
183
184 def getVirtualBox(self):
185 """
186 Gets a the IVirtualBox singleton.
187 """
188 return None;
189
190 def getSessionObject(self, oIVBox):
191 """
192 Get a session object that can be used for opening machine sessions.
193
194 The oIVBox parameter is an getVirtualBox() return value, i.e. an
195 IVirtualBox reference.
196
197 See also openMachineSession.
198 """
199 _ = oIVBox;
200 return None;
201
202 def getType(self):
203 """ Returns the platform type (class name sans 'Platform'). """
204 return None;
205
206 def isRemote(self):
207 """
208 Returns True if remote (web services) and False if local (COM/XPCOM).
209 """
210 return False
211
212 def getArray(self, oInterface, sAttrib):
213 """
214 Retrives the value of the array attribute 'sAttrib' from
215 interface 'oInterface'.
216
217 This is for hiding platform specific differences in attributes
218 returning arrays.
219 """
220 _ = oInterface;
221 _ = sAttrib;
222 return None;
223
224 def initPerThread(self):
225 """
226 Does backend specific initialization for the calling thread.
227 """
228 return True;
229
230 def deinitPerThread(self):
231 """
232 Does backend specific uninitialization for the calling thread.
233 """
234 return True;
235
236 def createListener(self, oImplClass, dArgs):
237 """
238 Instantiates and wraps an active event listener class so it can be
239 passed to an event source for registration.
240
241 oImplClass is a class (type, not instance) which implements
242 IEventListener.
243
244 dArgs is a dictionary with string indexed variables. This may be
245 modified by the method to pass platform specific parameters. Can
246 be None.
247
248 This currently only works on XPCOM. COM support is not possible due to
249 shortcuts taken in the COM bridge code, which is not under our control.
250 Use passive listeners for COM and web services.
251 """
252 _ = oImplClass;
253 _ = dArgs;
254 raise Exception("No active listeners for this platform");
255 return None;
256
257 def waitForEvents(self, cMsTimeout):
258 """
259 Wait for events to arrive and process them.
260
261 The timeout (cMsTimeout) is in milliseconds for how long to wait for
262 events to arrive. A negative value means waiting for ever, while 0
263 does not wait at all.
264
265 Returns 0 if events was processed.
266 Returns 1 if timed out or interrupted in some way.
267 Returns 2 on error (like not supported for web services).
268
269 Raises an exception if the calling thread is not the main thread (the one
270 that initialized VirtualBoxManager) or if the time isn't an integer.
271 """
272 _ = cMsTimeout;
273 return 2;
274
275 def interruptWaitEvents(self):
276 """
277 Interrupt a waitForEvents call.
278 This is normally called from a worker thread to wake up the main thread.
279
280 Returns True on success, False on failure.
281 """
282 return False;
283
284 def deinit(self):
285 """
286 Unitializes the platform specific backend.
287 """
288 return None;
289
290 def queryInterface(self, oIUnknown, sClassName):
291 """
292 IUnknown::QueryInterface wrapper.
293
294 oIUnknown is who to ask.
295 sClassName is the name of the interface we're asking for.
296 """
297 return None;
298
299 #
300 # Error (exception) access methods.
301 #
302
303 def xcptGetStatus(self, oXcpt):
304 """
305 Returns the COM status code from the VBox API given exception.
306 """
307 return None;
308
309 def xcptIsDeadInterface(self, oXcpt):
310 """
311 Returns True if the exception indicates that the interface is dead, False if not.
312 """
313 return False;
314
315 def xcptIsEqual(self, oXcpt, hrStatus):
316 """
317 Checks if the exception oXcpt is equal to the COM/XPCOM status code
318 hrStatus.
319
320 The oXcpt parameter can be any kind of object, we'll just return True
321 if it doesn't behave like a our exception class.
322
323 Will not raise any exception as long as hrStatus and self are not bad.
324 """
325 try:
326 hrXcpt = self.xcptGetStatus(oXcpt);
327 except AttributeError:
328 return False;
329 if hrXcpt == hrStatus:
330 return True;
331
332 # Fudge for 32-bit signed int conversion.
333 if hrStatus > 0x7fffffff and hrStatus <= 0xffffffff and hrXcpt < 0:
334 if (hrStatus - 0x100000000) == hrXcpt:
335 return True;
336 return False;
337
338 def xcptGetMessage(self, oXcpt):
339 """
340 Returns the best error message found in the COM-like exception.
341 Returns None to fall back on xcptToString.
342 Raises exception if oXcpt isn't our kind of exception object.
343 """
344 return None;
345
346 def xcptGetBaseXcpt(self):
347 """
348 Returns the base exception class.
349 """
350 return None;
351
352 def xcptSetupConstants(self, oDst):
353 """
354 Copy/whatever all error constants onto oDst.
355 """
356 return oDst;
357
358 @staticmethod
359 def xcptCopyErrorConstants(oDst, oSrc):
360 """
361 Copy everything that looks like error constants from oDst to oSrc.
362 """
363 for sAttr in dir(oSrc):
364 if sAttr[0].isupper() and (sAttr[1].isupper() or sAttr[1] == '_'):
365 oAttr = getattr(oSrc, sAttr);
366 if type(oAttr) is int:
367 setattr(oDst, sAttr, oAttr);
368 return oDst;
369
370
371
372class PlatformMSCOM(PlatformBase):
373 """
374 Platform specific code for MS COM.
375 """
376
377 ## @name VirtualBox COM Typelib definitions (should be generate)
378 #
379 # @remarks Must be updated when the corresponding VirtualBox.xidl bits
380 # are changed. Fortunately this isn't very often.
381 # @{
382 VBOX_TLB_GUID = '{D7569351-1750-46F0-936E-BD127D5BC264}'
383 VBOX_TLB_LCID = 0
384 VBOX_TLB_MAJOR = 1
385 VBOX_TLB_MINOR = 3
386 ## @}
387
388
389 class ConstantFake(object):
390 """ Class to fake access to constants in style of foo.bar.boo """
391
392 def __init__(self, parent, name):
393 self.__dict__['_parent'] = parent
394 self.__dict__['_name'] = name
395 self.__dict__['_consts'] = {}
396 try:
397 self.__dict__['_depth']=parent.__dict__['_depth']+1
398 except:
399 self.__dict__['_depth']=0
400 if self.__dict__['_depth'] > 4:
401 raise AttributeError
402
403 def __getattr__(self, attr):
404 import win32com
405 from win32com.client import constants
406
407 if attr.startswith("__"):
408 raise AttributeError
409
410 consts = self.__dict__['_consts']
411
412 fake = consts.get(attr, None)
413 if fake != None:
414 return fake
415 try:
416 name = self.__dict__['_name']
417 parent = self.__dict__['_parent']
418 while parent != None:
419 if parent._name is not None:
420 name = parent._name+'_'+name
421 parent = parent._parent
422
423 if name is not None:
424 name += "_" + attr
425 else:
426 name = attr
427 return win32com.client.constants.__getattr__(name)
428 except AttributeError, e:
429 fake = PlatformMSCOM.ConstantFake(self, attr)
430 consts[attr] = fake
431 return fake
432
433
434 class InterfacesWrapper:
435 def __init__(self):
436 self.__dict__['_rootFake'] = PlatformMSCOM.ConstantFake(None, None)
437
438 def __getattr__(self, a):
439 import win32com
440 from win32com.client import constants
441 if a.startswith("__"):
442 raise AttributeError
443 try:
444 return win32com.client.constants.__getattr__(a)
445 except AttributeError, e:
446 return self.__dict__['_rootFake'].__getattr__(a)
447
448 def __init__(self, dParams):
449 PlatformBase.__init__(self, dParams);
450
451 #
452 # Since the code runs on all platforms, we have to do a lot of
453 # importing here instead of at the top of the file where it's normally located.
454 #
455 from win32com import universal
456 from win32com.client import gencache, DispatchBaseClass
457 from win32com.client import constants, getevents
458 import win32com
459 import pythoncom
460 import win32api
461 import winerror
462 from win32con import DUPLICATE_SAME_ACCESS
463 from win32api import GetCurrentThread, GetCurrentThreadId, DuplicateHandle, GetCurrentProcess
464 import threading
465
466 self.winerror = winerror;
467
468 pid = GetCurrentProcess()
469 self.tid = GetCurrentThreadId()
470 handle = DuplicateHandle(pid, GetCurrentThread(), pid, 0, 0, DUPLICATE_SAME_ACCESS)
471 self.handles = []
472 self.handles.append(handle)
473
474 # Hack the COM dispatcher base class so we can modify method and
475 # attribute names to match those in xpcom.
476 if _g_dCOMForward['setattr'] is None:
477 _g_dCOMForward['getattr'] = DispatchBaseClass.__dict__['__getattr__']
478 DispatchBaseClass.__dict__['__getattr__'] = _CustomGetAttr
479 _g_dCOMForward['setattr'] = DispatchBaseClass.__dict__['__setattr__']
480 DispatchBaseClass.__dict__['__setattr__'] = _CustomSetAttr
481
482 # Hack the exception base class so the users doesn't need to check for
483 # XPCOM or COM and do different things.
484 ## @todo
485
486
487 win32com.client.gencache.EnsureDispatch('VirtualBox.Session')
488 win32com.client.gencache.EnsureDispatch('VirtualBox.VirtualBox')
489
490 self.oIntCv = threading.Condition()
491 self.fInterrupted = False;
492
493 _ = dParams;
494
495 def getSessionObject(self, oIVBox):
496 _ = oIVBox
497 import win32com
498 from win32com.client import Dispatch
499 return win32com.client.Dispatch("VirtualBox.Session")
500
501 def getVirtualBox(self):
502 import win32com
503 from win32com.client import Dispatch
504 return win32com.client.Dispatch("VirtualBox.VirtualBox")
505
506 def getType(self):
507 return 'MSCOM'
508
509 def getArray(self, oInterface, sAttrib):
510 return oInterface.__getattr__(sAttrib)
511
512 def initPerThread(self):
513 import pythoncom
514 pythoncom.CoInitializeEx(0)
515
516 def deinitPerThread(self):
517 import pythoncom
518 pythoncom.CoUninitialize()
519
520 def createListener(self, oImplClass, dArgs):
521 if True:
522 raise Exception('no active listeners on Windows as PyGatewayBase::QueryInterface() '
523 'returns new gateway objects all the time, thus breaking EventQueue '
524 'assumptions about the listener interface pointer being constants between calls ');
525 # Did this code ever really work?
526 d = {}
527 d['BaseClass'] = oImplClass
528 d['dArgs'] = dArgs
529 d['tlb_guid'] = PlatformMSCOM.VBOX_TLB_GUID
530 d['tlb_major'] = PlatformMSCOM.VBOX_TLB_MAJOR
531 d['tlb_minor'] = PlatformMSCOM.VBOX_TLB_MINOR
532 str = ""
533 str += "import win32com.server.util\n"
534 str += "import pythoncom\n"
535
536 str += "class ListenerImpl(BaseClass):\n"
537 str += " _com_interfaces_ = ['IEventListener']\n"
538 str += " _typelib_guid_ = tlb_guid\n"
539 str += " _typelib_version_ = tlb_major, tlb_minor\n"
540 str += " _reg_clsctx_ = pythoncom.CLSCTX_INPROC_SERVER\n"
541 # Maybe we'd better implement Dynamic invoke policy, to be more flexible here
542 str += " _reg_policy_spec_ = 'win32com.server.policy.EventHandlerPolicy'\n"
543
544 # capitalized version of listener method
545 str += " HandleEvent=BaseClass.handleEvent\n"
546 str += " def __init__(self): BaseClass.__init__(self, dArgs)\n"
547 str += "result = win32com.server.util.wrap(ListenerImpl())\n"
548 exec(str, d, d)
549 return d['result']
550
551 def waitForEvents(self, timeout):
552 from win32api import GetCurrentThreadId
553 from win32event import INFINITE
554 from win32event import MsgWaitForMultipleObjects, \
555 QS_ALLINPUT, WAIT_TIMEOUT, WAIT_OBJECT_0
556 from pythoncom import PumpWaitingMessages
557 import types
558
559 if not isinstance(timeout, types.IntType):
560 raise TypeError("The timeout argument is not an integer")
561 if (self.tid != GetCurrentThreadId()):
562 raise Exception("wait for events from the same thread you inited!")
563
564 if timeout < 0:
565 cMsTimeout = INFINITE
566 else:
567 cMsTimeout = timeout
568 rc = MsgWaitForMultipleObjects(self.handles, 0, cMsTimeout, QS_ALLINPUT)
569 if rc >= WAIT_OBJECT_0 and rc < WAIT_OBJECT_0+len(self.handles):
570 # is it possible?
571 rc = 2;
572 elif rc==WAIT_OBJECT_0 + len(self.handles):
573 # Waiting messages
574 PumpWaitingMessages()
575 rc = 0;
576 else:
577 # Timeout
578 rc = 1;
579
580 # check for interruption
581 self.oIntCv.acquire()
582 if self.fInterrupted:
583 self.fInterrupted = False
584 rc = 1;
585 self.oIntCv.release()
586
587 return rc;
588
589 def interruptWaitEvents(self):
590 """
591 Basically a python implementation of NativeEventQueue::postEvent().
592
593 The magic value must be in sync with the C++ implementation or this
594 won't work.
595
596 Note that because of this method we cannot easily make use of a
597 non-visible Window to handle the message like we would like to do.
598 """
599 from win32api import PostThreadMessage
600 from win32con import WM_USER
601 self.oIntCv.acquire()
602 self.fInterrupted = True
603 self.oIntCv.release()
604 try:
605 PostThreadMessage(self.tid, WM_USER, None, 0xf241b819)
606 except:
607 return False;
608 return True;
609
610 def deinit(self):
611 import pythoncom
612 from win32file import CloseHandle
613
614 for h in self.handles:
615 if h is not None:
616 CloseHandle(h)
617 self.handles = None
618 pythoncom.CoUninitialize()
619 pass
620
621 def queryInterface(self, oIUnknown, sClassName):
622 from win32com.client import CastTo
623 return CastTo(oIUnknown, sClassName)
624
625 def xcptGetStatus(self, oXcpt):
626 # The DISP_E_EXCEPTION + excptinfo fun needs checking up, only
627 # empirical info on it so far.
628 hrXcpt = oXcpt.hresult
629 if hrXcpt == self.winerror.DISP_E_EXCEPTION:
630 try: hrXcpt = oXcpt.excepinfo[5];
631 except: pass;
632 return hrXcpt;
633
634 def xcptIsDeadInterface(self, oXcpt):
635 return self.xcptGetStatus(oXcpt) in [
636 0x800706ba, -2147023174, # RPC_S_SERVER_UNAVAILABLE.
637 0x800706be, -2147023170, # RPC_S_CALL_FAILED.
638 0x800706bf, -2147023169, # RPC_S_CALL_FAILED_DNE.
639 0x80010108, -2147417848, # RPC_E_DISCONNECTED.
640 0x800706b5, -2147023179, # RPC_S_UNKNOWN_IF
641 ];
642
643
644 def xcptGetMessage(self, oXcpt):
645 if hasattr(oXcpt, 'excepinfo'):
646 try:
647 if len(oXcpt.excepinfo) >= 3:
648 sRet = oXcpt.excepinfo[2];
649 if len(sRet) > 0:
650 return sRet[0:];
651 except:
652 pass;
653 if hasattr(oXcpt, 'strerror'):
654 try:
655 sRet = oXcpt.strerror;
656 if len(sRet) > 0:
657 return sRet;
658 except:
659 pass;
660 return None;
661
662 def xcptGetBaseXcpt(self):
663 import pythoncom;
664 return pythoncom.com_error;
665
666 def xcptSetupConstants(self, oDst):
667 import winerror;
668 oDst = self.xcptCopyErrorConstants(oDst, winerror);
669
670 # XPCOM compatability constants.
671 oDst.NS_OK = oDst.S_OK;
672 oDst.NS_ERROR_FAILURE = oDst.E_FAIL;
673 oDst.NS_ERROR_ABORT = oDst.E_ABORT;
674 oDst.NS_ERROR_NULL_POINTER = oDst.E_POINTER;
675 oDst.NS_ERROR_NO_INTERFACE = oDst.E_NOINTERFACE;
676 oDst.NS_ERROR_INVALID_ARG = oDst.E_INVALIDARG;
677 oDst.NS_ERROR_OUT_OF_MEMORY = oDst.E_OUTOFMEMORY;
678 oDst.NS_ERROR_NOT_IMPLEMENTED = oDst.E_NOTIMPL;
679 oDst.NS_ERROR_UNEXPECTED = oDst.E_UNEXPECTED;
680 return oDst;
681
682
683class PlatformXPCOM(PlatformBase):
684 """
685 Platform specific code for XPCOM.
686 """
687
688 def __init__(self, dParams):
689 PlatformBase.__init__(self, dParams);
690 sys.path.append(VBoxSdkDir+'/bindings/xpcom/python/')
691 import xpcom.vboxxpcom
692 import xpcom
693 import xpcom.components
694 _ = dParams;
695
696 def getSessionObject(self, oIVBox):
697 _ = oIVBox;
698 import xpcom.components
699 return xpcom.components.classes["@virtualbox.org/Session;1"].createInstance()
700
701 def getVirtualBox(self):
702 import xpcom.components
703 return xpcom.components.classes["@virtualbox.org/VirtualBox;1"].createInstance()
704
705 def getType(self):
706 return 'XPCOM'
707
708 def getArray(self, oInterface, sAttrib):
709 return oInterface.__getattr__('get'+ComifyName(sAttrib))()
710
711 def initPerThread(self):
712 import xpcom
713 xpcom._xpcom.AttachThread()
714
715 def deinitPerThread(self):
716 import xpcom
717 xpcom._xpcom.DetachThread()
718
719 def createListener(self, oImplClass, dArgs):
720 d = {}
721 d['BaseClass'] = oImplClass
722 d['dArgs'] = dArgs
723 str = ""
724 str += "import xpcom.components\n"
725 str += "class ListenerImpl(BaseClass):\n"
726 str += " _com_interfaces_ = xpcom.components.interfaces.IEventListener\n"
727 str += " def __init__(self): BaseClass.__init__(self, dArgs)\n"
728 str += "result = ListenerImpl()\n"
729 exec (str, d, d)
730 return d['result']
731
732 def waitForEvents(self, timeout):
733 import xpcom
734 return xpcom._xpcom.WaitForEvents(timeout)
735
736 def interruptWaitEvents(self):
737 import xpcom
738 return xpcom._xpcom.InterruptWait()
739
740 def deinit(self):
741 import xpcom
742 xpcom._xpcom.DeinitCOM()
743
744 def queryInterface(self, oIUnknown, sClassName):
745 import xpcom.components
746 return oIUnknown.queryInterface(getattr(xpcom.components.interfaces, sClassName))
747
748 def xcptGetStatus(self, oXcpt):
749 return oXcpt.errno;
750
751 def xcptIsDeadInterface(self, oXcpt):
752 return self.xcptGetStatus(oXcpt) in [
753 0x80004004, -2147467260, # NS_ERROR_ABORT
754 0x800706be, -2147023170, # NS_ERROR_CALL_FAILED (RPC_S_CALL_FAILED)
755 ];
756
757 def xcptGetMessage(self, oXcpt):
758 if hasattr(oXcpt, 'msg'):
759 try:
760 sRet = oXcpt.msg;
761 if len(sRet) > 0:
762 return sRet;
763 except:
764 pass;
765 return None;
766
767 def xcptGetBaseXcpt(self):
768 import xpcom;
769 return xpcom.Exception;
770
771 def xcptSetupConstants(self, oDst):
772 import xpcom;
773 oDst = self.xcptCopyErrorConstants(oDst, xpcom.nsError);
774
775 # COM compatability constants.
776 oDst.E_ACCESSDENIED = -2147024891; # see VBox/com/defs.h
777 oDst.S_OK = oDst.NS_OK;
778 oDst.E_FAIL = oDst.NS_ERROR_FAILURE;
779 oDst.E_ABORT = oDst.NS_ERROR_ABORT;
780 oDst.E_POINTER = oDst.NS_ERROR_NULL_POINTER;
781 oDst.E_NOINTERFACE = oDst.NS_ERROR_NO_INTERFACE;
782 oDst.E_INVALIDARG = oDst.NS_ERROR_INVALID_ARG;
783 oDst.E_OUTOFMEMORY = oDst.NS_ERROR_OUT_OF_MEMORY;
784 oDst.E_NOTIMPL = oDst.NS_ERROR_NOT_IMPLEMENTED;
785 oDst.E_UNEXPECTED = oDst.NS_ERROR_UNEXPECTED;
786 oDst.DISP_E_EXCEPTION = -2147352567; # For COM compatability only.
787 return oDst;
788
789
790class PlatformWEBSERVICE(PlatformBase):
791 """
792 VirtualBox Web Services API specific code.
793 """
794
795 def __init__(self, dParams):
796 PlatformBase.__init__(self, dParams);
797 # Import web services stuff. Fix the sys.path the first time.
798 sWebServLib = os.path.join(VBoxSdkDir, 'bindings', 'webservice', 'python', 'lib');
799 if sWebServLib not in sys.path:
800 sys.path.append(sWebServLib);
801 import VirtualBox_wrappers
802 from VirtualBox_wrappers import IWebsessionManager2
803
804 # Initialize instance variables from parameters.
805 if dParams is not None:
806 self.user = dParams.get("user", "")
807 self.password = dParams.get("password", "")
808 self.url = dParams.get("url", "")
809 else:
810 self.user = ""
811 self.password = ""
812 self.url = None
813 self.vbox = None
814 self.wsmgr = None;
815
816 #
817 # Base class overrides.
818 #
819
820 def getSessionObject(self, oIVBox):
821 return self.wsmgr.getSessionObject(oIVBox)
822
823 def getVirtualBox(self):
824 return self.connect(self.url, self.user, self.password)
825
826 def getType(self):
827 return 'WEBSERVICE'
828
829 def isRemote(self):
830 """ Returns True if remote VBox host, False if local. """
831 return True
832
833 def getArray(self, oInterface, sAttrib):
834 return oInterface.__getattr__(sAttrib)
835
836 def waitForEvents(self, timeout):
837 # Webservices cannot do that yet
838 return 2;
839
840 def interruptWaitEvents(self, timeout):
841 # Webservices cannot do that yet
842 return False;
843
844 def deinit(self):
845 try:
846 disconnect()
847 except:
848 pass
849
850 def queryInterface(self, oIUnknown, sClassName):
851 d = {}
852 d['oIUnknown'] = oIUnknown
853 str = ""
854 str += "from VirtualBox_wrappers import "+sClassName+"\n"
855 str += "result = "+sClassName+"(oIUnknown.mgr, oIUnknown.handle)\n"
856 # wrong, need to test if class indeed implements this interface
857 exec (str, d, d)
858 return d['result']
859
860 #
861 # Web service specific methods.
862 #
863
864 def connect(self, url, user, passwd):
865 if self.vbox is not None:
866 self.disconnect()
867 from VirtualBox_wrappers import IWebsessionManager2
868 if url is None:
869 url = ""
870 self.url = url
871 if user is None:
872 user = ""
873 self.user = user
874 if passwd is None:
875 passwd = ""
876 self.password = passwd
877 self.wsmgr = IWebsessionManager2(self.url)
878 self.vbox = self.wsmgr.logon(self.user, self.password)
879 if not self.vbox.handle:
880 raise Exception("cannot connect to '"+self.url+"' as '"+self.user+"'")
881 return self.vbox
882
883 def disconnect(self):
884 if self.vbox is not None and self.wsmgr is not None:
885 self.wsmgr.logoff(self.vbox)
886 self.vbox = None
887 self.wsmgr = None
888
889
890## The current (last) exception class.
891# This is reinitalized whenever VirtualBoxManager is called, so it will hold
892# the reference to the error exception class for the last platform/style that
893# was used. Most clients does talk to multiple VBox instance on different
894# platforms at the same time, so this should be sufficent for most uses and
895# be way simpler to use than VirtualBoxManager::oXcptClass.
896CurXctpClass = None;
897
898
899class VirtualBoxManager(object):
900 """
901 VirtualBox API manager class.
902
903 The API users will have to instantiate this. If no parameters are given,
904 it will default to interface with the VirtualBox running on the local
905 machine. sStyle can be None (default), MSCOM, XPCOM or WEBSERVICES. Most
906 users will either be specifying None or WEBSERVICES.
907
908 The dPlatformParams is an optional dictionary for passing parameters to the
909 WEBSERVICE backend.
910 """
911
912 class Statuses(object):
913 def __init__(self):
914 pass;
915
916 def __init__(self, sStyle = None, dPlatformParams = None):
917 if sStyle is None:
918 if sys.platform == 'win32':
919 sStyle = "MSCOM"
920 else:
921 sStyle = "XPCOM"
922 if sStyle == 'XPCOM':
923 self.platform = PlatformXPCOM(dPlatformParams);
924 elif sStyle == 'MSCOM':
925 self.platform = PlatformMSCOM(dPlatformParams);
926 elif sStyle == 'WEBSERVICE':
927 self.platform = PlatformWEBSERVICE(dPlatformParams);
928 else:
929 raise Exception('Unknown sStyle=%s' % (sStyle,));
930 self.style = sStyle
931 self.type = self.platform.getType()
932 self.remote = self.platform.isRemote()
933 ## VirtualBox API constants (for webservices, enums are symbolic).
934 self.constants = VirtualBoxReflectionInfo(sStyle == "WEBSERVICE")
935
936 ## Status constants.
937 self.statuses = self.platform.xcptSetupConstants(VirtualBoxManager.Statuses());
938 ## @todo Add VBOX_E_XXX to statuses? They're already in constants...
939 ## Dictionary for errToString, built on demand.
940 self._dErrorValToName = None;
941
942 ## The exception class for the selected platform.
943 self.oXcptClass = self.platform.xcptGetBaseXcpt();
944 global CurXcptClass;
945 CurXcptClass = self.oXcptClass;
946
947 # Get the virtualbox singleton.
948 try:
949 self.vbox = self.platform.getVirtualBox()
950 except NameError, ne:
951 print "Installation problem: check that appropriate libs in place"
952 traceback.print_exc()
953 raise ne
954 except Exception, e:
955 print "init exception: ", e
956 traceback.print_exc()
957 if self.remote:
958 self.vbox = None
959 else:
960 raise e
961 ## @deprecated
962 # This used to refer to a session manager class with only one method
963 # called getSessionObject. The method has moved into this call.
964 self.mgr = self;
965
966 def __del__(self):
967 self.deinit()
968
969 def getPythonApiRevision(self):
970 """
971 Returns a Python API revision number.
972 This will be incremented when features are added to this file.
973 """
974 return 3;
975
976
977 #
978 # Wrappers for self.platform methods.
979 #
980
981 def getVirtualBox(self):
982 """ See PlatformBase::getVirtualBox(). """
983 return self.platform.getVirtualBox()
984
985 def getSessionObject(self, oIVBox):
986 """ See PlatformBase::getSessionObject(). """
987 return self.platform.getSessionObject(oIVBox);
988
989 def getArray(self, oInterface, sAttrib):
990 """ See PlatformBase::getArray(). """
991 return self.platform.getArray(oInterface, sAttrib)
992
993 def createListener(self, oImplClass, dArgs = None):
994 """ See PlatformBase::createListener(). """
995 return self.platform.createListener(oImplClass, dArgs)
996
997 def waitForEvents(self, cMsTimeout):
998 """ See PlatformBase::waitForEvents(). """
999 return self.platform.waitForEvents(cMsTimeout)
1000
1001 def interruptWaitEvents(self):
1002 """ See PlatformBase::interruptWaitEvents(). """
1003 return self.platform.interruptWaitEvents()
1004
1005 def queryInterface(self, oIUnknown, sClassName):
1006 """ See PlatformBase::queryInterface(). """
1007 return self.platform.queryInterface(oIUnknown, sClassName)
1008
1009
1010 #
1011 # Init and uninit.
1012 #
1013
1014 def initPerThread(self):
1015 """ See PlatformBase::deinitPerThread(). """
1016 self.platform.initPerThread()
1017
1018 def deinitPerThread(self):
1019 """ See PlatformBase::deinitPerThread(). """
1020 return self.platform.deinitPerThread()
1021
1022 def deinit(self):
1023 """
1024 For unitializing the manager.
1025 Do not access it after calling this method.
1026 """
1027 if hasattr(self, "vbox"):
1028 del self.vbox
1029 self.vbox = None
1030 if hasattr(self, "platform"):
1031 self.platform.deinit()
1032 self.platform = None
1033 return True;
1034
1035
1036 #
1037 # Utility methods.
1038 #
1039
1040 def openMachineSession(self, oIMachine, fPermitSharing = True):
1041 """
1042 Attemts to open the a session to the machine.
1043 Returns a session object on success.
1044 Raises exception on failure.
1045 """
1046 oSession = self.mgr.getSessionObject(self.vbox);
1047 if fPermitSharing:
1048 type = self.constants.LockType_Shared;
1049 else:
1050 type = self.constants.LockType_Write;
1051 oIMachine.lockMachine(oSession, type);
1052 return oSession;
1053
1054 def closeMachineSession(self, oSession):
1055 """
1056 Closes a session opened by openMachineSession.
1057 Ignores None parameters.
1058 """
1059 if oSession is not None:
1060 oSession.unlockMachine()
1061 return True;
1062
1063 def getPerfCollector(self, oIVBox):
1064 """
1065 Returns a helper class (PerfCollector) for accessing performance
1066 collector goodies. See PerfCollector for details.
1067 """
1068 return PerfCollector(self, oIVBox)
1069
1070 def getBinDir(self):
1071 """
1072 Returns the VirtualBox binary directory.
1073 """
1074 global VBoxBinDir
1075 return VBoxBinDir
1076
1077 def getSdkDir(self):
1078 """
1079 Returns the VirtualBox SDK directory.
1080 """
1081 global VBoxSdkDir
1082 return VBoxSdkDir
1083
1084
1085 #
1086 # Error code utilities.
1087 #
1088
1089 ## @todo port to webservices!
1090
1091 def xcptGetStatus(self, oXcpt = None):
1092 """
1093 Gets the status code from an exception. If the exception parameter
1094 isn't specified, the current exception is examined.
1095 """
1096 if oXcpt is None:
1097 oXcpt = sys.exc_info()[1];
1098 return self.platform.xcptGetStatus(oXcpt);
1099
1100 def xcptIsDeadInterface(self, oXcpt = None):
1101 """
1102 Returns True if the exception indicates that the interface is dead,
1103 False if not. If the exception parameter isn't specified, the current
1104 exception is examined.
1105 """
1106 if oXcpt is None:
1107 oXcpt = sys.exc_info()[1];
1108 return self.platform.xcptIsDeadInterface(oXcpt);
1109
1110 def xcptIsOurXcptKind(self, oXcpt = None):
1111 """
1112 Checks if the exception is one that could come from the VBox API. If
1113 the exception parameter isn't specified, the current exception is
1114 examined.
1115 """
1116 if self.oXcptClass is None: ## @todo find the exception class for web services!
1117 return False;
1118 if oXcpt is None:
1119 oXcpt = sys.exc_info()[1];
1120 return isinstance(oXcpt, self.oXcptClass);
1121
1122 def xcptIsEqual(self, oXcpt, hrStatus):
1123 """
1124 Checks if the exception oXcpt is equal to the COM/XPCOM status code
1125 hrStatus.
1126
1127 The oXcpt parameter can be any kind of object, we'll just return True
1128 if it doesn't behave like a our exception class. If it's None, we'll
1129 query the current exception and examine that.
1130
1131 Will not raise any exception as long as hrStatus and self are not bad.
1132 """
1133 if oXcpt is None:
1134 oXcpt = sys.exc_info()[1];
1135 return self.platform.xcptIsEqual(oXcpt, hrStatus);
1136
1137 def xcptIsNotEqual(self, oXcpt, hrStatus):
1138 """
1139 Negated xcptIsEqual.
1140 """
1141 return not self.xcptIsEqual(oXcpt, hrStatus);
1142
1143 def xcptToString(self, hrStatusOrXcpt = None):
1144 """
1145 Converts the specified COM status code, or the status code of the
1146 specified exception, to a C constant string. If the parameter isn't
1147 specified (is None), the current exception is examined.
1148 """
1149
1150 # Deal with exceptions.
1151 if hrStatusOrXcpt is None or self.xcptIsOurXcptKind(hrStatusOrXcpt):
1152 hrStatus = self.xcptGetStatus(hrStatusOrXcpt);
1153 else:
1154 hrStatus = hrStatusOrXcpt;
1155
1156 # Build the dictionary on demand.
1157 if self._dErrorValToName is None:
1158 dErrorValToName = dict();
1159 for sKey in dir(self.statuses):
1160 if sKey[0].isupper():
1161 oValue = getattr(self.statuses, sKey);
1162 if type(oValue) is int:
1163 dErrorValToName[oValue] = sKey;
1164 self._dErrorValToName = dErrorValToName;
1165
1166 # Do the lookup, falling back on formatting the status number.
1167 try:
1168 sStr = self._dErrorValToName[int(hrStatus)];
1169 except KeyError:
1170 hrLong = long(hrStatus);
1171 sStr = '%#x (%d)' % (hrLong, hrLong);
1172 return sStr;
1173
1174 def xcptGetMessage(self, oXcpt = None):
1175 """
1176 Returns the best error message found in the COM-like exception. If the
1177 exception parameter isn't specified, the current exception is examined.
1178 """
1179 if oXcpt is None:
1180 oXcpt = sys.exc_info()[1];
1181 sRet = self.platform.xcptGetMessage(oXcpt);
1182 if sRet is None:
1183 sRet = self.xcptToString(oXcpt);
1184 return sRet;
1185
1186 # Legacy, remove in a day or two.
1187 errGetStatus = xcptGetStatus
1188 errIsDeadInterface = xcptIsDeadInterface
1189 errIsOurXcptKind = xcptIsOurXcptKind
1190 errGetMessage = xcptGetMessage
1191
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette