VirtualBox

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

Last change on this file since 44649 was 44649, checked in by vboxsync, 12 years ago

Documentation: added new paragraphs into chapter "Incompatible API changes with version 4.3". Fixed python script vboxshell.py. Fixed python example inside SDK documentation. PR5434.

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