VirtualBox

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

Last change on this file since 86446 was 84926, checked in by vboxsync, 4 years ago

Validation Kit/vboxwrappers: Toned down verboseness of AdditionsStatusTask() when polling for status changes.

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