VirtualBox

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

Last change on this file since 91350 was 91055, checked in by vboxsync, 3 years ago

Audio/Validation Kit: Make sure to always enable input / output in the VM's audio adapter via the test driver [build fix, forgot a file]. ​bugref:10008

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

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