VirtualBox

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

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

change comment style

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