VirtualBox

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

Last change on this file since 21906 was 21906, checked in by vboxsync, 16 years ago

Python glue: use Vbox platform in PerfCollector, not system platfrom, as webservices can run on both

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.5 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.215389.xyz. 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.platform.getType() == '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 self.constants = PlatformMSCOM.InterfacesWrapper()
208 from win32con import DUPLICATE_SAME_ACCESS
209 from win32api import GetCurrentThread,GetCurrentThreadId,DuplicateHandle,GetCurrentProcess
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
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 getConstants(self):
233 return self.constants
234
235 def getType(self):
236 return 'MSCOM'
237
238 def getRemote(self):
239 return False
240
241 def getArray(self, obj, field):
242 return obj.__getattr__(field)
243
244 def initPerThread(self):
245 import pythoncom
246 pythoncom.CoInitializeEx(0)
247
248 def deinitPerThread(self):
249 import pythoncom
250 pythoncom.CoUninitialize()
251
252 def createCallback(self, iface, impl, arg):
253 d = {}
254 d['BaseClass'] = impl
255 d['arg'] = arg
256 d['tlb_guid'] = PlatformMSCOM.VBOX_TLB_GUID
257 str = ""
258 str += "import win32com.server.util\n"
259 #str += "import win32com.server.register\n"
260 #str += "from win32com import universal\n"
261 str += "import pythoncom\n"
262 #str += "universal.RegisterInterfaces(tlb_guid, 0, 1, 0, ['"+iface+"'])\n"
263
264 str += "class "+iface+"Impl(BaseClass):\n"
265 str += " _com_interfaces_ = ['"+iface+"']\n"
266 str += " _typelib_guid_ = tlb_guid\n"
267 str += " _typelib_version_ = 1, 0\n"
268 #str += " _reg_clsctx_ = pythoncom.CLSCTX_LOCAL_SERVER\n"
269 #str += " _reg_clsid_ = '{F21202A2-959A-4149-B1C3-68B9013F3335}'\n"
270 #str += " _reg_progid_ = 'VirtualBox."+iface+"Impl'\n"
271 #str += " _reg_desc_ = 'Generated callback implementation class'\n"
272 #str += " _reg_policy_spec_ = 'win32com.server.policy.EventHandlerPolicy'\n"
273
274 # generate capitalized version of callbacks - that's how Python COM
275 # looks them up on Windows
276 for m in dir(impl):
277 if m.startswith("on"):
278 str += " "+ComifyName(m)+"=BaseClass."+m+"\n"
279
280 str += " def __init__(self): BaseClass.__init__(self, arg)\n"
281 #str += "win32com.server.register.UseCommandLine("+iface+"Impl)\n"
282
283 str += "result = win32com.server.util.wrap("+iface+"Impl())\n"
284 exec (str,d,d)
285 return d['result']
286
287 def waitForEvents(self, timeout):
288 from win32api import GetCurrentThreadId
289 from win32event import MsgWaitForMultipleObjects, \
290 QS_ALLINPUT, WAIT_TIMEOUT, WAIT_OBJECT_0
291 from pythoncom import PumpWaitingMessages
292
293 if (self.tid != GetCurrentThreadId()):
294 raise Exception("wait for events from the same thread you inited!")
295
296 rc = MsgWaitForMultipleObjects(self.handles, 0, timeout, QS_ALLINPUT)
297 if rc >= WAIT_OBJECT_0 and rc < WAIT_OBJECT_0+len(self.handles):
298 # is it possible?
299 pass
300 elif rc==WAIT_OBJECT_0 + len(self.handles):
301 # Waiting messages
302 PumpWaitingMessages()
303 else:
304 # Timeout
305 pass
306
307 def deinit(self):
308 import pythoncom
309 from win32file import CloseHandle
310
311 for h in self.handles:
312 if h is not None:
313 CloseHandle(h)
314 self.handles = None
315 pythoncom.CoUninitialize()
316 pass
317
318
319class PlatformXPCOM:
320 def __init__(self, params):
321 sys.path.append(VboxSdkDir+'/bindings/xpcom/python/')
322 import xpcom.vboxxpcom
323 import xpcom
324 import xpcom.components
325
326 def getSessionObject(self, vbox):
327 import xpcom.components
328 return xpcom.components.classes["@virtualbox.org/Session;1"].createInstance()
329
330 def getVirtualBox(self):
331 import xpcom.components
332 return xpcom.components.classes["@virtualbox.org/VirtualBox;1"].createInstance()
333
334 def getConstants(self):
335 import xpcom.components
336 return xpcom.components.interfaces
337
338 def getType(self):
339 return 'XPCOM'
340
341 def getRemote(self):
342 return False
343
344 def getArray(self, obj, field):
345 return obj.__getattr__('get'+ComifyName(field))()
346
347 def initPerThread(self):
348 pass
349
350 def deinitPerThread(self):
351 pass
352
353 def createCallback(self, iface, impl, arg):
354 d = {}
355 d['BaseClass'] = impl
356 d['arg'] = arg
357 str = ""
358 str += "import xpcom.components\n"
359 str += "class "+iface+"Impl(BaseClass):\n"
360 str += " _com_interfaces_ = xpcom.components.interfaces."+iface+"\n"
361 str += " def __init__(self): BaseClass.__init__(self, arg)\n"
362 str += "result = "+iface+"Impl()\n"
363 exec (str,d,d)
364 return d['result']
365
366 def waitForEvents(self, timeout):
367 import xpcom
368 xpcom._xpcom.WaitForEvents(timeout)
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 getConstants(self):
424 return None
425
426 def getType(self):
427 return 'WEBSERVICE'
428
429 def getRemote(self):
430 return True
431
432 def getArray(self, obj, field):
433 return obj.__getattr__(field)
434
435 def initPerThread(self):
436 pass
437
438 def deinitPerThread(self):
439 pass
440
441 def createCallback(self, iface, impl, arg):
442 raise Exception("no callbacks for webservices")
443
444 def waitForEvents(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 exec "self.platform = Platform"+style+"(platparams)"
470
471 self.constants = VirtualBoxReflectionInfo()
472 self.type = self.platform.getType()
473 self.remote = self.platform.getRemote()
474 self.style = style
475 self.mgr = SessionManager(self)
476
477 try:
478 self.vbox = self.platform.getVirtualBox()
479 except NameError,ne:
480 print "Installation problem: check that appropriate libs in place"
481 traceback.print_exc()
482 raise ne
483 except Exception,e:
484 print "init exception: ",e
485 traceback.print_exc()
486 if self.remote:
487 self.vbox = None
488 else:
489 raise e
490
491 def getArray(self, obj, field):
492 return self.platform.getArray(obj, field)
493
494 def getVirtualBox(self):
495 return self.platform.getVirtualBox()
496
497 def __del__(self):
498 self.deinit()
499
500 def deinit(self):
501 if hasattr(self, "vbox"):
502 del self.vbox
503 self.vbox = None
504 if hasattr(self, "platform"):
505 self.platform.deinit()
506 self.platform = None
507
508 def initPerThread(self):
509 self.platform.initPerThread()
510
511 def openMachineSession(self, machineId):
512 session = self.mgr.getSessionObject(self.vbox)
513 self.vbox.openSession(session, machineId)
514 return session
515
516 def closeMachineSession(self, session):
517 session.close()
518
519 def deinitPerThread(self):
520 self.platform.deinitPerThread()
521
522 def createCallback(self, iface, impl, arg):
523 return self.platform.createCallback(iface, impl, arg)
524
525 def waitForEvents(self, timeout):
526 return self.platform.waitForEvents(timeout)
527
528 def getPerfCollector(self, vbox):
529 return PerfCollector(self, vbox)
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette