PageRenderTime 101ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/src/VBox/Frontends/VBoxShell/vboxshell.py

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