VirtualBox

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

Last change on this file since 30430 was 30393, checked in by vboxsync, 14 years ago

Main, glue: webservice events

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