VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxShell/vboxshell.py@ 24564

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

Python: shell command to save guest screenshot

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 35.7 KB
Line 
1#!/usr/bin/python
2#
3# Copyright (C) 2009 Sun Microsystems, Inc.
4#
5# This file is part of VirtualBox Open Source Edition (OSE), as
6# available from http://www.virtualbox.org. This file is free software;
7# you can redistribute it and/or modify it under the terms of the GNU
8# General Public License (GPL) as published by the Free Software
9# Foundation, in version 2 as it comes in the "COPYING" file of the
10# VirtualBox OSE distribution. VirtualBox OSE is distributed in the
11# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
12#
13# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
14# Clara, CA 95054 USA or visit http://www.sun.com if you need
15# additional information or have any questions.
16#
17#################################################################################
18# This program is a simple interactive shell for VirtualBox. You can query #
19# information and issue commands from a simple command line. #
20# #
21# It also provides you with examples on how to use VirtualBox's Python API. #
22# This shell is even somewhat documented and supports TAB-completion and #
23# history if you have Python readline installed. #
24# #
25# Enjoy. #
26################################################################################
27
28import os,sys
29import traceback
30import shlex
31import time
32
33# Simple implementation of IConsoleCallback, one can use it as skeleton
34# for custom implementations
35class GuestMonitor:
36 def __init__(self, mach):
37 self.mach = mach
38
39 def onMousePointerShapeChange(self, visible, alpha, xHot, yHot, width, height, shape):
40 print "%s: onMousePointerShapeChange: visible=%d" %(self.mach.name, visible)
41 def onMouseCapabilityChange(self, supportsAbsolute, needsHostCursor):
42 print "%s: onMouseCapabilityChange: needsHostCursor=%d" %(self.mach.name, needsHostCursor)
43
44 def onKeyboardLedsChange(self, numLock, capsLock, scrollLock):
45 print "%s: onKeyboardLedsChange capsLock=%d" %(self.mach.name, capsLock)
46
47 def onStateChange(self, state):
48 print "%s: onStateChange state=%d" %(self.mach.name, state)
49
50 def onAdditionsStateChange(self):
51 print "%s: onAdditionsStateChange" %(self.mach.name)
52
53 def onNetworkAdapterChange(self, adapter):
54 print "%s: onNetworkAdapterChange" %(self.mach.name)
55
56 def onSerialPortChange(self, port):
57 print "%s: onSerialPortChange" %(self.mach.name)
58
59 def onParallelPortChange(self, port):
60 print "%s: onParallelPortChange" %(self.mach.name)
61
62 def onStorageControllerChange(self):
63 print "%s: onStorageControllerChange" %(self.mach.name)
64
65 def onMediumChange(self, attachment):
66 print "%s: onMediumChange" %(self.mach.name)
67
68 def onVRDPServerChange(self):
69 print "%s: onVRDPServerChange" %(self.mach.name)
70
71 def onUSBControllerChange(self):
72 print "%s: onUSBControllerChange" %(self.mach.name)
73
74 def onUSBDeviceStateChange(self, device, attached, error):
75 print "%s: onUSBDeviceStateChange" %(self.mach.name)
76
77 def onSharedFolderChange(self, scope):
78 print "%s: onSharedFolderChange" %(self.mach.name)
79
80 def onRuntimeError(self, fatal, id, message):
81 print "%s: onRuntimeError fatal=%d message=%s" %(self.mach.name, fatal, message)
82
83 def onCanShowWindow(self):
84 print "%s: onCanShowWindow" %(self.mach.name)
85 return True
86
87 def onShowWindow(self, winId):
88 print "%s: onShowWindow: %d" %(self.mach.name, winId)
89
90class VBoxMonitor:
91 def __init__(self, params):
92 self.vbox = params[0]
93 self.isMscom = params[1]
94 pass
95
96 def onMachineStateChange(self, id, state):
97 print "onMachineStateChange: %s %d" %(id, state)
98
99 def onMachineDataChange(self,id):
100 print "onMachineDataChange: %s" %(id)
101
102 def onExtraDataCanChange(self, id, key, value):
103 print "onExtraDataCanChange: %s %s=>%s" %(id, key, value)
104 # Witty COM bridge thinks if someone wishes to return tuple, hresult
105 # is one of values we want to return
106 if self.isMscom:
107 return "", 0, True
108 else:
109 return True, ""
110
111 def onExtraDataChange(self, id, key, value):
112 print "onExtraDataChange: %s %s=>%s" %(id, key, value)
113
114 def onMediaRegistered(self, id, type, registered):
115 print "onMediaRegistered: %s" %(id)
116
117 def onMachineRegistered(self, id, registred):
118 print "onMachineRegistered: %s" %(id)
119
120 def onSessionStateChange(self, id, state):
121 print "onSessionStateChange: %s %d" %(id, state)
122
123 def onSnapshotTaken(self, mach, id):
124 print "onSnapshotTaken: %s %s" %(mach, id)
125
126 def onSnapshotDiscarded(self, mach, id):
127 print "onSnapshotDiscarded: %s %s" %(mach, id)
128
129 def onSnapshotChange(self, mach, id):
130 print "onSnapshotChange: %s %s" %(mach, id)
131
132 def onGuestPropertyChange(self, id, name, newValue, flags):
133 print "onGuestPropertyChange: %s: %s=%s" %(id, name, newValue)
134
135g_hasreadline = 1
136try:
137 import readline
138 import rlcompleter
139except:
140 g_hasreadline = 0
141
142
143if g_hasreadline:
144 class CompleterNG(rlcompleter.Completer):
145 def __init__(self, dic, ctx):
146 self.ctx = ctx
147 return rlcompleter.Completer.__init__(self,dic)
148
149 def complete(self, text, state):
150 """
151 taken from:
152 http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/496812
153 """
154 if text == "":
155 return ['\t',None][state]
156 else:
157 return rlcompleter.Completer.complete(self,text,state)
158
159 def global_matches(self, text):
160 """
161 Compute matches when text is a simple name.
162 Return a list of all names currently defined
163 in self.namespace that match.
164 """
165
166 matches = []
167 n = len(text)
168
169 for list in [ self.namespace ]:
170 for word in list:
171 if word[:n] == text:
172 matches.append(word)
173
174
175 try:
176 for m in getMachines(self.ctx):
177 # although it has autoconversion, we need to cast
178 # explicitly for subscripts to work
179 word = str(m.name)
180 if word[:n] == text:
181 matches.append(word)
182 word = str(m.id)
183 if word[0] == '{':
184 word = word[1:-1]
185 if word[:n] == text:
186 matches.append(word)
187 except Exception,e:
188 traceback.print_exc()
189 print e
190
191 return matches
192
193
194def autoCompletion(commands, ctx):
195 if not g_hasreadline:
196 return
197
198 comps = {}
199 for (k,v) in commands.items():
200 comps[k] = None
201 completer = CompleterNG(comps, ctx)
202 readline.set_completer(completer.complete)
203 readline.parse_and_bind("tab: complete")
204
205g_verbose = True
206
207def split_no_quotes(s):
208 return shlex.split(s)
209
210def progressBar(ctx,p,wait=1000):
211 try:
212 while not p.completed:
213 print "%d %%\r" %(p.percent),
214 sys.stdout.flush()
215 p.waitForCompletion(wait)
216 ctx['global'].waitForEvents(0)
217 except KeyboardInterrupt:
218 print "Interrupted."
219
220
221def createVm(ctx,name,kind,base):
222 mgr = ctx['mgr']
223 vb = ctx['vb']
224 mach = vb.createMachine(name, kind, base, "")
225 mach.saveSettings()
226 print "created machine with UUID",mach.id
227 vb.registerMachine(mach)
228 # update cache
229 getMachines(ctx, True)
230
231def removeVm(ctx,mach):
232 mgr = ctx['mgr']
233 vb = ctx['vb']
234 id = mach.id
235 print "removing machine ",mach.name,"with UUID",id
236 session = ctx['global'].openMachineSession(id)
237 try:
238 mach = session.machine
239 for d in ctx['global'].getArray(mach, 'hardDiskAttachments'):
240 mach.detachHardDisk(d.controller, d.port, d.device)
241 except:
242 traceback.print_exc()
243 mach.saveSettings()
244 ctx['global'].closeMachineSession(session)
245 mach = vb.unregisterMachine(id)
246 if mach:
247 mach.deleteSettings()
248 # update cache
249 getMachines(ctx, True)
250
251def startVm(ctx,mach,type):
252 mgr = ctx['mgr']
253 vb = ctx['vb']
254 perf = ctx['perf']
255 session = mgr.getSessionObject(vb)
256 uuid = mach.id
257 progress = vb.openRemoteSession(session, uuid, type, "")
258 progressBar(ctx, progress, 100)
259 completed = progress.completed
260 rc = int(progress.resultCode)
261 print "Completed:", completed, "rc:",hex(rc&0xffffffff)
262 if rc == 0:
263 # we ignore exceptions to allow starting VM even if
264 # perf collector cannot be started
265 if perf:
266 try:
267 perf.setup(['*'], [mach], 10, 15)
268 except Exception,e:
269 print e
270 if g_verbose:
271 traceback.print_exc()
272 pass
273 # if session not opened, close doesn't make sense
274 session.close()
275 else:
276 # Not yet implemented error string query API for remote API
277 if not ctx['remote']:
278 print session.QueryErrorObject(rc)
279
280def getMachines(ctx, invalidate = False):
281 if ctx['vb'] is not None:
282 if ctx['_machlist'] is None or invalidate:
283 ctx['_machlist'] = ctx['global'].getArray(ctx['vb'], 'machines')
284 return ctx['_machlist']
285 else:
286 return []
287
288def asState(var):
289 if var:
290 return 'on'
291 else:
292 return 'off'
293
294def guestStats(ctx,mach):
295 if not ctx['perf']:
296 return
297 for metric in ctx['perf'].query(["*"], [mach]):
298 print metric['name'], metric['values_as_string']
299
300def guestExec(ctx, machine, console, cmds):
301 exec cmds
302
303def monitorGuest(ctx, machine, console, dur):
304 cb = ctx['global'].createCallback('IConsoleCallback', GuestMonitor, machine)
305 console.registerCallback(cb)
306 if dur == -1:
307 # not infinity, but close enough
308 dur = 100000
309 try:
310 end = time.time() + dur
311 while time.time() < end:
312 ctx['global'].waitForEvents(500)
313 # We need to catch all exceptions here, otherwise callback will never be unregistered
314 except:
315 pass
316 console.unregisterCallback(cb)
317
318
319def monitorVBox(ctx, dur):
320 vbox = ctx['vb']
321 isMscom = (ctx['global'].type == 'MSCOM')
322 cb = ctx['global'].createCallback('IVirtualBoxCallback', VBoxMonitor, [vbox, isMscom])
323 vbox.registerCallback(cb)
324 if dur == -1:
325 # not infinity, but close enough
326 dur = 100000
327 try:
328 end = time.time() + dur
329 while time.time() < end:
330 ctx['global'].waitForEvents(500)
331 # We need to catch all exceptions here, otherwise callback will never be unregistered
332 except:
333 pass
334 vbox.unregisterCallback(cb)
335
336
337def takeScreenshot(ctx,console,args):
338 from PIL import Image
339 display = console.display
340 if len(args) > 0:
341 f = args[0]
342 else:
343 f = "/tmp/screenshot.png"
344 if len(args) > 1:
345 w = args[1]
346 else:
347 w = console.display.width
348 if len(args) > 2:
349 h = args[2]
350 else:
351 h = console.display.height
352 print "Saving screenshot (%d x %d) in %s..." %(w,h,f)
353 data = display.takeScreenShotSlow(w,h)
354 size = (w,h)
355 mode = "RGBA"
356 im = Image.frombuffer(mode, size, data, "raw", mode, 0, 1)
357 im.save(f, "PNG")
358
359
360def cmdExistingVm(ctx,mach,cmd,args):
361 mgr=ctx['mgr']
362 vb=ctx['vb']
363 session = mgr.getSessionObject(vb)
364 uuid = mach.id
365 try:
366 progress = vb.openExistingSession(session, uuid)
367 except Exception,e:
368 print "Session to '%s' not open: %s" %(mach.name,e)
369 if g_verbose:
370 traceback.print_exc()
371 return
372 if session.state != ctx['ifaces'].SessionState_Open:
373 print "Session to '%s' in wrong state: %s" %(mach.name, session.state)
374 return
375 # unfortunately IGuest is suppressed, thus WebServices knows not about it
376 # this is an example how to handle local only functionality
377 if ctx['remote'] and cmd == 'stats2':
378 print 'Trying to use local only functionality, ignored'
379 return
380 console=session.console
381 ops={'pause': lambda: console.pause(),
382 'resume': lambda: console.resume(),
383 'powerdown': lambda: console.powerDown(),
384 'powerbutton': lambda: console.powerButton(),
385 'stats': lambda: guestStats(ctx, mach),
386 'guest': lambda: guestExec(ctx, mach, console, args),
387 'monitorGuest': lambda: monitorGuest(ctx, mach, console, args),
388 'save': lambda: progressBar(ctx,console.saveState()),
389 'screenshot': lambda: takeScreenshot(ctx,console,args)
390 }
391 try:
392 ops[cmd]()
393 except Exception, e:
394 print 'failed: ',e
395 if g_verbose:
396 traceback.print_exc()
397
398 session.close()
399
400def machById(ctx,id):
401 mach = None
402 for m in getMachines(ctx):
403 if m.name == id:
404 mach = m
405 break
406 mid = str(m.id)
407 if mid[0] == '{':
408 mid = mid[1:-1]
409 if mid == id:
410 mach = m
411 break
412 return mach
413
414def argsToMach(ctx,args):
415 if len(args) < 2:
416 print "usage: %s [vmname|uuid]" %(args[0])
417 return None
418 id = args[1]
419 m = machById(ctx, id)
420 if m == None:
421 print "Machine '%s' is unknown, use list command to find available machines" %(id)
422 return m
423
424def helpSingleCmd(cmd,h,sp):
425 if sp != 0:
426 spec = " [ext from "+sp+"]"
427 else:
428 spec = ""
429 print " %s: %s%s" %(cmd,h,spec)
430
431def helpCmd(ctx, args):
432 if len(args) == 1:
433 print "Help page:"
434 names = commands.keys()
435 names.sort()
436 for i in names:
437 helpSingleCmd(i, commands[i][0], commands[i][2])
438 else:
439 cmd = args[1]
440 c = commands.get(cmd)
441 if c == None:
442 print "Command '%s' not known" %(cmd)
443 else:
444 helpSingleCmd(cmd, c[0], c[2])
445 return 0
446
447def listCmd(ctx, args):
448 for m in getMachines(ctx, True):
449 print "Machine '%s' [%s], state=%s" %(m.name,m.id,m.sessionState)
450 return 0
451
452def getControllerType(type):
453 if type == 0:
454 return "Null"
455 elif type == 1:
456 return "LsiLogic"
457 elif type == 2:
458 return "BusLogic"
459 elif type == 3:
460 return "IntelAhci"
461 elif type == 4:
462 return "PIIX3"
463 elif type == 5:
464 return "PIIX4"
465 elif type == 6:
466 return "ICH6"
467 else:
468 return "Unknown"
469
470def infoCmd(ctx,args):
471 if (len(args) < 2):
472 print "usage: info [vmname|uuid]"
473 return 0
474 mach = argsToMach(ctx,args)
475 if mach == None:
476 return 0
477 os = ctx['vb'].getGuestOSType(mach.OSTypeId)
478 print " One can use setvar <mach> <var> <value> to change variable, using name in []."
479 print " Name [name]: %s" %(mach.name)
480 print " ID [n/a]: %s" %(mach.id)
481 print " OS Type [n/a]: %s" %(os.description)
482 print " Firmware [firmwareType]: %s" %(mach.firmwareType)
483 print
484 print " CPUs [CPUCount]: %d" %(mach.CPUCount)
485 print " RAM [memorySize]: %dM" %(mach.memorySize)
486 print " VRAM [VRAMSize]: %dM" %(mach.VRAMSize)
487 print " Monitors [monitorCount]: %d" %(mach.monitorCount)
488 print
489 print " Clipboard mode [clipboardMode]: %d" %(mach.clipboardMode)
490 print " Machine status [n/a]: %d" % (mach.sessionState)
491 print
492 bios = mach.BIOSSettings
493 print " ACPI [BIOSSettings.ACPIEnabled]: %s" %(asState(bios.ACPIEnabled))
494 print " APIC [BIOSSettings.IOAPICEnabled]: %s" %(asState(bios.IOAPICEnabled))
495 hwVirtEnabled = mach.getHWVirtExProperty(ctx['global'].constants.HWVirtExPropertyType_Enabled)
496 print " Hardware virtualization [mach.setHWVirtExProperty(ctx['global'].constants.HWVirtExPropertyType_Enabled,value)]: " + asState(hwVirtEnabled)
497 hwVirtVPID = mach.getHWVirtExProperty(ctx['global'].constants.HWVirtExPropertyType_VPID)
498 print " VPID support [mach.setHWVirtExProperty(ctx['global'].constants.HWVirtExPropertyType_VPID,value)]: " + asState(hwVirtVPID)
499 hwVirtNestedPaging = mach.getHWVirtExProperty(ctx['global'].constants.HWVirtExPropertyType_NestedPaging)
500 print " Nested paging [mach.setHWVirtExProperty(ctx['global'].constants.HWVirtExPropertyType_NestedPaging,value)]: " + asState(hwVirtNestedPaging)
501
502 print " Hardware 3d acceleration[accelerate3DEnabled]: " + asState(mach.accelerate3DEnabled)
503 print " Hardware 2d video acceleration[accelerate2DVideoEnabled]: " + asState(mach.accelerate2DVideoEnabled)
504
505 print " Last changed [n/a]: " + time.asctime(time.localtime(long(mach.lastStateChange)/1000))
506 print " VRDP server [VRDPServer.enabled]: %s" %(asState(mach.VRDPServer.enabled))
507
508 controllers = ctx['global'].getArray(mach, 'storageControllers')
509 if controllers:
510 print
511 print " Controllers:"
512 for controller in controllers:
513 print " %s %s bus: %d" % (controller.name, getControllerType(controller.controllerType), controller.bus)
514
515 attaches = ctx['global'].getArray(mach, 'mediumAttachments')
516 if attaches:
517 print
518 print " Mediums:"
519 for a in attaches:
520 print " Controller: %s port: %d device: %d type: %s:" % (a.controller, a.port, a.device, a.type)
521 m = a.medium
522 if a.type == ctx['global'].constants.DeviceType_HardDisk:
523 print " HDD:"
524 print " Id: %s" %(m.id)
525 print " Location: %s" %(m.location)
526 print " Name: %s" %(m.name)
527 print " Format: %s" %(m.format)
528
529 if a.type == ctx['global'].constants.DeviceType_DVD:
530 print " DVD:"
531 if m:
532 print " Id: %s" %(m.id)
533 print " Name: %s" %(m.name)
534 if m.hostDrive:
535 print " Host DVD %s" %(m.location)
536 if a.passthrough:
537 print " [passthrough mode]"
538 else:
539 print " Virtual image at %s" %(m.location)
540 print " Size: %s" %(m.size)
541
542 if a.type == ctx['global'].constants.DeviceType_Floppy:
543 print " Floppy:"
544 if m:
545 print " Id: %s" %(m.id)
546 print " Name: %s" %(m.name)
547 if m.hostDrive:
548 print " Host floppy %s" %(m.location)
549 else:
550 print " Virtual image at %s" %(m.location)
551 print " Size: %s" %(m.size)
552
553 return 0
554
555def startCmd(ctx, args):
556 mach = argsToMach(ctx,args)
557 if mach == None:
558 return 0
559 if len(args) > 2:
560 type = args[2]
561 else:
562 type = "gui"
563 startVm(ctx, mach, type)
564 return 0
565
566def createCmd(ctx, args):
567 if (len(args) < 3 or len(args) > 4):
568 print "usage: create name ostype <basefolder>"
569 return 0
570 name = args[1]
571 oskind = args[2]
572 if len(args) == 4:
573 base = args[3]
574 else:
575 base = ''
576 try:
577 ctx['vb'].getGuestOSType(oskind)
578 except Exception, e:
579 print 'Unknown OS type:',oskind
580 return 0
581 createVm(ctx, name, oskind, base)
582 return 0
583
584def removeCmd(ctx, args):
585 mach = argsToMach(ctx,args)
586 if mach == None:
587 return 0
588 removeVm(ctx, mach)
589 return 0
590
591def pauseCmd(ctx, args):
592 mach = argsToMach(ctx,args)
593 if mach == None:
594 return 0
595 cmdExistingVm(ctx, mach, 'pause', '')
596 return 0
597
598def powerdownCmd(ctx, args):
599 mach = argsToMach(ctx,args)
600 if mach == None:
601 return 0
602 cmdExistingVm(ctx, mach, 'powerdown', '')
603 return 0
604
605def powerbuttonCmd(ctx, args):
606 mach = argsToMach(ctx,args)
607 if mach == None:
608 return 0
609 cmdExistingVm(ctx, mach, 'powerbutton', '')
610 return 0
611
612def resumeCmd(ctx, args):
613 mach = argsToMach(ctx,args)
614 if mach == None:
615 return 0
616 cmdExistingVm(ctx, mach, 'resume', '')
617 return 0
618
619def saveCmd(ctx, args):
620 mach = argsToMach(ctx,args)
621 if mach == None:
622 return 0
623 cmdExistingVm(ctx, mach, 'save', '')
624 return 0
625
626def statsCmd(ctx, args):
627 mach = argsToMach(ctx,args)
628 if mach == None:
629 return 0
630 cmdExistingVm(ctx, mach, 'stats', '')
631 return 0
632
633def guestCmd(ctx, args):
634 if (len(args) < 3):
635 print "usage: guest name commands"
636 return 0
637 mach = argsToMach(ctx,args)
638 if mach == None:
639 return 0
640 cmdExistingVm(ctx, mach, 'guest', ' '.join(args[2:]))
641 return 0
642
643def screenshotCmd(ctx, args):
644 if (len(args) < 3):
645 print "usage: screenshot name file <width> <height>"
646 return 0
647 mach = argsToMach(ctx,args)
648 if mach == None:
649 return 0
650 cmdExistingVm(ctx, mach, 'screenshot', args[2:])
651 return 0
652
653def setvarCmd(ctx, args):
654 if (len(args) < 4):
655 print "usage: setvar [vmname|uuid] expr value"
656 return 0
657 mach = argsToMach(ctx,args)
658 if mach == None:
659 return 0
660 session = ctx['global'].openMachineSession(mach.id)
661 mach = session.machine
662 expr = 'mach.'+args[2]+' = '+args[3]
663 print "Executing",expr
664 try:
665 exec expr
666 except Exception, e:
667 print 'failed: ',e
668 if g_verbose:
669 traceback.print_exc()
670 mach.saveSettings()
671 session.close()
672 return 0
673
674def quitCmd(ctx, args):
675 return 1
676
677def aliasCmd(ctx, args):
678 if (len(args) == 3):
679 aliases[args[1]] = args[2]
680 return 0
681
682 for (k,v) in aliases.items():
683 print "'%s' is an alias for '%s'" %(k,v)
684 return 0
685
686def verboseCmd(ctx, args):
687 global g_verbose
688 g_verbose = not g_verbose
689 return 0
690
691def getUSBStateString(state):
692 if state == 0:
693 return "NotSupported"
694 elif state == 1:
695 return "Unavailable"
696 elif state == 2:
697 return "Busy"
698 elif state == 3:
699 return "Available"
700 elif state == 4:
701 return "Held"
702 elif state == 5:
703 return "Captured"
704 else:
705 return "Unknown"
706
707def hostCmd(ctx, args):
708 host = ctx['vb'].host
709 cnt = host.processorCount
710 print "Processor count:",cnt
711 for i in range(0,cnt):
712 print "Processor #%d speed: %dMHz %s" %(i,host.getProcessorSpeed(i), host.getProcessorDescription(i))
713
714 print "RAM: %dM (free %dM)" %(host.memorySize, host.memoryAvailable)
715 print "OS: %s (%s)" %(host.operatingSystem, host.OSVersion)
716 if host.Acceleration3DAvailable:
717 print "3D acceleration available"
718 else:
719 print "3D acceleration NOT available"
720
721 print "Network interfaces:"
722 for ni in ctx['global'].getArray(host, 'networkInterfaces'):
723 print " %s (%s)" %(ni.name, ni.IPAddress)
724
725 print "DVD drives:"
726 for dd in ctx['global'].getArray(host, 'DVDDrives'):
727 print " %s - %s" %(dd.name, dd.description)
728
729 print "USB devices:"
730 for ud in ctx['global'].getArray(host, 'USBDevices'):
731 print " %s (vendorId=%d productId=%d serial=%s) %s" %(ud.product, ud.vendorId, ud.productId, ud.serialNumber, getUSBStateString(ud.state))
732
733 if ctx['perf']:
734 for metric in ctx['perf'].query(["*"], [host]):
735 print metric['name'], metric['values_as_string']
736
737 return 0
738
739def monitorGuestCmd(ctx, args):
740 if (len(args) < 2):
741 print "usage: monitorGuest name (duration)"
742 return 0
743 mach = argsToMach(ctx,args)
744 if mach == None:
745 return 0
746 dur = 5
747 if len(args) > 2:
748 dur = float(args[2])
749 cmdExistingVm(ctx, mach, 'monitorGuest', dur)
750 return 0
751
752def monitorVBoxCmd(ctx, args):
753 if (len(args) > 2):
754 print "usage: monitorVBox (duration)"
755 return 0
756 dur = 5
757 if len(args) > 1:
758 dur = float(args[1])
759 monitorVBox(ctx, dur)
760 return 0
761
762def getAdapterType(ctx, type):
763 if (type == ctx['global'].constants.NetworkAdapterType_Am79C970A or
764 type == ctx['global'].constants.NetworkAdapterType_Am79C973):
765 return "pcnet"
766 elif (type == ctx['global'].constants.NetworkAdapterType_I82540EM or
767 type == ctx['global'].constants.NetworkAdapterType_I82545EM or
768 type == ctx['global'].constants.NetworkAdapterType_I82543GC):
769 return "e1000"
770 elif (type == ctx['global'].constants.NetworkAdapterType_Virtio):
771 return "virtio"
772 elif (type == ctx['global'].constants.NetworkAdapterType_Null):
773 return None
774 else:
775 raise Exception("Unknown adapter type: "+type)
776
777
778def portForwardCmd(ctx, args):
779 if (len(args) != 5):
780 print "usage: portForward <vm> <adapter> <hostPort> <guestPort>"
781 return 0
782 mach = argsToMach(ctx,args)
783 if mach == None:
784 return 0
785 adapterNum = int(args[2])
786 hostPort = int(args[3])
787 guestPort = int(args[4])
788 proto = "TCP"
789 session = ctx['global'].openMachineSession(mach.id)
790 mach = session.machine
791
792 adapter = mach.getNetworkAdapter(adapterNum)
793 adapterType = getAdapterType(ctx, adapter.adapterType)
794
795 profile_name = proto+"_"+str(hostPort)+"_"+str(guestPort)
796 config = "VBoxInternal/Devices/" + adapterType + "/"
797 config = config + str(adapter.slot) +"/LUN#0/Config/" + profile_name
798
799 mach.setExtraData(config + "/Protocol", proto)
800 mach.setExtraData(config + "/HostPort", str(hostPort))
801 mach.setExtraData(config + "/GuestPort", str(guestPort))
802
803 mach.saveSettings()
804 session.close()
805
806 return 0
807
808
809def showLogCmd(ctx, args):
810 if (len(args) < 2):
811 print "usage: showLog <vm> <num>"
812 return 0
813 mach = argsToMach(ctx,args)
814 if mach == None:
815 return 0
816
817 log = "VBox.log"
818 if (len(args) > 2):
819 log += "."+args[2]
820 fileName = os.path.join(mach.logFolder, log)
821
822 try:
823 lf = open(fileName, 'r')
824 except IOError,e:
825 print "cannot open: ",e
826 return 0
827
828 for line in lf:
829 print line,
830 lf.close()
831
832 return 0
833
834def evalCmd(ctx, args):
835 expr = ' '.join(args[1:])
836 try:
837 exec expr
838 except Exception, e:
839 print 'failed: ',e
840 if g_verbose:
841 traceback.print_exc()
842 return 0
843
844def reloadExtCmd(ctx, args):
845 # maybe will want more args smartness
846 checkUserExtensions(ctx, commands, getHomeFolder(ctx))
847 autoCompletion(commands, ctx)
848 return 0
849
850
851def runScriptCmd(ctx, args):
852 if (len(args) != 2):
853 print "usage: runScript <script>"
854 return 0
855 try:
856 lf = open(args[1], 'r')
857 except IOError,e:
858 print "cannot open:",args[1], ":",e
859 return 0
860
861 try:
862 for line in lf:
863 done = runCommand(ctx, line)
864 if done != 0: break
865 except Exception,e:
866 print "error:",e
867 if g_verbose:
868 traceback.print_exc()
869 lf.close()
870 return 0
871
872def sleepCmd(ctx, args):
873 if (len(args) != 2):
874 print "usage: sleep <secs>"
875 return 0
876
877 try:
878 time.sleep(float(args[1]))
879 except:
880 # to allow sleep interrupt
881 pass
882 return 0
883
884
885def shellCmd(ctx, args):
886 if (len(args) < 2):
887 print "usage: shell <commands>"
888 return 0
889 cmd = ' '.join(args[1:])
890 try:
891 os.system(cmd)
892 except KeyboardInterrupt:
893 # to allow shell command interruption
894 pass
895 return 0
896
897
898def connectCmd(ctx, args):
899 if (len(args) > 4):
900 print "usage: connect [url] [username] [passwd]"
901 return 0
902
903 if ctx['vb'] is not None:
904 print "Already connected, disconnect first..."
905 return 0
906
907 if (len(args) > 1):
908 url = args[1]
909 else:
910 url = None
911
912 if (len(args) > 2):
913 user = args[2]
914 else:
915 user = ""
916
917 if (len(args) > 3):
918 passwd = args[3]
919 else:
920 passwd = ""
921
922 vbox = ctx['global'].platform.connect(url, user, passwd)
923 ctx['vb'] = vbox
924 print "Running VirtualBox version %s" %(vbox.version)
925 ctx['perf'] = ctx['global'].getPerfCollector(ctx['vb'])
926 return 0
927
928def disconnectCmd(ctx, args):
929 if (len(args) != 1):
930 print "usage: disconnect"
931 return 0
932
933 if ctx['vb'] is None:
934 print "Not connected yet."
935 return 0
936
937 try:
938 ctx['global'].platform.disconnect()
939 except:
940 ctx['vb'] = None
941 raise
942
943 ctx['vb'] = None
944 return 0
945
946def exportVMCmd(ctx, args):
947 import sys
948
949 if len(args) < 3:
950 print "usage: exportVm <machine> <path> <format> <license>"
951 return 0
952 mach = ctx['machById'](args[1])
953 if mach is None:
954 return 0
955 path = args[2]
956 if (len(args) > 3):
957 format = args[3]
958 else:
959 format = "ovf-1.0"
960 if (len(args) > 4):
961 license = args[4]
962 else:
963 license = "GPL"
964
965 app = ctx['vb'].createAppliance()
966 desc = mach.export(app)
967 desc.addDescription(ctx['global'].constants.VirtualSystemDescriptionType_License, license, "")
968 p = app.write(format, path)
969 progressBar(ctx, p)
970 print "Exported to %s in format %s" %(path, format)
971 return 0
972
973aliases = {'s':'start',
974 'i':'info',
975 'l':'list',
976 'h':'help',
977 'a':'alias',
978 'q':'quit', 'exit':'quit',
979 'v':'verbose'}
980
981commands = {'help':['Prints help information', helpCmd, 0],
982 'start':['Start virtual machine by name or uuid', startCmd, 0],
983 'create':['Create virtual machine', createCmd, 0],
984 'remove':['Remove virtual machine', removeCmd, 0],
985 'pause':['Pause virtual machine', pauseCmd, 0],
986 'resume':['Resume virtual machine', resumeCmd, 0],
987 'save':['Save execution state of virtual machine', saveCmd, 0],
988 'stats':['Stats for virtual machine', statsCmd, 0],
989 'powerdown':['Power down virtual machine', powerdownCmd, 0],
990 'powerbutton':['Effectively press power button', powerbuttonCmd, 0],
991 'list':['Shows known virtual machines', listCmd, 0],
992 'info':['Shows info on machine', infoCmd, 0],
993 'alias':['Control aliases', aliasCmd, 0],
994 'verbose':['Toggle verbosity', verboseCmd, 0],
995 'setvar':['Set VMs variable: setvar Fedora BIOSSettings.ACPIEnabled True', setvarCmd, 0],
996 'eval':['Evaluate arbitrary Python construction: eval \'for m in getMachines(ctx): print m.name,"has",m.memorySize,"M"\'', evalCmd, 0],
997 'quit':['Exits', quitCmd, 0],
998 'host':['Show host information', hostCmd, 0],
999 'guest':['Execute command for guest: guest Win32 \'console.mouse.putMouseEvent(20, 20, 0, 0)\'', guestCmd, 0],
1000 'monitorGuest':['Monitor what happens with the guest for some time: monitorGuest Win32 10', monitorGuestCmd, 0],
1001 'monitorVBox':['Monitor what happens with Virtual Box for some time: monitorVBox 10', monitorVBoxCmd, 0],
1002 'portForward':['Setup permanent port forwarding for a VM, takes adapter number host port and guest port: portForward Win32 0 8080 80', portForwardCmd, 0],
1003 'showLog':['Show log file of the VM, : showLog Win32', showLogCmd, 0],
1004 'reloadExt':['Reload custom extensions: reloadExt', reloadExtCmd, 0],
1005 'runScript':['Run VBox script: runScript script.vbox', runScriptCmd, 0],
1006 'sleep':['Sleep for specified number of seconds: sleep 3.14159', sleepCmd, 0],
1007 'shell':['Execute external shell command: shell "ls /etc/rc*"', shellCmd, 0],
1008 'exportVm':['Export VM in OVF format: export Win /tmp/win.ovf', exportVMCmd, 0],
1009 'screenshot':['Take VM screenshot to a file: screenshot Win /tmp/win.png 1024 768', screenshotCmd, 0]
1010 }
1011
1012def runCommandArgs(ctx, args):
1013 c = args[0]
1014 if aliases.get(c, None) != None:
1015 c = aliases[c]
1016 ci = commands.get(c,None)
1017 if ci == None:
1018 print "Unknown command: '%s', type 'help' for list of known commands" %(c)
1019 return 0
1020 return ci[1](ctx, args)
1021
1022
1023def runCommand(ctx, cmd):
1024 if len(cmd) == 0: return 0
1025 args = split_no_quotes(cmd)
1026 if len(args) == 0: return 0
1027 return runCommandArgs(ctx, args)
1028
1029#
1030# To write your own custom commands to vboxshell, create
1031# file ~/.VirtualBox/shellext.py with content like
1032#
1033# def runTestCmd(ctx, args):
1034# print "Testy test", ctx['vb']
1035# return 0
1036#
1037# commands = {
1038# 'test': ['Test help', runTestCmd]
1039# }
1040# and issue reloadExt shell command.
1041# This file also will be read automatically on startup or 'reloadExt'.
1042#
1043# Also one can put shell extensions into ~/.VirtualBox/shexts and
1044# they will also be picked up, so this way one can exchange
1045# shell extensions easily.
1046def addExtsFromFile(ctx, cmds, file):
1047 if not os.path.isfile(file):
1048 return
1049 d = {}
1050 try:
1051 execfile(file, d, d)
1052 for (k,v) in d['commands'].items():
1053 if g_verbose:
1054 print "customize: adding \"%s\" - %s" %(k, v[0])
1055 cmds[k] = [v[0], v[1], file]
1056 except:
1057 print "Error loading user extensions from %s" %(file)
1058 traceback.print_exc()
1059
1060
1061def checkUserExtensions(ctx, cmds, folder):
1062 folder = str(folder)
1063 name = os.path.join(folder, "shellext.py")
1064 addExtsFromFile(ctx, cmds, name)
1065 # also check 'exts' directory for all files
1066 shextdir = os.path.join(folder, "shexts")
1067 if not os.path.isdir(shextdir):
1068 return
1069 exts = os.listdir(shextdir)
1070 for e in exts:
1071 addExtsFromFile(ctx, cmds, os.path.join(shextdir,e))
1072
1073def getHomeFolder(ctx):
1074 if ctx['remote'] or ctx['vb'] is None:
1075 return os.path.join(os.path.expanduser("~"), ".VirtualBox")
1076 else:
1077 return ctx['vb'].homeFolder
1078
1079def interpret(ctx):
1080 if ctx['remote']:
1081 commands['connect'] = ["Connect to remote VBox instance", connectCmd, 0]
1082 commands['disconnect'] = ["Disconnect from remote VBox instance", disconnectCmd, 0]
1083
1084 vbox = ctx['vb']
1085
1086 if vbox is not None:
1087 print "Running VirtualBox version %s" %(vbox.version)
1088 ctx['perf'] = ctx['global'].getPerfCollector(vbox)
1089 else:
1090 ctx['perf'] = None
1091
1092 home = getHomeFolder(ctx)
1093 checkUserExtensions(ctx, commands, home)
1094
1095 autoCompletion(commands, ctx)
1096
1097 # to allow to print actual host information, we collect info for
1098 # last 150 secs maximum, (sample every 10 secs and keep up to 15 samples)
1099 if ctx['perf']:
1100 try:
1101 ctx['perf'].setup(['*'], [vbox.host], 10, 15)
1102 except:
1103 pass
1104
1105 while True:
1106 try:
1107 cmd = raw_input("vbox> ")
1108 done = runCommand(ctx, cmd)
1109 if done != 0: break
1110 except KeyboardInterrupt:
1111 print '====== You can type quit or q to leave'
1112 break
1113 except EOFError:
1114 break;
1115 except Exception,e:
1116 print e
1117 if g_verbose:
1118 traceback.print_exc()
1119 ctx['global'].waitForEvents(0)
1120 try:
1121 # There is no need to disable metric collection. This is just an example.
1122 if ct['perf']:
1123 ctx['perf'].disable(['*'], [vbox.host])
1124 except:
1125 pass
1126
1127def runCommandCb(ctx, cmd, args):
1128 args.insert(0, cmd)
1129 return runCommandArgs(ctx, args)
1130
1131def main(argv):
1132 style = None
1133 autopath = False
1134 argv.pop(0)
1135 while len(argv) > 0:
1136 if argv[0] == "-w":
1137 style = "WEBSERVICE"
1138 if argv[0] == "-a":
1139 autopath = True
1140 argv.pop(0)
1141
1142 if autopath:
1143 cwd = os.getcwd()
1144 vpp = os.environ.get("VBOX_PROGRAM_PATH")
1145 if vpp is None and (os.path.isfile(os.path.join(cwd, "VirtualBox")) or os.path.isfile(os.path.join(cwd, "VirtualBox.exe"))) :
1146 vpp = cwd
1147 print "Autodetected VBOX_PROGRAM_PATH as",vpp
1148 os.environ["VBOX_PROGRAM_PATH"] = cwd
1149 sys.path.append(os.path.join(vpp, "sdk", "installer"))
1150
1151 from vboxapi import VirtualBoxManager
1152 g_virtualBoxManager = VirtualBoxManager(style, None)
1153 ctx = {'global':g_virtualBoxManager,
1154 'mgr':g_virtualBoxManager.mgr,
1155 'vb':g_virtualBoxManager.vbox,
1156 'ifaces':g_virtualBoxManager.constants,
1157 'remote':g_virtualBoxManager.remote,
1158 'type':g_virtualBoxManager.type,
1159 'run': lambda cmd,args: runCommandCb(ctx, cmd, args),
1160 'machById': lambda id: machById(ctx,id),
1161 'progressBar': lambda p: progressBar(ctx,p),
1162 '_machlist':None
1163 }
1164 interpret(ctx)
1165 g_virtualBoxManager.deinit()
1166 del g_virtualBoxManager
1167
1168if __name__ == '__main__':
1169 main(sys.argv)
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