VirtualBox

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

Last change on this file since 92137 was 92050, checked in by vboxsync, 4 years ago

ValidationKit: bugref:9932 Use host-only networks instead of adapters on Mac OS

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

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