VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxShell/shellcommon.py@ 19020

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

SDK: proper SVN props

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.9 KB
Line 
1import traceback
2import sys
3import pdb
4
5class PerfCollector:
6 """ This class provides a wrapper over IPerformanceCollector in order to
7 get more 'pythonic' interface.
8
9 To begin collection of metrics use setup() method.
10
11 To get collected data use query() method.
12
13 It is possible to disable metric collection without changing collection
14 parameters with disable() method. The enable() method resumes metric
15 collection.
16 """
17
18 def __init__(self, vb):
19 """ Initializes the instance.
20
21 Pass an instance of IVirtualBox as parameter.
22 """
23 self.collector = vb.performanceCollector
24
25 def setup(self, names, objects, period, nsamples):
26 """ Discards all previously collected values for the specified
27 metrics, sets the period of collection and the number of retained
28 samples, enables collection.
29 """
30 self.collector.setupMetrics(names, objects, period, nsamples)
31
32 def enable(self, names, objects):
33 """ Resumes metric collection for the specified metrics.
34 """
35 self.collector.enableMetrics(names, objects)
36
37 def disable(self, names, objects):
38 """ Suspends metric collection for the specified metrics.
39 """
40 self.collector.disableMetrics(names, objects)
41
42 def query(self, names, objects):
43 """ Retrieves collected metric values as well as some auxiliary
44 information. Returns an array of dictionaries, one dictionary per
45 metric. Each dictionary contains the following entries:
46 'name': metric name
47 'object': managed object this metric associated with
48 'unit': unit of measurement
49 'scale': divide 'values' by this number to get float numbers
50 'values': collected data
51 'values_as_string': pre-processed values ready for 'print' statement
52 """
53 (values, names_out, objects_out, units, scales, sequence_numbers,
54 indices, lengths) = self.collector.queryMetricsData(names, objects)
55 out = []
56 for i in xrange(0, len(names_out)):
57 scale = int(scales[i])
58 if scale != 1:
59 fmt = '%.2f%s'
60 else:
61 fmt = '%d %s'
62 out.append({
63 'name':str(names_out[i]),
64 'object':str(objects_out[i]),
65 'unit':str(units[i]),
66 'scale':scale,
67 'values':[int(values[j]) for j in xrange(int(indices[i]), int(indices[i])+int(lengths[i]))],
68 'values_as_string':'['+', '.join([fmt % (int(values[j])/scale, units[i]) for j in xrange(int(indices[i]), int(indices[i])+int(lengths[i]))])+']'
69 })
70 return out
71
72g_hasreadline = 1
73try:
74 import readline
75 import rlcompleter
76except:
77 g_hasreadline = 0
78
79
80if g_hasreadline:
81 class CompleterNG(rlcompleter.Completer):
82 def __init__(self, dic, ctx):
83 self.ctx = ctx
84 return rlcompleter.Completer.__init__(self,dic)
85
86 def complete(self, text, state):
87 """
88 taken from:
89 http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/496812
90 """
91 if text == "":
92 return ['\t',None][state]
93 else:
94 return rlcompleter.Completer.complete(self,text,state)
95
96 def global_matches(self, text):
97 """
98 Compute matches when text is a simple name.
99 Return a list of all names currently defined
100 in self.namespace that match.
101 """
102
103 matches = []
104 n = len(text)
105
106 for list in [ self.namespace ]:
107 for word in list:
108 if word[:n] == text:
109 matches.append(word)
110
111
112 try:
113 for m in getMachines(self.ctx):
114 # although it has autoconversion, we need to cast
115 # explicitly for subscripts to work
116 word = str(m.name)
117 if word[:n] == text:
118 matches.append(word)
119 word = str(m.id)
120 if word[0] == '{':
121 word = word[1:-1]
122 if word[:n] == text:
123 matches.append(word)
124 except Exception,e:
125 traceback.print_exc()
126 print e
127
128 return matches
129
130
131def autoCompletion(commands, ctx):
132 if not g_hasreadline:
133 return
134
135 comps = {}
136 for (k,v) in commands.items():
137 comps[k] = None
138 completer = CompleterNG(comps, ctx)
139 readline.set_completer(completer.complete)
140 readline.parse_and_bind("tab: complete")
141
142g_verbose = True
143
144def split_no_quotes(s):
145 return s.split()
146
147def createVm(ctx,name,kind,base):
148 mgr = ctx['mgr']
149 vb = ctx['vb']
150 session = mgr.getSessionObject(vb)
151 mach = vb.createMachine(name, kind, base,
152 "00000000-0000-0000-0000-000000000000")
153 mach.saveSettings()
154 print "created machine with UUID",mach.id
155 vb.registerMachine(mach)
156
157def removeVm(ctx,mach):
158 mgr = ctx['mgr']
159 vb = ctx['vb']
160 print "removing machine ",mach.name,"with UUID",mach.id
161 mach = vb.unregisterMachine(mach.id)
162 if mach:
163 mach.deleteSettings()
164
165def startVm(ctx,mach,type):
166 mgr = ctx['mgr']
167 vb = ctx['vb']
168 perf = ctx['perf']
169 session = mgr.getSessionObject(vb)
170 uuid = mach.id
171 progress = vb.openRemoteSession(session, uuid, type, "")
172 progress.waitForCompletion(-1)
173 completed = progress.completed
174 rc = progress.resultCode
175 print "Completed:", completed, "rc:",hex(rc&0xffffffff)
176 if int(rc) == 0:
177 # we ignore exceptions to allow starting VM even if
178 # perf collector cannot be started
179 try:
180 perf.setup(['*'], [mach], 10, 15)
181 except:
182 print e
183 if g_verbose:
184 traceback.print_exc()
185 pass
186 # if session not opened, close doesn't make sense
187 session.close()
188 else:
189 # Not yet implemented error string query API for remote API
190 if not ctx['remote']:
191 print session.QueryErrorObject(rc)
192
193def getMachines(ctx):
194 return ctx['vb'].getMachines()
195
196def asState(var):
197 if var:
198 return 'on'
199 else:
200 return 'off'
201
202def guestStats(ctx,mach):
203 for metric in ctx['perf'].query(["*"], [mach]):
204 print metric['name'], metric['values_as_string']
205
206def guestExec(ctx, machine, console, cmds):
207 exec cmds
208
209def cmdExistingVm(ctx,mach,cmd,args):
210 mgr=ctx['mgr']
211 vb=ctx['vb']
212 session = mgr.getSessionObject(vb)
213 uuid = mach.id
214 try:
215 progress = vb.openExistingSession(session, uuid)
216 except Exception,e:
217 print "Session to '%s' not open: %s" %(mach.name,e)
218 if g_verbose:
219 traceback.print_exc()
220 return
221 if session.state != ctx['ifaces'].SessionState.Open:
222 print "Session to '%s' in wrong state: %s" %(mach.name, session.state)
223 return
224 # unfortunately IGuest is suppressed, thus WebServices knows not about it
225 # this is an example how to handle local only functionality
226 if ctx['remote'] and cmd == 'stats2':
227 print 'Trying to use local only functionality, ignored'
228 return
229 console=session.console
230 ops={'pause' : lambda: console.pause(),
231 'resume': lambda: console.resume(),
232 'powerdown': lambda: console.powerDown(),
233 'stats': lambda: guestStats(ctx, mach),
234 'guest': lambda: guestExec(ctx, mach, console, args)
235 }
236 try:
237 ops[cmd]()
238 except Exception, e:
239 print 'failed: ',e
240 if g_verbose:
241 traceback.print_exc()
242
243 session.close()
244
245# can cache known machines, if needed
246def machById(ctx,id):
247 mach = None
248 for m in getMachines(ctx):
249 if m.name == id:
250 mach = m
251 break
252 mid = str(m.id)
253 if mid[0] == '{':
254 mid = mid[1:-1]
255 if mid == id:
256 mach = m
257 break
258 return mach
259
260def argsToMach(ctx,args):
261 if len(args) < 2:
262 print "usage: %s [vmname|uuid]" %(args[0])
263 return None
264 id = args[1]
265 m = machById(ctx, id)
266 if m == None:
267 print "Machine '%s' is unknown, use list command to find available machines" %(id)
268 return m
269
270def helpCmd(ctx, args):
271 if len(args) == 1:
272 print "Help page:"
273 for i in commands:
274 print " ",i,":", commands[i][0]
275 else:
276 c = commands.get(args[1], None)
277 if c == None:
278 print "Command '%s' not known" %(args[1])
279 else:
280 print " ",args[1],":", c[0]
281 return 0
282
283def listCmd(ctx, args):
284 for m in getMachines(ctx):
285 print "Machine '%s' [%s], state=%s" %(m.name,m.id,m.sessionState)
286 return 0
287
288def infoCmd(ctx,args):
289 if (len(args) < 2):
290 print "usage: info [vmname|uuid]"
291 return 0
292 mach = argsToMach(ctx,args)
293 if mach == None:
294 return 0
295 os = ctx['vb'].getGuestOSType(mach.OSTypeId)
296 print " Name: ",mach.name
297 print " ID: ",mach.id
298 print " OS Type: ",os.description
299 print " RAM: %dM" %(mach.memorySize)
300 print " VRAM: %dM" %(mach.VRAMSize)
301 print " Clipboard mode: %d" %(mach.clipboardMode)
302 print " Machine status: " ,mach.sessionState
303 bios = mach.BIOSSettings
304 print " BIOS ACPI: ",bios.ACPIEnabled
305 print " PAE: ",mach.PAEEnabled
306 print " Hardware virtualization: ",asState(mach.HWVirtExEnabled)
307 print " Nested paging: ",asState(mach.HWVirtExNestedPagingEnabled)
308 print " Last changed: ",mach.lastStateChange
309
310 return 0
311
312def startCmd(ctx, args):
313 mach = argsToMach(ctx,args)
314 if mach == None:
315 return 0
316 if len(args) > 2:
317 type = args[2]
318 else:
319 type = "gui"
320 startVm(ctx, mach, type)
321 return 0
322
323def createCmd(ctx, args):
324 if (len(args) < 3 or len(args) > 4):
325 print "usage: create name ostype <basefolder>"
326 return 0
327 name = args[1]
328 oskind = args[2]
329 if len(args) == 4:
330 base = args[3]
331 else:
332 base = ''
333 try:
334 ctx['vb'].getGuestOSType(oskind)
335 except Exception, e:
336 print 'Unknown OS type:',oskind
337 return 0
338 createVm(ctx, name, oskind, base)
339 return 0
340
341def removeCmd(ctx, args):
342 mach = argsToMach(ctx,args)
343 if mach == None:
344 return 0
345 removeVm(ctx, mach)
346 return 0
347
348def pauseCmd(ctx, args):
349 mach = argsToMach(ctx,args)
350 if mach == None:
351 return 0
352 cmdExistingVm(ctx, mach, 'pause', '')
353 return 0
354
355def powerdownCmd(ctx, args):
356 mach = argsToMach(ctx,args)
357 if mach == None:
358 return 0
359 cmdExistingVm(ctx, mach, 'powerdown', '')
360 return 0
361
362def resumeCmd(ctx, args):
363 mach = argsToMach(ctx,args)
364 if mach == None:
365 return 0
366 cmdExistingVm(ctx, mach, 'resume', '')
367 return 0
368
369def statsCmd(ctx, args):
370 mach = argsToMach(ctx,args)
371 if mach == None:
372 return 0
373 cmdExistingVm(ctx, mach, 'stats', '')
374 return 0
375
376def guestCmd(ctx, args):
377 if (len(args) < 3):
378 print "usage: guest name commands"
379 return 0
380 mach = argsToMach(ctx,args)
381 if mach == None:
382 return 0
383 cmdExistingVm(ctx, mach, 'guest', ' '.join(args[2:]))
384 return 0
385
386def setvarCmd(ctx, args):
387 if (len(args) < 4):
388 print "usage: setvar [vmname|uuid] expr value"
389 return 0
390 mach = argsToMach(ctx,args)
391 if mach == None:
392 return 0
393 vbox = ctx['vb']
394 session = ctx['mgr'].getSessionObject(vbox)
395 vbox.openSession(session, mach.id)
396 mach = session.machine
397 expr = 'mach.'+args[2]+' = '+args[3]
398 print "Executing",expr
399 try:
400 exec expr
401 except Exception, e:
402 print 'failed: ',e
403 if g_verbose:
404 traceback.print_exc()
405 mach.saveSettings()
406 session.close()
407 return 0
408
409def quitCmd(ctx, args):
410 return 1
411
412def aliasesCmd(ctx, args):
413 for (k,v) in aliases.items():
414 print "'%s' is an alias for '%s'" %(k,v)
415 return 0
416
417def verboseCmd(ctx, args):
418 global g_verbose
419 g_verbose = not g_verbose
420 return 0
421
422def hostCmd(ctx, args):
423 host = ctx['vb'].host
424 cnt = host.processorCount
425 print "Processor count:",cnt
426 for i in range(0,cnt):
427 print "Processor #%d speed: %dMHz" %(i,host.getProcessorSpeed(i))
428
429 for metric in ctx['perf'].query(["*"], [host]):
430 print metric['name'], metric['values_as_string']
431
432 return 0
433
434
435def evalCmd(ctx, args):
436 expr = ' '.join(args[1:])
437 try:
438 exec expr
439 except Exception, e:
440 print 'failed: ',e
441 if g_verbose:
442 traceback.print_exc()
443 return 0
444
445aliases = {'s':'start',
446 'i':'info',
447 'l':'list',
448 'h':'help',
449 'a':'aliases',
450 'q':'quit', 'exit':'quit',
451 'v':'verbose'}
452
453commands = {'help':['Prints help information', helpCmd],
454 'start':['Start virtual machine by name or uuid', startCmd],
455 'create':['Create virtual machine', createCmd],
456 'remove':['Remove virtual machine', removeCmd],
457 'pause':['Pause virtual machine', pauseCmd],
458 'resume':['Resume virtual machine', resumeCmd],
459 'stats':['Stats for virtual machine', statsCmd],
460 'powerdown':['Power down virtual machine', powerdownCmd],
461 'list':['Shows known virtual machines', listCmd],
462 'info':['Shows info on machine', infoCmd],
463 'aliases':['Shows aliases', aliasesCmd],
464 'verbose':['Toggle verbosity', verboseCmd],
465 'setvar':['Set VMs variable: setvar Fedora BIOSSettings.ACPIEnabled True', setvarCmd],
466 'eval':['Evaluate arbitrary Python construction: eval for m in getMachines(ctx): print m.name,"has",m.memorySize,"M"', evalCmd],
467 'quit':['Exits', quitCmd],
468 'host':['Show host information', hostCmd],
469 'guest':['Execute command for guest: guest Win32 console.mouse.putMouseEvent(20, 20, 0, 0)', guestCmd],
470 }
471
472def runCommand(ctx, cmd):
473 if len(cmd) == 0: return 0
474 args = split_no_quotes(cmd)
475 if len(args) == 0: return 0
476 c = args[0]
477 if aliases.get(c, None) != None:
478 c = aliases[c]
479 ci = commands.get(c,None)
480 if ci == None:
481 print "Unknown command: '%s', type 'help' for list of known commands" %(c)
482 return 0
483 return ci[1](ctx, args)
484
485
486def interpret(ctx):
487 vbox = ctx['vb']
488 print "Running VirtualBox version %s" %(vbox.version)
489
490 ctx['perf'] = PerfCollector(vbox)
491
492 autoCompletion(commands, ctx)
493
494 # to allow to print actual host information, we collect info for
495 # last 150 secs maximum, (sample every 10 secs and keep up to 15 samples)
496 try:
497 ctx['perf'].setup(['*'], [vbox.host], 10, 15)
498 except:
499 pass
500
501 while True:
502 try:
503 cmd = raw_input("vbox> ")
504 done = runCommand(ctx, cmd)
505 if done != 0: break
506 except KeyboardInterrupt:
507 print '====== You can type quit or q to leave'
508 break
509 except EOFError:
510 break;
511 except Exception,e:
512 print e
513 if g_verbose:
514 traceback.print_exc()
515
516 try:
517 # There is no need to disable metric collection. This is just an example.
518 ctx['perf'].disable(['*'], [vbox.host])
519 except:
520 pass
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