VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/testdriver/vboxwrappers.py@ 90957

Last change on this file since 90957 was 90244, checked in by vboxsync, 3 years ago

ValidationKit: Add support for testing IOMMU. Ubuntu 20.04 smoketest is prepared to test both Intel and AMD IOMMUs.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 140.4 KB
Line 
1# -*- coding: utf-8 -*-
2# $Id: vboxwrappers.py 90244 2021-07-19 17:18:35Z vboxsync $
3# pylint: disable=too-many-lines
4
5"""
6VirtualBox Wrapper Classes
7"""
8
9__copyright__ = \
10"""
11Copyright (C) 2010-2020 Oracle Corporation
12
13This file is part of VirtualBox Open Source Edition (OSE), as
14available from http://www.virtualbox.org. This file is free software;
15you can redistribute it and/or modify it under the terms of the GNU
16General Public License (GPL) as published by the Free Software
17Foundation, in version 2 as it comes in the "COPYING" file of the
18VirtualBox OSE distribution. VirtualBox OSE is distributed in the
19hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
20
21The contents of this file may alternatively be used under the terms
22of the Common Development and Distribution License Version 1.0
23(CDDL) only, as it comes in the "COPYING.CDDL" file of the
24VirtualBox OSE distribution, in which case the provisions of the
25CDDL are applicable instead of those of the GPL.
26
27You may elect to license modified versions of this file under the
28terms and conditions of either the GPL or the CDDL or both.
29"""
30__version__ = "$Revision: 90244 $"
31
32
33# Standard Python imports.
34import os;
35import socket;
36import sys;
37
38# Validation Kit imports.
39from common import utils;
40from common import netutils;
41from testdriver import base;
42from testdriver import reporter;
43from testdriver import txsclient;
44from testdriver import vboxcon;
45from testdriver import vbox;
46from testdriver.base import TdTaskBase;
47
48
49def _ControllerNameToBusAndType(sController):
50 """ Translate a controller name to a storage bus. """
51 if sController == "IDE Controller":
52 eBus = vboxcon.StorageBus_IDE;
53 eType = vboxcon.StorageControllerType_PIIX4;
54 elif sController == "SATA Controller":
55 eBus = vboxcon.StorageBus_SATA;
56 eType = vboxcon.StorageControllerType_IntelAhci;
57 elif sController == "Floppy Controller":
58 eType = vboxcon.StorageControllerType_I82078;
59 eBus = vboxcon.StorageBus_Floppy;
60 elif sController == "SAS Controller":
61 eBus = vboxcon.StorageBus_SAS;
62 eType = vboxcon.StorageControllerType_LsiLogicSas;
63 elif sController == "SCSI Controller":
64 eBus = vboxcon.StorageBus_SCSI;
65 eType = vboxcon.StorageControllerType_LsiLogic;
66 elif sController == "BusLogic SCSI Controller":
67 eBus = vboxcon.StorageBus_SCSI;
68 eType = vboxcon.StorageControllerType_BusLogic;
69 elif sController == "NVMe Controller":
70 eBus = vboxcon.StorageBus_PCIe;
71 eType = vboxcon.StorageControllerType_NVMe;
72 elif sController == "VirtIO SCSI Controller":
73 eBus = vboxcon.StorageBus_VirtioSCSI;
74 eType = vboxcon.StorageControllerType_VirtioSCSI;
75 else:
76 eBus = vboxcon.StorageBus_Null;
77 eType = vboxcon.StorageControllerType_Null;
78 return (eBus, eType);
79
80
81def _nameMachineState(eState):
82 """ Gets the name (string) of a machine state."""
83 if eState == vboxcon.MachineState_PoweredOff: return 'PoweredOff';
84 if eState == vboxcon.MachineState_Saved: return 'Saved';
85 if eState == vboxcon.MachineState_Teleported: return 'Teleported';
86 if eState == vboxcon.MachineState_Aborted: return 'Aborted';
87 if eState == vboxcon.MachineState_Running: return 'Running';
88 if eState == vboxcon.MachineState_Paused: return 'Paused';
89 if eState == vboxcon.MachineState_Stuck: return 'GuruMeditation';
90 if eState == vboxcon.MachineState_Teleporting: return 'Teleporting';
91 if eState == vboxcon.MachineState_LiveSnapshotting: return 'LiveSnapshotting';
92 if eState == vboxcon.MachineState_Starting: return 'Starting';
93 if eState == vboxcon.MachineState_Stopping: return 'Stopping';
94 if eState == vboxcon.MachineState_Saving: return 'Saving';
95 if eState == vboxcon.MachineState_Restoring: return 'Restoring';
96 if eState == vboxcon.MachineState_TeleportingPausedVM: return 'TeleportingPausedVM';
97 if eState == vboxcon.MachineState_TeleportingIn: return 'TeleportingIn';
98 if eState == vboxcon.MachineState_DeletingSnapshotOnline: return 'DeletingSnapshotOnline';
99 if eState == vboxcon.MachineState_DeletingSnapshotPaused: return 'DeletingSnapshotPaused';
100 if eState == vboxcon.MachineState_RestoringSnapshot: return 'RestoringSnapshot';
101 if eState == vboxcon.MachineState_DeletingSnapshot: return 'DeletingSnapshot';
102 if eState == vboxcon.MachineState_SettingUp: return 'SettingUp';
103 if hasattr(vboxcon, 'MachineState_FaultTolerantSyncing'):
104 if eState == vboxcon.MachineState_FaultTolerantSyncing: return 'FaultTolerantSyncing';
105 return 'Unknown-%s' % (eState,);
106
107
108class VirtualBoxWrapper(object): # pylint: disable=too-few-public-methods
109 """
110 Wrapper around the IVirtualBox object that adds some (hopefully) useful
111 utility methods
112
113 The real object can be accessed thru the o member. That said, members can
114 be accessed directly as well.
115 """
116
117 def __init__(self, oVBox, oVBoxMgr, fpApiVer, oTstDrv):
118 self.o = oVBox;
119 self.oVBoxMgr = oVBoxMgr;
120 self.fpApiVer = fpApiVer;
121 self.oTstDrv = oTstDrv;
122
123 def __getattr__(self, sName):
124 # Try ourselves first.
125 try:
126 oAttr = self.__dict__[sName];
127 except:
128 #try:
129 # oAttr = dir(self)[sName];
130 #except AttributeError:
131 oAttr = getattr(self.o, sName);
132 return oAttr;
133
134 #
135 # Utilities.
136 #
137
138 def registerDerivedEventHandler(self, oSubClass, dArgs = None):
139 """
140 Create an instance of the given VirtualBoxEventHandlerBase sub-class
141 and register it.
142
143 The new instance is returned on success. None is returned on error.
144 """
145 dArgsCopy = dArgs.copy() if dArgs is not None else dict();
146 dArgsCopy['oVBox'] = self;
147 return oSubClass.registerDerivedEventHandler(self.oVBoxMgr, self.fpApiVer, oSubClass, dArgsCopy,
148 self.o, 'IVirtualBox', 'IVirtualBoxCallback');
149
150 def deleteHdByLocation(self, sHdLocation):
151 """
152 Deletes a disk image from the host, given it's location.
153 Returns True on success and False on failure. Error information is logged.
154 """
155 try:
156 oIMedium = self.o.findHardDisk(sHdLocation);
157 except:
158 try:
159 if self.fpApiVer >= 4.1:
160 oIMedium = self.o.openMedium(sHdLocation, vboxcon.DeviceType_HardDisk,
161 vboxcon.AccessMode_ReadWrite, False);
162 elif self.fpApiVer >= 4.0:
163 oIMedium = self.o.openMedium(sHdLocation, vboxcon.DeviceType_HardDisk,
164 vboxcon.AccessMode_ReadWrite);
165 else:
166 oIMedium = self.o.openHardDisk(sHdLocation, vboxcon.AccessMode_ReadOnly, False, "", False, "");
167 except:
168 return reporter.errorXcpt('failed to open hd "%s"' % (sHdLocation));
169 return self.deleteHdByMedium(oIMedium)
170
171 def deleteHdByMedium(self, oIMedium):
172 """
173 Deletes a disk image from the host, given an IMedium reference.
174 Returns True on success and False on failure. Error information is logged.
175 """
176 try: oProgressCom = oIMedium.deleteStorage();
177 except: return reporter.errorXcpt('deleteStorage() for disk %s failed' % (oIMedium,));
178 try: oProgress = ProgressWrapper(oProgressCom, self.oVBoxMgr, self.oTstDrv, 'delete disk %s' % (oIMedium.location));
179 except: return reporter.errorXcpt();
180 oProgress.wait();
181 oProgress.logResult();
182 return oProgress.isSuccess();
183
184
185
186class ProgressWrapper(TdTaskBase):
187 """
188 Wrapper around a progress object for making it a task and providing useful
189 utility methods.
190 The real progress object can be accessed thru the o member.
191 """
192
193 def __init__(self, oProgress, oVBoxMgr, oTstDrv, sName):
194 TdTaskBase.__init__(self, utils.getCallerName());
195 self.o = oProgress;
196 self.oVBoxMgr = oVBoxMgr;
197 self.oTstDrv = oTstDrv;
198 self.sName = sName;
199
200 def toString(self):
201 return '<%s sName=%s, oProgress=%s >' \
202 % (TdTaskBase.toString(self), self.sName, self.o);
203
204 #
205 # TdTaskBase overrides.
206 #
207
208 def pollTask(self, fLocked = False):
209 """
210 Overrides TdTaskBase.pollTask().
211
212 This method returns False until the progress object has completed.
213 """
214 self.doQuickApiTest();
215 try:
216 try:
217 if self.o.completed:
218 return True;
219 except:
220 pass;
221 finally:
222 self.oTstDrv.processPendingEvents();
223 return False;
224
225 def waitForTask(self, cMsTimeout = 0):
226 """
227 Overrides TdTaskBase.waitForTask().
228 Process XPCOM/COM events while waiting.
229 """
230 msStart = base.timestampMilli();
231 fState = self.pollTask(False);
232 while not fState:
233 cMsElapsed = base.timestampMilli() - msStart;
234 if cMsElapsed > cMsTimeout:
235 break;
236 cMsToWait = cMsTimeout - cMsElapsed;
237 if cMsToWait > 500:
238 cMsToWait = 500;
239 try:
240 self.o.waitForCompletion(cMsToWait);
241 except KeyboardInterrupt: raise;
242 except: pass;
243 if self.fnProcessEvents:
244 self.fnProcessEvents();
245 reporter.doPollWork('ProgressWrapper.waitForTask');
246 fState = self.pollTask(False);
247 return fState;
248
249 #
250 # Utility methods.
251 #
252
253 def isSuccess(self):
254 """
255 Tests if the progress object completed successfully.
256 Returns True on success, False on failure or incomplete.
257 """
258 if not self.isCompleted():
259 return False;
260 return self.getResult() >= 0;
261
262 def isCompleted(self):
263 """
264 Wrapper around IProgress.completed.
265 """
266 return self.pollTask();
267
268 def isCancelable(self):
269 """
270 Wrapper around IProgress.cancelable.
271 """
272 try:
273 fRc = self.o.cancelable;
274 except:
275 reporter.logXcpt();
276 fRc = False;
277 return fRc;
278
279 def wasCanceled(self):
280 """
281 Wrapper around IProgress.canceled.
282 """
283 try:
284 fRc = self.o.canceled;
285 except:
286 reporter.logXcpt(self.sName);
287 fRc = False;
288 return fRc;
289
290 def cancel(self):
291 """
292 Wrapper around IProgress.cancel()
293 Returns True on success, False on failure (logged as error).
294 """
295 try:
296 self.o.cancel();
297 except:
298 reporter.errorXcpt(self.sName);
299 return False;
300 return True;
301
302 def getResult(self):
303 """
304 Wrapper around IProgress.resultCode.
305 """
306 try:
307 iRc = self.o.resultCode;
308 except:
309 reporter.logXcpt(self.sName);
310 iRc = -1;
311 return iRc;
312
313 def getErrInfoResultCode(self):
314 """
315 Wrapper around IProgress.errorInfo.resultCode.
316
317 Returns the string on success, -1 on bad objects (logged as error), and
318 -2 on missing errorInfo object.
319 """
320 iRc = -1;
321 try:
322 oErrInfo = self.o.errorInfo;
323 except:
324 reporter.errorXcpt(self.sName);
325 else:
326 if oErrInfo is None:
327 iRc = -2;
328 else:
329 try:
330 iRc = oErrInfo.resultCode;
331 except:
332 reporter.errorXcpt();
333 return iRc;
334
335 def getErrInfoText(self):
336 """
337 Wrapper around IProgress.errorInfo.text.
338
339 Returns the string on success, None on failure. Missing errorInfo is
340 not logged as an error, all other failures are.
341 """
342 sText = None;
343 try:
344 oErrInfo = self.o.errorInfo;
345 except:
346 reporter.log2Xcpt(self.sName);
347 else:
348 if oErrInfo is not None:
349 try:
350 sText = oErrInfo.text;
351 except:
352 reporter.errorXcpt();
353 return sText;
354
355 def stringifyErrorInfo(self):
356 """
357 Formats IProgress.errorInfo into a string.
358 """
359 try:
360 oErrInfo = self.o.errorInfo;
361 except:
362 reporter.logXcpt(self.sName);
363 sErr = 'no error info';
364 else:
365 sErr = vbox.stringifyErrorInfo(oErrInfo);
366 return sErr;
367
368 def stringifyResult(self):
369 """
370 Stringify the result.
371 """
372 if self.isCompleted():
373 if self.wasCanceled():
374 sRet = 'Progress %s: Canceled, hrc=%s' % (self.sName, vbox.ComError.toString(self.getResult()));
375 elif self.getResult() == 0:
376 sRet = 'Progress %s: Success' % (self.sName,);
377 elif self.getResult() > 0:
378 sRet = 'Progress %s: Success (hrc=%s)' % (self.sName, vbox.ComError.toString(self.getResult()));
379 else:
380 sRet = 'Progress %s: Failed! %s' % (self.sName, self.stringifyErrorInfo());
381 else:
382 sRet = 'Progress %s: Not completed yet...' % (self.sName);
383 return sRet;
384
385 def logResult(self, fIgnoreErrors = False):
386 """
387 Logs the result, failure logged as error unless fIgnoreErrors is True.
388 Return True on success, False on failure (and fIgnoreErrors is false).
389 """
390 sText = self.stringifyResult();
391 if self.isCompleted() and self.getResult() < 0 and fIgnoreErrors is False:
392 return reporter.error(sText);
393 reporter.log(sText);
394 return True;
395
396 def waitOnProgress(self, cMsInterval = 1000):
397 """
398 See vbox.TestDriver.waitOnProgress.
399 """
400 self.doQuickApiTest();
401 return self.oTstDrv.waitOnProgress(self.o, cMsInterval);
402
403 def wait(self, cMsTimeout = 60000, fErrorOnTimeout = True, cMsInterval = 1000):
404 """
405 Wait on the progress object for a while.
406
407 Returns the resultCode of the progress object if completed.
408 Returns -1 on timeout, logged as error if fErrorOnTimeout is set.
409 Returns -2 is the progress object is invalid or waitForCompletion
410 fails (logged as errors).
411 """
412 msStart = base.timestampMilli();
413 while True:
414 self.oTstDrv.processPendingEvents();
415 self.doQuickApiTest();
416 try:
417 if self.o.completed:
418 break;
419 except:
420 reporter.errorXcpt(self.sName);
421 return -2;
422 self.oTstDrv.processPendingEvents();
423
424 cMsElapsed = base.timestampMilli() - msStart;
425 if cMsElapsed > cMsTimeout:
426 if fErrorOnTimeout:
427 reporter.error('Timing out after waiting for %u s on "%s"' % (cMsTimeout / 1000, self.sName))
428 return -1;
429
430 try:
431 self.o.waitForCompletion(cMsInterval);
432 except:
433 reporter.errorXcpt(self.sName);
434 return -2;
435 reporter.doPollWork('ProgressWrapper.wait');
436
437 try:
438 rc = self.o.resultCode;
439 except:
440 rc = -2;
441 reporter.errorXcpt(self.sName);
442 self.oTstDrv.processPendingEvents();
443 return rc;
444
445 def waitForOperation(self, iOperation, cMsTimeout = 60000, fErrorOnTimeout = True, cMsInterval = 1000, \
446 fIgnoreErrors = False):
447 """
448 Wait for the completion of a operation.
449
450 Negative iOperation values are relative to operationCount (this
451 property may changed at runtime).
452
453 Returns 0 if the operation completed normally.
454 Returns -1 on timeout, logged as error if fErrorOnTimeout is set.
455 Returns -2 is the progress object is invalid or waitForCompletion
456 fails (logged as errors).
457 Returns -3 if if the operation completed with an error, this is logged
458 as an error.
459 """
460 msStart = base.timestampMilli();
461 while True:
462 self.oTstDrv.processPendingEvents();
463 self.doQuickApiTest();
464 try:
465 iCurrentOperation = self.o.operation;
466 cOperations = self.o.operationCount;
467 if iOperation >= 0:
468 iRealOperation = iOperation;
469 else:
470 iRealOperation = cOperations + iOperation;
471
472 if iCurrentOperation > iRealOperation:
473 return 0;
474 if iCurrentOperation == iRealOperation \
475 and iRealOperation >= cOperations - 1 \
476 and self.o.completed:
477 if self.o.resultCode < 0:
478 self.logResult(fIgnoreErrors);
479 return -3;
480 return 0;
481 except:
482 if fIgnoreErrors:
483 reporter.logXcpt();
484 else:
485 reporter.errorXcpt();
486 return -2;
487 self.oTstDrv.processPendingEvents();
488
489 cMsElapsed = base.timestampMilli() - msStart;
490 if cMsElapsed > cMsTimeout:
491 if fErrorOnTimeout:
492 if fIgnoreErrors:
493 reporter.log('Timing out after waiting for %s s on "%s" operation %d' \
494 % (cMsTimeout / 1000, self.sName, iOperation))
495 else:
496 reporter.error('Timing out after waiting for %s s on "%s" operation %d' \
497 % (cMsTimeout / 1000, self.sName, iOperation))
498 return -1;
499
500 try:
501 self.o.waitForOperationCompletion(iRealOperation, cMsInterval);
502 except:
503 if fIgnoreErrors:
504 reporter.logXcpt(self.sName);
505 else:
506 reporter.errorXcpt(self.sName);
507 return -2;
508 reporter.doPollWork('ProgressWrapper.waitForOperation');
509 # Not reached.
510 return -3; # Make pylin happy (for now).
511
512 def doQuickApiTest(self):
513 """
514 Queries everything that is stable and easy to get at and checks that
515 they don't throw errors.
516 """
517 if True is True: # pylint: disable=comparison-with-itself
518 try:
519 iPct = self.o.operationPercent;
520 sDesc = self.o.description;
521 fCancelable = self.o.cancelable;
522 cSecsRemain = self.o.timeRemaining;
523 fCanceled = self.o.canceled;
524 fCompleted = self.o.completed;
525 iOp = self.o.operation;
526 cOps = self.o.operationCount;
527 iOpPct = self.o.operationPercent;
528 sOpDesc = self.o.operationDescription;
529 except:
530 reporter.errorXcpt('%s: %s' % (self.sName, self.o,));
531 return False;
532 try:
533 # Very noisy -- only enable for debugging purposes.
534 #reporter.log2('%s: op=%u/%u/%s: %u%%; total=%u%% cancel=%s/%s compl=%s rem=%us; desc=%s' \
535 # % (self.sName, iOp, cOps, sOpDesc, iOpPct, iPct, fCanceled, fCancelable, fCompleted, \
536 # cSecsRemain, sDesc));
537 _ = iPct; _ = sDesc; _ = fCancelable; _ = cSecsRemain; _ = fCanceled; _ = fCompleted; _ = iOp;
538 _ = cOps; _ = iOpPct; _ = sOpDesc;
539 except:
540 reporter.errorXcpt();
541 return False;
542
543 return True;
544
545
546class SessionWrapper(TdTaskBase):
547 """
548 Wrapper around a machine session. The real session object can be accessed
549 thru the o member (short is good, right :-).
550 """
551
552 def __init__(self, oSession, oVM, oVBox, oVBoxMgr, oTstDrv, fRemoteSession, sFallbackName = None, sLogFile = None):
553 """
554 Initializes the session wrapper.
555 """
556 TdTaskBase.__init__(self, utils.getCallerName());
557 self.o = oSession;
558 self.oVBox = oVBox;
559 self.oVBoxMgr = oVBoxMgr;
560 self.oVM = oVM; # Not the session machine. Useful backdoor...
561 self.oTstDrv = oTstDrv;
562 self.fpApiVer = oTstDrv.fpApiVer;
563 self.fRemoteSession = fRemoteSession;
564 self.sLogFile = sLogFile;
565 self.oConsoleEventHandler = None;
566 self.uPid = None;
567 self.fPidFile = True;
568 self.fHostMemoryLow = False; # see signalHostMemoryLow; read-only for outsiders.
569
570 try:
571 self.sName = oSession.machine.name;
572 except:
573 if sFallbackName is not None:
574 self.sName = sFallbackName;
575 else:
576 try: self.sName = str(oSession.machine);
577 except: self.sName = 'is-this-vm-already-off'
578
579 try:
580 self.sUuid = oSession.machine.id;
581 except:
582 self.sUuid = None;
583
584 # Try cache the SessionPID.
585 self.getPid();
586
587 def __del__(self):
588 """
589 Destructor that makes sure the callbacks are deregistered and
590 that the session is closed.
591 """
592 self.deregisterEventHandlerForTask();
593
594 if self.o is not None:
595 try:
596 self.close();
597 reporter.log('close session %s' % (self.o));
598 except:
599 pass;
600 self.o = None;
601
602 TdTaskBase.__del__(self);
603
604 def toString(self):
605 return '<%s: sUuid=%s, sName=%s, uPid=%s, sDbgCreated=%s, fRemoteSession=%s, oSession=%s,' \
606 ' oConsoleEventHandler=%s, oVM=%s >' \
607 % (type(self).__name__, self.sUuid, self.sName, self.uPid, self.sDbgCreated, self.fRemoteSession,
608 self.o, self.oConsoleEventHandler, self.oVM,);
609
610 def __str__(self):
611 return self.toString();
612
613 #
614 # TdTaskBase overrides.
615 #
616
617 def __pollTask(self):
618 """ Internal poller """
619 # Poll for events after doing the remote GetState call, otherwise we
620 # might end up sleepless because XPCOM queues a cleanup event.
621 try:
622 try:
623 eState = self.o.machine.state;
624 except Exception as oXcpt:
625 if vbox.ComError.notEqual(oXcpt, vbox.ComError.E_UNEXPECTED):
626 reporter.logXcpt();
627 return True;
628 finally:
629 self.oTstDrv.processPendingEvents();
630
631 # Switch
632 if eState == vboxcon.MachineState_Running:
633 return False;
634 if eState == vboxcon.MachineState_Paused:
635 return False;
636 if eState == vboxcon.MachineState_Teleporting:
637 return False;
638 if eState == vboxcon.MachineState_LiveSnapshotting:
639 return False;
640 if eState == vboxcon.MachineState_Starting:
641 return False;
642 if eState == vboxcon.MachineState_Stopping:
643 return False;
644 if eState == vboxcon.MachineState_Saving:
645 return False;
646 if eState == vboxcon.MachineState_Restoring:
647 return False;
648 if eState == vboxcon.MachineState_TeleportingPausedVM:
649 return False;
650 if eState == vboxcon.MachineState_TeleportingIn:
651 return False;
652
653 # *Beeep* fudge!
654 if self.fpApiVer < 3.2 \
655 and eState == vboxcon.MachineState_PoweredOff \
656 and self.getAgeAsMs() < 3000:
657 return False;
658
659 reporter.log('SessionWrapper::pollTask: eState=%s' % (eState));
660 return True;
661
662
663 def pollTask(self, fLocked = False):
664 """
665 Overrides TdTaskBase.pollTask().
666
667 This method returns False while the VM is online and running normally.
668 """
669
670 # Call super to check if the task was signalled by runtime error or similar,
671 # if not then check the VM state via __pollTask.
672 fRc = super(SessionWrapper, self).pollTask(fLocked);
673 if not fRc:
674 fRc = self.__pollTask();
675
676 # HACK ALERT: Lazily try registering the console event handler if
677 # we're not ready.
678 if not fRc and self.oConsoleEventHandler is None:
679 self.registerEventHandlerForTask();
680
681 # HACK ALERT: Lazily try get the PID and add it to the PID file.
682 if not fRc and self.uPid is None:
683 self.getPid();
684
685 return fRc;
686
687 def waitForTask(self, cMsTimeout = 0):
688 """
689 Overrides TdTaskBase.waitForTask().
690 Process XPCOM/COM events while waiting.
691 """
692 msStart = base.timestampMilli();
693 fState = self.pollTask(False);
694 while not fState:
695 cMsElapsed = base.timestampMilli() - msStart;
696 if cMsElapsed > cMsTimeout:
697 break;
698 cMsSleep = cMsTimeout - cMsElapsed;
699 if cMsSleep > 10000:
700 cMsSleep = 10000;
701 try: self.oVBoxMgr.waitForEvents(cMsSleep);
702 except KeyboardInterrupt: raise;
703 except: pass;
704 if self.fnProcessEvents:
705 self.fnProcessEvents();
706 reporter.doPollWork('SessionWrapper.waitForTask');
707 fState = self.pollTask(False);
708 return fState;
709
710 def setTaskOwner(self, oOwner):
711 """
712 HACK ALERT!
713 Overrides TdTaskBase.setTaskOwner() so we can try call
714 registerEventHandlerForTask() again when when the testdriver calls
715 addTask() after VM has been spawned. Related to pollTask() above.
716
717 The testdriver must not add the task too early for this to work!
718 """
719 if oOwner is not None:
720 self.registerEventHandlerForTask()
721 return TdTaskBase.setTaskOwner(self, oOwner);
722
723
724 #
725 # Task helpers.
726 #
727
728 def registerEventHandlerForTask(self):
729 """
730 Registers the console event handlers for working the task state.
731 """
732 if self.oConsoleEventHandler is not None:
733 return True;
734 self.oConsoleEventHandler = self.registerDerivedEventHandler(vbox.SessionConsoleEventHandler, {}, False);
735 return self.oConsoleEventHandler is not None;
736
737 def deregisterEventHandlerForTask(self):
738 """
739 Deregisters the console event handlers.
740 """
741 if self.oConsoleEventHandler is not None:
742 self.oConsoleEventHandler.unregister();
743 self.oConsoleEventHandler = None;
744
745 def signalHostMemoryLow(self):
746 """
747 Used by a runtime error event handler to indicate that we're low on memory.
748 Signals the task.
749 """
750 self.fHostMemoryLow = True;
751 self.signalTask();
752 return True;
753
754 def needsPoweringOff(self):
755 """
756 Examins the machine state to see if the VM needs powering off.
757 """
758 try:
759 try:
760 eState = self.o.machine.state;
761 except Exception as oXcpt:
762 if vbox.ComError.notEqual(oXcpt, vbox.ComError.E_UNEXPECTED):
763 reporter.logXcpt();
764 return False;
765 finally:
766 self.oTstDrv.processPendingEvents();
767
768 # Switch
769 if eState == vboxcon.MachineState_Running:
770 return True;
771 if eState == vboxcon.MachineState_Paused:
772 return True;
773 if eState == vboxcon.MachineState_Stuck:
774 return True;
775 if eState == vboxcon.MachineState_Teleporting:
776 return True;
777 if eState == vboxcon.MachineState_LiveSnapshotting:
778 return True;
779 if eState == vboxcon.MachineState_Starting:
780 return True;
781 if eState == vboxcon.MachineState_Saving:
782 return True;
783 if eState == vboxcon.MachineState_Restoring:
784 return True;
785 if eState == vboxcon.MachineState_TeleportingPausedVM:
786 return True;
787 if eState == vboxcon.MachineState_TeleportingIn:
788 return True;
789 if hasattr(vboxcon, 'MachineState_FaultTolerantSyncing'):
790 if eState == vboxcon.MachineState_FaultTolerantSyncing:
791 return True;
792 return False;
793
794 def assertPoweredOff(self):
795 """
796 Asserts that the VM is powered off, reporting an error if not.
797 Returns True if powered off, False + error msg if not.
798 """
799 try:
800 try:
801 eState = self.oVM.state;
802 except Exception:
803 reporter.errorXcpt();
804 return True;
805 finally:
806 self.oTstDrv.processPendingEvents();
807
808 if eState == vboxcon.MachineState_PoweredOff:
809 return True;
810 reporter.error('Expected machine state "PoweredOff", machine is in the "%s" state instead.'
811 % (_nameMachineState(eState),));
812 return False;
813
814 def getMachineStateWithName(self):
815 """
816 Gets the current machine state both as a constant number/whatever and
817 as a human readable string. On error, the constants will be set to
818 None and the string will be the error message.
819 """
820 try:
821 eState = self.oVM.state;
822 except:
823 return (None, '[error getting state: %s]' % (self.oVBoxMgr.xcptToString(),));
824 finally:
825 self.oTstDrv.processPendingEvents();
826 return (eState, _nameMachineState(eState));
827
828 def reportPrematureTermination(self, sPrefix = ''):
829 """
830 Reports a premature virtual machine termination.
831 Returns False to facilitate simpler error paths.
832 """
833
834 reporter.error(sPrefix + 'The virtual machine terminated prematurely!!');
835 (enmState, sStateNm) = self.getMachineStateWithName();
836 reporter.error(sPrefix + 'Machine state: %s' % (sStateNm,));
837
838 if enmState is not None \
839 and enmState == vboxcon.MachineState_Aborted \
840 and self.uPid is not None:
841 #
842 # Look for process crash info.
843 #
844 def addCrashFile(sLogFile, fBinary):
845 """ processCollectCrashInfo callback. """
846 reporter.addLogFile(sLogFile, 'crash/dump/vm' if fBinary else 'crash/report/vm');
847 utils.processCollectCrashInfo(self.uPid, reporter.log, addCrashFile);
848
849 return False;
850
851
852
853 #
854 # ISession / IMachine / ISomethingOrAnother wrappers.
855 #
856
857 def close(self):
858 """
859 Closes the session if it's open and removes it from the
860 vbox.TestDriver.aoRemoteSessions list.
861 Returns success indicator.
862 """
863 fRc = True;
864 if self.o is not None:
865 # Get the pid in case we need to kill the process later on.
866 self.getPid();
867
868 # Try close it.
869 try:
870 if self.fpApiVer < 3.3:
871 self.o.close();
872 else:
873 self.o.unlockMachine();
874 self.o = None;
875 except KeyboardInterrupt:
876 raise;
877 except:
878 # Kludge to ignore VBoxSVC's closing of our session when the
879 # direct session closes / VM process terminates. Fun!
880 try: fIgnore = self.o.state == vboxcon.SessionState_Unlocked;
881 except: fIgnore = False;
882 if fIgnore:
883 self.o = None; # Must prevent a retry during GC.
884 else:
885 reporter.errorXcpt('ISession::unlockMachine failed on %s' % (self.o));
886 fRc = False;
887
888 # Remove it from the remote session list if applicable (not 100% clean).
889 if fRc and self.fRemoteSession:
890 try:
891 if self in self.oTstDrv.aoRemoteSessions:
892 reporter.log2('SessionWrapper::close: Removing myself from oTstDrv.aoRemoteSessions');
893 self.oTstDrv.aoRemoteSessions.remove(self)
894 except:
895 reporter.logXcpt();
896
897 if self.uPid is not None and self.fPidFile:
898 self.oTstDrv.pidFileRemove(self.uPid);
899 self.fPidFile = False;
900
901 # It's only logical to deregister the event handler after the session
902 # is closed. It also avoids circular references between the session
903 # and the listener, which causes trouble with garbage collection.
904 self.deregisterEventHandlerForTask();
905
906 self.oTstDrv.processPendingEvents();
907 return fRc;
908
909 def saveSettings(self, fClose = False):
910 """
911 Saves the settings and optionally closes the session.
912 Returns success indicator.
913 """
914 try:
915 try:
916 self.o.machine.saveSettings();
917 except:
918 reporter.errorXcpt('saveSettings failed on %s' % (self.o));
919 return False;
920 finally:
921 self.oTstDrv.processPendingEvents();
922 if fClose:
923 return self.close();
924 return True;
925
926 def discardSettings(self, fClose = False):
927 """
928 Discards the settings and optionally closes the session.
929 """
930 try:
931 try:
932 self.o.machine.discardSettings();
933 except:
934 reporter.errorXcpt('discardSettings failed on %s' % (self.o));
935 return False;
936 finally:
937 self.oTstDrv.processPendingEvents();
938 if fClose:
939 return self.close();
940 return True;
941
942 def enableVirtEx(self, fEnable):
943 """
944 Enables or disables AMD-V/VT-x.
945 Returns True on success and False on failure. Error information is logged.
946 """
947 # Enable/disable it.
948 fRc = True;
949 try:
950 self.o.machine.setHWVirtExProperty(vboxcon.HWVirtExPropertyType_Enabled, fEnable);
951 except:
952 reporter.errorXcpt('failed to set HWVirtExPropertyType_Enabled=%s for "%s"' % (fEnable, self.sName));
953 fRc = False;
954 else:
955 reporter.log('set HWVirtExPropertyType_Enabled=%s for "%s"' % (fEnable, self.sName));
956
957 # Force/unforce it.
958 if fRc and hasattr(vboxcon, 'HWVirtExPropertyType_Force'):
959 try:
960 self.o.machine.setHWVirtExProperty(vboxcon.HWVirtExPropertyType_Force, fEnable);
961 except:
962 reporter.errorXcpt('failed to set HWVirtExPropertyType_Force=%s for "%s"' % (fEnable, self.sName));
963 fRc = False;
964 else:
965 reporter.log('set HWVirtExPropertyType_Force=%s for "%s"' % (fEnable, self.sName));
966 else:
967 reporter.log('Warning! vboxcon has no HWVirtExPropertyType_Force attribute.');
968 ## @todo Modify CFGM to do the same for old VBox versions?
969
970 self.oTstDrv.processPendingEvents();
971 return fRc;
972
973 def enableNestedPaging(self, fEnable):
974 """
975 Enables or disables nested paging..
976 Returns True on success and False on failure. Error information is logged.
977 """
978 ## @todo Add/remove force CFGM thing, we don't want fallback logic when testing.
979 fRc = True;
980 try:
981 self.o.machine.setHWVirtExProperty(vboxcon.HWVirtExPropertyType_NestedPaging, fEnable);
982 except:
983 reporter.errorXcpt('failed to set HWVirtExPropertyType_NestedPaging=%s for "%s"' % (fEnable, self.sName));
984 fRc = False;
985 else:
986 reporter.log('set HWVirtExPropertyType_NestedPaging=%s for "%s"' % (fEnable, self.sName));
987 self.oTstDrv.processPendingEvents();
988 return fRc;
989
990 def enableLongMode(self, fEnable):
991 """
992 Enables or disables LongMode.
993 Returns True on success and False on failure. Error information is logged.
994 """
995 # Supported.
996 if self.fpApiVer < 4.2 or not hasattr(vboxcon, 'HWVirtExPropertyType_LongMode'):
997 return True;
998
999 # Enable/disable it.
1000 fRc = True;
1001 try:
1002 self.o.machine.setCPUProperty(vboxcon.CPUPropertyType_LongMode, fEnable);
1003 except:
1004 reporter.errorXcpt('failed to set CPUPropertyType_LongMode=%s for "%s"' % (fEnable, self.sName));
1005 fRc = False;
1006 else:
1007 reporter.log('set CPUPropertyType_LongMode=%s for "%s"' % (fEnable, self.sName));
1008 self.oTstDrv.processPendingEvents();
1009 return fRc;
1010
1011 def enableNestedHwVirt(self, fEnable):
1012 """
1013 Enables or disables Nested Hardware-Virtualization.
1014 Returns True on success and False on failure. Error information is logged.
1015 """
1016 # Supported.
1017 if self.fpApiVer < 5.3 or not hasattr(vboxcon, 'CPUPropertyType_HWVirt'):
1018 return True;
1019
1020 # Enable/disable it.
1021 fRc = True;
1022 try:
1023 self.o.machine.setCPUProperty(vboxcon.CPUPropertyType_HWVirt, fEnable);
1024 except:
1025 reporter.errorXcpt('failed to set CPUPropertyType_HWVirt=%s for "%s"' % (fEnable, self.sName));
1026 fRc = False;
1027 else:
1028 reporter.log('set CPUPropertyType_HWVirt=%s for "%s"' % (fEnable, self.sName));
1029 self.oTstDrv.processPendingEvents();
1030 return fRc;
1031
1032 def enablePae(self, fEnable):
1033 """
1034 Enables or disables PAE
1035 Returns True on success and False on failure. Error information is logged.
1036 """
1037 fRc = True;
1038 try:
1039 if self.fpApiVer >= 3.2: # great, ain't it?
1040 self.o.machine.setCPUProperty(vboxcon.CPUPropertyType_PAE, fEnable);
1041 else:
1042 self.o.machine.setCpuProperty(vboxcon.CpuPropertyType_PAE, fEnable);
1043 except:
1044 reporter.errorXcpt('failed to set CPUPropertyType_PAE=%s for "%s"' % (fEnable, self.sName));
1045 fRc = False;
1046 else:
1047 reporter.log('set CPUPropertyType_PAE=%s for "%s"' % (fEnable, self.sName));
1048 self.oTstDrv.processPendingEvents();
1049 return fRc;
1050
1051 def enableIoApic(self, fEnable):
1052 """
1053 Enables or disables the IO-APIC
1054 Returns True on success and False on failure. Error information is logged.
1055 """
1056 fRc = True;
1057 try:
1058 self.o.machine.BIOSSettings.IOAPICEnabled = fEnable;
1059 except:
1060 reporter.errorXcpt('failed to set BIOSSettings.IOAPICEnabled=%s for "%s"' % (fEnable, self.sName));
1061 fRc = False;
1062 else:
1063 reporter.log('set BIOSSettings.IOAPICEnabled=%s for "%s"' % (fEnable, self.sName));
1064 self.oTstDrv.processPendingEvents();
1065 return fRc;
1066
1067 def enableHpet(self, fEnable):
1068 """
1069 Enables or disables the HPET
1070 Returns True on success and False on failure. Error information is logged.
1071 """
1072 fRc = True;
1073 try:
1074 if self.fpApiVer >= 4.2:
1075 self.o.machine.HPETEnabled = fEnable;
1076 else:
1077 self.o.machine.hpetEnabled = fEnable;
1078 except:
1079 reporter.errorXcpt('failed to set HpetEnabled=%s for "%s"' % (fEnable, self.sName));
1080 fRc = False;
1081 else:
1082 reporter.log('set HpetEnabled=%s for "%s"' % (fEnable, self.sName));
1083 self.oTstDrv.processPendingEvents();
1084 return fRc;
1085
1086 def enableUsbHid(self, fEnable):
1087 """
1088 Enables or disables the USB HID
1089 Returns True on success and False on failure. Error information is logged.
1090 """
1091 fRc = True;
1092 try:
1093 if fEnable:
1094 if self.fpApiVer >= 4.3:
1095 cOhciCtls = self.o.machine.getUSBControllerCountByType(vboxcon.USBControllerType_OHCI);
1096 if cOhciCtls == 0:
1097 self.o.machine.addUSBController('OHCI', vboxcon.USBControllerType_OHCI);
1098 else:
1099 self.o.machine.usbController.enabled = True;
1100
1101 if self.fpApiVer >= 4.2:
1102 self.o.machine.pointingHIDType = vboxcon.PointingHIDType_ComboMouse;
1103 self.o.machine.keyboardHIDType = vboxcon.KeyboardHIDType_ComboKeyboard;
1104 else:
1105 self.o.machine.pointingHidType = vboxcon.PointingHidType_ComboMouse;
1106 self.o.machine.keyboardHidType = vboxcon.KeyboardHidType_ComboKeyboard;
1107 else:
1108 if self.fpApiVer >= 4.2:
1109 self.o.machine.pointingHIDType = vboxcon.PointingHIDType_PS2Mouse;
1110 self.o.machine.keyboardHIDType = vboxcon.KeyboardHIDType_PS2Keyboard;
1111 else:
1112 self.o.machine.pointingHidType = vboxcon.PointingHidType_PS2Mouse;
1113 self.o.machine.keyboardHidType = vboxcon.KeyboardHidType_PS2Keyboard;
1114 except:
1115 reporter.errorXcpt('failed to change UsbHid to %s for "%s"' % (fEnable, self.sName));
1116 fRc = False;
1117 else:
1118 reporter.log('changed UsbHid to %s for "%s"' % (fEnable, self.sName));
1119 self.oTstDrv.processPendingEvents();
1120 return fRc;
1121
1122 def enableUsbOhci(self, fEnable):
1123 """
1124 Enables or disables the USB OHCI controller
1125 Returns True on success and False on failure. Error information is logged.
1126 """
1127 fRc = True;
1128 try:
1129 if fEnable:
1130 if self.fpApiVer >= 4.3:
1131 cOhciCtls = self.o.machine.getUSBControllerCountByType(vboxcon.USBControllerType_OHCI);
1132 if cOhciCtls == 0:
1133 self.o.machine.addUSBController('OHCI', vboxcon.USBControllerType_OHCI);
1134 else:
1135 self.o.machine.usbController.enabled = True;
1136 else:
1137 if self.fpApiVer >= 4.3:
1138 cOhciCtls = self.o.machine.getUSBControllerCountByType(vboxcon.USBControllerType_OHCI);
1139 if cOhciCtls == 1:
1140 self.o.machine.removeUSBController('OHCI');
1141 else:
1142 self.o.machine.usbController.enabled = False;
1143 except:
1144 reporter.errorXcpt('failed to change OHCI to %s for "%s"' % (fEnable, self.sName));
1145 fRc = False;
1146 else:
1147 reporter.log('changed OHCI to %s for "%s"' % (fEnable, self.sName));
1148 self.oTstDrv.processPendingEvents();
1149 return fRc;
1150
1151 def enableUsbEhci(self, fEnable):
1152 """
1153 Enables or disables the USB EHCI controller, enables also OHCI if it is still disabled.
1154 Returns True on success and False on failure. Error information is logged.
1155 """
1156 fRc = True;
1157 try:
1158 if fEnable:
1159 if self.fpApiVer >= 4.3:
1160 cOhciCtls = self.o.machine.getUSBControllerCountByType(vboxcon.USBControllerType_OHCI);
1161 if cOhciCtls == 0:
1162 self.o.machine.addUSBController('OHCI', vboxcon.USBControllerType_OHCI);
1163
1164 cEhciCtls = self.o.machine.getUSBControllerCountByType(vboxcon.USBControllerType_EHCI);
1165 if cEhciCtls == 0:
1166 self.o.machine.addUSBController('EHCI', vboxcon.USBControllerType_EHCI);
1167 else:
1168 self.o.machine.usbController.enabled = True;
1169 self.o.machine.usbController.enabledEHCI = True;
1170 else:
1171 if self.fpApiVer >= 4.3:
1172 cEhciCtls = self.o.machine.getUSBControllerCountByType(vboxcon.USBControllerType_EHCI);
1173 if cEhciCtls == 1:
1174 self.o.machine.removeUSBController('EHCI');
1175 else:
1176 self.o.machine.usbController.enabledEHCI = False;
1177 except:
1178 reporter.errorXcpt('failed to change EHCI to %s for "%s"' % (fEnable, self.sName));
1179 fRc = False;
1180 else:
1181 reporter.log('changed EHCI to %s for "%s"' % (fEnable, self.sName));
1182 self.oTstDrv.processPendingEvents();
1183 return fRc;
1184
1185 def enableUsbXhci(self, fEnable):
1186 """
1187 Enables or disables the USB XHCI controller. Error information is logged.
1188 """
1189 fRc = True;
1190 try:
1191 if fEnable:
1192 cXhciCtls = self.o.machine.getUSBControllerCountByType(vboxcon.USBControllerType_XHCI);
1193 if cXhciCtls == 0:
1194 self.o.machine.addUSBController('XHCI', vboxcon.USBControllerType_XHCI);
1195 else:
1196 cXhciCtls = self.o.machine.getUSBControllerCountByType(vboxcon.USBControllerType_XHCI);
1197 if cXhciCtls == 1:
1198 self.o.machine.removeUSBController('XHCI');
1199 except:
1200 reporter.errorXcpt('failed to change XHCI to %s for "%s"' % (fEnable, self.sName));
1201 fRc = False;
1202 else:
1203 reporter.log('changed XHCI to %s for "%s"' % (fEnable, self.sName));
1204 self.oTstDrv.processPendingEvents();
1205 return fRc;
1206
1207 def setFirmwareType(self, eType):
1208 """
1209 Sets the firmware type.
1210 Returns True on success and False on failure. Error information is logged.
1211 """
1212 fRc = True;
1213 try:
1214 self.o.machine.firmwareType = eType;
1215 except:
1216 reporter.errorXcpt('failed to set firmwareType=%s for "%s"' % (eType, self.sName));
1217 fRc = False;
1218 else:
1219 reporter.log('set firmwareType=%s for "%s"' % (eType, self.sName));
1220 self.oTstDrv.processPendingEvents();
1221 return fRc;
1222
1223 def setChipsetType(self, eType):
1224 """
1225 Sets the chipset type.
1226 Returns True on success and False on failure. Error information is logged.
1227 """
1228 fRc = True;
1229 try:
1230 self.o.machine.chipsetType = eType;
1231 except:
1232 reporter.errorXcpt('failed to set chipsetType=%s for "%s"' % (eType, self.sName));
1233 fRc = False;
1234 else:
1235 reporter.log('set chipsetType=%s for "%s"' % (eType, self.sName));
1236 self.oTstDrv.processPendingEvents();
1237 return fRc;
1238
1239 def setIommuType(self, eType):
1240 """
1241 Sets the IOMMU type.
1242 Returns True on success and False on failure. Error information is logged.
1243 """
1244 # Supported.
1245 if self.fpApiVer < 6.2 or not hasattr(vboxcon, 'IommuType_Intel') or not hasattr(vboxcon, 'IommuType_AMD'):
1246 return True;
1247 fRc = True;
1248 try:
1249 self.o.machine.iommuType = eType;
1250 except:
1251 reporter.errorXcpt('failed to set iommuType=%s for "%s"' % (eType, self.sName));
1252 fRc = False;
1253 else:
1254 reporter.log('set iommuType=%s for "%s"' % (eType, self.sName));
1255 self.oTstDrv.processPendingEvents();
1256 return fRc;
1257
1258 def setupBootLogo(self, fEnable, cMsLogoDisplay = 0):
1259 """
1260 Sets up the boot logo. fEnable toggles the fade and boot menu
1261 settings as well as the mode.
1262 """
1263 fRc = True;
1264 try:
1265 self.o.machine.BIOSSettings.logoFadeIn = not fEnable;
1266 self.o.machine.BIOSSettings.logoFadeOut = not fEnable;
1267 self.o.machine.BIOSSettings.logoDisplayTime = cMsLogoDisplay;
1268 if fEnable:
1269 self.o.machine.BIOSSettings.bootMenuMode = vboxcon.BIOSBootMenuMode_Disabled;
1270 else:
1271 self.o.machine.BIOSSettings.bootMenuMode = vboxcon.BIOSBootMenuMode_MessageAndMenu;
1272 except:
1273 reporter.errorXcpt('failed to set logoFadeIn/logoFadeOut/bootMenuMode=%s for "%s"' % (fEnable, self.sName));
1274 fRc = False;
1275 else:
1276 reporter.log('set logoFadeIn/logoFadeOut/bootMenuMode=%s for "%s"' % (fEnable, self.sName));
1277 self.oTstDrv.processPendingEvents();
1278 return fRc;
1279
1280 def setupVrdp(self, fEnable, uPort = None):
1281 """
1282 Configures VRDP.
1283 """
1284 fRc = True;
1285 try:
1286 if self.fpApiVer >= 4.0:
1287 self.o.machine.VRDEServer.enabled = fEnable;
1288 else:
1289 self.o.machine.VRDPServer.enabled = fEnable;
1290 except:
1291 reporter.errorXcpt('failed to set VRDEServer::enabled=%s for "%s"' % (fEnable, self.sName));
1292 fRc = False;
1293
1294 if uPort is not None and fRc:
1295 try:
1296 if self.fpApiVer >= 4.0:
1297 self.o.machine.VRDEServer.setVRDEProperty("TCP/Ports", str(uPort));
1298 else:
1299 self.o.machine.VRDPServer.ports = str(uPort);
1300 except:
1301 reporter.errorXcpt('failed to set VRDEServer::ports=%s for "%s"' % (uPort, self.sName));
1302 fRc = False;
1303 if fRc:
1304 reporter.log('set VRDEServer.enabled/ports=%s/%s for "%s"' % (fEnable, uPort, self.sName));
1305 self.oTstDrv.processPendingEvents();
1306 return fRc;
1307
1308 def getNicDriverNameFromType(self, eNicType):
1309 """
1310 Helper that translate the adapter type into a driver name.
1311 """
1312 if eNicType in (vboxcon.NetworkAdapterType_Am79C970A, vboxcon.NetworkAdapterType_Am79C973):
1313 sName = 'pcnet';
1314 elif eNicType in (vboxcon.NetworkAdapterType_I82540EM,
1315 vboxcon.NetworkAdapterType_I82543GC,
1316 vboxcon.NetworkAdapterType_I82545EM):
1317 sName = 'e1000';
1318 elif eNicType == vboxcon.NetworkAdapterType_Virtio:
1319 sName = 'virtio-net';
1320 else:
1321 reporter.error('Unknown adapter type "%s" (VM: "%s")' % (eNicType, self.sName));
1322 sName = 'pcnet';
1323 return sName;
1324
1325 def setupNatForwardingForTxs(self, iNic = 0, iHostPort = 5042):
1326 """
1327 Sets up NAT forwarding for port 5042 if applicable, cleans up if not.
1328 """
1329 try:
1330 oNic = self.o.machine.getNetworkAdapter(iNic);
1331 except:
1332 reporter.errorXcpt('getNetworkAdapter(%s) failed for "%s"' % (iNic, self.sName));
1333 return False;
1334
1335 # Nuke the old setup for all possible adapter types (in case we're
1336 # called after it changed).
1337 for sName in ('pcnet', 'e1000', 'virtio-net'):
1338 for sConfig in ('VBoxInternal/Devices/%s/%u/LUN#0/AttachedDriver/Config' % (sName, iNic), \
1339 'VBoxInternal/Devices/%s/%u/LUN#0/Config' % (sName, iNic)):
1340 try:
1341 self.o.machine.setExtraData('%s/txs/Protocol' % (sConfig), '');
1342 self.o.machine.setExtraData('%s/txs/HostPort' % (sConfig), '');
1343 self.o.machine.setExtraData('%s/txs/GuestPort' % (sConfig), '');
1344 except:
1345 reporter.errorXcpt();
1346
1347 # Set up port forwarding if NAT attachment.
1348 try:
1349 eAttType = oNic.attachmentType;
1350 except:
1351 reporter.errorXcpt('attachmentType on %s failed for "%s"' % (iNic, self.sName));
1352 return False;
1353 if eAttType != vboxcon.NetworkAttachmentType_NAT:
1354 return True;
1355
1356 try:
1357 eNicType = oNic.adapterType;
1358 fTraceEnabled = oNic.traceEnabled;
1359 except:
1360 reporter.errorXcpt('attachmentType/traceEnabled on %s failed for "%s"' % (iNic, self.sName));
1361 return False;
1362
1363 if self.fpApiVer >= 4.1:
1364 try:
1365 if self.fpApiVer >= 4.2:
1366 oNatEngine = oNic.NATEngine;
1367 else:
1368 oNatEngine = oNic.natDriver;
1369 except:
1370 reporter.errorXcpt('Failed to get INATEngine data on "%s"' % (self.sName));
1371 return False;
1372 try: oNatEngine.removeRedirect('txs');
1373 except: pass;
1374 try:
1375 oNatEngine.addRedirect('txs', vboxcon.NATProtocol_TCP, '127.0.0.1', '%s' % (iHostPort), '', '5042');
1376 except:
1377 reporter.errorXcpt('Failed to add a addRedirect redirect on "%s"' % (self.sName));
1378 return False;
1379
1380 else:
1381 sName = self.getNicDriverNameFromType(eNicType);
1382 if fTraceEnabled:
1383 sConfig = 'VBoxInternal/Devices/%s/%u/LUN#0/AttachedDriver/Config' % (sName, iNic)
1384 else:
1385 sConfig = 'VBoxInternal/Devices/%s/%u/LUN#0/Config' % (sName, iNic)
1386
1387 try:
1388 self.o.machine.setExtraData('%s/txs/Protocol' % (sConfig), 'TCP');
1389 self.o.machine.setExtraData('%s/txs/HostPort' % (sConfig), '%s' % (iHostPort));
1390 self.o.machine.setExtraData('%s/txs/GuestPort' % (sConfig), '5042');
1391 except:
1392 reporter.errorXcpt('Failed to set NAT extra data on "%s"' % (self.sName));
1393 return False;
1394 return True;
1395
1396 def setNicType(self, eType, iNic = 0):
1397 """
1398 Sets the NIC type of the specified NIC.
1399 Returns True on success and False on failure. Error information is logged.
1400 """
1401 try:
1402 try:
1403 oNic = self.o.machine.getNetworkAdapter(iNic);
1404 except:
1405 reporter.errorXcpt('getNetworkAdapter(%s) failed for "%s"' % (iNic, self.sName));
1406 return False;
1407 try:
1408 oNic.adapterType = eType;
1409 except:
1410 reporter.errorXcpt('failed to set NIC type on slot %s to %s for VM "%s"' % (iNic, eType, self.sName));
1411 return False;
1412 finally:
1413 self.oTstDrv.processPendingEvents();
1414
1415 if not self.setupNatForwardingForTxs(iNic):
1416 return False;
1417 reporter.log('set NIC type on slot %s to %s for VM "%s"' % (iNic, eType, self.sName));
1418 return True;
1419
1420 def setNicTraceEnabled(self, fTraceEnabled, sTraceFile, iNic = 0):
1421 """
1422 Sets the NIC trace enabled flag and file path.
1423 Returns True on success and False on failure. Error information is logged.
1424 """
1425 try:
1426 try:
1427 oNic = self.o.machine.getNetworkAdapter(iNic);
1428 except:
1429 reporter.errorXcpt('getNetworkAdapter(%s) failed for "%s"' % (iNic, self.sName));
1430 return False;
1431 try:
1432 oNic.traceEnabled = fTraceEnabled;
1433 oNic.traceFile = sTraceFile;
1434 except:
1435 reporter.errorXcpt('failed to set NIC trace flag on slot %s to %s for VM "%s"' \
1436 % (iNic, fTraceEnabled, self.sName));
1437 return False;
1438 finally:
1439 self.oTstDrv.processPendingEvents();
1440
1441 if not self.setupNatForwardingForTxs(iNic):
1442 return False;
1443 reporter.log('set NIC trace on slot %s to "%s" (path "%s") for VM "%s"' %
1444 (iNic, fTraceEnabled, sTraceFile, self.sName));
1445 return True;
1446
1447 def getDefaultNicName(self, eAttachmentType):
1448 """
1449 Return the default network / interface name for the NIC attachment type.
1450 """
1451 sRetName = '';
1452 if eAttachmentType == vboxcon.NetworkAttachmentType_Bridged:
1453 if self.oTstDrv.sDefBridgedNic is not None:
1454 sRetName = self.oTstDrv.sDefBridgedNic;
1455 else:
1456 sRetName = 'eth0';
1457 try:
1458 aoHostNics = self.oVBoxMgr.getArray(self.oVBox.host, 'networkInterfaces');
1459 for oHostNic in aoHostNics:
1460 if oHostNic.interfaceType == vboxcon.HostNetworkInterfaceType_Bridged \
1461 and oHostNic.status == vboxcon.HostNetworkInterfaceStatus_Up:
1462 sRetName = oHostNic.name;
1463 break;
1464 except:
1465 reporter.errorXcpt();
1466
1467 elif eAttachmentType == vboxcon.NetworkAttachmentType_HostOnly:
1468 try:
1469 aoHostNics = self.oVBoxMgr.getArray(self.oVBox.host, 'networkInterfaces');
1470 for oHostNic in aoHostNics:
1471 if oHostNic.interfaceType == vboxcon.HostNetworkInterfaceType_HostOnly:
1472 if oHostNic.status == vboxcon.HostNetworkInterfaceStatus_Up:
1473 sRetName = oHostNic.name;
1474 break;
1475 if sRetName == '':
1476 sRetName = oHostNic.name;
1477 except:
1478 reporter.errorXcpt();
1479 if sRetName == '':
1480 # Create a new host-only interface.
1481 reporter.log("Creating host only NIC ...");
1482 try:
1483 (oIProgress, oIHostOnly) = self.oVBox.host.createHostOnlyNetworkInterface();
1484 oProgress = ProgressWrapper(oIProgress, self.oVBoxMgr, self.oTstDrv, 'Create host only NIC');
1485 oProgress.wait();
1486 if oProgress.logResult() is False:
1487 return '';
1488 sRetName = oIHostOnly.name;
1489 except:
1490 reporter.errorXcpt();
1491 return '';
1492 reporter.log("Created host only NIC: '%s'" % (sRetName,));
1493
1494 elif eAttachmentType == vboxcon.NetworkAttachmentType_Internal:
1495 sRetName = 'VBoxTest';
1496
1497 elif eAttachmentType == vboxcon.NetworkAttachmentType_NAT:
1498 sRetName = '';
1499
1500 else: ## @todo Support NetworkAttachmentType_NATNetwork
1501 reporter.error('eAttachmentType=%s is not known' % (eAttachmentType));
1502 return sRetName;
1503
1504 def setNicAttachment(self, eAttachmentType, sName = None, iNic = 0):
1505 """
1506 Sets the attachment type of the specified NIC.
1507 Returns True on success and False on failure. Error information is logged.
1508 """
1509 try:
1510 oNic = self.o.machine.getNetworkAdapter(iNic);
1511 except:
1512 reporter.errorXcpt('getNetworkAdapter(%s) failed for "%s"' % (iNic, self.sName));
1513 return False;
1514
1515 try:
1516 if eAttachmentType is not None:
1517 try:
1518 if self.fpApiVer >= 4.1:
1519 oNic.attachmentType = eAttachmentType;
1520 else:
1521 if eAttachmentType == vboxcon.NetworkAttachmentType_NAT:
1522 oNic.attachToNAT();
1523 elif eAttachmentType == vboxcon.NetworkAttachmentType_Bridged:
1524 oNic.attachToBridgedInterface();
1525 elif eAttachmentType == vboxcon.NetworkAttachmentType_Internal:
1526 oNic.attachToInternalNetwork();
1527 elif eAttachmentType == vboxcon.NetworkAttachmentType_HostOnly:
1528 oNic.attachToHostOnlyInterface();
1529 else:
1530 raise base.GenError("eAttachmentType=%s is invalid" % (eAttachmentType));
1531 except:
1532 reporter.errorXcpt('failed to set the attachment type on slot %s to %s for VM "%s"' \
1533 % (iNic, eAttachmentType, self.sName));
1534 return False;
1535 else:
1536 try:
1537 eAttachmentType = oNic.attachmentType;
1538 except:
1539 reporter.errorXcpt('failed to get the attachment type on slot %s for VM "%s"' % (iNic, self.sName));
1540 return False;
1541 finally:
1542 self.oTstDrv.processPendingEvents();
1543
1544 if sName is not None:
1545 # Resolve the special 'default' name.
1546 if sName == 'default':
1547 sName = self.getDefaultNicName(eAttachmentType);
1548
1549 # The name translate to different attributes depending on the
1550 # attachment type.
1551 try:
1552 if eAttachmentType == vboxcon.NetworkAttachmentType_Bridged:
1553 ## @todo check this out on windows, may have to do a
1554 # translation of the name there or smth IIRC.
1555 try:
1556 if self.fpApiVer >= 4.1:
1557 oNic.bridgedInterface = sName;
1558 else:
1559 oNic.hostInterface = sName;
1560 except:
1561 reporter.errorXcpt('failed to set the hostInterface property on slot %s to "%s" for VM "%s"'
1562 % (iNic, sName, self.sName,));
1563 return False;
1564 elif eAttachmentType == vboxcon.NetworkAttachmentType_HostOnly:
1565 try:
1566 if self.fpApiVer >= 4.1:
1567 oNic.hostOnlyInterface = sName;
1568 else:
1569 oNic.hostInterface = sName;
1570 except:
1571 reporter.errorXcpt('failed to set the internalNetwork property on slot %s to "%s" for VM "%s"'
1572 % (iNic, sName, self.sName,));
1573 return False;
1574 elif eAttachmentType == vboxcon.NetworkAttachmentType_Internal:
1575 try:
1576 oNic.internalNetwork = sName;
1577 except:
1578 reporter.errorXcpt('failed to set the internalNetwork property on slot %s to "%s" for VM "%s"'
1579 % (iNic, sName, self.sName,));
1580 return False;
1581 elif eAttachmentType == vboxcon.NetworkAttachmentType_NAT:
1582 try:
1583 oNic.NATNetwork = sName;
1584 except:
1585 reporter.errorXcpt('failed to set the NATNetwork property on slot %s to "%s" for VM "%s"'
1586 % (iNic, sName, self.sName,));
1587 return False;
1588 finally:
1589 self.oTstDrv.processPendingEvents();
1590
1591 if not self.setupNatForwardingForTxs(iNic):
1592 return False;
1593 reporter.log('set NIC type on slot %s to %s for VM "%s"' % (iNic, eAttachmentType, self.sName));
1594 return True;
1595
1596 def setNicMacAddress(self, sMacAddr, iNic = 0):
1597 """
1598 Sets the MAC address of the specified NIC.
1599
1600 The sMacAddr parameter is a string supplying the tail end of the MAC
1601 address, missing quads are supplied from a constant byte (2), the IPv4
1602 address of the host, and the NIC number.
1603
1604 Returns True on success and False on failure. Error information is logged.
1605 """
1606
1607 # Resolve missing MAC address prefix by feeding in the host IP address bytes.
1608 cchMacAddr = len(sMacAddr);
1609 if 0 < cchMacAddr < 12:
1610 sHostIP = netutils.getPrimaryHostIp();
1611 abHostIP = socket.inet_aton(sHostIP);
1612 if sys.version_info[0] < 3:
1613 abHostIP = (ord(abHostIP[0]), ord(abHostIP[1]), ord(abHostIP[2]), ord(abHostIP[3]));
1614
1615 if abHostIP[0] == 127 \
1616 or (abHostIP[0] == 169 and abHostIP[1] == 254) \
1617 or (abHostIP[0] == 192 and abHostIP[1] == 168 and abHostIP[2] == 56):
1618 return reporter.error('host IP for "%s" is %s, most likely not unique.' % (netutils.getHostnameFqdn(), sHostIP,));
1619
1620 sDefaultMac = '%02X%02X%02X%02X%02X%02X' % (0x02, abHostIP[0], abHostIP[1], abHostIP[2], abHostIP[3], iNic);
1621 sMacAddr = sDefaultMac[0:(12 - cchMacAddr)] + sMacAddr;
1622
1623 # Get the NIC object and try set it address.
1624 try:
1625 oNic = self.o.machine.getNetworkAdapter(iNic);
1626 except:
1627 return reporter.errorXcpt('getNetworkAdapter(%s) failed for "%s"' % (iNic, self.sName,));
1628
1629 try:
1630 oNic.MACAddress = sMacAddr;
1631 except:
1632 return reporter.errorXcpt('failed to set the MAC address on slot %s to "%s" for VM "%s"'
1633 % (iNic, sMacAddr, self.sName));
1634
1635 reporter.log('set MAC address on slot %s to %s for VM "%s"' % (iNic, sMacAddr, self.sName,));
1636 return True;
1637
1638 def setRamSize(self, cMB):
1639 """
1640 Set the RAM size of the VM.
1641 Returns True on success and False on failure. Error information is logged.
1642 """
1643 fRc = True;
1644 try:
1645 self.o.machine.memorySize = cMB;
1646 except:
1647 reporter.errorXcpt('failed to set the RAM size of "%s" to %s' % (self.sName, cMB));
1648 fRc = False;
1649 else:
1650 reporter.log('set the RAM size of "%s" to %s' % (self.sName, cMB));
1651 self.oTstDrv.processPendingEvents();
1652 return fRc;
1653
1654 def setVRamSize(self, cMB):
1655 """
1656 Set the RAM size of the VM.
1657 Returns True on success and False on failure. Error information is logged.
1658 """
1659 fRc = True;
1660 try:
1661 if self.fpApiVer >= 6.1 and hasattr(self.o.machine, 'graphicsAdapter'):
1662 self.o.machine.graphicsAdapter.VRAMSize = cMB;
1663 else:
1664 self.o.machine.VRAMSize = cMB;
1665 except:
1666 reporter.errorXcpt('failed to set the VRAM size of "%s" to %s' % (self.sName, cMB));
1667 fRc = False;
1668 else:
1669 reporter.log('set the VRAM size of "%s" to %s' % (self.sName, cMB));
1670 self.oTstDrv.processPendingEvents();
1671 return fRc;
1672
1673 def setVideoControllerType(self, eControllerType):
1674 """
1675 Set the video controller type of the VM.
1676 Returns True on success and False on failure. Error information is logged.
1677 """
1678 fRc = True;
1679 try:
1680 if self.fpApiVer >= 6.1 and hasattr(self.o.machine, 'graphicsAdapter'):
1681 self.o.machine.graphicsAdapter.graphicsControllerType = eControllerType;
1682 else:
1683 self.o.machine.graphicsControllerType = eControllerType;
1684 except:
1685 reporter.errorXcpt('failed to set the video controller type of "%s" to %s' % (self.sName, eControllerType));
1686 fRc = False;
1687 else:
1688 reporter.log('set the video controller type of "%s" to %s' % (self.sName, eControllerType));
1689 self.oTstDrv.processPendingEvents();
1690 return fRc;
1691
1692 def setAccelerate3DEnabled(self, fEnabled):
1693 """
1694 Set the video controller type of the VM.
1695 Returns True on success and False on failure. Error information is logged.
1696 """
1697 fRc = True;
1698 try:
1699 if self.fpApiVer >= 6.1 and hasattr(self.o.machine, 'graphicsAdapter'):
1700 self.o.machine.graphicsAdapter.accelerate3DEnabled = fEnabled;
1701 else:
1702 self.o.machine.accelerate3DEnabled = fEnabled;
1703 except:
1704 reporter.errorXcpt('failed to set the accelerate3DEnabled of "%s" to %s' % (self.sName, fEnabled));
1705 fRc = False;
1706 else:
1707 reporter.log('set the accelerate3DEnabled of "%s" to %s' % (self.sName, fEnabled));
1708 self.oTstDrv.processPendingEvents();
1709 return fRc;
1710
1711 def setCpuCount(self, cCpus):
1712 """
1713 Set the number of CPUs.
1714 Returns True on success and False on failure. Error information is logged.
1715 """
1716 fRc = True;
1717 try:
1718 self.o.machine.CPUCount = cCpus;
1719 except:
1720 reporter.errorXcpt('failed to set the CPU count of "%s" to %s' % (self.sName, cCpus));
1721 fRc = False;
1722 else:
1723 reporter.log('set the CPU count of "%s" to %s' % (self.sName, cCpus));
1724 self.oTstDrv.processPendingEvents();
1725 return fRc;
1726
1727 def getCpuCount(self):
1728 """
1729 Returns the number of CPUs.
1730 Returns the number of CPUs on success and 0 on failure. Error information is logged.
1731 """
1732 cCpus = 0;
1733 try:
1734 cCpus = self.o.machine.CPUCount;
1735 except:
1736 reporter.errorXcpt('failed to get the CPU count of "%s"' % (self.sName,));
1737
1738 self.oTstDrv.processPendingEvents();
1739 return cCpus;
1740
1741 def ensureControllerAttached(self, sController):
1742 """
1743 Makes sure the specified controller is attached to the VM, attaching it
1744 if necessary.
1745 """
1746 try:
1747 try:
1748 self.o.machine.getStorageControllerByName(sController);
1749 except:
1750 (eBus, eType) = _ControllerNameToBusAndType(sController);
1751 try:
1752 oCtl = self.o.machine.addStorageController(sController, eBus);
1753 except:
1754 reporter.errorXcpt('addStorageController("%s",%s) failed on "%s"' % (sController, eBus, self.sName) );
1755 return False;
1756 else:
1757 try:
1758 oCtl.controllerType = eType;
1759 reporter.log('added storage controller "%s" (bus %s, type %s) to %s'
1760 % (sController, eBus, eType, self.sName));
1761 except:
1762 reporter.errorXcpt('controllerType = %s on ("%s" / %s) failed on "%s"'
1763 % (eType, sController, eBus, self.sName) );
1764 return False;
1765 finally:
1766 self.oTstDrv.processPendingEvents();
1767 return True;
1768
1769 def setStorageControllerPortCount(self, sController, iPortCount):
1770 """
1771 Set maximum ports count for storage controller
1772 """
1773 try:
1774 oCtl = self.o.machine.getStorageControllerByName(sController)
1775 oCtl.portCount = iPortCount
1776 self.oTstDrv.processPendingEvents()
1777 reporter.log('set controller "%s" port count to value %d' % (sController, iPortCount))
1778 return True
1779 except:
1780 reporter.log('unable to set storage controller "%s" ports count to %d' % (sController, iPortCount))
1781
1782 return False
1783
1784 def setStorageControllerHostIoCache(self, sController, fUseHostIoCache):
1785 """
1786 Set maximum ports count for storage controller
1787 """
1788 try:
1789 oCtl = self.o.machine.getStorageControllerByName(sController);
1790 oCtl.useHostIOCache = fUseHostIoCache;
1791 self.oTstDrv.processPendingEvents();
1792 reporter.log('set controller "%s" host I/O cache setting to %r' % (sController, fUseHostIoCache));
1793 return True;
1794 except:
1795 reporter.log('unable to set storage controller "%s" host I/O cache setting to %r' % (sController, fUseHostIoCache));
1796
1797 return False;
1798
1799 def setBootOrder(self, iPosition, eType):
1800 """
1801 Set guest boot order type
1802 @param iPosition boot order position
1803 @param eType device type (vboxcon.DeviceType_HardDisk,
1804 vboxcon.DeviceType_DVD, vboxcon.DeviceType_Floppy)
1805 """
1806 try:
1807 self.o.machine.setBootOrder(iPosition, eType)
1808 except:
1809 return reporter.errorXcpt('Unable to set boot order.')
1810
1811 reporter.log('Set boot order [%d] for device %s' % (iPosition, str(eType)))
1812 self.oTstDrv.processPendingEvents();
1813
1814 return True
1815
1816 def setStorageControllerType(self, eType, sController = "IDE Controller"):
1817 """
1818 Similar to ensureControllerAttached, except it will change the type.
1819 """
1820 try:
1821 oCtl = self.o.machine.getStorageControllerByName(sController);
1822 except:
1823 (eBus, _) = _ControllerNameToBusAndType(sController);
1824 try:
1825 oCtl = self.o.machine.addStorageController(sController, eBus);
1826 reporter.log('added storage controller "%s" (bus %s) to %s' % (sController, eBus, self.sName));
1827 except:
1828 reporter.errorXcpt('addStorageController("%s",%s) failed on "%s"' % (sController, eBus, self.sName) );
1829 return False;
1830 try:
1831 oCtl.controllerType = eType;
1832 except:
1833 reporter.errorXcpt('failed to set controller type of "%s" on "%s" to %s' % (sController, self.sName, eType) );
1834 return False;
1835 reporter.log('set controller type of "%s" on "%s" to %s' % (sController, self.sName, eType) );
1836 self.oTstDrv.processPendingEvents();
1837 return True;
1838
1839 def attachDvd(self, sImage = None, sController = "IDE Controller", iPort = 1, iDevice = 0):
1840 """
1841 Attaches a DVD drive to a VM, optionally with an ISO inserted.
1842 Returns True on success and False on failure. Error information is logged.
1843 """
1844 # Input validation.
1845 if sImage is not None and not self.oTstDrv.isResourceFile(sImage)\
1846 and not os.path.isabs(sImage): ## fixme - testsuite unzip ++
1847 reporter.fatal('"%s" is not in the resource set' % (sImage));
1848 return None;
1849
1850 if not self.ensureControllerAttached(sController):
1851 return False;
1852
1853 # Find/register the image if specified.
1854 oImage = None;
1855 sImageUuid = "";
1856 if sImage is not None:
1857 sFullName = self.oTstDrv.getFullResourceName(sImage)
1858 try:
1859 oImage = self.oVBox.findDVDImage(sFullName);
1860 except:
1861 try:
1862 if self.fpApiVer >= 4.1:
1863 oImage = self.oVBox.openMedium(sFullName, vboxcon.DeviceType_DVD, vboxcon.AccessMode_ReadOnly, False);
1864 elif self.fpApiVer >= 4.0:
1865 oImage = self.oVBox.openMedium(sFullName, vboxcon.DeviceType_DVD, vboxcon.AccessMode_ReadOnly);
1866 else:
1867 oImage = self.oVBox.openDVDImage(sFullName, "");
1868 except vbox.ComException as oXcpt:
1869 if oXcpt.errno != -1:
1870 reporter.errorXcpt('failed to open DVD image "%s" xxx' % (sFullName));
1871 else:
1872 reporter.errorXcpt('failed to open DVD image "%s" yyy' % (sFullName));
1873 return False;
1874 except:
1875 reporter.errorXcpt('failed to open DVD image "%s"' % (sFullName));
1876 return False;
1877 try:
1878 sImageUuid = oImage.id;
1879 except:
1880 reporter.errorXcpt('failed to get the UUID of "%s"' % (sFullName));
1881 return False;
1882
1883 # Attach the DVD.
1884 fRc = True;
1885 try:
1886 if self.fpApiVer >= 4.0:
1887 self.o.machine.attachDevice(sController, iPort, iDevice, vboxcon.DeviceType_DVD, oImage);
1888 else:
1889 self.o.machine.attachDevice(sController, iPort, iDevice, vboxcon.DeviceType_DVD, sImageUuid);
1890 except:
1891 reporter.errorXcpt('attachDevice("%s",%s,%s,HardDisk,"%s") failed on "%s"' \
1892 % (sController, iPort, iDevice, sImageUuid, self.sName) );
1893 fRc = False;
1894 else:
1895 reporter.log('attached DVD to %s, image="%s"' % (self.sName, sImage));
1896 self.oTstDrv.processPendingEvents();
1897 return fRc;
1898
1899 def attachHd(self, sHd, sController = "IDE Controller", iPort = 0, iDevice = 0, fImmutable = True, fForceResource = True):
1900 """
1901 Attaches a HD to a VM.
1902 Returns True on success and False on failure. Error information is logged.
1903 """
1904 # Input validation.
1905 if fForceResource and not self.oTstDrv.isResourceFile(sHd):
1906 reporter.fatal('"%s" is not in the resource set' % (sHd,));
1907 return None;
1908
1909 if not self.ensureControllerAttached(sController):
1910 return False;
1911
1912 # Find the HD, registering it if necessary (as immutable).
1913 if fForceResource:
1914 sFullName = self.oTstDrv.getFullResourceName(sHd);
1915 else:
1916 sFullName = sHd;
1917 try:
1918 oHd = self.oVBox.findHardDisk(sFullName);
1919 except:
1920 try:
1921 if self.fpApiVer >= 4.1:
1922 oHd = self.oVBox.openMedium(sFullName, vboxcon.DeviceType_HardDisk, vboxcon.AccessMode_ReadOnly, False);
1923 elif self.fpApiVer >= 4.0:
1924 oHd = self.oVBox.openMedium(sFullName, vboxcon.DeviceType_HardDisk, vboxcon.AccessMode_ReadOnly);
1925 else:
1926 oHd = self.oVBox.openHardDisk(sFullName, vboxcon.AccessMode_ReadOnly, False, "", False, "");
1927 except:
1928 reporter.errorXcpt('failed to open hd "%s"' % (sFullName));
1929 return False;
1930 try:
1931 if fImmutable:
1932 oHd.type = vboxcon.MediumType_Immutable;
1933 else:
1934 oHd.type = vboxcon.MediumType_Normal;
1935 except:
1936 if fImmutable:
1937 reporter.errorXcpt('failed to set hd "%s" immutable' % (sHd));
1938 else:
1939 reporter.errorXcpt('failed to set hd "%s" normal' % (sHd));
1940 return False;
1941
1942 # Attach it.
1943 fRc = True;
1944 try:
1945 if self.fpApiVer >= 4.0:
1946 self.o.machine.attachDevice(sController, iPort, iDevice, vboxcon.DeviceType_HardDisk, oHd);
1947 else:
1948 self.o.machine.attachDevice(sController, iPort, iDevice, vboxcon.DeviceType_HardDisk, oHd.id);
1949 except:
1950 reporter.errorXcpt('attachDevice("%s",%s,%s,HardDisk,"%s") failed on "%s"' \
1951 % (sController, iPort, iDevice, oHd.id, self.sName) );
1952 fRc = False;
1953 else:
1954 reporter.log('attached "%s" to %s' % (sHd, self.sName));
1955 self.oTstDrv.processPendingEvents();
1956 return fRc;
1957
1958 def createBaseHd(self, sHd, sFmt = "VDI", cb = 10*1024*1024*1024, cMsTimeout = 60000, tMediumVariant = None):
1959 """
1960 Creates a base HD.
1961 Returns Medium object on success and None on failure. Error information is logged.
1962 """
1963 if tMediumVariant is None:
1964 tMediumVariant = (vboxcon.MediumVariant_Standard, );
1965
1966 try:
1967 if self.fpApiVer >= 5.0:
1968 oHd = self.oVBox.createMedium(sFmt, sHd, vboxcon.AccessMode_ReadWrite, vboxcon.DeviceType_HardDisk);
1969 else:
1970 oHd = self.oVBox.createHardDisk(sFmt, sHd);
1971 oProgressXpcom = oHd.createBaseStorage(cb, tMediumVariant);
1972 oProgress = ProgressWrapper(oProgressXpcom, self.oVBoxMgr, self.oTstDrv, 'create base disk %s' % (sHd));
1973 oProgress.wait(cMsTimeout);
1974 oProgress.logResult();
1975 except:
1976 reporter.errorXcpt('failed to create base hd "%s"' % (sHd));
1977 oHd = None
1978
1979 return oHd;
1980
1981 def createDiffHd(self, oParentHd, sHd, sFmt = "VDI"):
1982 """
1983 Creates a differencing HD.
1984 Returns Medium object on success and None on failure. Error information is logged.
1985 """
1986 # Detect the proper format if requested
1987 if sFmt is None:
1988 try:
1989 oHdFmt = oParentHd.mediumFormat;
1990 lstCaps = self.oVBoxMgr.getArray(oHdFmt, 'capabilities');
1991 if vboxcon.MediumFormatCapabilities_Differencing in lstCaps:
1992 sFmt = oHdFmt.id;
1993 else:
1994 sFmt = 'VDI';
1995 except:
1996 reporter.errorXcpt('failed to get preferred diff format for "%s"' % (sHd));
1997 return None;
1998 try:
1999 if self.fpApiVer >= 5.0:
2000 oHd = self.oVBox.createMedium(sFmt, sHd, vboxcon.AccessMode_ReadWrite, vboxcon.DeviceType_HardDisk);
2001 else:
2002 oHd = self.oVBox.createHardDisk(sFmt, sHd);
2003 oProgressXpcom = oParentHd.createDiffStorage(oHd, (vboxcon.MediumVariant_Standard, ))
2004 oProgress = ProgressWrapper(oProgressXpcom, self.oVBoxMgr, self.oTstDrv, 'create diff disk %s' % (sHd));
2005 oProgress.wait();
2006 oProgress.logResult();
2007 except:
2008 reporter.errorXcpt('failed to create diff hd "%s"' % (sHd));
2009 oHd = None
2010
2011 return oHd;
2012
2013 def createAndAttachHd(self, sHd, sFmt = "VDI", sController = "IDE Controller", cb = 10*1024*1024*1024, # pylint: disable=too-many-arguments
2014 iPort = 0, iDevice = 0, fImmutable = True, cMsTimeout = 60000, tMediumVariant = None):
2015 """
2016 Creates and attaches a HD to a VM.
2017 Returns True on success and False on failure. Error information is logged.
2018 """
2019 if not self.ensureControllerAttached(sController):
2020 return False;
2021
2022 oHd = self.createBaseHd(sHd, sFmt, cb, cMsTimeout, tMediumVariant);
2023 if oHd is None:
2024 return False;
2025
2026 fRc = True;
2027 try:
2028 if fImmutable:
2029 oHd.type = vboxcon.MediumType_Immutable;
2030 else:
2031 oHd.type = vboxcon.MediumType_Normal;
2032 except:
2033 if fImmutable:
2034 reporter.errorXcpt('failed to set hd "%s" immutable' % (sHd));
2035 else:
2036 reporter.errorXcpt('failed to set hd "%s" normal' % (sHd));
2037 fRc = False;
2038
2039 # Attach it.
2040 if fRc is True:
2041 try:
2042 if self.fpApiVer >= 4.0:
2043 self.o.machine.attachDevice(sController, iPort, iDevice, vboxcon.DeviceType_HardDisk, oHd);
2044 else:
2045 self.o.machine.attachDevice(sController, iPort, iDevice, vboxcon.DeviceType_HardDisk, oHd.id);
2046 except:
2047 reporter.errorXcpt('attachDevice("%s",%s,%s,HardDisk,"%s") failed on "%s"' \
2048 % (sController, iPort, iDevice, oHd.id, self.sName) );
2049 fRc = False;
2050 else:
2051 reporter.log('attached "%s" to %s' % (sHd, self.sName));
2052
2053 # Delete disk in case of an error
2054 if fRc is False:
2055 try:
2056 oProgressCom = oHd.deleteStorage();
2057 except:
2058 reporter.errorXcpt('deleteStorage() for disk %s failed' % (sHd,));
2059 else:
2060 oProgress = ProgressWrapper(oProgressCom, self.oVBoxMgr, self.oTstDrv, 'delete disk %s' % (sHd));
2061 oProgress.wait();
2062 oProgress.logResult();
2063
2064 self.oTstDrv.processPendingEvents();
2065 return fRc;
2066
2067 def detachHd(self, sController = "IDE Controller", iPort = 0, iDevice = 0):
2068 """
2069 Detaches a HD, if attached, and returns a reference to it (IMedium).
2070
2071 In order to delete the detached medium, the caller must first save
2072 the changes made in this session.
2073
2074 Returns (fRc, oHd), where oHd is None unless fRc is True, and fRc is
2075 your standard success indicator. Error information is logged.
2076 """
2077
2078 # What's attached?
2079 try:
2080 oHd = self.o.machine.getMedium(sController, iPort, iDevice);
2081 except:
2082 if self.oVBoxMgr.xcptIsOurXcptKind() \
2083 and self.oVBoxMgr.xcptIsEqual(None, self.oVBoxMgr.constants.VBOX_E_OBJECT_NOT_FOUND):
2084 reporter.log('No HD attached (to %s %s:%s)' % (sController, iPort, iDevice));
2085 return (True, None);
2086 return (reporter.errorXcpt('Error getting media at port %s, device %s, on %s.'
2087 % (iPort, iDevice, sController)), None);
2088 # Detach it.
2089 try:
2090 self.o.machine.detachDevice(sController, iPort, iDevice);
2091 except:
2092 return (reporter.errorXcpt('detachDevice("%s",%s,%s) failed on "%s"' \
2093 % (sController, iPort, iDevice, self.sName) ), None);
2094 reporter.log('detached HD ("%s",%s,%s) from %s' % (sController, iPort, iDevice, self.sName));
2095 return (True, oHd);
2096
2097 def attachFloppy(self, sFloppy, sController = "Floppy Controller", iPort = 0, iDevice = 0):
2098 """
2099 Attaches a floppy image to a VM.
2100 Returns True on success and False on failure. Error information is logged.
2101 """
2102 # Input validation.
2103 ## @todo Fix this wrt to bootsector-xxx.img from the validationkit.zip.
2104 ##if not self.oTstDrv.isResourceFile(sFloppy):
2105 ## reporter.fatal('"%s" is not in the resource set' % (sFloppy));
2106 ## return None;
2107
2108 if not self.ensureControllerAttached(sController):
2109 return False;
2110
2111 # Find the floppy image, registering it if necessary (as immutable).
2112 sFullName = self.oTstDrv.getFullResourceName(sFloppy);
2113 try:
2114 oFloppy = self.oVBox.findFloppyImage(sFullName);
2115 except:
2116 try:
2117 if self.fpApiVer >= 4.1:
2118 oFloppy = self.oVBox.openMedium(sFullName, vboxcon.DeviceType_Floppy, vboxcon.AccessMode_ReadOnly, False);
2119 elif self.fpApiVer >= 4.0:
2120 oFloppy = self.oVBox.openMedium(sFullName, vboxcon.DeviceType_Floppy, vboxcon.AccessMode_ReadOnly);
2121 else:
2122 oFloppy = self.oVBox.openFloppyImage(sFullName, "");
2123 except:
2124 reporter.errorXcpt('failed to open floppy "%s"' % (sFullName));
2125 return False;
2126 ## @todo the following works but causes trouble below (asserts in main).
2127 #try:
2128 # oFloppy.type = vboxcon.MediumType_Immutable;
2129 #except:
2130 # reporter.errorXcpt('failed to make floppy "%s" immutable' % (sFullName));
2131 # return False;
2132
2133 # Attach it.
2134 fRc = True;
2135 try:
2136 if self.fpApiVer >= 4.0:
2137 self.o.machine.attachDevice(sController, iPort, iDevice, vboxcon.DeviceType_Floppy, oFloppy);
2138 else:
2139 self.o.machine.attachDevice(sController, iPort, iDevice, vboxcon.DeviceType_Floppy, oFloppy.id);
2140 except:
2141 reporter.errorXcpt('attachDevice("%s",%s,%s,Floppy,"%s") failed on "%s"' \
2142 % (sController, iPort, iDevice, oFloppy.id, self.sName) );
2143 fRc = False;
2144 else:
2145 reporter.log('attached "%s" to %s' % (sFloppy, self.sName));
2146 self.oTstDrv.processPendingEvents();
2147 return fRc;
2148
2149 def setupNic(self, sType, sXXX):
2150 """
2151 Sets up a NIC to a VM.
2152 Returns True on success and False on failure. Error information is logged.
2153 """
2154 if sType == "PCNet": enmType = vboxcon.NetworkAdapterType_Am79C973;
2155 elif sType == "PCNetOld": enmType = vboxcon.NetworkAdapterType_Am79C970A;
2156 elif sType == "E1000": enmType = vboxcon.NetworkAdapterType_I82545EM; # MT Server
2157 elif sType == "E1000Desk": enmType = vboxcon.NetworkAdapterType_I82540EM; # MT Desktop
2158 elif sType == "E1000Srv2": enmType = vboxcon.NetworkAdapterType_I82543GC; # T Server
2159 elif sType == "Virtio": enmType = vboxcon.NetworkAdapterType_Virtio;
2160 else:
2161 reporter.error('Invalid NIC type: "%s" (sXXX=%s)' % (sType, sXXX));
2162 return False;
2163 ## @todo Implement me!
2164 if enmType is not None: pass
2165 return True;
2166
2167 def setupAudio(self, eAudioControllerType, fEnable = True, eAudioDriverType = None):
2168 """
2169 Sets up audio.
2170
2171 :param eAudioControllerType: The audio controller type (vboxcon.AudioControllerType_XXX).
2172 :param fEnable: Whether to enable or disable the audio controller (default enable).
2173 :param eAudioDriverType: The audio driver type (vboxcon.AudioDriverType_XXX), picks something suitable
2174 if None is passed (default).
2175 """
2176 try: oAudioAdapter = self.o.machine.audioAdapter;
2177 except: return reporter.errorXcpt('Failed to get the audio adapter.');
2178
2179 try: oAudioAdapter.audioController = eAudioControllerType;
2180 except: return reporter.errorXcpt('Failed to set the audio controller to %s.' % (eAudioControllerType,));
2181
2182 if eAudioDriverType is None:
2183 sHost = utils.getHostOs()
2184 if sHost == 'darwin': eAudioDriverType = vboxcon.AudioDriverType_CoreAudio;
2185 elif sHost == 'win': eAudioDriverType = vboxcon.AudioDriverType_DirectSound;
2186 elif sHost == 'linux': eAudioDriverType = vboxcon.AudioDriverType_Pulse;
2187 elif sHost == 'solaris': eAudioDriverType = vboxcon.AudioDriverType_OSS;
2188 else:
2189 reporter.error('PORTME: Do not know which audio driver to pick for: %s!' % (sHost,));
2190 eAudioDriverType = vboxcon.AudioDriverType_Null;
2191
2192 try: oAudioAdapter.audioDriver = eAudioDriverType;
2193 except: return reporter.errorXcpt('Failed to set the audio driver to %s.' % (eAudioDriverType,))
2194
2195 try: oAudioAdapter.enabled = fEnable;
2196 except: return reporter.errorXcpt('Failed to set the "enabled" property to %s.' % (fEnable,));
2197
2198 reporter.log('set audio adapter type to %d, driver to %d, and enabled to %s'
2199 % (eAudioControllerType, eAudioDriverType, fEnable,));
2200 self.oTstDrv.processPendingEvents();
2201 return True;
2202
2203 def setupPreferredConfig(self): # pylint: disable=too-many-locals
2204 """
2205 Configures the VM according to the preferences of the guest type.
2206 """
2207 try:
2208 sOsTypeId = self.o.machine.OSTypeId;
2209 except:
2210 reporter.errorXcpt('failed to obtain the OSTypeId for "%s"' % (self.sName));
2211 return False;
2212
2213 try:
2214 oOsType = self.oVBox.getGuestOSType(sOsTypeId);
2215 except:
2216 reporter.errorXcpt('getGuestOSType("%s") failed for "%s"' % (sOsTypeId, self.sName));
2217 return False;
2218
2219 # get the attributes.
2220 try:
2221 #sFamilyId = oOsType.familyId;
2222 #f64Bit = oOsType.is64Bit;
2223 fIoApic = oOsType.recommendedIOAPIC;
2224 fVirtEx = oOsType.recommendedVirtEx;
2225 cMBRam = oOsType.recommendedRAM;
2226 cMBVRam = oOsType.recommendedVRAM;
2227 #cMBHdd = oOsType.recommendedHDD;
2228 eNicType = oOsType.adapterType;
2229 if self.fpApiVer >= 3.2:
2230 if self.fpApiVer >= 4.2:
2231 fPae = oOsType.recommendedPAE;
2232 fUsbHid = oOsType.recommendedUSBHID;
2233 fHpet = oOsType.recommendedHPET;
2234 eStorCtlType = oOsType.recommendedHDStorageController;
2235 else:
2236 fPae = oOsType.recommendedPae;
2237 fUsbHid = oOsType.recommendedUsbHid;
2238 fHpet = oOsType.recommendedHpet;
2239 eStorCtlType = oOsType.recommendedHdStorageController;
2240 eFirmwareType = oOsType.recommendedFirmware;
2241 else:
2242 fPae = False;
2243 fUsbHid = False;
2244 fHpet = False;
2245 eFirmwareType = -1;
2246 eStorCtlType = vboxcon.StorageControllerType_PIIX4;
2247 if self.fpApiVer >= 4.0:
2248 eAudioCtlType = oOsType.recommendedAudioController;
2249 except:
2250 reporter.errorXcpt('exception reading IGuestOSType(%s) attribute' % (sOsTypeId));
2251 self.oTstDrv.processPendingEvents();
2252 return False;
2253 self.oTstDrv.processPendingEvents();
2254
2255 # Do the setting. Continue applying settings on error in case the
2256 # caller ignores the return code
2257 fRc = True;
2258 if not self.enableIoApic(fIoApic): fRc = False;
2259 if not self.enableVirtEx(fVirtEx): fRc = False;
2260 if not self.enablePae(fPae): fRc = False;
2261 if not self.setRamSize(cMBRam): fRc = False;
2262 if not self.setVRamSize(cMBVRam): fRc = False;
2263 if not self.setNicType(eNicType, 0): fRc = False;
2264 if self.fpApiVer >= 3.2:
2265 if not self.setFirmwareType(eFirmwareType): fRc = False;
2266 if not self.enableUsbHid(fUsbHid): fRc = False;
2267 if not self.enableHpet(fHpet): fRc = False;
2268 if eStorCtlType in (vboxcon.StorageControllerType_PIIX3,
2269 vboxcon.StorageControllerType_PIIX4,
2270 vboxcon.StorageControllerType_ICH6,):
2271 if not self.setStorageControllerType(eStorCtlType, "IDE Controller"):
2272 fRc = False;
2273 if self.fpApiVer >= 4.0:
2274 if not self.setupAudio(eAudioCtlType): fRc = False;
2275
2276 return fRc;
2277
2278 def addUsbDeviceFilter(self, sName, sVendorId = None, sProductId = None, sRevision = None, # pylint: disable=too-many-arguments
2279 sManufacturer = None, sProduct = None, sSerialNumber = None,
2280 sPort = None, sRemote = None):
2281 """
2282 Creates a USB device filter and inserts it into the VM.
2283 Returns True on success.
2284 Returns False on failure (logged).
2285 """
2286 fRc = True;
2287
2288 try:
2289 oUsbDevFilter = self.o.machine.USBDeviceFilters.createDeviceFilter(sName);
2290 oUsbDevFilter.active = True;
2291 if sVendorId is not None:
2292 oUsbDevFilter.vendorId = sVendorId;
2293 if sProductId is not None:
2294 oUsbDevFilter.productId = sProductId;
2295 if sRevision is not None:
2296 oUsbDevFilter.revision = sRevision;
2297 if sManufacturer is not None:
2298 oUsbDevFilter.manufacturer = sManufacturer;
2299 if sProduct is not None:
2300 oUsbDevFilter.product = sProduct;
2301 if sSerialNumber is not None:
2302 oUsbDevFilter.serialnumber = sSerialNumber;
2303 if sPort is not None:
2304 oUsbDevFilter.port = sPort;
2305 if sRemote is not None:
2306 oUsbDevFilter.remote = sRemote;
2307 try:
2308 self.o.machine.USBDeviceFilters.insertDeviceFilter(0, oUsbDevFilter);
2309 except:
2310 reporter.errorXcpt('insertDeviceFilter(%s) failed on "%s"' \
2311 % (0, self.sName) );
2312 fRc = False;
2313 else:
2314 reporter.log('inserted USB device filter "%s" to %s' % (sName, self.sName));
2315 except:
2316 reporter.errorXcpt('createDeviceFilter("%s") failed on "%s"' \
2317 % (sName, self.sName) );
2318 fRc = False;
2319 return fRc;
2320
2321 def getGuestPropertyValue(self, sName):
2322 """
2323 Gets a guest property value.
2324 Returns the value on success, None on failure (logged).
2325 """
2326 try:
2327 sValue = self.o.machine.getGuestPropertyValue(sName);
2328 except:
2329 reporter.errorXcpt('IMachine::getGuestPropertyValue("%s") failed' % (sName));
2330 return None;
2331 return sValue;
2332
2333 def setGuestPropertyValue(self, sName, sValue):
2334 """
2335 Sets a guest property value.
2336 Returns the True on success, False on failure (logged).
2337 """
2338 try:
2339 self.o.machine.setGuestPropertyValue(sName, sValue);
2340 except:
2341 reporter.errorXcpt('IMachine::setGuestPropertyValue("%s","%s") failed' % (sName, sValue));
2342 return False;
2343 return True;
2344
2345 def delGuestPropertyValue(self, sName):
2346 """
2347 Deletes a guest property value.
2348 Returns the True on success, False on failure (logged).
2349 """
2350 try:
2351 oMachine = self.o.machine;
2352 if self.fpApiVer >= 4.2:
2353 oMachine.deleteGuestProperty(sName);
2354 else:
2355 oMachine.setGuestPropertyValue(sName, '');
2356 except:
2357 reporter.errorXcpt('Unable to delete guest property "%s"' % (sName,));
2358 return False;
2359 return True;
2360
2361 def setExtraData(self, sKey, sValue):
2362 """
2363 Sets extra data.
2364 Returns the True on success, False on failure (logged).
2365 """
2366 try:
2367 self.o.machine.setExtraData(sKey, sValue);
2368 except:
2369 reporter.errorXcpt('IMachine::setExtraData("%s","%s") failed' % (sKey, sValue));
2370 return False;
2371 return True;
2372
2373 def getExtraData(self, sKey):
2374 """
2375 Gets extra data.
2376 Returns value on success, None on failure.
2377 """
2378 try:
2379 sValue = self.o.machine.getExtraData(sKey)
2380 except:
2381 reporter.errorXcpt('IMachine::setExtraData("%s","%s") failed' % (sKey, sValue))
2382 return None
2383 return sValue
2384
2385 def setupTeleporter(self, fEnabled=True, uPort = 6500, sAddress = '', sPassword = ''):
2386 """
2387 Sets up the teleporter for the VM.
2388 Returns True on success, False on failure (logged).
2389 """
2390 try:
2391 self.o.machine.teleporterAddress = sAddress;
2392 self.o.machine.teleporterPort = uPort;
2393 self.o.machine.teleporterPassword = sPassword;
2394 self.o.machine.teleporterEnabled = fEnabled;
2395 except:
2396 reporter.errorXcpt('setupTeleporter(%s, %s, %s, %s)' % (fEnabled, sPassword, uPort, sAddress));
2397 return False;
2398 return True;
2399
2400 def enableTeleporter(self, fEnable=True):
2401 """
2402 Enables or disables the teleporter of the VM.
2403 Returns True on success, False on failure (logged).
2404 """
2405 try:
2406 self.o.machine.teleporterEnabled = fEnable;
2407 except:
2408 reporter.errorXcpt('IMachine::teleporterEnabled=%s failed' % (fEnable));
2409 return False;
2410 return True;
2411
2412 def teleport(self, sHostname = 'localhost', uPort = 6500, sPassword = 'password', cMsMaxDowntime = 250):
2413 """
2414 Wrapper around the IConsole::teleport() method.
2415 Returns a progress object on success, None on failure (logged).
2416 """
2417 reporter.log2('"%s"::teleport(%s,%s,%s,%s)...' % (self.sName, sHostname, uPort, sPassword, cMsMaxDowntime));
2418 try:
2419 oProgress = self.o.console.teleport(sHostname, uPort, sPassword, cMsMaxDowntime)
2420 except:
2421 reporter.errorXcpt('IConsole::teleport(%s,%s,%s,%s) failed' % (sHostname, uPort, sPassword, cMsMaxDowntime));
2422 return None;
2423 return ProgressWrapper(oProgress, self.oVBoxMgr, self.oTstDrv, 'teleport %s' % (self.sName,));
2424
2425 def getOsType(self):
2426 """
2427 Gets the IGuestOSType interface for the machine.
2428
2429 return IGuestOSType interface on success, None + errorXcpt on failure.
2430 No exceptions raised.
2431 """
2432 try:
2433 sOsTypeId = self.o.machine.OSTypeId;
2434 except:
2435 reporter.errorXcpt('failed to obtain the OSTypeId for "%s"' % (self.sName));
2436 return None;
2437
2438 try:
2439 oOsType = self.oVBox.getGuestOSType(sOsTypeId);
2440 except:
2441 reporter.errorXcpt('getGuestOSType("%s") failed for "%s"' % (sOsTypeId, self.sName));
2442 return None;
2443
2444 return oOsType;
2445
2446 def setOsType(self, sNewTypeId):
2447 """
2448 Changes the OS type.
2449
2450 returns True on success, False + errorXcpt on failure.
2451 No exceptions raised.
2452 """
2453 try:
2454 self.o.machine.OSTypeId = sNewTypeId;
2455 except:
2456 reporter.errorXcpt('failed to set the OSTypeId for "%s" to "%s"' % (self.sName, sNewTypeId));
2457 return False;
2458 return True;
2459
2460
2461 def setParavirtProvider(self, iProvider):
2462 """
2463 Sets a paravirtualisation provider.
2464 Returns the True on success, False on failure (logged).
2465 """
2466 try:
2467 self.o.machine.paravirtProvider = iProvider
2468 except:
2469 reporter.errorXcpt('Unable to set paravirtualisation provider "%s"' % (iProvider,))
2470 return False;
2471 return True;
2472
2473
2474 def setupSerialToRawFile(self, iSerialPort, sRawFile):
2475 """
2476 Enables the given serial port (zero based) and redirects it to sRawFile.
2477 Returns the True on success, False on failure (logged).
2478 """
2479 try:
2480 oPort = self.o.machine.getSerialPort(iSerialPort);
2481 except:
2482 fRc = reporter.errorXcpt('failed to get serial port #%u' % (iSerialPort,));
2483 else:
2484 try:
2485 oPort.path = sRawFile;
2486 except:
2487 fRc = reporter.errorXcpt('failed to set the "path" property on serial port #%u to "%s"'
2488 % (iSerialPort, sRawFile));
2489 else:
2490 try:
2491 oPort.hostMode = vboxcon.PortMode_RawFile;
2492 except:
2493 fRc = reporter.errorXcpt('failed to set the "hostMode" property on serial port #%u to PortMode_RawFile'
2494 % (iSerialPort,));
2495 else:
2496 try:
2497 oPort.enabled = True;
2498 except:
2499 fRc = reporter.errorXcpt('failed to set the "enable" property on serial port #%u to True'
2500 % (iSerialPort,));
2501 else:
2502 reporter.log('set SerialPort[%s].enabled/hostMode/path=True/RawFile/%s' % (iSerialPort, sRawFile,));
2503 fRc = True;
2504 self.oTstDrv.processPendingEvents();
2505 return fRc;
2506
2507
2508 def enableSerialPort(self, iSerialPort):
2509 """
2510 Enables the given serial port setting the initial port mode to disconnected.
2511 """
2512 try:
2513 oPort = self.o.machine.getSerialPort(iSerialPort);
2514 except:
2515 fRc = reporter.errorXcpt('failed to get serial port #%u' % (iSerialPort,));
2516 else:
2517 try:
2518 oPort.hostMode = vboxcon.PortMode_Disconnected;
2519 except:
2520 fRc = reporter.errorXcpt('failed to set the "hostMode" property on serial port #%u to PortMode_Disconnected'
2521 % (iSerialPort,));
2522 else:
2523 try:
2524 oPort.enabled = True;
2525 except:
2526 fRc = reporter.errorXcpt('failed to set the "enable" property on serial port #%u to True'
2527 % (iSerialPort,));
2528 else:
2529 reporter.log('set SerialPort[%s].enabled/hostMode/=True/Disconnected' % (iSerialPort,));
2530 fRc = True;
2531 self.oTstDrv.processPendingEvents();
2532 return fRc;
2533
2534
2535 def changeSerialPortAttachment(self, iSerialPort, ePortMode, sPath, fServer):
2536 """
2537 Changes the attachment of the given serial port to the attachment config given.
2538 """
2539 try:
2540 oPort = self.o.machine.getSerialPort(iSerialPort);
2541 except:
2542 fRc = reporter.errorXcpt('failed to get serial port #%u' % (iSerialPort,));
2543 else:
2544 try:
2545 # Change port mode to disconnected first so changes get picked up by a potentially running VM.
2546 oPort.hostMode = vboxcon.PortMode_Disconnected;
2547 except:
2548 fRc = reporter.errorXcpt('failed to set the "hostMode" property on serial port #%u to PortMode_Disconnected'
2549 % (iSerialPort,));
2550 else:
2551 try:
2552 oPort.path = sPath;
2553 oPort.server = fServer;
2554 oPort.hostMode = ePortMode;
2555 except:
2556 fRc = reporter.errorXcpt('failed to configure the serial port');
2557 else:
2558 reporter.log('set SerialPort[%s].hostMode/path/server=%s/%s/%s'
2559 % (iSerialPort, ePortMode, sPath, fServer));
2560 fRc = True;
2561 self.oTstDrv.processPendingEvents();
2562 return fRc;
2563
2564 #
2565 # IConsole wrappers.
2566 #
2567
2568 def powerOff(self, fFudgeOnFailure = True):
2569 """
2570 Powers off the VM.
2571
2572 Returns True on success.
2573 Returns False on IConsole::powerDown() failure.
2574 Returns None if the progress object returns failure.
2575 """
2576 #
2577 # Deregister event handler before we power off the VM, otherwise we're
2578 # racing for VM process termination and cause misleading spurious
2579 # error messages in the event handling code, because the event objects
2580 # disappear.
2581 #
2582 # Note! Doing this before powerDown to try prevent numerous smoketest
2583 # timeouts on XPCOM hosts.
2584 #
2585 self.deregisterEventHandlerForTask();
2586
2587
2588 # Try power if off.
2589 try:
2590 oProgress = self.o.console.powerDown();
2591 except:
2592 reporter.logXcpt('IConsole::powerDown failed on %s' % (self.sName));
2593 if fFudgeOnFailure:
2594 self.oTstDrv.waitOnDirectSessionClose(self.oVM, 5000); # fudge
2595 self.waitForTask(1000); # fudge
2596 return False;
2597
2598 # Wait on power off operation to complete.
2599 rc = self.oTstDrv.waitOnProgress(oProgress);
2600 if rc < 0:
2601 self.close();
2602 if fFudgeOnFailure:
2603 vbox.reportError(oProgress, 'powerDown for "%s" failed' % (self.sName));
2604 self.oTstDrv.waitOnDirectSessionClose(self.oVM, 5000); # fudge
2605 return None;
2606
2607 # Wait for the VM to really power off or we'll fail to open a new session to it.
2608 self.oTstDrv.waitOnDirectSessionClose(self.oVM, 5000); # fudge
2609 return self.waitForTask(30 * 1000); # fudge
2610
2611 def saveState(self, fPause = True):
2612 """
2613 Saves state of the VM.
2614
2615 Returns True on success.
2616 Returns False on IConsole::saveState() failure.
2617 Returns None if the progress object returns Failure.
2618 """
2619
2620 if fPause is True \
2621 and self.oVM.state is vboxcon.MachineState_Running:
2622 self.o.console.pause();
2623 if self.oVM.state is not vboxcon.MachineState_Paused:
2624 reporter.error('pause for "%s" failed' % (self.sName));
2625 # Try saving state.
2626 try:
2627 if self.fpApiVer >= 5.0:
2628 oProgress = self.o.machine.saveState()
2629 else:
2630 oProgress = self.o.console.saveState()
2631 except:
2632 reporter.logXcpt('IMachine::saveState failed on %s' % (self.sName));
2633 return False;
2634
2635 # Wait for saving state operation to complete.
2636 rc = self.oTstDrv.waitOnProgress(oProgress);
2637 if rc < 0:
2638 self.close();
2639 return None;
2640
2641 # Wait for the VM to really terminate or we'll fail to open a new session to it.
2642 self.oTstDrv.waitOnDirectSessionClose(self.oVM, 5000); # fudge
2643 return self.waitForTask(30 * 1000); # fudge
2644
2645 def discardSavedState(self, fRemove = True):
2646 """
2647 Discards saved state of the VM.
2648
2649 Returns True on success.
2650 Returns False on IConsole::discardSaveState() failure.
2651 """
2652
2653 try:
2654 if self.fpApiVer >= 5.0:
2655 self.o.machine.discardSavedState(fRemove)
2656 else:
2657 self.o.console.discardSavedState(fRemove)
2658 except:
2659 reporter.logXcpt('IMachine::discardSavedState failed on %s' % (self.sName))
2660 return False
2661 return True
2662
2663 def restoreSnapshot(self, oSnapshot, fFudgeOnFailure = True):
2664 """
2665 Restores the given snapshot.
2666
2667 Returns True on success.
2668 Returns False on IMachine::restoreSnapshot() failure.
2669 Returns None if the progress object returns failure.
2670 """
2671 try:
2672 if self.fpApiVer >= 5.0:
2673 oProgress = self.o.machine.restoreSnapshot(oSnapshot);
2674 else:
2675 oProgress = self.o.console.restoreSnapshot(oSnapshot);
2676 except:
2677 reporter.logXcpt('IMachine::restoreSnapshot failed on %s' % (self.sName));
2678 if fFudgeOnFailure:
2679 self.oTstDrv.waitOnDirectSessionClose(self.oVM, 5000); # fudge
2680 self.waitForTask(1000); # fudge
2681 return False;
2682
2683 rc = self.oTstDrv.waitOnProgress(oProgress);
2684 if rc < 0:
2685 self.close();
2686 if fFudgeOnFailure:
2687 vbox.reportError(oProgress, 'restoreSnapshot for "%s" failed' % (self.sName));
2688 return None;
2689
2690 return self.waitForTask(30 * 1000);
2691
2692 def deleteSnapshot(self, oSnapshot, fFudgeOnFailure = True, cMsTimeout = 30 * 1000):
2693 """
2694 Deletes the given snapshot merging the diff image into the base.
2695
2696 Returns True on success.
2697 Returns False on IMachine::deleteSnapshot() failure.
2698 """
2699 try:
2700 if self.fpApiVer >= 5.0:
2701 oProgressCom = self.o.machine.deleteSnapshot(oSnapshot);
2702 else:
2703 oProgressCom = self.o.console.deleteSnapshot(oSnapshot);
2704 oProgress = ProgressWrapper(oProgressCom, self.oVBoxMgr, self.oTstDrv, 'Delete Snapshot %s' % (oSnapshot));
2705 oProgress.wait(cMsTimeout);
2706 oProgress.logResult();
2707 except:
2708 reporter.logXcpt('IMachine::deleteSnapshot failed on %s' % (self.sName));
2709 if fFudgeOnFailure:
2710 self.oTstDrv.waitOnDirectSessionClose(self.oVM, 5000); # fudge
2711 self.waitForTask(1000); # fudge
2712 return False;
2713
2714 return True;
2715
2716 def takeSnapshot(self, sName, sDescription = '', fPause = True, fFudgeOnFailure = True, cMsTimeout = 30 * 1000):
2717 """
2718 Takes a snapshot with the given name
2719
2720 Returns True on success.
2721 Returns False on IMachine::takeSnapshot() or VM state change failure.
2722 """
2723 try:
2724 if fPause is True \
2725 and self.oVM.state is vboxcon.MachineState_Running:
2726 self.o.console.pause();
2727 if self.fpApiVer >= 5.0:
2728 (oProgressCom, _) = self.o.machine.takeSnapshot(sName, sDescription, True);
2729 else:
2730 oProgressCom = self.o.console.takeSnapshot(sName, sDescription);
2731 oProgress = ProgressWrapper(oProgressCom, self.oVBoxMgr, self.oTstDrv, 'Take Snapshot %s' % (sName));
2732 oProgress.wait(cMsTimeout);
2733 oProgress.logResult();
2734 except:
2735 reporter.logXcpt('IMachine::takeSnapshot failed on %s' % (self.sName));
2736 if fFudgeOnFailure:
2737 self.oTstDrv.waitOnDirectSessionClose(self.oVM, 5000); # fudge
2738 self.waitForTask(1000); # fudge
2739 return False;
2740
2741 if fPause is True \
2742 and self.oVM.state is vboxcon.MachineState_Paused:
2743 self.o.console.resume();
2744
2745 return True;
2746
2747 def findSnapshot(self, sName):
2748 """
2749 Returns the snapshot object with the given name
2750
2751 Returns snapshot object on success.
2752 Returns None if there is no snapshot with the given name.
2753 """
2754 return self.oVM.findSnapshot(sName);
2755
2756 def takeScreenshot(self, sFilename, iScreenId=0):
2757 """
2758 Take screenshot from the given display and save it to specified file.
2759
2760 Returns True on success
2761 Returns False on failure.
2762 """
2763 try:
2764 if self.fpApiVer >= 5.0:
2765 iWidth, iHeight, _, _, _, _ = self.o.console.display.getScreenResolution(iScreenId)
2766 aPngData = self.o.console.display.takeScreenShotToArray(iScreenId, iWidth, iHeight,
2767 vboxcon.BitmapFormat_PNG)
2768 else:
2769 iWidth, iHeight, _, _, _ = self.o.console.display.getScreenResolution(iScreenId)
2770 aPngData = self.o.console.display.takeScreenShotPNGToArray(iScreenId, iWidth, iHeight)
2771 except:
2772 reporter.logXcpt("Unable to take screenshot")
2773 return False
2774
2775 oFile = open(sFilename, 'wb')
2776 oFile.write(aPngData)
2777 oFile.close()
2778
2779 return True
2780
2781 def attachUsbDevice(self, sUuid, sCaptureFilename = None):
2782 """
2783 Attach given USB device UUID to the VM.
2784
2785 Returns True on success
2786 Returns False on failure.
2787 """
2788 fRc = True;
2789 try:
2790 if sCaptureFilename is None:
2791 self.o.console.attachUSBDevice(sUuid, '');
2792 else:
2793 self.o.console.attachUSBDevice(sUuid, sCaptureFilename);
2794 except:
2795 reporter.logXcpt('Unable to attach USB device %s' % (sUuid,));
2796 fRc = False;
2797
2798 return fRc;
2799
2800 def detachUsbDevice(self, sUuid):
2801 """
2802 Detach given USB device UUID from the VM.
2803
2804 Returns True on success
2805 Returns False on failure.
2806 """
2807 fRc = True;
2808 try:
2809 _ = self.o.console.detachUSBDevice(sUuid);
2810 except:
2811 reporter.logXcpt('Unable to detach USB device %s' % (sUuid,));
2812 fRc = False;
2813
2814 return fRc;
2815
2816
2817 #
2818 # IMachineDebugger wrappers.
2819 #
2820
2821 def queryOsKernelLog(self):
2822 """
2823 Tries to get the OS kernel log using the VM debugger interface.
2824
2825 Returns string containing the kernel log on success.
2826 Returns None on failure.
2827 """
2828 sOsKernelLog = None;
2829 try:
2830 self.o.console.debugger.loadPlugIn('all');
2831 except:
2832 reporter.logXcpt('Unable to load debugger plugins');
2833 else:
2834 try:
2835 sOsDetected = self.o.console.debugger.detectOS();
2836 except:
2837 reporter.logXcpt('Failed to detect the guest OS');
2838 else:
2839 try:
2840 sOsKernelLog = self.o.console.debugger.queryOSKernelLog(0);
2841 except:
2842 reporter.logXcpt('Unable to get the guest OS (%s) kernel log' % (sOsDetected,));
2843 return sOsKernelLog;
2844
2845 def queryDbgInfo(self, sItem, sArg = '', sDefault = None):
2846 """
2847 Simple wrapper around IMachineDebugger::info.
2848
2849 Returns string on success, sDefault on failure (logged).
2850 """
2851 try:
2852 return self.o.console.debugger.info(sItem, sArg);
2853 except:
2854 reporter.logXcpt('Unable to query "%s" with arg "%s"' % (sItem, sArg,));
2855 return sDefault;
2856
2857 def queryDbgInfoVgaText(self, sArg = 'all'):
2858 """
2859 Tries to get the 'info vgatext' output, provided we're in next mode.
2860
2861 Returns string containing text on success.
2862 Returns None on failure or not text mode.
2863 """
2864 sVgaText = None;
2865 try:
2866 sVgaText = self.o.console.debugger.info('vgatext', sArg);
2867 if sVgaText.startswith('Not in text mode!'):
2868 sVgaText = None;
2869 except:
2870 reporter.logXcpt('Unable to query vgatext with arg "%s"' % (sArg,));
2871 return sVgaText;
2872
2873 def queryDbgGuestStack(self, iCpu = 0):
2874 """
2875 Returns the guest stack for the given VCPU.
2876
2877 Returns string containing the guest stack for the selected VCPU on success.
2878 Returns None on failure.
2879 """
2880
2881 #
2882 # Load all plugins first and try to detect the OS so we can
2883 # get nicer stack traces.
2884 #
2885 try:
2886 self.o.console.debugger.loadPlugIn('all');
2887 except:
2888 reporter.logXcpt('Unable to load debugger plugins');
2889 else:
2890 try:
2891 sOsDetected = self.o.console.debugger.detectOS();
2892 _ = sOsDetected;
2893 except:
2894 reporter.logXcpt('Failed to detect the guest OS');
2895
2896 sGuestStack = None;
2897 try:
2898 sGuestStack = self.o.console.debugger.dumpGuestStack(iCpu);
2899 except:
2900 reporter.logXcpt('Unable to query guest stack for CPU %s' % (iCpu, ));
2901
2902 return sGuestStack;
2903
2904
2905 #
2906 # Other methods.
2907 #
2908
2909 def getPrimaryIp(self):
2910 """
2911 Tries to obtain the primary IP address of the guest via the guest
2912 properties.
2913
2914 Returns IP address on success.
2915 Returns empty string on failure.
2916 """
2917 sIpAddr = self.getGuestPropertyValue('/VirtualBox/GuestInfo/Net/0/V4/IP');
2918 if vbox.isIpAddrValid(sIpAddr):
2919 return sIpAddr;
2920 return '';
2921
2922 def getPid(self):
2923 """
2924 Gets the process ID for the direct session unless it's ourselves.
2925 """
2926 if self.uPid is None and self.o is not None and self.fRemoteSession:
2927 try:
2928 if self.fpApiVer >= 4.2:
2929 uPid = self.o.machine.sessionPID;
2930 else:
2931 uPid = self.o.machine.sessionPid;
2932 if uPid != os.getpid() and uPid != 0xffffffff:
2933 self.uPid = uPid;
2934 except Exception as oXcpt:
2935 if vbox.ComError.equal(oXcpt, vbox.ComError.E_UNEXPECTED):
2936 try:
2937 if self.fpApiVer >= 4.2:
2938 uPid = self.oVM.sessionPID;
2939 else:
2940 uPid = self.oVM.sessionPid;
2941 if uPid != os.getpid() and uPid != 0xffffffff:
2942 self.uPid = uPid;
2943 except:
2944 reporter.log2Xcpt();
2945 else:
2946 reporter.log2Xcpt();
2947 if self.uPid is not None:
2948 reporter.log2('getPid: %u' % (self.uPid,));
2949 self.fPidFile = self.oTstDrv.pidFileAdd(self.uPid, 'vm_%s' % (self.sName,), # Set-uid-to-root is similar to SUDO.
2950 fSudo = True);
2951 return self.uPid;
2952
2953 def addLogsToReport(self, cReleaseLogs = 1):
2954 """
2955 Retrieves and adds the release and debug logs to the test report.
2956 """
2957 fRc = True;
2958
2959 # Add each of the requested release logs to the report.
2960 for iLog in range(0, cReleaseLogs):
2961 try:
2962 if self.fpApiVer >= 3.2:
2963 sLogFile = self.oVM.queryLogFilename(iLog);
2964 elif iLog > 0:
2965 sLogFile = '%s/VBox.log' % (self.oVM.logFolder,);
2966 else:
2967 sLogFile = '%s/VBox.log.%u' % (self.oVM.logFolder, iLog);
2968 except:
2969 reporter.logXcpt('iLog=%s' % (iLog,));
2970 fRc = False;
2971 else:
2972 if sLogFile is not None and sLogFile != '': # the None bit is for a 3.2.0 bug.
2973 reporter.addLogFile(sLogFile, 'log/release/vm', '%s #%u' % (self.sName, iLog),
2974 sAltName = '%s-%s' % (self.sName, os.path.basename(sLogFile),));
2975
2976 # Now for the hardened windows startup log.
2977 try:
2978 sLogFile = os.path.join(self.oVM.logFolder, 'VBoxHardening.log');
2979 except:
2980 reporter.logXcpt();
2981 fRc = False;
2982 else:
2983 if os.path.isfile(sLogFile):
2984 reporter.addLogFile(sLogFile, 'log/release/vm', '%s hardening log' % (self.sName, ),
2985 sAltName = '%s-%s' % (self.sName, os.path.basename(sLogFile),));
2986
2987 # Now for the debug log.
2988 if self.sLogFile is not None and os.path.isfile(self.sLogFile):
2989 reporter.addLogFile(self.sLogFile, 'log/debug/vm', '%s debug' % (self.sName, ),
2990 sAltName = '%s-%s' % (self.sName, os.path.basename(self.sLogFile),));
2991
2992 return fRc;
2993
2994 def registerDerivedEventHandler(self, oSubClass, dArgs = None, fMustSucceed = True):
2995 """
2996 Create an instance of the given ConsoleEventHandlerBase sub-class and
2997 register it.
2998
2999 The new instance is returned on success. None is returned on error.
3000 """
3001
3002 # We need a console object.
3003 try:
3004 oConsole = self.o.console;
3005 except Exception as oXcpt:
3006 if fMustSucceed or vbox.ComError.notEqual(oXcpt, vbox.ComError.E_UNEXPECTED):
3007 reporter.errorXcpt('Failed to get ISession::console for "%s"' % (self.sName, ));
3008 return None;
3009
3010 # Add the base class arguments.
3011 dArgsCopy = dArgs.copy() if dArgs is not None else dict();
3012 dArgsCopy['oSession'] = self;
3013 dArgsCopy['oConsole'] = oConsole;
3014 sLogSuffix = 'on %s' % (self.sName,)
3015 return oSubClass.registerDerivedEventHandler(self.oVBoxMgr, self.fpApiVer, oSubClass, dArgsCopy,
3016 oConsole, 'IConsole', 'IConsoleCallback',
3017 fMustSucceed = fMustSucceed, sLogSuffix = sLogSuffix);
3018
3019 def enableVmmDevTestingPart(self, fEnabled, fEnableMMIO = False):
3020 """
3021 Enables the testing part of the VMMDev.
3022
3023 Returns True on success and False on failure. Error information is logged.
3024 """
3025 fRc = True;
3026 try:
3027 self.o.machine.setExtraData('VBoxInternal/Devices/VMMDev/0/Config/TestingEnabled',
3028 '1' if fEnabled else '');
3029 self.o.machine.setExtraData('VBoxInternal/Devices/VMMDev/0/Config/TestingMMIO',
3030 '1' if fEnableMMIO and fEnabled else '');
3031 except:
3032 reporter.errorXcpt('VM name "%s", fEnabled=%s' % (self.sName, fEnabled));
3033 fRc = False;
3034 else:
3035 reporter.log('set VMMDevTesting=%s for "%s"' % (fEnabled, self.sName));
3036 self.oTstDrv.processPendingEvents();
3037 return fRc;
3038
3039 #
3040 # Test eXecution Service methods.
3041 #
3042
3043 def txsConnectViaTcp(self, cMsTimeout = 10*60000, sIpAddr = None, fNatForwardingForTxs = False):
3044 """
3045 Connects to the TXS using TCP/IP as transport. If no IP or MAC is
3046 addresses are specified, we'll get the IP from the guest additions.
3047
3048 Returns a TxsConnectTask object on success, None + log on failure.
3049 """
3050 # If the VM is configured with a NAT interface, connect to local host.
3051 fReversedSetup = False;
3052 fUseNatForTxs = False;
3053 sMacAddr = None;
3054 oIDhcpServer = None;
3055 if sIpAddr is None:
3056 try:
3057 oNic = self.oVM.getNetworkAdapter(0);
3058 enmAttachmentType = oNic.attachmentType;
3059 if enmAttachmentType == vboxcon.NetworkAttachmentType_NAT:
3060 fUseNatForTxs = True;
3061 elif enmAttachmentType == vboxcon.NetworkAttachmentType_HostOnly and not sIpAddr:
3062 # Get the MAC address and find the DHCP server.
3063 sMacAddr = oNic.MACAddress;
3064 sHostOnlyNIC = oNic.hostOnlyInterface;
3065 oIHostOnlyIf = self.oVBox.host.findHostNetworkInterfaceByName(sHostOnlyNIC);
3066 sHostOnlyNet = oIHostOnlyIf.networkName;
3067 oIDhcpServer = self.oVBox.findDHCPServerByNetworkName(sHostOnlyNet);
3068 except:
3069 reporter.errorXcpt();
3070 return None;
3071
3072 if fUseNatForTxs:
3073 fReversedSetup = not fNatForwardingForTxs;
3074 sIpAddr = '127.0.0.1';
3075
3076 # Kick off the task.
3077 try:
3078 oTask = TxsConnectTask(self, cMsTimeout, sIpAddr, sMacAddr, oIDhcpServer, fReversedSetup,
3079 fnProcessEvents = self.oTstDrv.processPendingEvents);
3080 except:
3081 reporter.errorXcpt();
3082 oTask = None;
3083 return oTask;
3084
3085 def txsTryConnectViaTcp(self, cMsTimeout, sHostname, fReversed = False):
3086 """
3087 Attempts to connect to a TXS instance.
3088
3089 Returns True if a connection was established, False if not (only grave
3090 failures are logged as errors).
3091
3092 Note! The timeout is more of a guideline...
3093 """
3094
3095 if sHostname is None or sHostname.strip() == '':
3096 raise base.GenError('Empty sHostname is not implemented yet');
3097
3098 oTxsSession = txsclient.tryOpenTcpSession(cMsTimeout, sHostname, fReversedSetup = fReversed,
3099 cMsIdleFudge = cMsTimeout // 2,
3100 fnProcessEvents = self.oTstDrv.processPendingEvents);
3101 if oTxsSession is None:
3102 return False;
3103
3104 # Wait for the connect task to time out.
3105 self.oTstDrv.addTask(oTxsSession);
3106 self.oTstDrv.processPendingEvents();
3107 oRc = self.oTstDrv.waitForTasks(cMsTimeout);
3108 self.oTstDrv.removeTask(oTxsSession);
3109 if oRc != oTxsSession:
3110 if oRc is not None:
3111 reporter.log('oRc=%s, expected %s' % (oRc, oTxsSession));
3112 self.oTstDrv.processPendingEvents();
3113 oTxsSession.cancelTask(); # this is synchronous
3114 return False;
3115
3116 # Check the status.
3117 reporter.log2('TxsSession is ready, isSuccess() -> %s.' % (oTxsSession.isSuccess(),));
3118 if not oTxsSession.isSuccess():
3119 return False;
3120
3121 reporter.log2('Disconnecting from TXS...');
3122 return oTxsSession.syncDisconnect();
3123
3124
3125
3126class TxsConnectTask(TdTaskBase):
3127 """
3128 Class that takes care of connecting to a VM.
3129 """
3130
3131 class TxsConnectTaskVBoxCallback(vbox.VirtualBoxEventHandlerBase):
3132 """ Class for looking for IPv4 address changes on interface 0."""
3133 def __init__(self, dArgs):
3134 vbox.VirtualBoxEventHandlerBase.__init__(self, dArgs);
3135 self.oParentTask = dArgs['oParentTask'];
3136 self.sMachineId = dArgs['sMachineId'];
3137
3138 def onGuestPropertyChange(self, sMachineId, sName, sValue, sFlags):
3139 """Look for IP address."""
3140 reporter.log2('onGuestPropertyChange(,%s,%s,%s,%s)' % (sMachineId, sName, sValue, sFlags));
3141 if sMachineId == self.sMachineId \
3142 and sName == '/VirtualBox/GuestInfo/Net/0/V4/IP':
3143 oParentTask = self.oParentTask;
3144 if oParentTask:
3145 oParentTask._setIp(sValue); # pylint: disable=protected-access
3146
3147
3148 def __init__(self, oSession, cMsTimeout, sIpAddr, sMacAddr, oIDhcpServer, fReversedSetup, fnProcessEvents = None):
3149 TdTaskBase.__init__(self, utils.getCallerName(), fnProcessEvents = fnProcessEvents);
3150 self.cMsTimeout = cMsTimeout;
3151 self.fnProcessEvents = fnProcessEvents;
3152 self.sIpAddr = None;
3153 self.sNextIpAddr = None;
3154 self.sMacAddr = sMacAddr;
3155 self.oIDhcpServer = oIDhcpServer;
3156 self.fReversedSetup = fReversedSetup;
3157 self.oVBoxEventHandler = None;
3158 self.oTxsSession = None;
3159
3160 # Check that the input makes sense:
3161 if (sMacAddr is None) != (oIDhcpServer is None) \
3162 or (sMacAddr and fReversedSetup) \
3163 or (sMacAddr and sIpAddr):
3164 reporter.error('TxsConnectTask sMacAddr=%s oIDhcpServer=%s sIpAddr=%s fReversedSetup=%s'
3165 % (sMacAddr, oIDhcpServer, sIpAddr, fReversedSetup,));
3166 raise base.GenError();
3167
3168 reporter.log2('TxsConnectTask: sIpAddr=%s fReversedSetup=%s' % (sIpAddr, fReversedSetup))
3169 if fReversedSetup is True:
3170 self._openTcpSession(sIpAddr, fReversedSetup = True);
3171 elif sIpAddr is not None and sIpAddr.strip() != '':
3172 self._openTcpSession(sIpAddr, cMsIdleFudge = 5000);
3173 else:
3174 #
3175 # If we've got no IP address, register callbacks that listens for
3176 # the primary network adaptor of the VM to set a IPv4 guest prop.
3177 # Note! The order in which things are done here is kind of important.
3178 #
3179
3180 # 0. The caller zaps the property before starting the VM.
3181 #try:
3182 # oSession.delGuestPropertyValue('/VirtualBox/GuestInfo/Net/0/V4/IP');
3183 #except:
3184 # reporter.logXcpt();
3185
3186 # 1. Register the callback / event listener object.
3187 dArgs = {'oParentTask':self, 'sMachineId':oSession.o.machine.id};
3188 self.oVBoxEventHandler = oSession.oVBox.registerDerivedEventHandler(self.TxsConnectTaskVBoxCallback, dArgs);
3189
3190 # 2. Query the guest properties.
3191 try:
3192 sIpAddr = oSession.getGuestPropertyValue('/VirtualBox/GuestInfo/Net/0/V4/IP');
3193 except:
3194 reporter.errorXcpt('IMachine::getGuestPropertyValue("/VirtualBox/GuestInfo/Net/0/V4/IP") failed');
3195 self._deregisterEventHandler();
3196 raise;
3197 else:
3198 if sIpAddr is not None:
3199 self._setIp(sIpAddr);
3200
3201 #
3202 # If the network adapter of the VM is host-only we can talk poll IDHCPServer
3203 # for the guest IP, allowing us to detect it for VMs without guest additions.
3204 # This will when we're polled.
3205 #
3206 if sMacAddr is not None:
3207 assert self.oIDhcpServer is not None;
3208
3209
3210 # end __init__
3211
3212 def __del__(self):
3213 """ Make sure we deregister the callback. """
3214 self._deregisterEventHandler();
3215 return TdTaskBase.__del__(self);
3216
3217 def toString(self):
3218 return '<%s cMsTimeout=%s, sIpAddr=%s, sNextIpAddr=%s, sMacAddr=%s, fReversedSetup=%s,' \
3219 ' oTxsSession=%s oVBoxEventHandler=%s>' \
3220 % (TdTaskBase.toString(self), self.cMsTimeout, self.sIpAddr, self.sNextIpAddr, self.sMacAddr, self.fReversedSetup,
3221 self.oTxsSession, self.oVBoxEventHandler);
3222
3223 def _deregisterEventHandler(self):
3224 """Deregisters the event handler."""
3225 fRc = True;
3226 oVBoxEventHandler = self.oVBoxEventHandler;
3227 if oVBoxEventHandler is not None:
3228 self.oVBoxEventHandler = None;
3229 fRc = oVBoxEventHandler.unregister();
3230 oVBoxEventHandler.oParentTask = None; # Try avoid cylic deps.
3231 return fRc;
3232
3233 def _setIp(self, sIpAddr, fInitCall = False):
3234 """Called when we get an IP. Will create a TXS session and signal the task."""
3235 sIpAddr = sIpAddr.strip();
3236
3237 if sIpAddr is not None \
3238 and sIpAddr != '':
3239 if vbox.isIpAddrValid(sIpAddr) or fInitCall:
3240 try:
3241 for s in sIpAddr.split('.'):
3242 i = int(s);
3243 if str(i) != s:
3244 raise Exception();
3245 except:
3246 reporter.fatalXcpt();
3247 else:
3248 reporter.log('TxsConnectTask: opening session to ip "%s"' % (sIpAddr));
3249 self._openTcpSession(sIpAddr, cMsIdleFudge = 5000);
3250 return None;
3251
3252 reporter.log('TxsConnectTask: Ignoring Bad ip "%s"' % (sIpAddr));
3253 else:
3254 reporter.log2('TxsConnectTask: Ignoring empty ip "%s"' % (sIpAddr));
3255 return None;
3256
3257 def _openTcpSession(self, sIpAddr, uPort = None, fReversedSetup = False, cMsIdleFudge = 0):
3258 """
3259 Calls txsclient.openTcpSession and switches our task to reflect the
3260 state of the subtask.
3261 """
3262 self.oCv.acquire();
3263 if self.oTxsSession is None:
3264 reporter.log2('_openTcpSession: sIpAddr=%s, uPort=%d, fReversedSetup=%s' %
3265 (sIpAddr, uPort if uPort is not None else 0, fReversedSetup));
3266 self.sIpAddr = sIpAddr;
3267 self.oTxsSession = txsclient.openTcpSession(self.cMsTimeout, sIpAddr, uPort, fReversedSetup,
3268 cMsIdleFudge, fnProcessEvents = self.fnProcessEvents);
3269 self.oTxsSession.setTaskOwner(self);
3270 else:
3271 self.sNextIpAddr = sIpAddr;
3272 reporter.log2('_openTcpSession: sNextIpAddr=%s' % (sIpAddr,));
3273 self.oCv.release();
3274 return None;
3275
3276 def notifyAboutReadyTask(self, oTxsSession):
3277 """
3278 Called by the TXS session task when it's done.
3279
3280 We'll signal the task completed or retry depending on the result.
3281 """
3282
3283 self.oCv.acquire();
3284
3285 # Disassociate ourselves with the session (avoid cyclic ref)
3286 oTxsSession.setTaskOwner(None);
3287 fSuccess = oTxsSession.isSuccess();
3288 if self.oTxsSession is not None:
3289 if not fSuccess:
3290 self.oTxsSession = None;
3291 if fSuccess and self.fReversedSetup:
3292 self.sIpAddr = oTxsSession.oTransport.sHostname;
3293 else:
3294 fSuccess = False;
3295
3296 # Signal done, or retry?
3297 fDeregister = False;
3298 if fSuccess \
3299 or self.fReversedSetup \
3300 or self.getAgeAsMs() >= self.cMsTimeout:
3301 self.signalTaskLocked();
3302 fDeregister = True;
3303 else:
3304 sIpAddr = self.sNextIpAddr if self.sNextIpAddr is not None else self.sIpAddr;
3305 self._openTcpSession(sIpAddr, cMsIdleFudge = 5000);
3306
3307 self.oCv.release();
3308
3309 # If we're done, deregister the callback (w/o owning lock). It will
3310 if fDeregister:
3311 self._deregisterEventHandler();
3312 return True;
3313
3314 def _pollDhcpServer(self):
3315 """
3316 Polls the DHCP server by MAC address in host-only setups.
3317 """
3318
3319 if self.sIpAddr:
3320 return False;
3321
3322 if self.oIDhcpServer is None or not self.sMacAddr:
3323 return False;
3324
3325 try:
3326 (sIpAddr, sState, secIssued, secExpire) = self.oIDhcpServer.findLeaseByMAC(self.sMacAddr, 0);
3327 except:
3328 reporter.log4Xcpt('sMacAddr=%s' % (self.sMacAddr,));
3329 return False;
3330
3331 secNow = utils.secondsSinceUnixEpoch();
3332 reporter.log2('dhcp poll: secNow=%s secExpire=%s secIssued=%s sState=%s sIpAddr=%s'
3333 % (secNow, secExpire, secIssued, sState, sIpAddr,));
3334 if secNow > secExpire or sState != 'acked' or not sIpAddr:
3335 return False;
3336
3337 reporter.log('dhcp poll: sIpAddr=%s secExpire=%s (%s TTL) secIssued=%s (%s ago)'
3338 % (sIpAddr, secExpire, secExpire - secNow, secIssued, secNow - secIssued,));
3339 self._setIp(sIpAddr);
3340 return True;
3341
3342 #
3343 # Task methods
3344 #
3345
3346 def pollTask(self, fLocked = False):
3347 """
3348 Overridden pollTask method.
3349 """
3350 self._pollDhcpServer();
3351 return TdTaskBase.pollTask(self, fLocked);
3352
3353 #
3354 # Public methods
3355 #
3356
3357 def getResult(self):
3358 """
3359 Returns the connected TXS session object on success.
3360 Returns None on failure or if the task has not yet completed.
3361 """
3362 self.oCv.acquire();
3363 oTxsSession = self.oTxsSession;
3364 self.oCv.release();
3365
3366 if oTxsSession is not None and not oTxsSession.isSuccess():
3367 oTxsSession = None;
3368 return oTxsSession;
3369
3370 def cancelTask(self):
3371 """ Cancels the task. """
3372 self._deregisterEventHandler(); # (make sure to avoid cyclic fun)
3373 self.oCv.acquire();
3374 if not self.fSignalled:
3375 oTxsSession = self.oTxsSession;
3376 if oTxsSession is not None:
3377 self.oCv.release();
3378 oTxsSession.setTaskOwner(None);
3379 oTxsSession.cancelTask();
3380 oTxsSession.waitForTask(1000);
3381 self.oCv.acquire();
3382 self.signalTaskLocked();
3383 self.oCv.release();
3384 return True;
3385
3386
3387
3388class AdditionsStatusTask(TdTaskBase):
3389 """
3390 Class that takes care of waiting till the guest additions are in a given state.
3391 """
3392
3393 class AdditionsStatusTaskCallback(vbox.EventHandlerBase):
3394 """ Class for looking for IPv4 address changes on interface 0."""
3395 def __init__(self, dArgs):
3396 self.oParentTask = dArgs['oParentTask'];
3397 vbox.EventHandlerBase.__init__(self, dArgs, self.oParentTask.oSession.fpApiVer,
3398 'AdditionsStatusTaskCallback/%s' % (self.oParentTask.oSession.sName,));
3399
3400 def handleEvent(self, oEvt):
3401 try:
3402 enmType = oEvt.type;
3403 except:
3404 reporter.errorXcpt();
3405 else:
3406 reporter.log2('AdditionsStatusTaskCallback:handleEvent: enmType=%s' % (enmType,));
3407 if enmType == vboxcon.VBoxEventType_OnGuestAdditionsStatusChanged:
3408 oParentTask = self.oParentTask;
3409 if oParentTask:
3410 oParentTask.pollTask();
3411
3412 # end
3413
3414
3415 def __init__(self, oSession, oIGuest, cMsTimeout = 120000, aenmWaitForRunLevels = None, aenmWaitForActive = None,
3416 aenmWaitForInactive = None):
3417 """
3418 aenmWaitForRunLevels - List of run level values to wait for (success if one matches).
3419 aenmWaitForActive - List facilities (type values) that must be active.
3420 aenmWaitForInactive - List facilities (type values) that must be inactive.
3421
3422 The default is to wait for AdditionsRunLevelType_Userland if all three lists
3423 are unspecified or empty.
3424 """
3425 TdTaskBase.__init__(self, utils.getCallerName());
3426 self.oSession = oSession # type: vboxwrappers.SessionWrapper
3427 self.oIGuest = oIGuest;
3428 self.cMsTimeout = cMsTimeout;
3429 self.fSucceeded = False;
3430 self.oVBoxEventHandler = None;
3431 self.aenmWaitForRunLevels = aenmWaitForRunLevels if aenmWaitForRunLevels else [];
3432 self.aenmWaitForActive = aenmWaitForActive if aenmWaitForActive else [];
3433 self.aenmWaitForInactive = aenmWaitForInactive if aenmWaitForInactive else [];
3434
3435 # Provide a sensible default if nothing is given.
3436 if not self.aenmWaitForRunLevels and not self.aenmWaitForActive and not self.aenmWaitForInactive:
3437 self.aenmWaitForRunLevels = [vboxcon.AdditionsRunLevelType_Userland,];
3438
3439 # Register the event handler on hosts which has it:
3440 if oSession.fpApiVer >= 6.1 or hasattr(vboxcon, 'VBoxEventType_OnGuestAdditionsStatusChanged'):
3441 aenmEvents = (vboxcon.VBoxEventType_OnGuestAdditionsStatusChanged,);
3442 dArgs = {
3443 'oParentTask': self,
3444 };
3445 self.oVBoxEventHandler = vbox.EventHandlerBase.registerDerivedEventHandler(oSession.oVBoxMgr,
3446 oSession.fpApiVer,
3447 self.AdditionsStatusTaskCallback,
3448 dArgs,
3449 oIGuest,
3450 'IGuest',
3451 'AdditionsStatusTaskCallback',
3452 aenmEvents = aenmEvents);
3453 reporter.log2('AdditionsStatusTask: %s' % (self.toString(), ));
3454
3455 def __del__(self):
3456 """ Make sure we deregister the callback. """
3457 self._deregisterEventHandler();
3458 self.oIGuest = None;
3459 return TdTaskBase.__del__(self);
3460
3461 def toString(self):
3462 return '<%s cMsTimeout=%s, fSucceeded=%s, aenmWaitForRunLevels=%s, aenmWaitForActive=%s, aenmWaitForInactive=%s, ' \
3463 'oVBoxEventHandler=%s>' \
3464 % (TdTaskBase.toString(self), self.cMsTimeout, self.fSucceeded, self.aenmWaitForRunLevels, self.aenmWaitForActive,
3465 self.aenmWaitForInactive, self.oVBoxEventHandler,);
3466
3467 def _deregisterEventHandler(self):
3468 """Deregisters the event handler."""
3469 fRc = True;
3470 oVBoxEventHandler = self.oVBoxEventHandler;
3471 if oVBoxEventHandler is not None:
3472 self.oVBoxEventHandler = None;
3473 fRc = oVBoxEventHandler.unregister();
3474 oVBoxEventHandler.oParentTask = None; # Try avoid cylic deps.
3475 return fRc;
3476
3477 def _poll(self):
3478 """
3479 Internal worker for pollTask() that returns the new signalled state.
3480 """
3481
3482 #
3483 # Check if any of the runlevels we wait for have been reached:
3484 #
3485 if self.aenmWaitForRunLevels:
3486 try:
3487 enmRunLevel = self.oIGuest.additionsRunLevel;
3488 except:
3489 reporter.errorXcpt();
3490 return True;
3491 if enmRunLevel not in self.aenmWaitForRunLevels:
3492 reporter.log6('AdditionsStatusTask/poll: enmRunLevel=%s not in %s' % (enmRunLevel, self.aenmWaitForRunLevels,));
3493 return False;
3494 reporter.log2('AdditionsStatusTask/poll: enmRunLevel=%s matched %s!' % (enmRunLevel, self.aenmWaitForRunLevels,));
3495
3496
3497 #
3498 # Check for the facilities that must all be active.
3499 #
3500 for enmFacility in self.aenmWaitForActive:
3501 try:
3502 (enmStatus, _) = self.oIGuest.getFacilityStatus(enmFacility);
3503 except:
3504 reporter.errorXcpt('enmFacility=%s' % (enmFacility,));
3505 return True;
3506 if enmStatus != vboxcon.AdditionsFacilityStatus_Active:
3507 reporter.log2('AdditionsStatusTask/poll: enmFacility=%s not active: %s' % (enmFacility, enmStatus,));
3508 return False;
3509
3510 #
3511 # Check for the facilities that must all be inactive or terminated.
3512 #
3513 for enmFacility in self.aenmWaitForInactive:
3514 try:
3515 (enmStatus, _) = self.oIGuest.getFacilityStatus(enmFacility);
3516 except:
3517 reporter.errorXcpt('enmFacility=%s' % (enmFacility,));
3518 return True;
3519 if enmStatus not in (vboxcon.AdditionsFacilityStatus_Inactive,
3520 vboxcon.AdditionsFacilityStatus_Terminated):
3521 reporter.log2('AdditionsStatusTask/poll: enmFacility=%s not inactive: %s' % (enmFacility, enmStatus,));
3522 return False;
3523
3524
3525 reporter.log('AdditionsStatusTask: Poll succeeded, signalling...');
3526 self.fSucceeded = True;
3527 return True;
3528
3529
3530 #
3531 # Task methods
3532 #
3533
3534 def pollTask(self, fLocked = False):
3535 """
3536 Overridden pollTask method.
3537 """
3538 if not fLocked:
3539 self.lockTask();
3540
3541 fDeregister = False;
3542 fRc = self.fSignalled;
3543 if not fRc:
3544 fRc = self._poll();
3545 if fRc or self.getAgeAsMs() >= self.cMsTimeout:
3546 self.signalTaskLocked();
3547 fDeregister = True;
3548
3549 if not fLocked:
3550 self.unlockTask();
3551
3552 # If we're done, deregister the event callback (w/o owning lock).
3553 if fDeregister:
3554 self._deregisterEventHandler();
3555 return fRc;
3556
3557 def getResult(self):
3558 """
3559 Returns true if the we succeeded.
3560 Returns false if not. If the task is signalled already, then we
3561 encountered a problem while polling.
3562 """
3563 return self.fSucceeded;
3564
3565 def cancelTask(self):
3566 """
3567 Cancels the task.
3568 Just to actively disengage the event handler.
3569 """
3570 self._deregisterEventHandler();
3571 return True;
3572
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette