VirtualBox

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

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

VBoxShell: foreach with simple XPath-like nodes addressing

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