VirtualBox

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

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

python: Emit VBOX_E_xxx constants. Make pretty output.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.1 KB
Line 
1"""
2Copyright (C) 2009-2013 Oracle Corporation
3
4This file is part of VirtualBox Open Source Edition (OSE), as
5available from http://www.virtualbox.org. This file is free software;
6you can redistribute it and/or modify it under the terms of the GNU
7General Public License (GPL) as published by the Free Software
8Foundation, in version 2 as it comes in the "COPYING" file of the
9VirtualBox OSE distribution. VirtualBox OSE is distributed in the
10hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
11"""
12
13import sys, os
14import traceback
15
16# To set Python bitness on OSX use 'export VERSIONER_PYTHON_PREFER_32_BIT=yes'
17
18VBoxBinDir = os.environ.get("VBOX_PROGRAM_PATH", None)
19VBoxSdkDir = os.environ.get("VBOX_SDK_PATH", None)
20
21if VBoxBinDir is None:
22 # Will be set by the installer
23 VBoxBinDir = "%VBOX_INSTALL_PATH%"
24
25if VBoxSdkDir is None:
26 # Will be set by the installer
27 VBoxSdkDir = "%VBOX_SDK_PATH%"
28
29os.environ["VBOX_PROGRAM_PATH"] = VBoxBinDir
30os.environ["VBOX_SDK_PATH"] = VBoxSdkDir
31sys.path.append(VBoxBinDir)
32
33from VirtualBox_constants import VirtualBoxReflectionInfo
34
35class PerfCollector:
36 """ This class provides a wrapper over IPerformanceCollector in order to
37 get more 'pythonic' interface.
38
39 To begin collection of metrics use setup() method.
40
41 To get collected data use query() method.
42
43 It is possible to disable metric collection without changing collection
44 parameters with disable() method. The enable() method resumes metric
45 collection.
46 """
47
48 def __init__(self, mgr, vbox):
49 """ Initializes the instance.
50
51 """
52 self.mgr = mgr
53 self.isMscom = (mgr.type == 'MSCOM')
54 self.collector = vbox.performanceCollector
55
56 def setup(self, names, objects, period, nsamples):
57 """ Discards all previously collected values for the specified
58 metrics, sets the period of collection and the number of retained
59 samples, enables collection.
60 """
61 self.collector.setupMetrics(names, objects, period, nsamples)
62
63 def enable(self, names, objects):
64 """ Resumes metric collection for the specified metrics.
65 """
66 self.collector.enableMetrics(names, objects)
67
68 def disable(self, names, objects):
69 """ Suspends metric collection for the specified metrics.
70 """
71 self.collector.disableMetrics(names, objects)
72
73 def query(self, names, objects):
74 """ Retrieves collected metric values as well as some auxiliary
75 information. Returns an array of dictionaries, one dictionary per
76 metric. Each dictionary contains the following entries:
77 'name': metric name
78 'object': managed object this metric associated with
79 'unit': unit of measurement
80 'scale': divide 'values' by this number to get float numbers
81 'values': collected data
82 'values_as_string': pre-processed values ready for 'print' statement
83 """
84 # Get around the problem with input arrays returned in output
85 # parameters (see #3953) for MSCOM.
86 if self.isMscom:
87 (values, names, objects, names_out, objects_out, units, scales, sequence_numbers,
88 indices, lengths) = self.collector.queryMetricsData(names, objects)
89 else:
90 (values, names_out, objects_out, units, scales, sequence_numbers,
91 indices, lengths) = self.collector.queryMetricsData(names, objects)
92 out = []
93 for i in xrange(0, len(names_out)):
94 scale = int(scales[i])
95 if scale != 1:
96 fmt = '%.2f%s'
97 else:
98 fmt = '%d %s'
99 out.append({
100 'name':str(names_out[i]),
101 'object':str(objects_out[i]),
102 'unit':str(units[i]),
103 'scale':scale,
104 'values':[int(values[j]) for j in xrange(int(indices[i]), int(indices[i])+int(lengths[i]))],
105 'values_as_string':'['+', '.join([fmt % (int(values[j])/scale, units[i]) for j in xrange(int(indices[i]), int(indices[i])+int(lengths[i]))])+']'
106 })
107 return out
108
109def ComifyName(name):
110 return name[0].capitalize()+name[1:]
111
112_COMForward = { 'getattr' : None,
113 'setattr' : None}
114
115def CustomGetAttr(self, attr):
116 # fastpath
117 if self.__class__.__dict__.get(attr) != None:
118 return self.__class__.__dict__.get(attr)
119
120 # try case-insensitivity workaround for class attributes (COM methods)
121 for k in self.__class__.__dict__.keys():
122 if k.lower() == attr.lower():
123 self.__class__.__dict__[attr] = self.__class__.__dict__[k]
124 return getattr(self, k)
125 try:
126 return _COMForward['getattr'](self, ComifyName(attr))
127 except AttributeError:
128 return _COMForward['getattr'](self, attr)
129
130def CustomSetAttr(self, attr, value):
131 try:
132 return _COMForward['setattr'](self, ComifyName(attr), value)
133 except AttributeError:
134 return _COMForward['setattr'](self, attr, value)
135
136class PlatformMSCOM:
137 # Class to fake access to constants in style of foo.bar.boo
138 class ConstantFake:
139 def __init__(self, parent, name):
140 self.__dict__['_parent'] = parent
141 self.__dict__['_name'] = name
142 self.__dict__['_consts'] = {}
143 try:
144 self.__dict__['_depth']=parent.__dict__['_depth']+1
145 except:
146 self.__dict__['_depth']=0
147 if self.__dict__['_depth'] > 4:
148 raise AttributeError
149
150 def __getattr__(self, attr):
151 import win32com
152 from win32com.client import constants
153
154 if attr.startswith("__"):
155 raise AttributeError
156
157 consts = self.__dict__['_consts']
158
159 fake = consts.get(attr, None)
160 if fake != None:
161 return fake
162 try:
163 name = self.__dict__['_name']
164 parent = self.__dict__['_parent']
165 while parent != None:
166 if parent._name is not None:
167 name = parent._name+'_'+name
168 parent = parent._parent
169
170 if name is not None:
171 name += "_" + attr
172 else:
173 name = attr
174 return win32com.client.constants.__getattr__(name)
175 except AttributeError, e:
176 fake = PlatformMSCOM.ConstantFake(self, attr)
177 consts[attr] = fake
178 return fake
179
180
181 class InterfacesWrapper:
182 def __init__(self):
183 self.__dict__['_rootFake'] = PlatformMSCOM.ConstantFake(None, None)
184
185 def __getattr__(self, a):
186 import win32com
187 from win32com.client import constants
188 if a.startswith("__"):
189 raise AttributeError
190 try:
191 return win32com.client.constants.__getattr__(a)
192 except AttributeError, e:
193 return self.__dict__['_rootFake'].__getattr__(a)
194
195 VBOX_TLB_GUID = '{D7569351-1750-46F0-936E-BD127D5BC264}'
196 VBOX_TLB_LCID = 0
197 VBOX_TLB_MAJOR = 1
198 VBOX_TLB_MINOR = 3
199
200 def __init__(self, params):
201 from win32com import universal
202 from win32com.client import gencache, DispatchBaseClass
203 from win32com.client import constants, getevents
204 import win32com
205 import pythoncom
206 import win32api
207 from win32con import DUPLICATE_SAME_ACCESS
208 from win32api import GetCurrentThread, GetCurrentThreadId, DuplicateHandle, GetCurrentProcess
209 import threading
210 pid = GetCurrentProcess()
211 self.tid = GetCurrentThreadId()
212 handle = DuplicateHandle(pid, GetCurrentThread(), pid, 0, 0, DUPLICATE_SAME_ACCESS)
213 self.handles = []
214 self.handles.append(handle)
215 _COMForward['getattr'] = DispatchBaseClass.__dict__['__getattr__']
216 DispatchBaseClass.__dict__['__getattr__'] = CustomGetAttr
217 _COMForward['setattr'] = DispatchBaseClass.__dict__['__setattr__']
218 DispatchBaseClass.__dict__['__setattr__'] = CustomSetAttr
219 win32com.client.gencache.EnsureDispatch('VirtualBox.Session')
220 win32com.client.gencache.EnsureDispatch('VirtualBox.VirtualBox')
221 self.oIntCv = threading.Condition()
222 self.fInterrupted = False;
223
224 def getSessionObject(self, vbox):
225 import win32com
226 from win32com.client import Dispatch
227 return win32com.client.Dispatch("VirtualBox.Session")
228
229 def getVirtualBox(self):
230 import win32com
231 from win32com.client import Dispatch
232 return win32com.client.Dispatch("VirtualBox.VirtualBox")
233
234 def getType(self):
235 return 'MSCOM'
236
237 def getRemote(self):
238 return False
239
240 def getArray(self, obj, field):
241 return obj.__getattr__(field)
242
243 def initPerThread(self):
244 import pythoncom
245 pythoncom.CoInitializeEx(0)
246
247 def deinitPerThread(self):
248 import pythoncom
249 pythoncom.CoUninitialize()
250
251 def createListener(self, impl, arg):
252 d = {}
253 d['BaseClass'] = impl
254 d['arg'] = arg
255 d['tlb_guid'] = PlatformMSCOM.VBOX_TLB_GUID
256 d['tlb_major'] = PlatformMSCOM.VBOX_TLB_MAJOR
257 d['tlb_minor'] = PlatformMSCOM.VBOX_TLB_MINOR
258 str = ""
259 str += "import win32com.server.util\n"
260 str += "import pythoncom\n"
261
262 str += "class ListenerImpl(BaseClass):\n"
263 str += " _com_interfaces_ = ['IEventListener']\n"
264 str += " _typelib_guid_ = tlb_guid\n"
265 str += " _typelib_version_ = tlb_major, tlb_minor\n"
266 str += " _reg_clsctx_ = pythoncom.CLSCTX_INPROC_SERVER\n"
267 # Maybe we'd better implement Dynamic invoke policy, to be more flexible here
268 str += " _reg_policy_spec_ = 'win32com.server.policy.EventHandlerPolicy'\n"
269
270 # capitalized version of listener method
271 str += " HandleEvent=BaseClass.handleEvent\n"
272 str += " def __init__(self): BaseClass.__init__(self, arg)\n"
273 str += "result = win32com.server.util.wrap(ListenerImpl())\n"
274 exec (str, d, d)
275 return d['result']
276
277 def waitForEvents(self, timeout):
278 from win32api import GetCurrentThreadId
279 from win32event import INFINITE
280 from win32event import MsgWaitForMultipleObjects, \
281 QS_ALLINPUT, WAIT_TIMEOUT, WAIT_OBJECT_0
282 from pythoncom import PumpWaitingMessages
283 import types
284
285 if not isinstance(timeout, types.IntType):
286 raise TypeError("The timeout argument is not an integer")
287 if (self.tid != GetCurrentThreadId()):
288 raise Exception("wait for events from the same thread you inited!")
289
290 if timeout < 0:
291 cMsTimeout = INFINITE
292 else:
293 cMsTimeout = timeout
294 rc = MsgWaitForMultipleObjects(self.handles, 0, cMsTimeout, QS_ALLINPUT)
295 if rc >= WAIT_OBJECT_0 and rc < WAIT_OBJECT_0+len(self.handles):
296 # is it possible?
297 rc = 2;
298 elif rc==WAIT_OBJECT_0 + len(self.handles):
299 # Waiting messages
300 PumpWaitingMessages()
301 rc = 0;
302 else:
303 # Timeout
304 rc = 1;
305
306 # check for interruption
307 self.oIntCv.acquire()
308 if self.fInterrupted:
309 self.fInterrupted = False
310 rc = 1;
311 self.oIntCv.release()
312
313 return rc;
314
315 def interruptWaitEvents(self):
316 """
317 Basically a python implementation of EventQueue::postEvent().
318
319 The magic value must be in sync with the C++ implementation or this
320 won't work.
321
322 Note that because of this method we cannot easily make use of a
323 non-visible Window to handle the message like we would like to do.
324 """
325 from win32api import PostThreadMessage
326 from win32con import WM_USER
327 self.oIntCv.acquire()
328 self.fInterrupted = True
329 self.oIntCv.release()
330 try:
331 PostThreadMessage(self.tid, WM_USER, None, 0xf241b819)
332 except:
333 return False;
334 return True;
335
336 def deinit(self):
337 import pythoncom
338 from win32file import CloseHandle
339
340 for h in self.handles:
341 if h is not None:
342 CloseHandle(h)
343 self.handles = None
344 pythoncom.CoUninitialize()
345 pass
346
347 def queryInterface(self, obj, className):
348 from win32com.client import CastTo
349 return CastTo(obj, className)
350
351class PlatformXPCOM:
352 def __init__(self, params):
353 sys.path.append(VBoxSdkDir+'/bindings/xpcom/python/')
354 import xpcom.vboxxpcom
355 import xpcom
356 import xpcom.components
357
358 def getSessionObject(self, vbox):
359 import xpcom.components
360 return xpcom.components.classes["@virtualbox.org/Session;1"].createInstance()
361
362 def getVirtualBox(self):
363 import xpcom.components
364 return xpcom.components.classes["@virtualbox.org/VirtualBox;1"].createInstance()
365
366 def getType(self):
367 return 'XPCOM'
368
369 def getRemote(self):
370 return False
371
372 def getArray(self, obj, field):
373 return obj.__getattr__('get'+ComifyName(field))()
374
375 def initPerThread(self):
376 import xpcom
377 xpcom._xpcom.AttachThread()
378
379 def deinitPerThread(self):
380 import xpcom
381 xpcom._xpcom.DetachThread()
382
383 def createListener(self, impl, arg):
384 d = {}
385 d['BaseClass'] = impl
386 d['arg'] = arg
387 str = ""
388 str += "import xpcom.components\n"
389 str += "class ListenerImpl(BaseClass):\n"
390 str += " _com_interfaces_ = xpcom.components.interfaces.IEventListener\n"
391 str += " def __init__(self): BaseClass.__init__(self, arg)\n"
392 str += "result = ListenerImpl()\n"
393 exec (str, d, d)
394 return d['result']
395
396 def waitForEvents(self, timeout):
397 import xpcom
398 return xpcom._xpcom.WaitForEvents(timeout)
399
400 def interruptWaitEvents(self):
401 import xpcom
402 return xpcom._xpcom.InterruptWait()
403
404 def deinit(self):
405 import xpcom
406 xpcom._xpcom.DeinitCOM()
407
408 def queryInterface(self, obj, className):
409 import xpcom.components
410 return obj.queryInterface(getattr(xpcom.components.interfaces, className))
411
412class PlatformWEBSERVICE:
413 def __init__(self, params):
414 sys.path.append(os.path.join(VBoxSdkDir, 'bindings', 'webservice', 'python', 'lib'))
415 #import VirtualBox_services
416 import VirtualBox_wrappers
417 from VirtualBox_wrappers import IWebsessionManager2
418
419 if params is not None:
420 self.user = params.get("user", "")
421 self.password = params.get("password", "")
422 self.url = params.get("url", "")
423 else:
424 self.user = ""
425 self.password = ""
426 self.url = None
427 self.vbox = None
428
429 def getSessionObject(self, vbox):
430 return self.wsmgr.getSessionObject(vbox)
431
432 def getVirtualBox(self):
433 return self.connect(self.url, self.user, self.password)
434
435 def connect(self, url, user, passwd):
436 if self.vbox is not None:
437 self.disconnect()
438 from VirtualBox_wrappers import IWebsessionManager2
439 if url is None:
440 url = ""
441 self.url = url
442 if user is None:
443 user = ""
444 self.user = user
445 if passwd is None:
446 passwd = ""
447 self.password = passwd
448 self.wsmgr = IWebsessionManager2(self.url)
449 self.vbox = self.wsmgr.logon(self.user, self.password)
450 if not self.vbox.handle:
451 raise Exception("cannot connect to '"+self.url+"' as '"+self.user+"'")
452 return self.vbox
453
454 def disconnect(self):
455 if self.vbox is not None and self.wsmgr is not None:
456 self.wsmgr.logoff(self.vbox)
457 self.vbox = None
458 self.wsmgr = None
459
460 def getType(self):
461 return 'WEBSERVICE'
462
463 def getRemote(self):
464 return True
465
466 def getArray(self, obj, field):
467 return obj.__getattr__(field)
468
469 def initPerThread(self):
470 pass
471
472 def deinitPerThread(self):
473 pass
474
475 def createListener(self, impl, arg):
476 raise Exception("no active listeners for webservices")
477
478 def waitForEvents(self, timeout):
479 # Webservices cannot do that yet
480 return 2;
481
482 def interruptWaitEvents(self, timeout):
483 # Webservices cannot do that yet
484 return False;
485
486 def deinit(self):
487 try:
488 disconnect()
489 except:
490 pass
491
492 def queryInterface(self, obj, className):
493 d = {}
494 d['obj'] = obj
495 str = ""
496 str += "from VirtualBox_wrappers import "+className+"\n"
497 str += "result = "+className+"(obj.mgr, obj.handle)\n"
498 # wrong, need to test if class indeed implements this interface
499 exec (str, d, d)
500 return d['result']
501
502class SessionManager:
503 def __init__(self, mgr):
504 self.mgr = mgr
505
506 def getSessionObject(self, vbox):
507 return self.mgr.platform.getSessionObject(vbox)
508
509class VirtualBoxManager:
510 def __init__(self, style, platparams):
511 if style is None:
512 if sys.platform == 'win32':
513 style = "MSCOM"
514 else:
515 style = "XPCOM"
516
517
518 exec "self.platform = Platform"+style+"(platparams)"
519 # for webservices, enums are symbolic
520 self.constants = VirtualBoxReflectionInfo(style == "WEBSERVICE")
521 self.type = self.platform.getType()
522 self.remote = self.platform.getRemote()
523 self.style = style
524 self.mgr = SessionManager(self)
525
526 try:
527 self.vbox = self.platform.getVirtualBox()
528 except NameError, ne:
529 print "Installation problem: check that appropriate libs in place"
530 traceback.print_exc()
531 raise ne
532 except Exception, e:
533 print "init exception: ", e
534 traceback.print_exc()
535 if self.remote:
536 self.vbox = None
537 else:
538 raise e
539
540 def getArray(self, obj, field):
541 return self.platform.getArray(obj, field)
542
543 def getVirtualBox(self):
544 return self.platform.getVirtualBox()
545
546 def __del__(self):
547 self.deinit()
548
549 def deinit(self):
550 if hasattr(self, "vbox"):
551 del self.vbox
552 self.vbox = None
553 if hasattr(self, "platform"):
554 self.platform.deinit()
555 self.platform = None
556
557 def initPerThread(self):
558 self.platform.initPerThread()
559
560 def openMachineSession(self, mach, permitSharing = True):
561 session = self.mgr.getSessionObject(self.vbox)
562 if permitSharing:
563 type = self.constants.LockType_Shared
564 else:
565 type = self.constants.LockType_Write
566 mach.lockMachine(session, type)
567 return session
568
569 def closeMachineSession(self, session):
570 if session is not None:
571 session.unlockMachine()
572
573 def deinitPerThread(self):
574 self.platform.deinitPerThread()
575
576 def createListener(self, impl, arg = None):
577 return self.platform.createListener(impl, arg)
578
579 def waitForEvents(self, timeout):
580 """
581 Wait for events to arrive and process them.
582
583 The timeout is in milliseconds. A negative value means waiting for
584 ever, while 0 does not wait at all.
585
586 Returns 0 if events was processed.
587 Returns 1 if timed out or interrupted in some way.
588 Returns 2 on error (like not supported for web services).
589
590 Raises an exception if the calling thread is not the main thread (the one
591 that initialized VirtualBoxManager) or if the time isn't an integer.
592 """
593 return self.platform.waitForEvents(timeout)
594
595 def interruptWaitEvents(self):
596 """
597 Interrupt a waitForEvents call.
598 This is normally called from a worker thread.
599
600 Returns True on success, False on failure.
601 """
602 return self.platform.interruptWaitEvents()
603
604 def getPerfCollector(self, vbox):
605 return PerfCollector(self, vbox)
606
607 def getBinDir(self):
608 """
609 Returns the VirtualBox binary directory.
610 """
611 global VBoxBinDir
612 return VBoxBinDir
613
614 def getSdkDir(self):
615 """
616 Returns the VirtualBox SDK directory.
617 """
618 global VBoxSdkDir
619 return VBoxSdkDir
620
621 def queryInterface(self, obj, className):
622 return self.platform.queryInterface(obj, className)
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