VirtualBox

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

Last change on this file since 22394 was 22394, checked in by vboxsync, 15 years ago

Python: event waiting interruptible via API

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.7 KB
Line 
1#
2# Copyright (C) 2009 Sun Microsystems, Inc.
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#
12# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
13# Clara, CA 95054 USA or visit http://www.sun.com if you need
14# additional information or have any questions.
15#
16import sys,os
17import traceback
18
19VboxBinDir = os.environ.get("VBOX_PROGRAM_PATH", None)
20VboxSdkDir = os.environ.get("VBOX_SDK_PATH", None)
21
22if VboxBinDir is None:
23 # Will be set by the installer
24 VboxBinDir = "%VBOX_INSTALL_PATH%"
25
26if VboxSdkDir is None:
27 VboxSdkDir = os.path.join(VboxBinDir,"sdk")
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 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 win32com.client.gencache.EnsureDispatch('VirtualBox.CallbackWrapper')
221
222 def getSessionObject(self, vbox):
223 import win32com
224 from win32com.client import Dispatch
225 return win32com.client.Dispatch("VirtualBox.Session")
226
227 def getVirtualBox(self):
228 import win32com
229 from win32com.client import Dispatch
230 return win32com.client.Dispatch("VirtualBox.VirtualBox")
231
232 def getType(self):
233 return 'MSCOM'
234
235 def getRemote(self):
236 return False
237
238 def getArray(self, obj, field):
239 return obj.__getattr__(field)
240
241 def initPerThread(self):
242 import pythoncom
243 pythoncom.CoInitializeEx(0)
244
245 def deinitPerThread(self):
246 import pythoncom
247 pythoncom.CoUninitialize()
248
249 def createCallback(self, iface, impl, arg):
250 d = {}
251 d['BaseClass'] = impl
252 d['arg'] = arg
253 d['tlb_guid'] = PlatformMSCOM.VBOX_TLB_GUID
254 str = ""
255 str += "import win32com.server.util\n"
256 str += "import pythoncom\n"
257
258 str += "class "+iface+"Impl(BaseClass):\n"
259 str += " _com_interfaces_ = ['"+iface+"']\n"
260 str += " _typelib_guid_ = tlb_guid\n"
261 str += " _typelib_version_ = 1, 0\n"
262 str += " _reg_clsctx_ = pythoncom.CLSCTX_INPROC_SERVER\n"
263 # Maybe we'd better implement Dynamic invoke policy, to be more flexible here
264 str += " _reg_policy_spec_ = 'win32com.server.policy.EventHandlerPolicy'\n"
265
266 # generate capitalized version of callback methods -
267 # that's how Python COM looks them up
268 for m in dir(impl):
269 if m.startswith("on"):
270 str += " "+ComifyName(m)+"=BaseClass."+m+"\n"
271
272 str += " def __init__(self): BaseClass.__init__(self, arg)\n"
273 str += "result = win32com.client.Dispatch('VirtualBox.CallbackWrapper')\n"
274 str += "result.SetLocalObject(win32com.server.util.wrap("+iface+"Impl()))\n"
275 exec (str,d,d)
276 return d['result']
277
278 def waitForEvents(self, timeout):
279 from win32api import GetCurrentThreadId
280 from win32event import MsgWaitForMultipleObjects, \
281 QS_ALLINPUT, WAIT_TIMEOUT, WAIT_OBJECT_0
282 from pythoncom import PumpWaitingMessages
283
284 if (self.tid != GetCurrentThreadId()):
285 raise Exception("wait for events from the same thread you inited!")
286
287 rc = MsgWaitForMultipleObjects(self.handles, 0, timeout, QS_ALLINPUT)
288 if rc >= WAIT_OBJECT_0 and rc < WAIT_OBJECT_0+len(self.handles):
289 # is it possible?
290 pass
291 elif rc==WAIT_OBJECT_0 + len(self.handles):
292 # Waiting messages
293 PumpWaitingMessages()
294 else:
295 # Timeout
296 pass
297
298 def interruptWaitEvents(self):
299 from win32api import PostThreadMessage
300 from win32con import WM_USER
301 PostThreadMessage(self.tid, WM_USER, None, None)
302
303 def deinit(self):
304 import pythoncom
305 from win32file import CloseHandle
306
307 for h in self.handles:
308 if h is not None:
309 CloseHandle(h)
310 self.handles = None
311 pythoncom.CoUninitialize()
312 pass
313
314
315class PlatformXPCOM:
316 def __init__(self, params):
317 sys.path.append(VboxSdkDir+'/bindings/xpcom/python/')
318 import xpcom.vboxxpcom
319 import xpcom
320 import xpcom.components
321
322 def getSessionObject(self, vbox):
323 import xpcom.components
324 return xpcom.components.classes["@virtualbox.org/Session;1"].createInstance()
325
326 def getVirtualBox(self):
327 import xpcom.components
328 return xpcom.components.classes["@virtualbox.org/VirtualBox;1"].createInstance()
329
330 def getType(self):
331 return 'XPCOM'
332
333 def getRemote(self):
334 return False
335
336 def getArray(self, obj, field):
337 return obj.__getattr__('get'+ComifyName(field))()
338
339 def initPerThread(self):
340 import xpcom
341 xpcom._xpcom.AttachThread()
342
343 def deinitPerThread(self):
344 import xpcom
345 xpcom._xpcom.DetachThread()
346
347 def createCallback(self, iface, impl, arg):
348 d = {}
349 d['BaseClass'] = impl
350 d['arg'] = arg
351 str = ""
352 str += "import xpcom.components\n"
353 str += "class "+iface+"Impl(BaseClass):\n"
354 str += " _com_interfaces_ = xpcom.components.interfaces."+iface+"\n"
355 str += " def __init__(self): BaseClass.__init__(self, arg)\n"
356 str += "result = xpcom.components.classes['@virtualbox.org/CallbackWrapper;1'].createInstance()\n"
357 # This wrapping is not entirely correct - we shall create a local object
358 str += "result.setLocalObject("+iface+"Impl())\n"
359 exec (str,d,d)
360 return d['result']
361
362 def waitForEvents(self, timeout):
363 import xpcom
364 xpcom._xpcom.WaitForEvents(timeout)
365
366 def interruptWaitEvents(self):
367 import xpcom
368 xpcom._xpcom.InterruptWait()
369
370 def deinit(self):
371 import xpcom
372 xpcom._xpcom.DeinitCOM()
373
374class PlatformWEBSERVICE:
375 def __init__(self, params):
376 sys.path.append(os.path.join(VboxSdkDir,'bindings', 'webservice', 'python', 'lib'))
377 # not really needed, but just fail early if misconfigured
378 import VirtualBox_services
379 import VirtualBox_wrappers
380 from VirtualBox_wrappers import IWebsessionManager2
381
382 if params is not None:
383 self.user = params.get("user", "")
384 self.password = params.get("password", "")
385 self.url = params.get("url", "")
386 else:
387 self.user = ""
388 self.password = ""
389 self.url = None
390 self.vbox = None
391
392 def getSessionObject(self, vbox):
393 return self.wsmgr.getSessionObject(vbox)
394
395 def getVirtualBox(self):
396 return self.connect(self.url, self.user, self.password)
397
398 def connect(self, url, user, passwd):
399 if self.vbox is not None:
400 self.disconnect()
401 from VirtualBox_wrappers import IWebsessionManager2
402 if url is None:
403 url = ""
404 self.url = url
405 if user is None:
406 user = ""
407 self.user = user
408 if passwd is None:
409 passwd = ""
410 self.password = passwd
411 self.wsmgr = IWebsessionManager2(self.url)
412 self.vbox = self.wsmgr.logon(self.user, self.password)
413 if not self.vbox.handle:
414 raise Exception("cannot connect to '"+self.url+"' as '"+self.user+"'")
415 return self.vbox
416
417 def disconnect(self):
418 if self.vbox is not None and self.wsmgr is not None:
419 self.wsmgr.logoff(self.vbox)
420 self.vbox = None
421 self.wsmgr = None
422
423 def getType(self):
424 return 'WEBSERVICE'
425
426 def getRemote(self):
427 return True
428
429 def getArray(self, obj, field):
430 return obj.__getattr__(field)
431
432 def initPerThread(self):
433 pass
434
435 def deinitPerThread(self):
436 pass
437
438 def createCallback(self, iface, impl, arg):
439 raise Exception("no callbacks for webservices")
440
441 def waitForEvents(self, timeout):
442 # Webservices cannot do that yet
443 pass
444
445 def interruptWaitEvents(self, timeout):
446 # Webservices cannot do that yet
447 pass
448
449 def deinit(self):
450 try:
451 disconnect()
452 except:
453 pass
454
455class SessionManager:
456 def __init__(self, mgr):
457 self.mgr = mgr
458
459 def getSessionObject(self, vbox):
460 return self.mgr.platform.getSessionObject(vbox)
461
462class VirtualBoxManager:
463 def __init__(self, style, platparams):
464 if style is None:
465 if sys.platform == 'win32':
466 style = "MSCOM"
467 else:
468 style = "XPCOM"
469
470
471 exec "self.platform = Platform"+style+"(platparams)"
472 # for webservices, enums are symbolic
473 self.constants = VirtualBoxReflectionInfo(style == "WEBSERVICE")
474 self.type = self.platform.getType()
475 self.remote = self.platform.getRemote()
476 self.style = style
477 self.mgr = SessionManager(self)
478
479 try:
480 self.vbox = self.platform.getVirtualBox()
481 except NameError,ne:
482 print "Installation problem: check that appropriate libs in place"
483 traceback.print_exc()
484 raise ne
485 except Exception,e:
486 print "init exception: ",e
487 traceback.print_exc()
488 if self.remote:
489 self.vbox = None
490 else:
491 raise e
492
493 def getArray(self, obj, field):
494 return self.platform.getArray(obj, field)
495
496 def getVirtualBox(self):
497 return self.platform.getVirtualBox()
498
499 def __del__(self):
500 self.deinit()
501
502 def deinit(self):
503 if hasattr(self, "vbox"):
504 del self.vbox
505 self.vbox = None
506 if hasattr(self, "platform"):
507 self.platform.deinit()
508 self.platform = None
509
510 def initPerThread(self):
511 self.platform.initPerThread()
512
513 def openMachineSession(self, machineId):
514 session = self.mgr.getSessionObject(self.vbox)
515 self.vbox.openSession(session, machineId)
516 return session
517
518 def closeMachineSession(self, session):
519 session.close()
520
521 def deinitPerThread(self):
522 self.platform.deinitPerThread()
523
524 def createCallback(self, iface, impl, arg):
525 return self.platform.createCallback(iface, impl, arg)
526
527 def waitForEvents(self, timeout):
528 return self.platform.waitForEvents(timeout)
529
530 def interruptWaitEvents(self):
531 return self.platform.interruptWaitEvents()
532
533 def getPerfCollector(self, vbox):
534 return PerfCollector(self, vbox)
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