VirtualBox

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

Last change on this file since 30257 was 30207, checked in by vboxsync, 14 years ago

Main: console COM events, cleanup, locking

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.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 pid = GetCurrentProcess()
209 self.tid = GetCurrentThreadId()
210 handle = DuplicateHandle(pid, GetCurrentThread(), pid, 0, 0, DUPLICATE_SAME_ACCESS)
211 self.handles = []
212 self.handles.append(handle)
213 _COMForward['getattr'] = DispatchBaseClass.__dict__['__getattr__']
214 DispatchBaseClass.__dict__['__getattr__'] = CustomGetAttr
215 _COMForward['setattr'] = DispatchBaseClass.__dict__['__setattr__']
216 DispatchBaseClass.__dict__['__setattr__'] = CustomSetAttr
217 win32com.client.gencache.EnsureDispatch('VirtualBox.Session')
218 win32com.client.gencache.EnsureDispatch('VirtualBox.VirtualBox')
219 win32com.client.gencache.EnsureDispatch('VirtualBox.Console')
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 str += "result.setLocalObject("+iface+"Impl())\n"
358 exec (str,d,d)
359 return d['result']
360
361 def waitForEvents(self, timeout):
362 import xpcom
363 xpcom._xpcom.WaitForEvents(timeout)
364
365 def interruptWaitEvents(self):
366 import xpcom
367 xpcom._xpcom.InterruptWait()
368
369 def deinit(self):
370 import xpcom
371 xpcom._xpcom.DeinitCOM()
372
373class PlatformWEBSERVICE:
374 def __init__(self, params):
375 sys.path.append(os.path.join(VboxSdkDir,'bindings', 'webservice', 'python', 'lib'))
376 # not really needed, but just fail early if misconfigured
377 import VirtualBox_services
378 import VirtualBox_wrappers
379 from VirtualBox_wrappers import IWebsessionManager2
380
381 if params is not None:
382 self.user = params.get("user", "")
383 self.password = params.get("password", "")
384 self.url = params.get("url", "")
385 else:
386 self.user = ""
387 self.password = ""
388 self.url = None
389 self.vbox = None
390
391 def getSessionObject(self, vbox):
392 return self.wsmgr.getSessionObject(vbox)
393
394 def getVirtualBox(self):
395 return self.connect(self.url, self.user, self.password)
396
397 def connect(self, url, user, passwd):
398 if self.vbox is not None:
399 self.disconnect()
400 from VirtualBox_wrappers import IWebsessionManager2
401 if url is None:
402 url = ""
403 self.url = url
404 if user is None:
405 user = ""
406 self.user = user
407 if passwd is None:
408 passwd = ""
409 self.password = passwd
410 self.wsmgr = IWebsessionManager2(self.url)
411 self.vbox = self.wsmgr.logon(self.user, self.password)
412 if not self.vbox.handle:
413 raise Exception("cannot connect to '"+self.url+"' as '"+self.user+"'")
414 return self.vbox
415
416 def disconnect(self):
417 if self.vbox is not None and self.wsmgr is not None:
418 self.wsmgr.logoff(self.vbox)
419 self.vbox = None
420 self.wsmgr = None
421
422 def getType(self):
423 return 'WEBSERVICE'
424
425 def getRemote(self):
426 return True
427
428 def getArray(self, obj, field):
429 return obj.__getattr__(field)
430
431 def initPerThread(self):
432 pass
433
434 def deinitPerThread(self):
435 pass
436
437 def createCallback(self, iface, impl, arg):
438 raise Exception("no callbacks for webservices")
439
440 def waitForEvents(self, timeout):
441 # Webservices cannot do that yet
442 pass
443
444 def interruptWaitEvents(self, timeout):
445 # Webservices cannot do that yet
446 pass
447
448 def deinit(self):
449 try:
450 disconnect()
451 except:
452 pass
453
454class SessionManager:
455 def __init__(self, mgr):
456 self.mgr = mgr
457
458 def getSessionObject(self, vbox):
459 return self.mgr.platform.getSessionObject(vbox)
460
461class VirtualBoxManager:
462 def __init__(self, style, platparams):
463 if style is None:
464 if sys.platform == 'win32':
465 style = "MSCOM"
466 else:
467 style = "XPCOM"
468
469
470 exec "self.platform = Platform"+style+"(platparams)"
471 # for webservices, enums are symbolic
472 self.constants = VirtualBoxReflectionInfo(style == "WEBSERVICE")
473 self.type = self.platform.getType()
474 self.remote = self.platform.getRemote()
475 self.style = style
476 self.mgr = SessionManager(self)
477
478 try:
479 self.vbox = self.platform.getVirtualBox()
480 except NameError,ne:
481 print "Installation problem: check that appropriate libs in place"
482 traceback.print_exc()
483 raise ne
484 except Exception,e:
485 print "init exception: ",e
486 traceback.print_exc()
487 if self.remote:
488 self.vbox = None
489 else:
490 raise e
491
492 def getArray(self, obj, field):
493 return self.platform.getArray(obj, field)
494
495 def getVirtualBox(self):
496 return self.platform.getVirtualBox()
497
498 def __del__(self):
499 self.deinit()
500
501 def deinit(self):
502 if hasattr(self, "vbox"):
503 del self.vbox
504 self.vbox = None
505 if hasattr(self, "platform"):
506 self.platform.deinit()
507 self.platform = None
508
509 def initPerThread(self):
510 self.platform.initPerThread()
511
512 def openMachineSession(self, machineId):
513 session = self.mgr.getSessionObject(self.vbox)
514 try:
515 self.vbox.openExistingSession(session, machineId)
516 except:
517 self.vbox.openSession(session, machineId)
518 return session
519
520 def closeMachineSession(self, session):
521 if session is not None:
522 session.close()
523
524 def deinitPerThread(self):
525 self.platform.deinitPerThread()
526
527 def createCallback(self, iface, impl, arg):
528 return self.platform.createCallback(iface, impl, arg)
529
530 def waitForEvents(self, timeout):
531 return self.platform.waitForEvents(timeout)
532
533 def interruptWaitEvents(self):
534 return self.platform.interruptWaitEvents()
535
536 def getPerfCollector(self, vbox):
537 return PerfCollector(self, vbox)
538
539 def getBinDir(self):
540 global VboxBinDir
541 return VboxBinDir
542
543 def getSdkDir(self):
544 global VboxSdkDir
545 return VboxSdkDir
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