VirtualBox

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

Last change on this file since 42898 was 31710, checked in by vboxsync, 14 years ago

excessive

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