VirtualBox

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

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

vboxapi.py: Use TLB_MAJOR and TLB_MINOR.

  • 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 = '{46137EEC-703B-4FE5-AFD4-7C9BBBBA0259}'
196 VBOX_TLB_LCID = 0
197 VBOX_TLB_MAJOR = 1
198 VBOX_TLB_MINOR = 0
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: cMsTimeout = INFINITE
291 else: cMsTimeout = timeout
292 rc = MsgWaitForMultipleObjects(self.handles, 0, cMsTimeout, QS_ALLINPUT)
293 if rc >= WAIT_OBJECT_0 and rc < WAIT_OBJECT_0+len(self.handles):
294 # is it possible?
295 rc = 2;
296 elif rc==WAIT_OBJECT_0 + len(self.handles):
297 # Waiting messages
298 PumpWaitingMessages()
299 rc = 0;
300 else:
301 # Timeout
302 rc = 1;
303
304 # check for interruption
305 self.oIntCv.acquire()
306 if self.fInterrupted:
307 self.fInterrupted = False
308 rc = 1;
309 self.oIntCv.release()
310
311 return rc;
312
313 def interruptWaitEvents(self):
314 """
315 Basically a python implementation of EventQueue::postEvent().
316
317 The magic value must be in sync with the C++ implementation or this
318 won't work.
319
320 Note that because of this method we cannot easily make use of a
321 non-visible Window to handle the message like we would like to do.
322 """
323 from win32api import PostThreadMessage
324 from win32con import WM_USER
325 self.oIntCv.acquire()
326 self.fInterrupted = True
327 self.oIntCv.release()
328 try:
329 PostThreadMessage(self.tid, WM_USER, None, 0xf241b819)
330 except:
331 return False;
332 return True;
333
334 def deinit(self):
335 import pythoncom
336 from win32file import CloseHandle
337
338 for h in self.handles:
339 if h is not None:
340 CloseHandle(h)
341 self.handles = None
342 pythoncom.CoUninitialize()
343 pass
344
345 def queryInterface(self, obj, klazzName):
346 from win32com.client import CastTo
347 return CastTo(obj, klazzName)
348
349class PlatformXPCOM:
350 def __init__(self, params):
351 sys.path.append(VboxSdkDir+'/bindings/xpcom/python/')
352 import xpcom.vboxxpcom
353 import xpcom
354 import xpcom.components
355
356 def getSessionObject(self, vbox):
357 import xpcom.components
358 return xpcom.components.classes["@virtualbox.org/Session;1"].createInstance()
359
360 def getVirtualBox(self):
361 import xpcom.components
362 return xpcom.components.classes["@virtualbox.org/VirtualBox;1"].createInstance()
363
364 def getType(self):
365 return 'XPCOM'
366
367 def getRemote(self):
368 return False
369
370 def getArray(self, obj, field):
371 return obj.__getattr__('get'+ComifyName(field))()
372
373 def initPerThread(self):
374 import xpcom
375 xpcom._xpcom.AttachThread()
376
377 def deinitPerThread(self):
378 import xpcom
379 xpcom._xpcom.DetachThread()
380
381 def createListener(self, impl, arg):
382 d = {}
383 d['BaseClass'] = impl
384 d['arg'] = arg
385 str = ""
386 str += "import xpcom.components\n"
387 str += "class ListenerImpl(BaseClass):\n"
388 str += " _com_interfaces_ = xpcom.components.interfaces.IEventListener\n"
389 str += " def __init__(self): BaseClass.__init__(self, arg)\n"
390 str += "result = ListenerImpl()\n"
391 exec (str,d,d)
392 return d['result']
393
394 def waitForEvents(self, timeout):
395 import xpcom
396 return xpcom._xpcom.WaitForEvents(timeout)
397
398 def interruptWaitEvents(self):
399 import xpcom
400 return xpcom._xpcom.InterruptWait()
401
402 def deinit(self):
403 import xpcom
404 xpcom._xpcom.DeinitCOM()
405
406 def queryInterface(self, obj, klazzName):
407 import xpcom.components
408 return obj.queryInterface(getattr(xpcom.components.interfaces, klazzName))
409
410class PlatformWEBSERVICE:
411 def __init__(self, params):
412 sys.path.append(os.path.join(VboxSdkDir,'bindings', 'webservice', 'python', 'lib'))
413 #import VirtualBox_services
414 import VirtualBox_wrappers
415 from VirtualBox_wrappers import IWebsessionManager2
416
417 if params is not None:
418 self.user = params.get("user", "")
419 self.password = params.get("password", "")
420 self.url = params.get("url", "")
421 else:
422 self.user = ""
423 self.password = ""
424 self.url = None
425 self.vbox = None
426
427 def getSessionObject(self, vbox):
428 return self.wsmgr.getSessionObject(vbox)
429
430 def getVirtualBox(self):
431 return self.connect(self.url, self.user, self.password)
432
433 def connect(self, url, user, passwd):
434 if self.vbox is not None:
435 self.disconnect()
436 from VirtualBox_wrappers import IWebsessionManager2
437 if url is None:
438 url = ""
439 self.url = url
440 if user is None:
441 user = ""
442 self.user = user
443 if passwd is None:
444 passwd = ""
445 self.password = passwd
446 self.wsmgr = IWebsessionManager2(self.url)
447 self.vbox = self.wsmgr.logon(self.user, self.password)
448 if not self.vbox.handle:
449 raise Exception("cannot connect to '"+self.url+"' as '"+self.user+"'")
450 return self.vbox
451
452 def disconnect(self):
453 if self.vbox is not None and self.wsmgr is not None:
454 self.wsmgr.logoff(self.vbox)
455 self.vbox = None
456 self.wsmgr = None
457
458 def getType(self):
459 return 'WEBSERVICE'
460
461 def getRemote(self):
462 return True
463
464 def getArray(self, obj, field):
465 return obj.__getattr__(field)
466
467 def initPerThread(self):
468 pass
469
470 def deinitPerThread(self):
471 pass
472
473 def createListener(self, impl, arg):
474 raise Exception("no active listeners for webservices")
475
476 def waitForEvents(self, timeout):
477 # Webservices cannot do that yet
478 return 2;
479
480 def interruptWaitEvents(self, timeout):
481 # Webservices cannot do that yet
482 return False;
483
484 def deinit(self):
485 try:
486 disconnect()
487 except:
488 pass
489
490 def queryInterface(self, obj, klazzName):
491 d = {}
492 d['obj'] = obj
493 str = ""
494 str += "from VirtualBox_wrappers import "+klazzName+"\n"
495 str += "result = "+klazzName+"(obj.mgr,obj.handle)\n"
496 # wrong, need to test if class indeed implements this interface
497 exec (str,d,d)
498 return d['result']
499
500class SessionManager:
501 def __init__(self, mgr):
502 self.mgr = mgr
503
504 def getSessionObject(self, vbox):
505 return self.mgr.platform.getSessionObject(vbox)
506
507class VirtualBoxManager:
508 def __init__(self, style, platparams):
509 if style is None:
510 if sys.platform == 'win32':
511 style = "MSCOM"
512 else:
513 style = "XPCOM"
514
515
516 exec "self.platform = Platform"+style+"(platparams)"
517 # for webservices, enums are symbolic
518 self.constants = VirtualBoxReflectionInfo(style == "WEBSERVICE")
519 self.type = self.platform.getType()
520 self.remote = self.platform.getRemote()
521 self.style = style
522 self.mgr = SessionManager(self)
523
524 try:
525 self.vbox = self.platform.getVirtualBox()
526 except NameError,ne:
527 print "Installation problem: check that appropriate libs in place"
528 traceback.print_exc()
529 raise ne
530 except Exception,e:
531 print "init exception: ",e
532 traceback.print_exc()
533 if self.remote:
534 self.vbox = None
535 else:
536 raise e
537
538 def getArray(self, obj, field):
539 return self.platform.getArray(obj, field)
540
541 def getVirtualBox(self):
542 return self.platform.getVirtualBox()
543
544 def __del__(self):
545 self.deinit()
546
547 def deinit(self):
548 if hasattr(self, "vbox"):
549 del self.vbox
550 self.vbox = None
551 if hasattr(self, "platform"):
552 self.platform.deinit()
553 self.platform = None
554
555 def initPerThread(self):
556 self.platform.initPerThread()
557
558 def openMachineSession(self, mach, permitSharing = True):
559 session = self.mgr.getSessionObject(self.vbox)
560 if permitSharing:
561 type = self.constants.LockType_Shared
562 else:
563 type = self.constants.LockType_Write
564 mach.lockMachine(session, type)
565 return session
566
567 def closeMachineSession(self, session):
568 if session is not None:
569 session.unlockMachine()
570
571 def deinitPerThread(self):
572 self.platform.deinitPerThread()
573
574 def createListener(self, impl, arg = None):
575 return self.platform.createListener(impl, arg)
576
577 def waitForEvents(self, timeout):
578 """
579 Wait for events to arrive and process them.
580
581 The timeout is in milliseconds. A negative value means waiting for
582 ever, while 0 does not wait at all.
583
584 Returns 0 if events was processed.
585 Returns 1 if timed out or interrupted in some way.
586 Returns 2 on error (like not supported for web services).
587
588 Raises an exception if the calling thread is not the main thread (the one
589 that initialized VirtualBoxManager) or if the time isn't an integer.
590 """
591 return self.platform.waitForEvents(timeout)
592
593 def interruptWaitEvents(self):
594 """
595 Interrupt a waitForEvents call.
596 This is normally called from a worker thread.
597
598 Returns True on success, False on failure.
599 """
600 return self.platform.interruptWaitEvents()
601
602 def getPerfCollector(self, vbox):
603 return PerfCollector(self, vbox)
604
605 def getBinDir(self):
606 global VboxBinDir
607 return VboxBinDir
608
609 def getSdkDir(self):
610 global VboxSdkDir
611 return VboxSdkDir
612
613 def queryInterface(self, obj, klazzName):
614 return self.platform.queryInterface(obj, klazzName)
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