VirtualBox

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

Last change on this file since 91452 was 91363, checked in by vboxsync, 3 years ago

FE/VBoxSDL+VirtualBox,Main/Console+Machine+VirtualBox.xidl: VMs which
crash while restoring from the 'Saved' state shouldn't lose their saved
state file. bugref:1484

A new machine state named 'AbortedSaved' has been added which a VM will
enter if it crashes when restoring from the 'Saved' state before the
'Running' state has been reached. A VM in the 'AbortedSaved' machine
state will have its saved state file preserved so that the VM can still be
restored once the cause of the failure to powerUp() and reach the
'Running' state has been resolved.

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