VirtualBox

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

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

VBoxShell: small fixes making extention coding easier.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 91.0 KB
Line 
1#!/usr/bin/python
2#
3# Copyright (C) 2009-2010 Oracle Corporation
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#################################################################################
14# This program is a simple interactive shell for VirtualBox. You can query #
15# information and issue commands from a simple command line. #
16# #
17# It also provides you with examples on how to use VirtualBox's Python API. #
18# This shell is even somewhat documented, supports TAB-completion and #
19# history if you have Python readline installed. #
20# #
21# Finally, shell allows arbitrary custom extensions, just create #
22# .VirtualBox/shexts/ and drop your extensions there. #
23# Enjoy. #
24################################################################################
25
26import os,sys
27import traceback
28import shlex
29import time
30import re
31import platform
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 shape=%d bytes" %(self.mach.name, visible,len(shape))
41
42 def onMouseCapabilityChange(self, supportsAbsolute, supportsRelative, needsHostCursor):
43 print "%s: onMouseCapabilityChange: supportsAbsolute = %d, supportsRelative = %d, needsHostCursor = %d" %(self.mach.name, supportsAbsolute, supportsRelative, needsHostCursor)
44
45 def onKeyboardLedsChange(self, numLock, capsLock, scrollLock):
46 print "%s: onKeyboardLedsChange capsLock=%d" %(self.mach.name, capsLock)
47
48 def onStateChange(self, state):
49 print "%s: onStateChange state=%d" %(self.mach.name, state)
50
51 def onAdditionsStateChange(self):
52 print "%s: onAdditionsStateChange" %(self.mach.name)
53
54 def onNetworkAdapterChange(self, adapter):
55 print "%s: onNetworkAdapterChange" %(self.mach.name)
56
57 def onSerialPortChange(self, port):
58 print "%s: onSerialPortChange" %(self.mach.name)
59
60 def onParallelPortChange(self, port):
61 print "%s: onParallelPortChange" %(self.mach.name)
62
63 def onStorageControllerChange(self):
64 print "%s: onStorageControllerChange" %(self.mach.name)
65
66 def onMediumChange(self, attachment):
67 print "%s: onMediumChange" %(self.mach.name)
68
69 def onVRDPServerChange(self):
70 print "%s: onVRDPServerChange" %(self.mach.name)
71
72 def onUSBControllerChange(self):
73 print "%s: onUSBControllerChange" %(self.mach.name)
74
75 def onUSBDeviceStateChange(self, device, attached, error):
76 print "%s: onUSBDeviceStateChange" %(self.mach.name)
77
78 def onSharedFolderChange(self, scope):
79 print "%s: onSharedFolderChange" %(self.mach.name)
80
81 def onRuntimeError(self, fatal, id, message):
82 print "%s: onRuntimeError fatal=%d message=%s" %(self.mach.name, fatal, message)
83
84 def onCanShowWindow(self):
85 print "%s: onCanShowWindow" %(self.mach.name)
86 return True
87
88 def onShowWindow(self, winId):
89 print "%s: onShowWindow: %d" %(self.mach.name, winId)
90
91class VBoxMonitor:
92 def __init__(self, params):
93 self.vbox = params[0]
94 self.isMscom = params[1]
95 pass
96
97 def onMachineStateChange(self, id, state):
98 print "onMachineStateChange: %s %d" %(id, state)
99
100 def onMachineDataChange(self,id):
101 print "onMachineDataChange: %s" %(id)
102
103 def onExtraDataCanChange(self, id, key, value):
104 print "onExtraDataCanChange: %s %s=>%s" %(id, key, value)
105 # Witty COM bridge thinks if someone wishes to return tuple, hresult
106 # is one of values we want to return
107 if self.isMscom:
108 return "", 0, True
109 else:
110 return True, ""
111
112 def onExtraDataChange(self, id, key, value):
113 print "onExtraDataChange: %s %s=>%s" %(id, key, value)
114
115 def onMediaRegistered(self, id, type, registered):
116 print "onMediaRegistered: %s" %(id)
117
118 def onMachineRegistered(self, id, registred):
119 print "onMachineRegistered: %s" %(id)
120
121 def onSessionStateChange(self, id, state):
122 print "onSessionStateChange: %s %d" %(id, state)
123
124 def onSnapshotTaken(self, mach, id):
125 print "onSnapshotTaken: %s %s" %(mach, id)
126
127 def onSnapshotDeleted(self, mach, id):
128 print "onSnapshotDeleted: %s %s" %(mach, id)
129
130 def onSnapshotChange(self, mach, id):
131 print "onSnapshotChange: %s %s" %(mach, id)
132
133 def onGuestPropertyChange(self, id, name, newValue, flags):
134 print "onGuestPropertyChange: %s: %s=%s" %(id, name, newValue)
135
136g_hasreadline = True
137try:
138 if g_hasreadline:
139 import readline
140 import rlcompleter
141except:
142 g_hasreadline = False
143
144
145g_hascolors = True
146term_colors = {
147 'red':'\033[31m',
148 'blue':'\033[94m',
149 'green':'\033[92m',
150 'yellow':'\033[93m',
151 'magenta':'\033[35m'
152 }
153def colored(string,color):
154 if not g_hascolors:
155 return string
156 global term_colors
157 col = term_colors.get(color,None)
158 if col:
159 return col+str(string)+'\033[0m'
160 else:
161 return string
162
163if g_hasreadline:
164 import string
165 class CompleterNG(rlcompleter.Completer):
166 def __init__(self, dic, ctx):
167 self.ctx = ctx
168 return rlcompleter.Completer.__init__(self,dic)
169
170 def complete(self, text, state):
171 """
172 taken from:
173 http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/496812
174 """
175 if False and text == "":
176 return ['\t',None][state]
177 else:
178 return rlcompleter.Completer.complete(self,text,state)
179
180 def canBeCommand(self, phrase, word):
181 spaceIdx = phrase.find(" ")
182 begIdx = readline.get_begidx()
183 firstWord = (spaceIdx == -1 or begIdx < spaceIdx)
184 if firstWord:
185 return True
186 if phrase.startswith('help'):
187 return True
188 return False
189
190 def canBeMachine(self,phrase,word):
191 return not self.canBeCommand(phrase, word)
192
193 def global_matches(self, text):
194 """
195 Compute matches when text is a simple name.
196 Return a list of all names currently defined
197 in self.namespace that match.
198 """
199
200 matches = []
201 n = len(text)
202 phrase = readline.get_line_buffer()
203
204 if self.canBeCommand(phrase,text):
205 for list in [ self.namespace ]:
206 for word in list:
207 if word[:n] == text:
208 matches.append(word)
209 try:
210 if self.canBeMachine(phrase,text):
211 for m in getMachines(self.ctx, False, True):
212 # although it has autoconversion, we need to cast
213 # explicitly for subscripts to work
214 word = re.sub("(?<!\\\\) ", "\\ ", str(m.name))
215 if word[:n] == text:
216 matches.append(word)
217 word = str(m.id)
218 if word[0] == '{':
219 word = word[1:-1]
220 if word[:n] == text:
221 matches.append(word)
222 except Exception,e:
223 printErr(e)
224 if g_verbose:
225 traceback.print_exc()
226
227 return matches
228
229def autoCompletion(commands, ctx):
230 if not g_hasreadline:
231 return
232
233 comps = {}
234 for (k,v) in commands.items():
235 comps[k] = None
236 completer = CompleterNG(comps, ctx)
237 readline.set_completer(completer.complete)
238 delims = readline.get_completer_delims()
239 readline.set_completer_delims(re.sub("[\\.]", "", delims)) # remove some of the delimiters
240 readline.parse_and_bind("set editing-mode emacs")
241 # OSX need it
242 if platform.system() == 'Darwin':
243 # see http://www.certif.com/spec_help/readline.html
244 readline.parse_and_bind ("bind ^I rl_complete")
245 readline.parse_and_bind ("bind ^W ed-delete-prev-word")
246 # Doesn't work well
247 # readline.parse_and_bind ("bind ^R em-inc-search-prev")
248 readline.parse_and_bind("tab: complete")
249
250
251g_verbose = False
252
253def split_no_quotes(s):
254 return shlex.split(s)
255
256def progressBar(ctx,p,wait=1000):
257 try:
258 while not p.completed:
259 print "%s %%\r" %(colored(str(p.percent),'red')),
260 sys.stdout.flush()
261 p.waitForCompletion(wait)
262 ctx['global'].waitForEvents(0)
263 return 1
264 except KeyboardInterrupt:
265 print "Interrupted."
266 if p.cancelable:
267 print "Canceling task..."
268 p.cancel()
269 return 0
270
271def printErr(ctx,e):
272 print colored(str(e), 'red')
273
274def reportError(ctx,progress):
275 ei = progress.errorInfo
276 if ei:
277 print colored("Error in %s: %s" %(ei.component, ei.text), 'red')
278
279def colCat(ctx,str):
280 return colored(str, 'magenta')
281
282def colVm(ctx,vm):
283 return colored(vm, 'blue')
284
285def colPath(ctx,p):
286 return colored(p, 'green')
287
288def colSize(ctx,m):
289 return colored(m, 'red')
290
291def colSizeM(ctx,m):
292 return colored(str(m)+'M', 'red')
293
294def createVm(ctx,name,kind,base):
295 mgr = ctx['mgr']
296 vb = ctx['vb']
297 mach = vb.createMachine(name, kind, base, "", False)
298 mach.saveSettings()
299 print "created machine with UUID",mach.id
300 vb.registerMachine(mach)
301 # update cache
302 getMachines(ctx, True)
303
304def removeVm(ctx,mach):
305 mgr = ctx['mgr']
306 vb = ctx['vb']
307 id = mach.id
308 print "removing machine ",mach.name,"with UUID",id
309 cmdClosedVm(ctx, mach, detachVmDevice, ["ALL"])
310 mach = vb.unregisterMachine(id)
311 if mach:
312 mach.deleteSettings()
313 # update cache
314 getMachines(ctx, True)
315
316def startVm(ctx,mach,type):
317 mgr = ctx['mgr']
318 vb = ctx['vb']
319 perf = ctx['perf']
320 session = mgr.getSessionObject(vb)
321 uuid = mach.id
322 progress = vb.openRemoteSession(session, uuid, type, "")
323 if progressBar(ctx, progress, 100) and int(progress.resultCode) == 0:
324 # we ignore exceptions to allow starting VM even if
325 # perf collector cannot be started
326 if perf:
327 try:
328 perf.setup(['*'], [mach], 10, 15)
329 except Exception,e:
330 printErr(ctx, e)
331 if g_verbose:
332 traceback.print_exc()
333 # if session not opened, close doesn't make sense
334 session.close()
335 else:
336 reportError(ctx,progress)
337
338class CachedMach:
339 def __init__(self, mach):
340 self.name = mach.name
341 self.id = mach.id
342
343def cacheMachines(ctx,list):
344 result = []
345 for m in list:
346 elem = CachedMach(m)
347 result.append(elem)
348 return result
349
350def getMachines(ctx, invalidate = False, simple=False):
351 if ctx['vb'] is not None:
352 if ctx['_machlist'] is None or invalidate:
353 ctx['_machlist'] = ctx['global'].getArray(ctx['vb'], 'machines')
354 ctx['_machlistsimple'] = cacheMachines(ctx,ctx['_machlist'])
355 if simple:
356 return ctx['_machlistsimple']
357 else:
358 return ctx['_machlist']
359 else:
360 return []
361
362def asState(var):
363 if var:
364 return colored('on', 'green')
365 else:
366 return colored('off', 'green')
367
368def asFlag(var):
369 if var:
370 return 'yes'
371 else:
372 return 'no'
373
374def perfStats(ctx,mach):
375 if not ctx['perf']:
376 return
377 for metric in ctx['perf'].query(["*"], [mach]):
378 print metric['name'], metric['values_as_string']
379
380def guestExec(ctx, machine, console, cmds):
381 exec cmds
382
383def monitorGuest(ctx, machine, console, dur):
384 cb = ctx['global'].createCallback('IConsoleCallback', GuestMonitor, machine)
385 console.registerCallback(cb)
386 if dur == -1:
387 # not infinity, but close enough
388 dur = 100000
389 try:
390 end = time.time() + dur
391 while time.time() < end:
392 ctx['global'].waitForEvents(500)
393 # We need to catch all exceptions here, otherwise callback will never be unregistered
394 except:
395 pass
396 console.unregisterCallback(cb)
397
398
399def monitorVBox(ctx, dur):
400 vbox = ctx['vb']
401 isMscom = (ctx['global'].type == 'MSCOM')
402 cb = ctx['global'].createCallback('IVirtualBoxCallback', VBoxMonitor, [vbox, isMscom])
403 vbox.registerCallback(cb)
404 if dur == -1:
405 # not infinity, but close enough
406 dur = 100000
407 try:
408 end = time.time() + dur
409 while time.time() < end:
410 ctx['global'].waitForEvents(500)
411 # We need to catch all exceptions here, otherwise callback will never be unregistered
412 except:
413 pass
414 vbox.unregisterCallback(cb)
415
416
417def takeScreenshot(ctx,console,args):
418 from PIL import Image
419 display = console.display
420 if len(args) > 0:
421 f = args[0]
422 else:
423 f = "/tmp/screenshot.png"
424 if len(args) > 3:
425 screen = int(args[3])
426 else:
427 screen = 0
428 (fbw, fbh, fbbpp) = display.getScreenResolution(screen)
429 if len(args) > 1:
430 w = int(args[1])
431 else:
432 w = fbw
433 if len(args) > 2:
434 h = int(args[2])
435 else:
436 h = fbh
437
438 print "Saving screenshot (%d x %d) screen %d in %s..." %(w,h,screen,f)
439 data = display.takeScreenShotToArray(screen, w,h)
440 size = (w,h)
441 mode = "RGBA"
442 im = Image.frombuffer(mode, size, str(data), "raw", mode, 0, 1)
443 im.save(f, "PNG")
444
445
446def teleport(ctx,session,console,args):
447 if args[0].find(":") == -1:
448 print "Use host:port format for teleport target"
449 return
450 (host,port) = args[0].split(":")
451 if len(args) > 1:
452 passwd = args[1]
453 else:
454 passwd = ""
455
456 if len(args) > 2:
457 maxDowntime = int(args[2])
458 else:
459 maxDowntime = 250
460
461 port = int(port)
462 print "Teleporting to %s:%d..." %(host,port)
463 progress = console.teleport(host, port, passwd, maxDowntime)
464 if progressBar(ctx, progress, 100) and int(progress.resultCode) == 0:
465 print "Success!"
466 else:
467 reportError(ctx,progress)
468
469
470def guestStats(ctx,console,args):
471 guest = console.guest
472 # we need to set up guest statistics
473 if len(args) > 0 :
474 update = args[0]
475 else:
476 update = 1
477 if guest.statisticsUpdateInterval != update:
478 guest.statisticsUpdateInterval = update
479 try:
480 time.sleep(float(update)+0.1)
481 except:
482 # to allow sleep interruption
483 pass
484 all_stats = ctx['ifaces'].all_values('GuestStatisticType')
485 cpu = 0
486 for s in all_stats.keys():
487 try:
488 val = guest.getStatistic( cpu, all_stats[s])
489 print "%s: %d" %(s, val)
490 except:
491 # likely not implemented
492 pass
493
494def plugCpu(ctx,machine,session,args):
495 cpu = int(args[0])
496 print "Adding CPU %d..." %(cpu)
497 machine.hotPlugCPU(cpu)
498
499def unplugCpu(ctx,machine,session,args):
500 cpu = int(args[0])
501 print "Removing CPU %d..." %(cpu)
502 machine.hotUnplugCPU(cpu)
503
504def mountIso(ctx,machine,session,args):
505 machine.mountMedium(args[0], args[1], args[2], args[3], args[4])
506 machine.saveSettings()
507
508def cond(c,v1,v2):
509 if c:
510 return v1
511 else:
512 return v2
513
514def printHostUsbDev(ctx,ud):
515 print " %s: %s (vendorId=%d productId=%d serial=%s) %s" %(ud.id, colored(ud.product,'blue'), ud.vendorId, ud.productId, ud.serialNumber,asEnumElem(ctx, 'USBDeviceState', ud.state))
516
517def printUsbDev(ctx,ud):
518 print " %s: %s (vendorId=%d productId=%d serial=%s)" %(ud.id, colored(ud.product,'blue'), ud.vendorId, ud.productId, ud.serialNumber)
519
520def printSf(ctx,sf):
521 print " name=%s host=%s %s %s" %(sf.name, sf.hostPath, cond(sf.accessible, "accessible", "not accessible"), cond(sf.writable, "writable", "read-only"))
522
523def ginfo(ctx,console, args):
524 guest = console.guest
525 if guest.additionsActive:
526 vers = int(str(guest.additionsVersion))
527 print "Additions active, version %d.%d" %(vers >> 16, vers & 0xffff)
528 print "Support seamless: %s" %(asFlag(guest.supportsSeamless))
529 print "Support graphics: %s" %(asFlag(guest.supportsGraphics))
530 print "Baloon size: %d" %(guest.memoryBalloonSize)
531 print "Statistic update interval: %d" %(guest.statisticsUpdateInterval)
532 else:
533 print "No additions"
534 usbs = ctx['global'].getArray(console, 'USBDevices')
535 print "Attached USB:"
536 for ud in usbs:
537 printUsbDev(ctx,ud)
538 rusbs = ctx['global'].getArray(console, 'remoteUSBDevices')
539 print "Remote USB:"
540 for ud in rusbs:
541 printHostUsbDev(ctx,ud)
542 print "Transient shared folders:"
543 sfs = rusbs = ctx['global'].getArray(console, 'sharedFolders')
544 for sf in sfs:
545 printSf(ctx,sf)
546
547def cmdExistingVm(ctx,mach,cmd,args):
548 session = None
549 try:
550 vb = ctx['vb']
551 session = ctx['mgr'].getSessionObject(vb)
552 vb.openExistingSession(session, mach.id)
553 except Exception,e:
554 printErr(ctx, "Session to '%s' not open: %s" %(mach.name,str(e)))
555 if g_verbose:
556 traceback.print_exc()
557 return
558 if session.state != ctx['ifaces'].SessionState_Open:
559 print "Session to '%s' in wrong state: %s" %(mach.name, session.state)
560 session.close()
561 return
562 # this could be an example how to handle local only (i.e. unavailable
563 # in Webservices) functionality
564 if ctx['remote'] and cmd == 'some_local_only_command':
565 print 'Trying to use local only functionality, ignored'
566 session.close()
567 return
568 console=session.console
569 ops={'pause': lambda: console.pause(),
570 'resume': lambda: console.resume(),
571 'powerdown': lambda: console.powerDown(),
572 'powerbutton': lambda: console.powerButton(),
573 'stats': lambda: perfStats(ctx, mach),
574 'guest': lambda: guestExec(ctx, mach, console, args),
575 'ginfo': lambda: ginfo(ctx, console, args),
576 'guestlambda': lambda: args[0](ctx, mach, console, args[1:]),
577 'monitorGuest': lambda: monitorGuest(ctx, mach, console, args),
578 'save': lambda: progressBar(ctx,console.saveState()),
579 'screenshot': lambda: takeScreenshot(ctx,console,args),
580 'teleport': lambda: teleport(ctx,session,console,args),
581 'gueststats': lambda: guestStats(ctx, console, args),
582 'plugcpu': lambda: plugCpu(ctx, session.machine, session, args),
583 'unplugcpu': lambda: unplugCpu(ctx, session.machine, session, args),
584 'mountiso': lambda: mountIso(ctx, session.machine, session, args),
585 }
586 try:
587 ops[cmd]()
588 except Exception, e:
589 printErr(ctx,e)
590 if g_verbose:
591 traceback.print_exc()
592
593 session.close()
594
595
596def cmdClosedVm(ctx,mach,cmd,args=[],save=True):
597 session = ctx['global'].openMachineSession(mach.id)
598 mach = session.machine
599 try:
600 cmd(ctx, mach, args)
601 except Exception, e:
602 save = False
603 printErr(ctx,e)
604 if g_verbose:
605 traceback.print_exc()
606 if save:
607 mach.saveSettings()
608 ctx['global'].closeMachineSession(session)
609
610
611def cmdAnyVm(ctx,mach,cmd, args=[],save=False):
612 session = ctx['global'].openMachineSession(mach.id)
613 mach = session.machine
614 try:
615 cmd(ctx, mach, session.console, args)
616 except Exception, e:
617 save = False;
618 printErr(ctx,e)
619 if g_verbose:
620 traceback.print_exc()
621 if save:
622 mach.saveSettings()
623 ctx['global'].closeMachineSession(session)
624
625def machById(ctx,id):
626 mach = None
627 for m in getMachines(ctx):
628 if m.name == id:
629 mach = m
630 break
631 mid = str(m.id)
632 if mid[0] == '{':
633 mid = mid[1:-1]
634 if mid == id:
635 mach = m
636 break
637 return mach
638
639def argsToMach(ctx,args):
640 if len(args) < 2:
641 print "usage: %s [vmname|uuid]" %(args[0])
642 return None
643 id = args[1]
644 m = machById(ctx, id)
645 if m == None:
646 print "Machine '%s' is unknown, use list command to find available machines" %(id)
647 return m
648
649def helpSingleCmd(cmd,h,sp):
650 if sp != 0:
651 spec = " [ext from "+sp+"]"
652 else:
653 spec = ""
654 print " %s: %s%s" %(colored(cmd,'blue'),h,spec)
655
656def helpCmd(ctx, args):
657 if len(args) == 1:
658 print "Help page:"
659 names = commands.keys()
660 names.sort()
661 for i in names:
662 helpSingleCmd(i, commands[i][0], commands[i][2])
663 else:
664 cmd = args[1]
665 c = commands.get(cmd)
666 if c == None:
667 print "Command '%s' not known" %(cmd)
668 else:
669 helpSingleCmd(cmd, c[0], c[2])
670 return 0
671
672def asEnumElem(ctx,enum,elem):
673 all = ctx['ifaces'].all_values(enum)
674 for e in all.keys():
675 if str(elem) == str(all[e]):
676 return colored(e, 'green')
677 return colored("<unknown>", 'green')
678
679def enumFromString(ctx,enum,str):
680 all = ctx['ifaces'].all_values(enum)
681 return all.get(str, None)
682
683def listCmd(ctx, args):
684 for m in getMachines(ctx, True):
685 if m.teleporterEnabled:
686 tele = "[T] "
687 else:
688 tele = " "
689 print "%sMachine '%s' [%s], machineState=%s, sessionState=%s" %(tele,colVm(ctx,m.name),m.id,asEnumElem(ctx, "MachineState", m.state), asEnumElem(ctx,"SessionState", m.sessionState))
690 return 0
691
692def infoCmd(ctx,args):
693 if (len(args) < 2):
694 print "usage: info [vmname|uuid]"
695 return 0
696 mach = argsToMach(ctx,args)
697 if mach == None:
698 return 0
699 os = ctx['vb'].getGuestOSType(mach.OSTypeId)
700 print " One can use setvar <mach> <var> <value> to change variable, using name in []."
701 print " Name [name]: %s" %(colVm(ctx,mach.name))
702 print " Description [description]: %s" %(mach.description)
703 print " ID [n/a]: %s" %(mach.id)
704 print " OS Type [via OSTypeId]: %s" %(os.description)
705 print " Firmware [firmwareType]: %s (%s)" %(asEnumElem(ctx,"FirmwareType", mach.firmwareType),mach.firmwareType)
706 print
707 print " CPUs [CPUCount]: %d" %(mach.CPUCount)
708 print " RAM [memorySize]: %dM" %(mach.memorySize)
709 print " VRAM [VRAMSize]: %dM" %(mach.VRAMSize)
710 print " Monitors [monitorCount]: %d" %(mach.monitorCount)
711 print
712 print " Clipboard mode [clipboardMode]: %s (%s)" %(asEnumElem(ctx,"ClipboardMode", mach.clipboardMode), mach.clipboardMode)
713 print " Machine status [n/a]: %s (%s)" % (asEnumElem(ctx,"SessionState", mach.sessionState), mach.sessionState)
714 print
715 if mach.teleporterEnabled:
716 print " Teleport target on port %d (%s)" %(mach.teleporterPort, mach.teleporterPassword)
717 print
718 bios = mach.BIOSSettings
719 print " ACPI [BIOSSettings.ACPIEnabled]: %s" %(asState(bios.ACPIEnabled))
720 print " APIC [BIOSSettings.IOAPICEnabled]: %s" %(asState(bios.IOAPICEnabled))
721 hwVirtEnabled = mach.getHWVirtExProperty(ctx['global'].constants.HWVirtExPropertyType_Enabled)
722 print " Hardware virtualization [mach.setHWVirtExProperty(ctx['global'].constants.HWVirtExPropertyType_Enabled,value)]: " + asState(hwVirtEnabled)
723 hwVirtVPID = mach.getHWVirtExProperty(ctx['global'].constants.HWVirtExPropertyType_VPID)
724 print " VPID support [mach.setHWVirtExProperty(ctx['global'].constants.HWVirtExPropertyType_VPID,value)]: " + asState(hwVirtVPID)
725 hwVirtNestedPaging = mach.getHWVirtExProperty(ctx['global'].constants.HWVirtExPropertyType_NestedPaging)
726 print " Nested paging [mach.setHWVirtExProperty(ctx['global'].constants.HWVirtExPropertyType_NestedPaging,value)]: " + asState(hwVirtNestedPaging)
727
728 print " Hardware 3d acceleration [accelerate3DEnabled]: " + asState(mach.accelerate3DEnabled)
729 print " Hardware 2d video acceleration [accelerate2DVideoEnabled]: " + asState(mach.accelerate2DVideoEnabled)
730
731 print " Use universal time [RTCUseUTC]: %s" %(asState(mach.RTCUseUTC))
732 print " HPET [hpetEnabled]: %s" %(asState(mach.hpetEnabled))
733 if mach.audioAdapter.enabled:
734 print " Audio [via audioAdapter]: chip %s; host driver %s" %(asEnumElem(ctx,"AudioControllerType", mach.audioAdapter.audioController), asEnumElem(ctx,"AudioDriverType", mach.audioAdapter.audioDriver))
735 if mach.USBController.enabled:
736 print " USB [via USBController]: high speed %s" %(asState(mach.USBController.enabledEhci))
737 print " CPU hotplugging [CPUHotPlugEnabled]: %s" %(asState(mach.CPUHotPlugEnabled))
738
739 print " Keyboard [keyboardHidType]: %s (%s)" %(asEnumElem(ctx,"KeyboardHidType", mach.keyboardHidType), mach.keyboardHidType)
740 print " Pointing device [pointingHidType]: %s (%s)" %(asEnumElem(ctx,"PointingHidType", mach.pointingHidType), mach.pointingHidType)
741 print " Last changed [n/a]: " + time.asctime(time.localtime(long(mach.lastStateChange)/1000))
742 print " VRDP server [VRDPServer.enabled]: %s" %(asState(mach.VRDPServer.enabled))
743
744 print
745 print colCat(ctx," I/O subsystem info:")
746 print " Cache enabled [ioCacheEnabled]: %s" %(asState(mach.ioCacheEnabled))
747 print " Cache size [ioCacheSize]: %dM" %(mach.ioCacheSize)
748 print " Bandwidth limit [ioBandwidthMax]: %dM/s" %(mach.ioBandwidthMax)
749
750 controllers = ctx['global'].getArray(mach, 'storageControllers')
751 if controllers:
752 print
753 print colCat(ctx," Controllers:")
754 for controller in controllers:
755 print " '%s': bus %s type %s" % (controller.name, asEnumElem(ctx,"StorageBus", controller.bus), asEnumElem(ctx,"StorageControllerType", controller.controllerType))
756
757 attaches = ctx['global'].getArray(mach, 'mediumAttachments')
758 if attaches:
759 print
760 print colCat(ctx," Media:")
761 for a in attaches:
762 print " Controller: '%s' port/device: %d:%d type: %s (%s):" % (a.controller, a.port, a.device, asEnumElem(ctx,"DeviceType", a.type), a.type)
763 m = a.medium
764 if a.type == ctx['global'].constants.DeviceType_HardDisk:
765 print " HDD:"
766 print " Id: %s" %(m.id)
767 print " Location: %s" %(m.location)
768 print " Name: %s" %(m.name)
769 print " Format: %s" %(m.format)
770
771 if a.type == ctx['global'].constants.DeviceType_DVD:
772 print " DVD:"
773 if m:
774 print " Id: %s" %(m.id)
775 print " Name: %s" %(m.name)
776 if m.hostDrive:
777 print " Host DVD %s" %(m.location)
778 if a.passthrough:
779 print " [passthrough mode]"
780 else:
781 print " Virtual image at %s" %(m.location)
782 print " Size: %s" %(m.size)
783
784 if a.type == ctx['global'].constants.DeviceType_Floppy:
785 print " Floppy:"
786 if m:
787 print " Id: %s" %(m.id)
788 print " Name: %s" %(m.name)
789 if m.hostDrive:
790 print " Host floppy %s" %(m.location)
791 else:
792 print " Virtual image at %s" %(m.location)
793 print " Size: %s" %(m.size)
794
795 print
796 print colCat(ctx," Shared folders:")
797 for sf in ctx['global'].getArray(mach, 'sharedFolders'):
798 printSf(ctx,sf)
799
800 return 0
801
802def startCmd(ctx, args):
803 mach = argsToMach(ctx,args)
804 if mach == None:
805 return 0
806 if len(args) > 2:
807 type = args[2]
808 else:
809 type = "gui"
810 startVm(ctx, mach, type)
811 return 0
812
813def createVmCmd(ctx, args):
814 if (len(args) < 3 or len(args) > 4):
815 print "usage: createvm name ostype <basefolder>"
816 return 0
817 name = args[1]
818 oskind = args[2]
819 if len(args) == 4:
820 base = args[3]
821 else:
822 base = ''
823 try:
824 ctx['vb'].getGuestOSType(oskind)
825 except Exception, e:
826 print 'Unknown OS type:',oskind
827 return 0
828 createVm(ctx, name, oskind, base)
829 return 0
830
831def ginfoCmd(ctx,args):
832 if (len(args) < 2):
833 print "usage: ginfo [vmname|uuid]"
834 return 0
835 mach = argsToMach(ctx,args)
836 if mach == None:
837 return 0
838 cmdExistingVm(ctx, mach, 'ginfo', '')
839 return 0
840
841def execInGuest(ctx,console,args,env):
842 if len(args) < 1:
843 print "exec in guest needs at least program name"
844 return
845 user = ""
846 passwd = ""
847 tmo = 0
848 guest = console.guest
849 # shall contain program name as argv[0]
850 gargs = args
851 print "executing %s with args %s" %(args[0], gargs)
852 (progress, pid) = guest.executeProcess(args[0], 0, gargs, env, user, passwd, tmo)
853 print "executed with pid %d" %(pid)
854 if pid != 0:
855 try:
856 while True:
857 data = guest.getProcessOutput(pid, 0, 1000, 4096)
858 if data and len(data) > 0:
859 sys.stdout.write(data)
860 continue
861 progress.waitForCompletion(100)
862 ctx['global'].waitForEvents(0)
863 if progress.completed:
864 break
865
866 except KeyboardInterrupt:
867 print "Interrupted."
868 if progress.cancelable:
869 progress.cancel()
870 return 0
871 else:
872 reportError(ctx, progress)
873
874def gexecCmd(ctx,args):
875 if (len(args) < 2):
876 print "usage: gexec [vmname|uuid] command args"
877 return 0
878 mach = argsToMach(ctx,args)
879 if mach == None:
880 return 0
881 gargs = args[2:]
882 env = [] # ["DISPLAY=:0"]
883 gargs.insert(0, lambda ctx,mach,console,args: execInGuest(ctx,console,args,env))
884 cmdExistingVm(ctx, mach, 'guestlambda', gargs)
885 return 0
886
887def gcatCmd(ctx,args):
888 if (len(args) < 2):
889 print "usage: gcat [vmname|uuid] local_file | guestProgram, such as gcat linux /home/nike/.bashrc | sh -c 'cat >'"
890 return 0
891 mach = argsToMach(ctx,args)
892 if mach == None:
893 return 0
894 gargs = args[2:]
895 env = []
896 gargs.insert(0, lambda ctx,mach,console,args: execInGuest(ctx,console,args,env))
897 cmdExistingVm(ctx, mach, 'guestlambda', gargs)
898 return 0
899
900
901def removeVmCmd(ctx, args):
902 mach = argsToMach(ctx,args)
903 if mach == None:
904 return 0
905 removeVm(ctx, mach)
906 return 0
907
908def pauseCmd(ctx, args):
909 mach = argsToMach(ctx,args)
910 if mach == None:
911 return 0
912 cmdExistingVm(ctx, mach, 'pause', '')
913 return 0
914
915def powerdownCmd(ctx, args):
916 mach = argsToMach(ctx,args)
917 if mach == None:
918 return 0
919 cmdExistingVm(ctx, mach, 'powerdown', '')
920 return 0
921
922def powerbuttonCmd(ctx, args):
923 mach = argsToMach(ctx,args)
924 if mach == None:
925 return 0
926 cmdExistingVm(ctx, mach, 'powerbutton', '')
927 return 0
928
929def resumeCmd(ctx, args):
930 mach = argsToMach(ctx,args)
931 if mach == None:
932 return 0
933 cmdExistingVm(ctx, mach, 'resume', '')
934 return 0
935
936def saveCmd(ctx, args):
937 mach = argsToMach(ctx,args)
938 if mach == None:
939 return 0
940 cmdExistingVm(ctx, mach, 'save', '')
941 return 0
942
943def statsCmd(ctx, args):
944 mach = argsToMach(ctx,args)
945 if mach == None:
946 return 0
947 cmdExistingVm(ctx, mach, 'stats', '')
948 return 0
949
950def guestCmd(ctx, args):
951 if (len(args) < 3):
952 print "usage: guest name commands"
953 return 0
954 mach = argsToMach(ctx,args)
955 if mach == None:
956 return 0
957 cmdExistingVm(ctx, mach, 'guest', ' '.join(args[2:]))
958 return 0
959
960def screenshotCmd(ctx, args):
961 if (len(args) < 2):
962 print "usage: screenshot vm <file> <width> <height> <monitor>"
963 return 0
964 mach = argsToMach(ctx,args)
965 if mach == None:
966 return 0
967 cmdExistingVm(ctx, mach, 'screenshot', args[2:])
968 return 0
969
970def teleportCmd(ctx, args):
971 if (len(args) < 3):
972 print "usage: teleport name host:port <password>"
973 return 0
974 mach = argsToMach(ctx,args)
975 if mach == None:
976 return 0
977 cmdExistingVm(ctx, mach, 'teleport', args[2:])
978 return 0
979
980def portalsettings(ctx,mach,args):
981 enabled = args[0]
982 mach.teleporterEnabled = enabled
983 if enabled:
984 port = args[1]
985 passwd = args[2]
986 mach.teleporterPort = port
987 mach.teleporterPassword = passwd
988
989def openportalCmd(ctx, args):
990 if (len(args) < 3):
991 print "usage: openportal name port <password>"
992 return 0
993 mach = argsToMach(ctx,args)
994 if mach == None:
995 return 0
996 port = int(args[2])
997 if (len(args) > 3):
998 passwd = args[3]
999 else:
1000 passwd = ""
1001 if not mach.teleporterEnabled or mach.teleporterPort != port or passwd:
1002 cmdClosedVm(ctx, mach, portalsettings, [True, port, passwd])
1003 startVm(ctx, mach, "gui")
1004 return 0
1005
1006def closeportalCmd(ctx, args):
1007 if (len(args) < 2):
1008 print "usage: closeportal name"
1009 return 0
1010 mach = argsToMach(ctx,args)
1011 if mach == None:
1012 return 0
1013 if mach.teleporterEnabled:
1014 cmdClosedVm(ctx, mach, portalsettings, [False])
1015 return 0
1016
1017def gueststatsCmd(ctx, args):
1018 if (len(args) < 2):
1019 print "usage: gueststats name <check interval>"
1020 return 0
1021 mach = argsToMach(ctx,args)
1022 if mach == None:
1023 return 0
1024 cmdExistingVm(ctx, mach, 'gueststats', args[2:])
1025 return 0
1026
1027def plugcpu(ctx,mach,args):
1028 plug = args[0]
1029 cpu = args[1]
1030 if plug:
1031 print "Adding CPU %d..." %(cpu)
1032 mach.hotPlugCPU(cpu)
1033 else:
1034 print "Removing CPU %d..." %(cpu)
1035 mach.hotUnplugCPU(cpu)
1036
1037def plugcpuCmd(ctx, args):
1038 if (len(args) < 2):
1039 print "usage: plugcpu name cpuid"
1040 return 0
1041 mach = argsToMach(ctx,args)
1042 if mach == None:
1043 return 0
1044 if str(mach.sessionState) != str(ctx['ifaces'].SessionState_Open):
1045 if mach.CPUHotPlugEnabled:
1046 cmdClosedVm(ctx, mach, plugcpu, [True, int(args[2])])
1047 else:
1048 cmdExistingVm(ctx, mach, 'plugcpu', args[2])
1049 return 0
1050
1051def unplugcpuCmd(ctx, args):
1052 if (len(args) < 2):
1053 print "usage: unplugcpu name cpuid"
1054 return 0
1055 mach = argsToMach(ctx,args)
1056 if mach == None:
1057 return 0
1058 if str(mach.sessionState) != str(ctx['ifaces'].SessionState_Open):
1059 if mach.CPUHotPlugEnabled:
1060 cmdClosedVm(ctx, mach, plugcpu, [False, int(args[2])])
1061 else:
1062 cmdExistingVm(ctx, mach, 'unplugcpu', args[2])
1063 return 0
1064
1065def setvar(ctx,mach,args):
1066 expr = 'mach.'+args[0]+' = '+args[1]
1067 print "Executing",expr
1068 exec expr
1069
1070def setvarCmd(ctx, args):
1071 if (len(args) < 4):
1072 print "usage: setvar [vmname|uuid] expr value"
1073 return 0
1074 mach = argsToMach(ctx,args)
1075 if mach == None:
1076 return 0
1077 cmdClosedVm(ctx, mach, setvar, args[2:])
1078 return 0
1079
1080def setvmextra(ctx,mach,args):
1081 key = args[0]
1082 value = args[1]
1083 print "%s: setting %s to %s" %(mach.name, key, value)
1084 mach.setExtraData(key, value)
1085
1086def setExtraDataCmd(ctx, args):
1087 if (len(args) < 3):
1088 print "usage: setextra [vmname|uuid|global] key <value>"
1089 return 0
1090 key = args[2]
1091 if len(args) == 4:
1092 value = args[3]
1093 else:
1094 value = None
1095 if args[1] == 'global':
1096 ctx['vb'].setExtraData(key, value)
1097 return 0
1098
1099 mach = argsToMach(ctx,args)
1100 if mach == None:
1101 return 0
1102 cmdClosedVm(ctx, mach, setvmextra, [key, value])
1103 return 0
1104
1105def printExtraKey(obj, key, value):
1106 print "%s: '%s' = '%s'" %(obj, key, value)
1107
1108def getExtraDataCmd(ctx, args):
1109 if (len(args) < 2):
1110 print "usage: getextra [vmname|uuid|global] <key>"
1111 return 0
1112 if len(args) == 3:
1113 key = args[2]
1114 else:
1115 key = None
1116
1117 if args[1] == 'global':
1118 obj = ctx['vb']
1119 else:
1120 obj = argsToMach(ctx,args)
1121 if obj == None:
1122 return 0
1123
1124 if key == None:
1125 keys = obj.getExtraDataKeys()
1126 else:
1127 keys = [ key ]
1128 for k in keys:
1129 printExtraKey(args[1], k, obj.getExtraData(k))
1130
1131 return 0
1132
1133def quitCmd(ctx, args):
1134 return 1
1135
1136def aliasCmd(ctx, args):
1137 if (len(args) == 3):
1138 aliases[args[1]] = args[2]
1139 return 0
1140
1141 for (k,v) in aliases.items():
1142 print "'%s' is an alias for '%s'" %(k,v)
1143 return 0
1144
1145def verboseCmd(ctx, args):
1146 global g_verbose
1147 g_verbose = not g_verbose
1148 return 0
1149
1150def colorsCmd(ctx, args):
1151 global g_hascolors
1152 g_hascolors = not g_hascolors
1153 return 0
1154
1155def hostCmd(ctx, args):
1156 vb = ctx['vb']
1157 print "VirtualBox version %s" %(colored(vb.version, 'blue'))
1158 props = vb.systemProperties
1159 print "Machines: %s" %(colPath(ctx,props.defaultMachineFolder))
1160 print "HDDs: %s" %(colPath(ctx,props.defaultHardDiskFolder))
1161
1162 #print "Global shared folders:"
1163 #for ud in ctx['global'].getArray(vb, 'sharedFolders'):
1164 # printSf(ctx,sf)
1165 host = vb.host
1166 cnt = host.processorCount
1167 print colCat(ctx,"Processors:")
1168 print " available/online: %d/%d " %(cnt,host.processorOnlineCount)
1169 for i in range(0,cnt):
1170 print " processor #%d speed: %dMHz %s" %(i,host.getProcessorSpeed(i), host.getProcessorDescription(i))
1171
1172 print colCat(ctx, "RAM:")
1173 print " %dM (free %dM)" %(host.memorySize, host.memoryAvailable)
1174 print colCat(ctx,"OS:");
1175 print " %s (%s)" %(host.operatingSystem, host.OSVersion)
1176 if host.Acceleration3DAvailable:
1177 print colCat(ctx,"3D acceleration available")
1178 else:
1179 print colCat(ctx,"3D acceleration NOT available")
1180
1181 print colCat(ctx,"Network interfaces:")
1182 for ni in ctx['global'].getArray(host, 'networkInterfaces'):
1183 print " %s (%s)" %(ni.name, ni.IPAddress)
1184
1185 print colCat(ctx,"DVD drives:")
1186 for dd in ctx['global'].getArray(host, 'DVDDrives'):
1187 print " %s - %s" %(dd.name, dd.description)
1188
1189 print colCat(ctx,"Floppy drives:")
1190 for dd in ctx['global'].getArray(host, 'floppyDrives'):
1191 print " %s - %s" %(dd.name, dd.description)
1192
1193 print colCat(ctx,"USB devices:")
1194 for ud in ctx['global'].getArray(host, 'USBDevices'):
1195 printHostUsbDev(ctx,ud)
1196
1197 if ctx['perf']:
1198 for metric in ctx['perf'].query(["*"], [host]):
1199 print metric['name'], metric['values_as_string']
1200
1201 return 0
1202
1203def monitorGuestCmd(ctx, args):
1204 if (len(args) < 2):
1205 print "usage: monitorGuest name (duration)"
1206 return 0
1207 mach = argsToMach(ctx,args)
1208 if mach == None:
1209 return 0
1210 dur = 5
1211 if len(args) > 2:
1212 dur = float(args[2])
1213 cmdExistingVm(ctx, mach, 'monitorGuest', dur)
1214 return 0
1215
1216def monitorVBoxCmd(ctx, args):
1217 if (len(args) > 2):
1218 print "usage: monitorVBox (duration)"
1219 return 0
1220 dur = 5
1221 if len(args) > 1:
1222 dur = float(args[1])
1223 monitorVBox(ctx, dur)
1224 return 0
1225
1226def getAdapterType(ctx, type):
1227 if (type == ctx['global'].constants.NetworkAdapterType_Am79C970A or
1228 type == ctx['global'].constants.NetworkAdapterType_Am79C973):
1229 return "pcnet"
1230 elif (type == ctx['global'].constants.NetworkAdapterType_I82540EM or
1231 type == ctx['global'].constants.NetworkAdapterType_I82545EM or
1232 type == ctx['global'].constants.NetworkAdapterType_I82543GC):
1233 return "e1000"
1234 elif (type == ctx['global'].constants.NetworkAdapterType_Virtio):
1235 return "virtio"
1236 elif (type == ctx['global'].constants.NetworkAdapterType_Null):
1237 return None
1238 else:
1239 raise Exception("Unknown adapter type: "+type)
1240
1241
1242def portForwardCmd(ctx, args):
1243 if (len(args) != 5):
1244 print "usage: portForward <vm> <adapter> <hostPort> <guestPort>"
1245 return 0
1246 mach = argsToMach(ctx,args)
1247 if mach == None:
1248 return 0
1249 adapterNum = int(args[2])
1250 hostPort = int(args[3])
1251 guestPort = int(args[4])
1252 proto = "TCP"
1253 session = ctx['global'].openMachineSession(mach.id)
1254 mach = session.machine
1255
1256 adapter = mach.getNetworkAdapter(adapterNum)
1257 adapterType = getAdapterType(ctx, adapter.adapterType)
1258
1259 profile_name = proto+"_"+str(hostPort)+"_"+str(guestPort)
1260 config = "VBoxInternal/Devices/" + adapterType + "/"
1261 config = config + str(adapter.slot) +"/LUN#0/Config/" + profile_name
1262
1263 mach.setExtraData(config + "/Protocol", proto)
1264 mach.setExtraData(config + "/HostPort", str(hostPort))
1265 mach.setExtraData(config + "/GuestPort", str(guestPort))
1266
1267 mach.saveSettings()
1268 session.close()
1269
1270 return 0
1271
1272
1273def showLogCmd(ctx, args):
1274 if (len(args) < 2):
1275 print "usage: showLog vm <num>"
1276 return 0
1277 mach = argsToMach(ctx,args)
1278 if mach == None:
1279 return 0
1280
1281 log = 0
1282 if (len(args) > 2):
1283 log = args[2]
1284
1285 uOffset = 0
1286 while True:
1287 data = mach.readLog(log, uOffset, 4096)
1288 if (len(data) == 0):
1289 break
1290 # print adds either NL or space to chunks not ending with a NL
1291 sys.stdout.write(str(data))
1292 uOffset += len(data)
1293
1294 return 0
1295
1296def findLogCmd(ctx, args):
1297 if (len(args) < 3):
1298 print "usage: findLog vm pattern <num>"
1299 return 0
1300 mach = argsToMach(ctx,args)
1301 if mach == None:
1302 return 0
1303
1304 log = 0
1305 if (len(args) > 3):
1306 log = args[3]
1307
1308 pattern = args[2]
1309 uOffset = 0
1310 while True:
1311 # to reduce line splits on buffer boundary
1312 data = mach.readLog(log, uOffset, 512*1024)
1313 if (len(data) == 0):
1314 break
1315 d = str(data).split("\n")
1316 for s in d:
1317 m = re.findall(pattern, s)
1318 if len(m) > 0:
1319 for mt in m:
1320 s = s.replace(mt, colored(mt,'red'))
1321 print s
1322 uOffset += len(data)
1323
1324 return 0
1325
1326def evalCmd(ctx, args):
1327 expr = ' '.join(args[1:])
1328 try:
1329 exec expr
1330 except Exception, e:
1331 printErr(ctx,e)
1332 if g_verbose:
1333 traceback.print_exc()
1334 return 0
1335
1336def reloadExtCmd(ctx, args):
1337 # maybe will want more args smartness
1338 checkUserExtensions(ctx, commands, getHomeFolder(ctx))
1339 autoCompletion(commands, ctx)
1340 return 0
1341
1342
1343def runScriptCmd(ctx, args):
1344 if (len(args) != 2):
1345 print "usage: runScript <script>"
1346 return 0
1347 try:
1348 lf = open(args[1], 'r')
1349 except IOError,e:
1350 print "cannot open:",args[1], ":",e
1351 return 0
1352
1353 try:
1354 for line in lf:
1355 done = runCommand(ctx, line)
1356 if done != 0: break
1357 except Exception,e:
1358 printErr(ctx,e)
1359 if g_verbose:
1360 traceback.print_exc()
1361 lf.close()
1362 return 0
1363
1364def sleepCmd(ctx, args):
1365 if (len(args) != 2):
1366 print "usage: sleep <secs>"
1367 return 0
1368
1369 try:
1370 time.sleep(float(args[1]))
1371 except:
1372 # to allow sleep interrupt
1373 pass
1374 return 0
1375
1376
1377def shellCmd(ctx, args):
1378 if (len(args) < 2):
1379 print "usage: shell <commands>"
1380 return 0
1381 cmd = ' '.join(args[1:])
1382
1383 try:
1384 os.system(cmd)
1385 except KeyboardInterrupt:
1386 # to allow shell command interruption
1387 pass
1388 return 0
1389
1390
1391def connectCmd(ctx, args):
1392 if (len(args) > 4):
1393 print "usage: connect url <username> <passwd>"
1394 return 0
1395
1396 if ctx['vb'] is not None:
1397 print "Already connected, disconnect first..."
1398 return 0
1399
1400 if (len(args) > 1):
1401 url = args[1]
1402 else:
1403 url = None
1404
1405 if (len(args) > 2):
1406 user = args[2]
1407 else:
1408 user = ""
1409
1410 if (len(args) > 3):
1411 passwd = args[3]
1412 else:
1413 passwd = ""
1414
1415 ctx['wsinfo'] = [url, user, passwd]
1416 vbox = ctx['global'].platform.connect(url, user, passwd)
1417 ctx['vb'] = vbox
1418 print "Running VirtualBox version %s" %(vbox.version)
1419 ctx['perf'] = ctx['global'].getPerfCollector(ctx['vb'])
1420 return 0
1421
1422def disconnectCmd(ctx, args):
1423 if (len(args) != 1):
1424 print "usage: disconnect"
1425 return 0
1426
1427 if ctx['vb'] is None:
1428 print "Not connected yet."
1429 return 0
1430
1431 try:
1432 ctx['global'].platform.disconnect()
1433 except:
1434 ctx['vb'] = None
1435 raise
1436
1437 ctx['vb'] = None
1438 return 0
1439
1440def reconnectCmd(ctx, args):
1441 if ctx['wsinfo'] is None:
1442 print "Never connected..."
1443 return 0
1444
1445 try:
1446 ctx['global'].platform.disconnect()
1447 except:
1448 pass
1449
1450 [url,user,passwd] = ctx['wsinfo']
1451 ctx['vb'] = ctx['global'].platform.connect(url, user, passwd)
1452 print "Running VirtualBox version %s" %(ctx['vb'].version)
1453 return 0
1454
1455def exportVMCmd(ctx, args):
1456 import sys
1457
1458 if len(args) < 3:
1459 print "usage: exportVm <machine> <path> <format> <license>"
1460 return 0
1461 mach = argsToMach(ctx,args)
1462 if mach is None:
1463 return 0
1464 path = args[2]
1465 if (len(args) > 3):
1466 format = args[3]
1467 else:
1468 format = "ovf-1.0"
1469 if (len(args) > 4):
1470 license = args[4]
1471 else:
1472 license = "GPL"
1473
1474 app = ctx['vb'].createAppliance()
1475 desc = mach.export(app)
1476 desc.addDescription(ctx['global'].constants.VirtualSystemDescriptionType_License, license, "")
1477 p = app.write(format, path)
1478 if (progressBar(ctx, p) and int(p.resultCode) == 0):
1479 print "Exported to %s in format %s" %(path, format)
1480 else:
1481 reportError(ctx,p)
1482 return 0
1483
1484# PC XT scancodes
1485scancodes = {
1486 'a': 0x1e,
1487 'b': 0x30,
1488 'c': 0x2e,
1489 'd': 0x20,
1490 'e': 0x12,
1491 'f': 0x21,
1492 'g': 0x22,
1493 'h': 0x23,
1494 'i': 0x17,
1495 'j': 0x24,
1496 'k': 0x25,
1497 'l': 0x26,
1498 'm': 0x32,
1499 'n': 0x31,
1500 'o': 0x18,
1501 'p': 0x19,
1502 'q': 0x10,
1503 'r': 0x13,
1504 's': 0x1f,
1505 't': 0x14,
1506 'u': 0x16,
1507 'v': 0x2f,
1508 'w': 0x11,
1509 'x': 0x2d,
1510 'y': 0x15,
1511 'z': 0x2c,
1512 '0': 0x0b,
1513 '1': 0x02,
1514 '2': 0x03,
1515 '3': 0x04,
1516 '4': 0x05,
1517 '5': 0x06,
1518 '6': 0x07,
1519 '7': 0x08,
1520 '8': 0x09,
1521 '9': 0x0a,
1522 ' ': 0x39,
1523 '-': 0xc,
1524 '=': 0xd,
1525 '[': 0x1a,
1526 ']': 0x1b,
1527 ';': 0x27,
1528 '\'': 0x28,
1529 ',': 0x33,
1530 '.': 0x34,
1531 '/': 0x35,
1532 '\t': 0xf,
1533 '\n': 0x1c,
1534 '`': 0x29
1535};
1536
1537extScancodes = {
1538 'ESC' : [0x01],
1539 'BKSP': [0xe],
1540 'SPACE': [0x39],
1541 'TAB': [0x0f],
1542 'CAPS': [0x3a],
1543 'ENTER': [0x1c],
1544 'LSHIFT': [0x2a],
1545 'RSHIFT': [0x36],
1546 'INS': [0xe0, 0x52],
1547 'DEL': [0xe0, 0x53],
1548 'END': [0xe0, 0x4f],
1549 'HOME': [0xe0, 0x47],
1550 'PGUP': [0xe0, 0x49],
1551 'PGDOWN': [0xe0, 0x51],
1552 'LGUI': [0xe0, 0x5b], # GUI, aka Win, aka Apple key
1553 'RGUI': [0xe0, 0x5c],
1554 'LCTR': [0x1d],
1555 'RCTR': [0xe0, 0x1d],
1556 'LALT': [0x38],
1557 'RALT': [0xe0, 0x38],
1558 'APPS': [0xe0, 0x5d],
1559 'F1': [0x3b],
1560 'F2': [0x3c],
1561 'F3': [0x3d],
1562 'F4': [0x3e],
1563 'F5': [0x3f],
1564 'F6': [0x40],
1565 'F7': [0x41],
1566 'F8': [0x42],
1567 'F9': [0x43],
1568 'F10': [0x44 ],
1569 'F11': [0x57],
1570 'F12': [0x58],
1571 'UP': [0xe0, 0x48],
1572 'LEFT': [0xe0, 0x4b],
1573 'DOWN': [0xe0, 0x50],
1574 'RIGHT': [0xe0, 0x4d],
1575};
1576
1577def keyDown(ch):
1578 code = scancodes.get(ch, 0x0)
1579 if code != 0:
1580 return [code]
1581 extCode = extScancodes.get(ch, [])
1582 if len(extCode) == 0:
1583 print "bad ext",ch
1584 return extCode
1585
1586def keyUp(ch):
1587 codes = keyDown(ch)[:] # make a copy
1588 if len(codes) > 0:
1589 codes[len(codes)-1] += 0x80
1590 return codes
1591
1592def typeInGuest(console, text, delay):
1593 import time
1594 pressed = []
1595 group = False
1596 modGroupEnd = True
1597 i = 0
1598 while i < len(text):
1599 ch = text[i]
1600 i = i+1
1601 if ch == '{':
1602 # start group, all keys to be pressed at the same time
1603 group = True
1604 continue
1605 if ch == '}':
1606 # end group, release all keys
1607 for c in pressed:
1608 console.keyboard.putScancodes(keyUp(c))
1609 pressed = []
1610 group = False
1611 continue
1612 if ch == 'W':
1613 # just wait a bit
1614 time.sleep(0.3)
1615 continue
1616 if ch == '^' or ch == '|' or ch == '$' or ch == '_':
1617 if ch == '^':
1618 ch = 'LCTR'
1619 if ch == '|':
1620 ch = 'LSHIFT'
1621 if ch == '_':
1622 ch = 'LALT'
1623 if ch == '$':
1624 ch = 'LGUI'
1625 if not group:
1626 modGroupEnd = False
1627 else:
1628 if ch == '\\':
1629 if i < len(text):
1630 ch = text[i]
1631 i = i+1
1632 if ch == 'n':
1633 ch = '\n'
1634 elif ch == '&':
1635 combo = ""
1636 while i < len(text):
1637 ch = text[i]
1638 i = i+1
1639 if ch == ';':
1640 break
1641 combo += ch
1642 ch = combo
1643 modGroupEnd = True
1644 console.keyboard.putScancodes(keyDown(ch))
1645 pressed.insert(0, ch)
1646 if not group and modGroupEnd:
1647 for c in pressed:
1648 console.keyboard.putScancodes(keyUp(c))
1649 pressed = []
1650 modGroupEnd = True
1651 time.sleep(delay)
1652
1653def typeGuestCmd(ctx, args):
1654 import sys
1655
1656 if len(args) < 3:
1657 print "usage: typeGuest <machine> <text> <charDelay>"
1658 return 0
1659 mach = argsToMach(ctx,args)
1660 if mach is None:
1661 return 0
1662
1663 text = args[2]
1664
1665 if len(args) > 3:
1666 delay = float(args[3])
1667 else:
1668 delay = 0.1
1669
1670 gargs = [lambda ctx,mach,console,args: typeInGuest(console, text, delay)]
1671 cmdExistingVm(ctx, mach, 'guestlambda', gargs)
1672
1673 return 0
1674
1675def optId(verbose,id):
1676 if verbose:
1677 return ": "+id
1678 else:
1679 return ""
1680
1681def asSize(val,inBytes):
1682 if inBytes:
1683 return int(val)/(1024*1024)
1684 else:
1685 return int(val)
1686
1687def listMediaCmd(ctx,args):
1688 if len(args) > 1:
1689 verbose = int(args[1])
1690 else:
1691 verbose = False
1692 hdds = ctx['global'].getArray(ctx['vb'], 'hardDisks')
1693 print colCat(ctx,"Hard disks:")
1694 for hdd in hdds:
1695 if hdd.state != ctx['global'].constants.MediumState_Created:
1696 hdd.refreshState()
1697 print " %s (%s)%s %s [logical %s]" %(colPath(ctx,hdd.location), hdd.format, optId(verbose,hdd.id),colSizeM(ctx,asSize(hdd.size, True)), colSizeM(ctx,asSize(hdd.logicalSize, False)))
1698
1699 dvds = ctx['global'].getArray(ctx['vb'], 'DVDImages')
1700 print colCat(ctx,"CD/DVD disks:")
1701 for dvd in dvds:
1702 if dvd.state != ctx['global'].constants.MediumState_Created:
1703 dvd.refreshState()
1704 print " %s (%s)%s %s" %(colPath(ctx,dvd.location), dvd.format,optId(verbose,hdd.id),colSizeM(ctx,asSize(hdd.size, True)))
1705
1706 floppys = ctx['global'].getArray(ctx['vb'], 'floppyImages')
1707 print colCat(ctx,"Floppy disks:")
1708 for floppy in floppys:
1709 if floppy.state != ctx['global'].constants.MediumState_Created:
1710 floppy.refreshState()
1711 print " %s (%s)%s %s" %(colPath(ctx,floppy.location), floppy.format,optId(verbose,hdd.id), colSizeM(ctx,asSize(hdd.size, True)))
1712
1713 return 0
1714
1715def listUsbCmd(ctx,args):
1716 if (len(args) > 1):
1717 print "usage: listUsb"
1718 return 0
1719
1720 host = ctx['vb'].host
1721 for ud in ctx['global'].getArray(host, 'USBDevices'):
1722 printHostUsbDev(ctx,ud)
1723
1724 return 0
1725
1726def findDevOfType(ctx,mach,type):
1727 atts = ctx['global'].getArray(mach, 'mediumAttachments')
1728 for a in atts:
1729 if a.type == type:
1730 return [a.controller, a.port, a.device]
1731 return [None, 0, 0]
1732
1733def createHddCmd(ctx,args):
1734 if (len(args) < 3):
1735 print "usage: createHdd sizeM location type"
1736 return 0
1737
1738 size = int(args[1])
1739 loc = args[2]
1740 if len(args) > 3:
1741 format = args[3]
1742 else:
1743 format = "vdi"
1744
1745 hdd = ctx['vb'].createHardDisk(format, loc)
1746 progress = hdd.createBaseStorage(size, ctx['global'].constants.MediumVariant_Standard)
1747 if progressBar(ctx,progress) and hdd.id:
1748 print "created HDD at %s as %s" %(hdd.location, hdd.id)
1749 else:
1750 print "cannot create disk (file %s exist?)" %(loc)
1751 reportError(ctx,progress)
1752 return 0
1753
1754 return 0
1755
1756def registerHddCmd(ctx,args):
1757 if (len(args) < 2):
1758 print "usage: registerHdd location"
1759 return 0
1760
1761 vb = ctx['vb']
1762 loc = args[1]
1763 setImageId = False
1764 imageId = ""
1765 setParentId = False
1766 parentId = ""
1767 hdd = vb.openHardDisk(loc, ctx['global'].constants.AccessMode_ReadWrite, setImageId, imageId, setParentId, parentId)
1768 print "registered HDD as %s" %(hdd.id)
1769 return 0
1770
1771def controldevice(ctx,mach,args):
1772 [ctr,port,slot,type,id] = args
1773 mach.attachDevice(ctr, port, slot,type,id)
1774
1775def attachHddCmd(ctx,args):
1776 if (len(args) < 3):
1777 print "usage: attachHdd vm hdd controller port:slot"
1778 return 0
1779
1780 mach = argsToMach(ctx,args)
1781 if mach is None:
1782 return 0
1783 vb = ctx['vb']
1784 loc = args[2]
1785 try:
1786 hdd = vb.findHardDisk(loc)
1787 except:
1788 print "no HDD with path %s registered" %(loc)
1789 return 0
1790 if len(args) > 3:
1791 ctr = args[3]
1792 (port,slot) = args[4].split(":")
1793 else:
1794 [ctr, port, slot] = findDevOfType(ctx, mach, ctx['global'].constants.DeviceType_HardDisk)
1795
1796 cmdClosedVm(ctx, mach, lambda ctx,mach,args: mach.attachDevice(ctr, port, slot, ctx['global'].constants.DeviceType_HardDisk,hdd.id))
1797 return 0
1798
1799def detachVmDevice(ctx,mach,args):
1800 atts = ctx['global'].getArray(mach, 'mediumAttachments')
1801 hid = args[0]
1802 for a in atts:
1803 if a.medium:
1804 if hid == "ALL" or a.medium.id == hid:
1805 mach.detachDevice(a.controller, a.port, a.device)
1806
1807def detachMedium(ctx,mid,medium):
1808 cmdClosedVm(ctx, mach, detachVmDevice, [medium.id])
1809
1810def detachHddCmd(ctx,args):
1811 if (len(args) < 3):
1812 print "usage: detachHdd vm hdd"
1813 return 0
1814
1815 mach = argsToMach(ctx,args)
1816 if mach is None:
1817 return 0
1818 vb = ctx['vb']
1819 loc = args[2]
1820 try:
1821 hdd = vb.findHardDisk(loc)
1822 except:
1823 print "no HDD with path %s registered" %(loc)
1824 return 0
1825
1826 detachMedium(ctx,mach.id,hdd)
1827 return 0
1828
1829def unregisterHddCmd(ctx,args):
1830 if (len(args) < 2):
1831 print "usage: unregisterHdd path <vmunreg>"
1832 return 0
1833
1834 vb = ctx['vb']
1835 loc = args[1]
1836 if (len(args) > 2):
1837 vmunreg = int(args[2])
1838 else:
1839 vmunreg = 0
1840 try:
1841 hdd = vb.findHardDisk(loc)
1842 except:
1843 print "no HDD with path %s registered" %(loc)
1844 return 0
1845
1846 if vmunreg != 0:
1847 machs = ctx['global'].getArray(hdd, 'machineIds')
1848 try:
1849 for m in machs:
1850 print "Trying to detach from %s" %(m)
1851 detachMedium(ctx,m,hdd)
1852 except Exception, e:
1853 print 'failed: ',e
1854 return 0
1855 hdd.close()
1856 return 0
1857
1858def removeHddCmd(ctx,args):
1859 if (len(args) != 2):
1860 print "usage: removeHdd path"
1861 return 0
1862
1863 vb = ctx['vb']
1864 loc = args[1]
1865 try:
1866 hdd = vb.findHardDisk(loc)
1867 except:
1868 print "no HDD with path %s registered" %(loc)
1869 return 0
1870
1871 progress = hdd.deleteStorage()
1872 progressBar(ctx,progress)
1873
1874 return 0
1875
1876def registerIsoCmd(ctx,args):
1877 if (len(args) < 2):
1878 print "usage: registerIso location"
1879 return 0
1880 vb = ctx['vb']
1881 loc = args[1]
1882 id = ""
1883 iso = vb.openDVDImage(loc, id)
1884 print "registered ISO as %s" %(iso.id)
1885 return 0
1886
1887def unregisterIsoCmd(ctx,args):
1888 if (len(args) != 2):
1889 print "usage: unregisterIso path"
1890 return 0
1891
1892 vb = ctx['vb']
1893 loc = args[1]
1894 try:
1895 dvd = vb.findDVDImage(loc)
1896 except:
1897 print "no DVD with path %s registered" %(loc)
1898 return 0
1899
1900 progress = dvd.close()
1901 print "Unregistered ISO at %s" %(dvd.location)
1902
1903 return 0
1904
1905def removeIsoCmd(ctx,args):
1906 if (len(args) != 2):
1907 print "usage: removeIso path"
1908 return 0
1909
1910 vb = ctx['vb']
1911 loc = args[1]
1912 try:
1913 dvd = vb.findDVDImage(loc)
1914 except:
1915 print "no DVD with path %s registered" %(loc)
1916 return 0
1917
1918 progress = dvd.deleteStorage()
1919 if progressBar(ctx,progress):
1920 print "Removed ISO at %s" %(dvd.location)
1921 else:
1922 reportError(ctx,progress)
1923 return 0
1924
1925def attachIsoCmd(ctx,args):
1926 if (len(args) < 3):
1927 print "usage: attachIso vm iso controller port:slot"
1928 return 0
1929
1930 mach = argsToMach(ctx,args)
1931 if mach is None:
1932 return 0
1933 vb = ctx['vb']
1934 loc = args[2]
1935 try:
1936 dvd = vb.findDVDImage(loc)
1937 except:
1938 print "no DVD with path %s registered" %(loc)
1939 return 0
1940 if len(args) > 3:
1941 ctr = args[3]
1942 (port,slot) = args[4].split(":")
1943 else:
1944 [ctr, port, slot] = findDevOfType(ctx, mach, ctx['global'].constants.DeviceType_DVD)
1945 cmdClosedVm(ctx, mach, lambda ctx,mach,args: mach.attachDevice(ctr, port, slot, ctx['global'].constants.DeviceType_DVD,dvd.id))
1946 return 0
1947
1948def detachIsoCmd(ctx,args):
1949 if (len(args) < 3):
1950 print "usage: detachIso vm iso"
1951 return 0
1952
1953 mach = argsToMach(ctx,args)
1954 if mach is None:
1955 return 0
1956 vb = ctx['vb']
1957 loc = args[2]
1958 try:
1959 dvd = vb.findDVDImage(loc)
1960 except:
1961 print "no DVD with path %s registered" %(loc)
1962 return 0
1963
1964 detachMedium(ctx,mach.id,dvd)
1965 return 0
1966
1967def mountIsoCmd(ctx,args):
1968 if (len(args) < 3):
1969 print "usage: mountIso vm iso controller port:slot"
1970 return 0
1971
1972 mach = argsToMach(ctx,args)
1973 if mach is None:
1974 return 0
1975 vb = ctx['vb']
1976 loc = args[2]
1977 try:
1978 dvd = vb.findDVDImage(loc)
1979 except:
1980 print "no DVD with path %s registered" %(loc)
1981 return 0
1982
1983 if len(args) > 3:
1984 ctr = args[3]
1985 (port,slot) = args[4].split(":")
1986 else:
1987 # autodetect controller and location, just find first controller with media == DVD
1988 [ctr, port, slot] = findDevOfType(ctx, mach, ctx['global'].constants.DeviceType_DVD)
1989
1990 cmdExistingVm(ctx, mach, 'mountiso', [ctr, port, slot, dvd.id, True])
1991
1992 return 0
1993
1994def unmountIsoCmd(ctx,args):
1995 if (len(args) < 2):
1996 print "usage: unmountIso vm controller port:slot"
1997 return 0
1998
1999 mach = argsToMach(ctx,args)
2000 if mach is None:
2001 return 0
2002 vb = ctx['vb']
2003
2004 if len(args) > 2:
2005 ctr = args[2]
2006 (port,slot) = args[3].split(":")
2007 else:
2008 # autodetect controller and location, just find first controller with media == DVD
2009 [ctr, port, slot] = findDevOfType(ctx, mach, ctx['global'].constants.DeviceType_DVD)
2010
2011 cmdExistingVm(ctx, mach, 'mountiso', [ctr, port, slot, "", True])
2012
2013 return 0
2014
2015def attachCtr(ctx,mach,args):
2016 [name, bus, type] = args
2017 ctr = mach.addStorageController(name, bus)
2018 if type != None:
2019 ctr.controllerType = type
2020
2021def attachCtrCmd(ctx,args):
2022 if (len(args) < 4):
2023 print "usage: attachCtr vm cname bus <type>"
2024 return 0
2025
2026 if len(args) > 4:
2027 type = enumFromString(ctx,'StorageControllerType', args[4])
2028 if type == None:
2029 print "Controller type %s unknown" %(args[4])
2030 return 0
2031 else:
2032 type = None
2033
2034 mach = argsToMach(ctx,args)
2035 if mach is None:
2036 return 0
2037 bus = enumFromString(ctx,'StorageBus', args[3])
2038 if bus is None:
2039 print "Bus type %s unknown" %(args[3])
2040 return 0
2041 name = args[2]
2042 cmdClosedVm(ctx, mach, attachCtr, [name, bus, type])
2043 return 0
2044
2045def detachCtrCmd(ctx,args):
2046 if (len(args) < 3):
2047 print "usage: detachCtr vm name"
2048 return 0
2049
2050 mach = argsToMach(ctx,args)
2051 if mach is None:
2052 return 0
2053 ctr = args[2]
2054 cmdClosedVm(ctx, mach, lambda ctx,mach,args: mach.removeStorageController(ctr))
2055 return 0
2056
2057def usbctr(ctx,mach,console,args):
2058 if (args[0]):
2059 console.attachUSBDevice(args[1])
2060 else:
2061 console.detachUSBDevice(args[1])
2062
2063def attachUsbCmd(ctx,args):
2064 if (len(args) < 3):
2065 print "usage: attachUsb vm deviceuid"
2066 return 0
2067
2068 mach = argsToMach(ctx,args)
2069 if mach is None:
2070 return 0
2071 dev = args[2]
2072 cmdExistingVm(ctx, mach, 'guestlambda', [usbctr,True,dev])
2073 return 0
2074
2075def detachUsbCmd(ctx,args):
2076 if (len(args) < 3):
2077 print "usage: detachUsb vm deviceuid"
2078 return 0
2079
2080 mach = argsToMach(ctx,args)
2081 if mach is None:
2082 return 0
2083 dev = args[2]
2084 cmdExistingVm(ctx, mach, 'guestlambda', [usbctr,False,dev])
2085 return 0
2086
2087
2088def guiCmd(ctx,args):
2089 if (len(args) > 1):
2090 print "usage: gui"
2091 return 0
2092
2093 binDir = ctx['global'].getBinDir()
2094
2095 vbox = os.path.join(binDir, 'VirtualBox')
2096 try:
2097 os.system(vbox)
2098 except KeyboardInterrupt:
2099 # to allow interruption
2100 pass
2101 return 0
2102
2103def shareFolderCmd(ctx,args):
2104 if (len(args) < 4):
2105 print "usage: shareFolder vm path name <writable> <persistent>"
2106 return 0
2107
2108 mach = argsToMach(ctx,args)
2109 if mach is None:
2110 return 0
2111 path = args[2]
2112 name = args[3]
2113 writable = False
2114 persistent = False
2115 if len(args) > 4:
2116 for a in args[4:]:
2117 if a == 'writable':
2118 writable = True
2119 if a == 'persistent':
2120 persistent = True
2121 if persistent:
2122 cmdClosedVm(ctx, mach, lambda ctx,mach,args: mach.createSharedFolder(name, path, writable), [])
2123 else:
2124 cmdExistingVm(ctx, mach, 'guestlambda', [lambda ctx,mach,console,args: console.createSharedFolder(name, path, writable)])
2125 return 0
2126
2127def unshareFolderCmd(ctx,args):
2128 if (len(args) < 3):
2129 print "usage: unshareFolder vm name"
2130 return 0
2131
2132 mach = argsToMach(ctx,args)
2133 if mach is None:
2134 return 0
2135 name = args[2]
2136 found = False
2137 for sf in ctx['global'].getArray(mach, 'sharedFolders'):
2138 if sf.name == name:
2139 cmdClosedVm(ctx, mach, lambda ctx,mach,args: mach.removeSharedFolder(name), [])
2140 found = True
2141 break
2142 if not found:
2143 cmdExistingVm(ctx, mach, 'guestlambda', [lambda ctx,mach,console,args: console.removeSharedFolder(name)])
2144 return 0
2145
2146
2147def snapshotCmd(ctx,args):
2148 if (len(args) < 2 or args[1] == 'help'):
2149 print "Take snapshot: snapshot vm take name <description>"
2150 print "Restore snapshot: snapshot vm restore name"
2151 print "Merge snapshot: snapshot vm merge name"
2152 return 0
2153
2154 mach = argsToMach(ctx,args)
2155 if mach is None:
2156 return 0
2157 cmd = args[2]
2158 if cmd == 'take':
2159 if (len(args) < 4):
2160 print "usage: snapshot vm take name <description>"
2161 return 0
2162 name = args[3]
2163 if (len(args) > 4):
2164 desc = args[4]
2165 else:
2166 desc = ""
2167 cmdAnyVm(ctx, mach, lambda ctx,mach,console,args: progressBar(ctx, console.takeSnapshot(name,desc)))
2168
2169 if cmd == 'restore':
2170 if (len(args) < 4):
2171 print "usage: snapshot vm restore name"
2172 return 0
2173 name = args[3]
2174 snap = mach.findSnapshot(name)
2175 cmdAnyVm(ctx, mach, lambda ctx,mach,console,args: progressBar(ctx, console.restoreSnapshot(snap)))
2176 return 0
2177
2178 if cmd == 'restorecurrent':
2179 if (len(args) < 4):
2180 print "usage: snapshot vm restorecurrent"
2181 return 0
2182 snap = mach.currentSnapshot()
2183 cmdAnyVm(ctx, mach, lambda ctx,mach,console,args: progressBar(ctx, console.restoreSnapshot(snap)))
2184 return 0
2185
2186 if cmd == 'delete':
2187 if (len(args) < 4):
2188 print "usage: snapshot vm delete name"
2189 return 0
2190 name = args[3]
2191 snap = mach.findSnapshot(name)
2192 cmdAnyVm(ctx, mach, lambda ctx,mach,console,args: progressBar(ctx, console.deleteSnapshot(snap.id)))
2193 return 0
2194
2195 print "Command '%s' is unknown" %(cmd)
2196
2197 return 0
2198
2199def natAlias(ctx, mach, nicnum, nat, args=[]):
2200 """This command shows/alters NAT's alias settings.
2201 usage: nat <vm> <nicnum> alias [default|[log] [proxyonly] [sameports]]
2202 default - set settings to default values
2203 log - switch on alias loging
2204 proxyonly - switch proxyonly mode on
2205 sameports - enforces NAT using the same ports
2206 """
2207 alias = {
2208 'log': 0x1,
2209 'proxyonly': 0x2,
2210 'sameports': 0x4
2211 }
2212 if len(args) == 1:
2213 first = 0
2214 msg = ''
2215 for aliasmode, aliaskey in alias.iteritems():
2216 if first == 0:
2217 first = 1
2218 else:
2219 msg += ', '
2220 if int(nat.aliasMode) & aliaskey:
2221 msg += '{0}: {1}'.format(aliasmode, 'on')
2222 else:
2223 msg += '{0}: {1}'.format(aliasmode, 'off')
2224 msg += ')'
2225 return (0, [msg])
2226 else:
2227 nat.aliasMode = 0
2228 if 'default' not in args:
2229 for a in range(1, len(args)):
2230 if not alias.has_key(args[a]):
2231 print 'Invalid alias mode: ' + args[a]
2232 print natAlias.__doc__
2233 return (1, None)
2234 nat.aliasMode = int(nat.aliasMode) | alias[args[a]];
2235 return (0, None)
2236
2237def natSettings(ctx, mach, nicnum, nat, args):
2238 """This command shows/alters NAT settings.
2239 usage: nat <vm> <nicnum> settings [<mtu> [[<socsndbuf> <sockrcvbuf> [<tcpsndwnd> <tcprcvwnd>]]]]
2240 mtu - set mtu <= 16000
2241 socksndbuf/sockrcvbuf - sets amount of kb for socket sending/receiving buffer
2242 tcpsndwnd/tcprcvwnd - sets size of initial tcp sending/receiving window
2243 """
2244 if len(args) == 1:
2245 (mtu, socksndbuf, sockrcvbuf, tcpsndwnd, tcprcvwnd) = nat.getNetworkSettings();
2246 if mtu == 0: mtu = 1500
2247 if socksndbuf == 0: socksndbuf = 64
2248 if sockrcvbuf == 0: sockrcvbuf = 64
2249 if tcpsndwnd == 0: tcpsndwnd = 64
2250 if tcprcvwnd == 0: tcprcvwnd = 64
2251 msg = 'mtu:{0} socket(snd:{1}, rcv:{2}) tcpwnd(snd:{3}, rcv:{4})'.format(mtu, socksndbuf, sockrcvbuf, tcpsndwnd, tcprcvwnd);
2252 return (0, [msg])
2253 else:
2254 if args[1] < 16000:
2255 print 'invalid mtu value ({0} no in range [65 - 16000])'.format(args[1])
2256 return (1, None)
2257 for i in range(2, len(args)):
2258 if not args[i].isdigit() or int(args[i]) < 8 or int(args[i]) > 1024:
2259 print 'invalid {0} parameter ({1} not in range [8-1024])'.format(i, args[i])
2260 return (1, None)
2261 a = [args[1]]
2262 if len(args) < 6:
2263 for i in range(2, len(args)): a.append(args[i])
2264 for i in range(len(args), 6): a.append(0)
2265 else:
2266 for i in range(2, len(args)): a.append(args[i])
2267 #print a
2268 nat.setNetworkSettings(int(a[0]), int(a[1]), int(a[2]), int(a[3]), int(a[4]))
2269 return (0, None)
2270
2271def natDns(ctx, mach, nicnum, nat, args):
2272 """This command shows/alters DNS's NAT settings
2273 usage: nat <vm> <nicnum> dns [passdomain] [proxy] [usehostresolver]
2274 passdomain - enforces builtin DHCP server to pass domain
2275 proxy - switch on builtin NAT DNS proxying mechanism
2276 usehostresolver - proxies all DNS requests to Host Resolver interface
2277 """
2278 yesno = {0: 'off', 1: 'on'}
2279 if len(args) == 1:
2280 msg = 'passdomain:{0}, proxy:{1}, usehostresolver:{2}'.format(yesno[int(nat.dnsPassDomain)], yesno[int(nat.dnsProxy)], yesno[int(nat.dnsUseHostResolver)])
2281 return (0, [msg])
2282 else:
2283 nat.dnsPassDomain = 'passdomain' in args
2284 nat.dnsProxy = 'proxy' in args
2285 nat.dnsUseHostResolver = 'usehostresolver' in args
2286 return (0, None)
2287
2288def natTftp(ctx, mach, nicnum, nat, args):
2289 """This command shows/alters TFTP settings
2290 usage nat <vm> <nicnum> tftp [prefix <prefix>| bootfile <bootfile>| server <server>]
2291 prefix - alters prefix TFTP settings
2292 bootfile - alters bootfile TFTP settings
2293 server - sets booting server
2294 """
2295 if len(args) == 1:
2296 server = nat.tftpNextServer
2297 if server is None:
2298 server = nat.network
2299 if server is None:
2300 server = '10.0.{0}/24'.format(int(nicnum) + 2)
2301 (server,mask) = server.split('/')
2302 while server.count('.') != 3:
2303 server += '.0'
2304 (a,b,c,d) = server.split('.')
2305 server = '{0}.{1}.{2}.4'.format(a,b,c)
2306 prefix = nat.tftpPrefix
2307 if prefix is None:
2308 prefix = '{0}/TFTP/'.format(ctx['vb'].homeFolder)
2309 bootfile = nat.tftpBootFile
2310 if bootfile is None:
2311 bootfile = '{0}.pxe'.format(mach.name)
2312 msg = 'server:{0}, prefix:{1}, bootfile:{2}'.format(server, prefix, bootfile)
2313 return (0, [msg])
2314 else:
2315
2316 cmd = args[1]
2317 if len(args) != 3:
2318 print 'invalid args:', args
2319 print natTftp.__doc__
2320 return (1, None)
2321 if cmd == 'prefix': nat.tftpPrefix = args[2]
2322 elif cmd == 'bootfile': nat.tftpBootFile = args[2]
2323 elif cmd == 'server': nat.tftpNextServer = args[2]
2324 else:
2325 print "invalid cmd:", cmd
2326 return (1, None)
2327 return (0, None)
2328
2329def natPortForwarding(ctx, mach, nicnum, nat, args):
2330 """This command shows/manages port-forwarding settings
2331 usage:
2332 nat <vm> <nicnum> <pf> [ simple tcp|udp <hostport> <guestport>]
2333 |[no_name tcp|udp <hostip> <hostport> <guestip> <guestport>]
2334 |[ex tcp|udp <pf-name> <hostip> <hostport> <guestip> <guestport>]
2335 |[delete <pf-name>]
2336 """
2337 if len(args) == 1:
2338 # note: keys/values are swapped in defining part of the function
2339 proto = {0: 'udp', 1: 'tcp'}
2340 msg = []
2341 pfs = ctx['global'].getArray(nat, 'redirects')
2342 for pf in pfs:
2343 (pfnme, pfp, pfhip, pfhp, pfgip, pfgp) = str(pf).split(',')
2344 msg.append('{0}: {1} {2}:{3} => {4}:{5}'.format(pfnme, proto[int(pfp)], pfhip, pfhp, pfgip, pfgp))
2345 return (0, msg) # msg is array
2346 else:
2347 proto = {'udp': 0, 'tcp': 1}
2348 pfcmd = {
2349 'simple': {
2350 'validate': lambda: args[1] in pfcmd.keys() and args[2] in proto.keys() and len(args) == 5,
2351 'func':lambda: nat.addRedirect('', proto[args[2]], '', int(args[3]), '', int(args[4]))
2352 },
2353 'no_name': {
2354 'validate': lambda: args[1] in pfcmd.keys() and args[2] in proto.keys() and len(args) == 7,
2355 'func': lambda: nat.addRedirect('', proto[args[2]], args[3], int(args[4]), args[5], int(args[6]))
2356 },
2357 'ex': {
2358 'validate': lambda: args[1] in pfcmd.keys() and args[2] in proto.keys() and len(args) == 8,
2359 'func': lambda: nat.addRedirect(args[3], proto[args[2]], args[4], int(args[5]), args[6], int(args[7]))
2360 },
2361 'delete': {
2362 'validate': lambda: len(args) == 3,
2363 'func': lambda: nat.removeRedirect(args[2])
2364 }
2365 }
2366
2367 if not pfcmd[args[1]]['validate']():
2368 print 'invalid port-forwarding or args of sub command ', args[1]
2369 print natPortForwarding.__doc__
2370 return (1, None)
2371
2372 a = pfcmd[args[1]]['func']()
2373 return (0, None)
2374
2375def natNetwork(ctx, mach, nicnum, nat, args):
2376 """This command shows/alters NAT network settings
2377 usage: nat <vm> <nicnum> network [<network>]
2378 """
2379 if len(args) == 1:
2380 if nat.network is not None and len(str(nat.network)) != 0:
2381 msg = '\'%s\'' % (nat.network)
2382 else:
2383 msg = '10.0.{0}.0/24'.format(int(nicnum) + 2)
2384 return (0, [msg])
2385 else:
2386 (addr, mask) = args[1].split('/')
2387 if addr.count('.') > 3 or int(mask) < 0 or int(mask) > 32:
2388 print 'Invalid arguments'
2389 return (1, None)
2390 nat.network = args[1]
2391 return (0, None)
2392def natCmd(ctx, args):
2393 """This command is entry point to NAT settins management
2394 usage: nat <vm> <nicnum> <cmd> <cmd-args>
2395 cmd - [alias|settings|tftp|dns|pf|network]
2396 for more information about commands:
2397 nat help <cmd>
2398 """
2399
2400 natcommands = {
2401 'alias' : natAlias,
2402 'settings' : natSettings,
2403 'tftp': natTftp,
2404 'dns': natDns,
2405 'pf': natPortForwarding,
2406 'network': natNetwork
2407 }
2408
2409 if args[1] == 'help':
2410 if len(args) > 2:
2411 print natcommands[args[2]].__doc__
2412 else:
2413 print natCmd.__doc__
2414 return 0
2415 if len(args) == 1 or len(args) < 4 or args[3] not in natcommands:
2416 print natCmd.__doc__
2417 return 0
2418 mach = ctx['argsToMach'](args)
2419 if mach == None:
2420 print "please specify vm"
2421 return 0
2422 if len(args) < 3 or not args[2].isdigit() or int(args[2]) not in range(0, ctx['vb'].systemProperties.networkAdapterCount):
2423 print 'please specify adapter num {0} isn\'t in range [0-{1}]'.format(args[2], ctx['vb'].systemProperties.networkAdapterCount)
2424 return 0
2425 nicnum = int(args[2])
2426 cmdargs = []
2427 for i in range(3, len(args)):
2428 cmdargs.append(args[i])
2429
2430 # @todo vvl if nicnum is missed but command is entered
2431 # use NAT func for every adapter on machine.
2432 func = args[3]
2433 rosession = 1
2434 session = None
2435 if len(cmdargs) > 1:
2436 rosession = 0
2437 session = ctx['global'].openMachineSession(mach.id);
2438 mach = session.machine;
2439
2440 adapter = mach.getNetworkAdapter(nicnum)
2441 natEngine = adapter.natDriver
2442 (rc, report) = natcommands[func](ctx, mach, nicnum, natEngine, cmdargs)
2443 if rosession == 0:
2444 if rc == 0:
2445 mach.saveSettings()
2446 session.close()
2447 elif report is not None:
2448 for r in report:
2449 msg ='{0} nic{1} {2}: {3}'.format(mach.name, nicnum, func, r)
2450 print msg
2451 return 0
2452
2453def nicSwitchOnOff(adapter, attr, args):
2454 if len(args) == 1:
2455 yesno = {0: 'off', 1: 'on'}
2456 r = yesno[int(adapter.__getattr__(attr))]
2457 return (0, r)
2458 else:
2459 yesno = {'off' : 0, 'on' : 1}
2460 if args[1] not in yesno:
2461 print '%s isn\'t acceptable, please choose %s' % (args[1], yesno.keys())
2462 return (1, None)
2463 adapter.__setattr__(attr, yesno[args[1]])
2464 return (0, None)
2465
2466def nicTraceSubCmd(ctx, vm, nicnum, adapter, args):
2467 '''
2468 usage: nic <vm> <nicnum> trace [on|off [file]]
2469 '''
2470 (rc, r) = nicSwitchOnOff(adapter, 'traceEnabled', args)
2471 if len(args) == 1 and rc == 0:
2472 r = '%s file:%s' % (r, adapter.traceFile)
2473 return (0, r)
2474 elif len(args) == 3 and rc == 0:
2475 adapter.traceFile = args[2]
2476 return (0, None)
2477
2478def nicLineSpeedSubCmd(ctx, vm, nicnum, adapter, args):
2479 if len(args) == 1:
2480 r = '%d kbps'%(adapter.lineSpeed)
2481 return (0, r)
2482 else:
2483 if not args[1].isdigit():
2484 print '%s isn\'t a number'.format(args[1])
2485 print (1, None)
2486 adapter.lineSpeed = int(args[1])
2487 return (0, None)
2488
2489def nicCableSubCmd(ctx, vm, nicnum, adapter, args):
2490 '''
2491 usage: nic <vm> <nicnum> cable [on|off]
2492 '''
2493 return nicSwitchOnOff(adapter, 'cableConnected', args)
2494
2495def nicEnableSubCmd(ctx, vm, nicnum, adapter, args):
2496 '''
2497 usage: nic <vm> <nicnum> enable [on|off]
2498 '''
2499 return nicSwitchOnOff(adapter, 'enabled', args)
2500
2501def nicTypeSubCmd(ctx, vm, nicnum, adapter, args):
2502 '''
2503 usage: nic <vm> <nicnum> type [Am79c970A|Am79c970A|I82540EM|I82545EM|I82543GC|Virtio]
2504 '''
2505 if len(args) == 1:
2506 nictypes = ctx['ifaces'].all_values('NetworkAdapterType')
2507 for n in nictypes.keys():
2508 if str(adapter.adapterType) == str(nictypes[n]):
2509 return (0, str(n))
2510 return (1, None)
2511 else:
2512 nictypes = ctx['ifaces'].all_values('NetworkAdapterType')
2513 if args[1] not in nictypes.keys():
2514 print '%s not in acceptable values (%s)' % (args[1], nictypes.keys())
2515 return (1, None)
2516 adapter.adapterType = nictypes[args[1]]
2517 return (0, None)
2518
2519def nicAttachmentSubCmd(ctx, vm, nicnum, adapter, args):
2520 '''
2521 usage: nic <vm> <nicnum> attachment [Null|NAT|Bridged <interface>|Internal <name>|HostOnly <interface>]
2522 '''
2523 if len(args) == 1:
2524 nicAttachmentType = {
2525 ctx['global'].constants.NetworkAttachmentType_Null: ('Null', ''),
2526 ctx['global'].constants.NetworkAttachmentType_NAT: ('NAT', ''),
2527 ctx['global'].constants.NetworkAttachmentType_Bridged: ('Bridged', adapter.hostInterface),
2528 ctx['global'].constants.NetworkAttachmentType_Internal: ('Internal', adapter.internalNetwork),
2529 ctx['global'].constants.NetworkAttachmentType_HostOnly: ('HostOnly', adapter.hostInterface),
2530 #ctx['global'].constants.NetworkAttachmentType_VDE: ('VDE', adapter.VDENetwork)
2531 }
2532 import types
2533 if type(adapter.attachmentType) != types.IntType:
2534 t = str(adapter.attachmentType)
2535 else:
2536 t = adapter.attachmentType
2537 (r, p) = nicAttachmentType[t]
2538 return (0, 'attachment:{0}, name:{1}'.format(r, p))
2539 else:
2540 nicAttachmentType = {
2541 'Null': {
2542 'v': lambda: len(args) == 2,
2543 'p': lambda: 'do nothing',
2544 'f': lambda: adapter.detach()},
2545 'NAT': {
2546 'v': lambda: len(args) == 2,
2547 'p': lambda: 'do nothing',
2548 'f': lambda: adapter.attachToNAT()},
2549 'Bridged': {
2550 'v': lambda: len(args) == 3,
2551 'p': lambda: adapter.__setattr__('hostInterface', args[2]),
2552 'f': lambda: adapter.attachToBridgedInterface()},
2553 'Internal': {
2554 'v': lambda: len(args) == 3,
2555 'p': lambda: adapter.__setattr__('internalNetwork', args[2]),
2556 'f': lambda: adapter.attachToInternalNetwork()},
2557 'HostOnly': {
2558 'v': lambda: len(args) == 2,
2559 'p': lambda: adapter.__setattr__('hostInterface', args[2]),
2560 'f': lambda: adapter.attachToHostOnlyInterface()},
2561 'VDE': {
2562 'v': lambda: len(args) == 3,
2563 'p': lambda: adapter.__setattr__('VDENetwork', args[2]),
2564 'f': lambda: adapter.attachToVDE()}
2565 }
2566 if args[1] not in nicAttachmentType.keys():
2567 print '{0} not in acceptable values ({1})'.format(args[1], nicAttachmentType.keys())
2568 return (1, None)
2569 if not nicAttachmentType[args[1]]['v']():
2570 print nicAttachmentType.__doc__
2571 return (1, None)
2572 nicAttachmentType[args[1]]['p']()
2573 nicAttachmentType[args[1]]['f']()
2574 return (0, None)
2575
2576def nicCmd(ctx, args):
2577 '''
2578 This command to manage network adapters
2579 usage: nic <vm> <nicnum> <cmd> <cmd-args>
2580 where cmd : attachment, trace, linespeed, cable, enable, type
2581 '''
2582 # 'command name':{'runtime': is_callable_at_runtime, 'op': function_name}
2583 niccomand = {
2584 'attachment': nicAttachmentSubCmd,
2585 'trace': nicTraceSubCmd,
2586 'linespeed': nicLineSpeedSubCmd,
2587 'cable': nicCableSubCmd,
2588 'enable': nicEnableSubCmd,
2589 'type': nicTypeSubCmd
2590 }
2591 if args[1] == 'help' \
2592 or len(args) < 2 \
2593 or (len(args) > 2 and args[3] not in niccomand):
2594 if len(args) == 3 \
2595 and args[2] in niccomand:
2596 print niccomand[args[2]].__doc__
2597 else:
2598 print nicCmd.__doc__
2599 return 0
2600
2601 vm = ctx['argsToMach'](args)
2602 if vm is None:
2603 print 'please specify vm'
2604 return 0
2605
2606 if len(args) < 3 \
2607 or not args[2].isdigit() \
2608 or int(args[2]) not in range(0, ctx['vb'].systemProperties.networkAdapterCount):
2609 print 'please specify adapter num %d isn\'t in range [0-%d]'%(args[2], ctx['vb'].systemProperties.networkAdapterCount)
2610 return 0
2611 nicnum = int(args[2])
2612 cmdargs = args[3:]
2613 func = args[3]
2614 session = None
2615 session = ctx['global'].openMachineSession(vm.id)
2616 vm = session.machine
2617 adapter = vm.getNetworkAdapter(nicnum)
2618 (rc, report) = niccomand[func](ctx, vm, nicnum, adapter, cmdargs)
2619 if rc == 0:
2620 vm.saveSettings()
2621 if report is not None:
2622 print '%s nic %d %s: %s' % (vm.name, nicnum, args[3], report)
2623 session.close()
2624 return 0
2625
2626
2627aliases = {'s':'start',
2628 'i':'info',
2629 'l':'list',
2630 'h':'help',
2631 'a':'alias',
2632 'q':'quit', 'exit':'quit',
2633 'tg': 'typeGuest',
2634 'v':'verbose'}
2635
2636commands = {'help':['Prints help information', helpCmd, 0],
2637 'start':['Start virtual machine by name or uuid: start Linux', startCmd, 0],
2638 'createVm':['Create virtual machine: createVm macvm MacOS', createVmCmd, 0],
2639 'removeVm':['Remove virtual machine', removeVmCmd, 0],
2640 'pause':['Pause virtual machine', pauseCmd, 0],
2641 'resume':['Resume virtual machine', resumeCmd, 0],
2642 'save':['Save execution state of virtual machine', saveCmd, 0],
2643 'stats':['Stats for virtual machine', statsCmd, 0],
2644 'powerdown':['Power down virtual machine', powerdownCmd, 0],
2645 'powerbutton':['Effectively press power button', powerbuttonCmd, 0],
2646 'list':['Shows known virtual machines', listCmd, 0],
2647 'info':['Shows info on machine', infoCmd, 0],
2648 'ginfo':['Shows info on guest', ginfoCmd, 0],
2649 'gexec':['Executes program in the guest', gexecCmd, 0],
2650 'alias':['Control aliases', aliasCmd, 0],
2651 'verbose':['Toggle verbosity', verboseCmd, 0],
2652 'setvar':['Set VMs variable: setvar Fedora BIOSSettings.ACPIEnabled True', setvarCmd, 0],
2653 'eval':['Evaluate arbitrary Python construction: eval \'for m in getMachines(ctx): print m.name,"has",m.memorySize,"M"\'', evalCmd, 0],
2654 'quit':['Exits', quitCmd, 0],
2655 'host':['Show host information', hostCmd, 0],
2656 'guest':['Execute command for guest: guest Win32 \'console.mouse.putMouseEvent(20, 20, 0, 0, 0)\'', guestCmd, 0],
2657 'monitorGuest':['Monitor what happens with the guest for some time: monitorGuest Win32 10', monitorGuestCmd, 0],
2658 'monitorVBox':['Monitor what happens with Virtual Box for some time: monitorVBox 10', monitorVBoxCmd, 0],
2659 'portForward':['Setup permanent port forwarding for a VM, takes adapter number host port and guest port: portForward Win32 0 8080 80', portForwardCmd, 0],
2660 'showLog':['Show log file of the VM, : showLog Win32', showLogCmd, 0],
2661 'findLog':['Show entries matching pattern in log file of the VM, : findLog Win32 PDM|CPUM', findLogCmd, 0],
2662 'reloadExt':['Reload custom extensions: reloadExt', reloadExtCmd, 0],
2663 'runScript':['Run VBox script: runScript script.vbox', runScriptCmd, 0],
2664 'sleep':['Sleep for specified number of seconds: sleep 3.14159', sleepCmd, 0],
2665 'shell':['Execute external shell command: shell "ls /etc/rc*"', shellCmd, 0],
2666 'exportVm':['Export VM in OVF format: exportVm Win /tmp/win.ovf', exportVMCmd, 0],
2667 'screenshot':['Take VM screenshot to a file: screenshot Win /tmp/win.png 1024 768', screenshotCmd, 0],
2668 'teleport':['Teleport VM to another box (see openportal): teleport Win anotherhost:8000 <passwd> <maxDowntime>', teleportCmd, 0],
2669 'typeGuest':['Type arbitrary text in guest: typeGuest Linux "^lls\\n&UP;&BKSP;ess /etc/hosts\\nq^c" 0.7', typeGuestCmd, 0],
2670 'openportal':['Open portal for teleportation of VM from another box (see teleport): openportal Win 8000 <passwd>', openportalCmd, 0],
2671 'closeportal':['Close teleportation portal (see openportal,teleport): closeportal Win', closeportalCmd, 0],
2672 'getextra':['Get extra data, empty key lists all: getextra <vm|global> <key>', getExtraDataCmd, 0],
2673 'setextra':['Set extra data, empty value removes key: setextra <vm|global> <key> <value>', setExtraDataCmd, 0],
2674 'gueststats':['Print available guest stats (only Windows guests with additions so far): gueststats Win32', gueststatsCmd, 0],
2675 'plugcpu':['Add a CPU to a running VM: plugcpu Win 1', plugcpuCmd, 0],
2676 'unplugcpu':['Remove a CPU from a running VM (additions required, Windows cannot unplug): unplugcpu Linux 1', unplugcpuCmd, 0],
2677 'createHdd': ['Create virtual HDD: createHdd 1000 /disk.vdi ', createHddCmd, 0],
2678 'removeHdd': ['Permanently remove virtual HDD: removeHdd /disk.vdi', removeHddCmd, 0],
2679 'registerHdd': ['Register HDD image with VirtualBox instance: registerHdd /disk.vdi', registerHddCmd, 0],
2680 'unregisterHdd': ['Unregister HDD image with VirtualBox instance: unregisterHdd /disk.vdi', unregisterHddCmd, 0],
2681 'attachHdd': ['Attach HDD to the VM: attachHdd win /disk.vdi "IDE Controller" 0:1', attachHddCmd, 0],
2682 'detachHdd': ['Detach HDD from the VM: detachHdd win /disk.vdi', detachHddCmd, 0],
2683 'registerIso': ['Register CD/DVD image with VirtualBox instance: registerIso /os.iso', registerIsoCmd, 0],
2684 'unregisterIso': ['Unregister CD/DVD image with VirtualBox instance: unregisterIso /os.iso', unregisterIsoCmd, 0],
2685 'removeIso': ['Permanently remove CD/DVD image: removeIso /os.iso', removeIsoCmd, 0],
2686 'attachIso': ['Attach CD/DVD to the VM: attachIso win /os.iso "IDE Controller" 0:1', attachIsoCmd, 0],
2687 'detachIso': ['Detach CD/DVD from the VM: detachIso win /os.iso', detachIsoCmd, 0],
2688 'mountIso': ['Mount CD/DVD to the running VM: mountIso win /os.iso "IDE Controller" 0:1', mountIsoCmd, 0],
2689 'unmountIso': ['Unmount CD/DVD from running VM: unmountIso win "IDE Controller" 0:1', unmountIsoCmd, 0],
2690 'attachCtr': ['Attach storage controller to the VM: attachCtr win Ctr0 IDE ICH6', attachCtrCmd, 0],
2691 'detachCtr': ['Detach HDD from the VM: detachCtr win Ctr0', detachCtrCmd, 0],
2692 'attachUsb': ['Attach USB device to the VM (use listUsb to show available devices): attachUsb win uuid', attachUsbCmd, 0],
2693 'detachUsb': ['Detach USB device from the VM: detachUsb win uuid', detachUsbCmd, 0],
2694 'listMedia': ['List media known to this VBox instance', listMediaCmd, 0],
2695 'listUsb': ['List known USB devices', listUsbCmd, 0],
2696 'shareFolder': ['Make host\'s folder visible to guest: shareFolder win /share share writable', shareFolderCmd, 0],
2697 'unshareFolder': ['Remove folder sharing', unshareFolderCmd, 0],
2698 'gui': ['Start GUI frontend', guiCmd, 0],
2699 'colors':['Toggle colors', colorsCmd, 0],
2700 'snapshot':['VM snapshot manipulation, snapshot help for more info', snapshotCmd, 0],
2701 'nat':['NAT manipulation, nat help for more info', natCmd, 0],
2702 'nic' : ['network adapter management', nicCmd, 0],
2703 }
2704
2705def runCommandArgs(ctx, args):
2706 c = args[0]
2707 if aliases.get(c, None) != None:
2708 c = aliases[c]
2709 ci = commands.get(c,None)
2710 if ci == None:
2711 print "Unknown command: '%s', type 'help' for list of known commands" %(c)
2712 return 0
2713 if ctx['remote'] and ctx['vb'] is None:
2714 if c not in ['connect', 'reconnect', 'help', 'quit']:
2715 print "First connect to remote server with %s command." %(colored('connect', 'blue'))
2716 return 0
2717 return ci[1](ctx, args)
2718
2719
2720def runCommand(ctx, cmd):
2721 if len(cmd) == 0: return 0
2722 args = split_no_quotes(cmd)
2723 if len(args) == 0: return 0
2724 return runCommandArgs(ctx, args)
2725
2726#
2727# To write your own custom commands to vboxshell, create
2728# file ~/.VirtualBox/shellext.py with content like
2729#
2730# def runTestCmd(ctx, args):
2731# print "Testy test", ctx['vb']
2732# return 0
2733#
2734# commands = {
2735# 'test': ['Test help', runTestCmd]
2736# }
2737# and issue reloadExt shell command.
2738# This file also will be read automatically on startup or 'reloadExt'.
2739#
2740# Also one can put shell extensions into ~/.VirtualBox/shexts and
2741# they will also be picked up, so this way one can exchange
2742# shell extensions easily.
2743def addExtsFromFile(ctx, cmds, file):
2744 if not os.path.isfile(file):
2745 return
2746 d = {}
2747 try:
2748 execfile(file, d, d)
2749 for (k,v) in d['commands'].items():
2750 if g_verbose:
2751 print "customize: adding \"%s\" - %s" %(k, v[0])
2752 cmds[k] = [v[0], v[1], file]
2753 except:
2754 print "Error loading user extensions from %s" %(file)
2755 traceback.print_exc()
2756
2757
2758def checkUserExtensions(ctx, cmds, folder):
2759 folder = str(folder)
2760 name = os.path.join(folder, "shellext.py")
2761 addExtsFromFile(ctx, cmds, name)
2762 # also check 'exts' directory for all files
2763 shextdir = os.path.join(folder, "shexts")
2764 if not os.path.isdir(shextdir):
2765 return
2766 exts = os.listdir(shextdir)
2767 for e in exts:
2768 # not editor temporary files, please.
2769 if e.endswith('.py'):
2770 addExtsFromFile(ctx, cmds, os.path.join(shextdir,e))
2771
2772def getHomeFolder(ctx):
2773 if ctx['remote'] or ctx['vb'] is None:
2774 if 'VBOX_USER_HOME' is os.environ:
2775 return os.path.join(os.environ['VBOX_USER_HOME'])
2776 return os.path.join(os.path.expanduser("~"), ".VirtualBox")
2777 else:
2778 return ctx['vb'].homeFolder
2779
2780def interpret(ctx):
2781 if ctx['remote']:
2782 commands['connect'] = ["Connect to remote VBox instance: connect http://server:18083 user password", connectCmd, 0]
2783 commands['disconnect'] = ["Disconnect from remote VBox instance", disconnectCmd, 0]
2784 commands['reconnect'] = ["Reconnect to remote VBox instance", reconnectCmd, 0]
2785 ctx['wsinfo'] = ["http://localhost:18083", "", ""]
2786
2787 vbox = ctx['vb']
2788
2789 if vbox is not None:
2790 print "Running VirtualBox version %s" %(vbox.version)
2791 ctx['perf'] = None # ctx['global'].getPerfCollector(vbox)
2792 else:
2793 ctx['perf'] = None
2794
2795 home = getHomeFolder(ctx)
2796 checkUserExtensions(ctx, commands, home)
2797 if platform.system() == 'Windows':
2798 global g_hascolors
2799 g_hascolors = False
2800 hist_file=os.path.join(home, ".vboxshellhistory")
2801 autoCompletion(commands, ctx)
2802
2803 if g_hasreadline and os.path.exists(hist_file):
2804 readline.read_history_file(hist_file)
2805
2806 # to allow to print actual host information, we collect info for
2807 # last 150 secs maximum, (sample every 10 secs and keep up to 15 samples)
2808 if ctx['perf']:
2809 try:
2810 ctx['perf'].setup(['*'], [vbox.host], 10, 15)
2811 except:
2812 pass
2813
2814 while True:
2815 try:
2816 cmd = raw_input("vbox> ")
2817 done = runCommand(ctx, cmd)
2818 if done != 0: break
2819 except KeyboardInterrupt:
2820 print '====== You can type quit or q to leave'
2821 except EOFError:
2822 break
2823 except Exception,e:
2824 printErr(ctx,e)
2825 if g_verbose:
2826 traceback.print_exc()
2827 ctx['global'].waitForEvents(0)
2828 try:
2829 # There is no need to disable metric collection. This is just an example.
2830 if ct['perf']:
2831 ctx['perf'].disable(['*'], [vbox.host])
2832 except:
2833 pass
2834 if g_hasreadline:
2835 readline.write_history_file(hist_file)
2836
2837def runCommandCb(ctx, cmd, args):
2838 args.insert(0, cmd)
2839 return runCommandArgs(ctx, args)
2840
2841def runGuestCommandCb(ctx, id, guestLambda, args):
2842 mach = machById(ctx,id)
2843 if mach == None:
2844 return 0
2845 args.insert(0, guestLambda)
2846 cmdExistingVm(ctx, mach, 'guestlambda', args)
2847 return 0
2848
2849def main(argv):
2850 style = None
2851 autopath = False
2852 argv.pop(0)
2853 while len(argv) > 0:
2854 if argv[0] == "-w":
2855 style = "WEBSERVICE"
2856 if argv[0] == "-a":
2857 autopath = True
2858 argv.pop(0)
2859
2860 if autopath:
2861 cwd = os.getcwd()
2862 vpp = os.environ.get("VBOX_PROGRAM_PATH")
2863 if vpp is None and (os.path.isfile(os.path.join(cwd, "VirtualBox")) or os.path.isfile(os.path.join(cwd, "VirtualBox.exe"))) :
2864 vpp = cwd
2865 print "Autodetected VBOX_PROGRAM_PATH as",vpp
2866 os.environ["VBOX_PROGRAM_PATH"] = cwd
2867 sys.path.append(os.path.join(vpp, "sdk", "installer"))
2868
2869 from vboxapi import VirtualBoxManager
2870 g_virtualBoxManager = VirtualBoxManager(style, None)
2871 ctx = {'global':g_virtualBoxManager,
2872 'mgr':g_virtualBoxManager.mgr,
2873 'vb':g_virtualBoxManager.vbox,
2874 'ifaces':g_virtualBoxManager.constants,
2875 'remote':g_virtualBoxManager.remote,
2876 'type':g_virtualBoxManager.type,
2877 'run': lambda cmd,args: runCommandCb(ctx, cmd, args),
2878 'guestlambda': lambda id,guestLambda,args: runGuestCommandCb(ctx, id, guestLambda, args),
2879 'machById': lambda id: machById(ctx,id),
2880 'argsToMach': lambda args: argsToMach(ctx,args),
2881 'progressBar': lambda p: progressBar(ctx,p),
2882 'typeInGuest': typeInGuest,
2883 '_machlist':None
2884 }
2885 interpret(ctx)
2886 g_virtualBoxManager.deinit()
2887 del g_virtualBoxManager
2888
2889if __name__ == '__main__':
2890 main(sys.argv)
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