VirtualBox

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

Last change on this file since 37200 was 37200, checked in by vboxsync, 14 years ago

API+Frontends: Generic network attachment driver support which obsoletes the special case for VDE. Big API cleanup in the same area. Adapt all frontends to these changes (full implementation in VBoxManage, minimum implementation in GUI).

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