VirtualBox

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

Last change on this file since 47984 was 47984, checked in by vboxsync, 12 years ago

this works.

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

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