VirtualBox

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

Last change on this file since 82837 was 82622, checked in by vboxsync, 5 years ago

ValidationKit/testdriver: Add support for the VirtIO SCSI controller, bugref:9440

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 138.0 KB
Line 
1# -*- coding: utf-8 -*-
2# $Id: vboxwrappers.py 82622 2019-12-19 14:55:09Z vboxsync $
3# pylint: disable=too-many-lines
4
5"""
6VirtualBox Wrapper Classes
7"""
8
9__copyright__ = \
10"""
11Copyright (C) 2010-2019 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: 82622 $"
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 setCpuCount(self, cCpus):
1653 """
1654 Set the number of CPUs.
1655 Returns True on success and False on failure. Error information is logged.
1656 """
1657 fRc = True;
1658 try:
1659 self.o.machine.CPUCount = cCpus;
1660 except:
1661 reporter.errorXcpt('failed to set the CPU count of "%s" to %s' % (self.sName, cCpus));
1662 fRc = False;
1663 else:
1664 reporter.log('set the CPU count of "%s" to %s' % (self.sName, cCpus));
1665 self.oTstDrv.processPendingEvents();
1666 return fRc;
1667
1668 def getCpuCount(self):
1669 """
1670 Returns the number of CPUs.
1671 Returns the number of CPUs on success and 0 on failure. Error information is logged.
1672 """
1673 cCpus = 0;
1674 try:
1675 cCpus = self.o.machine.CPUCount;
1676 except:
1677 reporter.errorXcpt('failed to get the CPU count of "%s"' % (self.sName,));
1678
1679 self.oTstDrv.processPendingEvents();
1680 return cCpus;
1681
1682 def ensureControllerAttached(self, sController):
1683 """
1684 Makes sure the specified controller is attached to the VM, attaching it
1685 if necessary.
1686 """
1687 try:
1688 try:
1689 self.o.machine.getStorageControllerByName(sController);
1690 except:
1691 (eBus, eType) = _ControllerNameToBusAndType(sController);
1692 try:
1693 oCtl = self.o.machine.addStorageController(sController, eBus);
1694 except:
1695 reporter.errorXcpt('addStorageController("%s",%s) failed on "%s"' % (sController, eBus, self.sName) );
1696 return False;
1697 else:
1698 try:
1699 oCtl.controllerType = eType;
1700 reporter.log('added storage controller "%s" (bus %s, type %s) to %s'
1701 % (sController, eBus, eType, self.sName));
1702 except:
1703 reporter.errorXcpt('controllerType = %s on ("%s" / %s) failed on "%s"'
1704 % (eType, sController, eBus, self.sName) );
1705 return False;
1706 finally:
1707 self.oTstDrv.processPendingEvents();
1708 return True;
1709
1710 def setStorageControllerPortCount(self, sController, iPortCount):
1711 """
1712 Set maximum ports count for storage controller
1713 """
1714 try:
1715 oCtl = self.o.machine.getStorageControllerByName(sController)
1716 oCtl.portCount = iPortCount
1717 self.oTstDrv.processPendingEvents()
1718 reporter.log('set controller "%s" port count to value %d' % (sController, iPortCount))
1719 return True
1720 except:
1721 reporter.log('unable to set storage controller "%s" ports count to %d' % (sController, iPortCount))
1722
1723 return False
1724
1725 def setStorageControllerHostIoCache(self, sController, fUseHostIoCache):
1726 """
1727 Set maximum ports count for storage controller
1728 """
1729 try:
1730 oCtl = self.o.machine.getStorageControllerByName(sController);
1731 oCtl.useHostIOCache = fUseHostIoCache;
1732 self.oTstDrv.processPendingEvents();
1733 reporter.log('set controller "%s" host I/O cache setting to %r' % (sController, fUseHostIoCache));
1734 return True;
1735 except:
1736 reporter.log('unable to set storage controller "%s" host I/O cache setting to %r' % (sController, fUseHostIoCache));
1737
1738 return False;
1739
1740 def setBootOrder(self, iPosition, eType):
1741 """
1742 Set guest boot order type
1743 @param iPosition boot order position
1744 @param eType device type (vboxcon.DeviceType_HardDisk,
1745 vboxcon.DeviceType_DVD, vboxcon.DeviceType_Floppy)
1746 """
1747 try:
1748 self.o.machine.setBootOrder(iPosition, eType)
1749 except:
1750 return reporter.errorXcpt('Unable to set boot order.')
1751
1752 reporter.log('Set boot order [%d] for device %s' % (iPosition, str(eType)))
1753 self.oTstDrv.processPendingEvents();
1754
1755 return True
1756
1757 def setStorageControllerType(self, eType, sController = "IDE Controller"):
1758 """
1759 Similar to ensureControllerAttached, except it will change the type.
1760 """
1761 try:
1762 oCtl = self.o.machine.getStorageControllerByName(sController);
1763 except:
1764 (eBus, _) = _ControllerNameToBusAndType(sController);
1765 try:
1766 oCtl = self.o.machine.addStorageController(sController, eBus);
1767 reporter.log('added storage controller "%s" (bus %s) to %s' % (sController, eBus, self.sName));
1768 except:
1769 reporter.errorXcpt('addStorageController("%s",%s) failed on "%s"' % (sController, eBus, self.sName) );
1770 return False;
1771 try:
1772 oCtl.controllerType = eType;
1773 except:
1774 reporter.errorXcpt('failed to set controller type of "%s" on "%s" to %s' % (sController, self.sName, eType) );
1775 return False;
1776 reporter.log('set controller type of "%s" on "%s" to %s' % (sController, self.sName, eType) );
1777 self.oTstDrv.processPendingEvents();
1778 return True;
1779
1780 def attachDvd(self, sImage = None, sController = "IDE Controller", iPort = 1, iDevice = 0):
1781 """
1782 Attaches a DVD drive to a VM, optionally with an ISO inserted.
1783 Returns True on success and False on failure. Error information is logged.
1784 """
1785 # Input validation.
1786 if sImage is not None and not self.oTstDrv.isResourceFile(sImage)\
1787 and not os.path.isabs(sImage): ## fixme - testsuite unzip ++
1788 reporter.fatal('"%s" is not in the resource set' % (sImage));
1789 return None;
1790
1791 if not self.ensureControllerAttached(sController):
1792 return False;
1793
1794 # Find/register the image if specified.
1795 oImage = None;
1796 sImageUuid = "";
1797 if sImage is not None:
1798 sFullName = self.oTstDrv.getFullResourceName(sImage)
1799 try:
1800 oImage = self.oVBox.findDVDImage(sFullName);
1801 except:
1802 try:
1803 if self.fpApiVer >= 4.1:
1804 oImage = self.oVBox.openMedium(sFullName, vboxcon.DeviceType_DVD, vboxcon.AccessMode_ReadOnly, False);
1805 elif self.fpApiVer >= 4.0:
1806 oImage = self.oVBox.openMedium(sFullName, vboxcon.DeviceType_DVD, vboxcon.AccessMode_ReadOnly);
1807 else:
1808 oImage = self.oVBox.openDVDImage(sFullName, "");
1809 except vbox.ComException as oXcpt:
1810 if oXcpt.errno != -1:
1811 reporter.errorXcpt('failed to open DVD image "%s" xxx' % (sFullName));
1812 else:
1813 reporter.errorXcpt('failed to open DVD image "%s" yyy' % (sFullName));
1814 return False;
1815 except:
1816 reporter.errorXcpt('failed to open DVD image "%s"' % (sFullName));
1817 return False;
1818 try:
1819 sImageUuid = oImage.id;
1820 except:
1821 reporter.errorXcpt('failed to get the UUID of "%s"' % (sFullName));
1822 return False;
1823
1824 # Attach the DVD.
1825 fRc = True;
1826 try:
1827 if self.fpApiVer >= 4.0:
1828 self.o.machine.attachDevice(sController, iPort, iDevice, vboxcon.DeviceType_DVD, oImage);
1829 else:
1830 self.o.machine.attachDevice(sController, iPort, iDevice, vboxcon.DeviceType_DVD, sImageUuid);
1831 except:
1832 reporter.errorXcpt('attachDevice("%s",%s,%s,HardDisk,"%s") failed on "%s"' \
1833 % (sController, iPort, iDevice, sImageUuid, self.sName) );
1834 fRc = False;
1835 else:
1836 reporter.log('attached DVD to %s, image="%s"' % (self.sName, sImage));
1837 self.oTstDrv.processPendingEvents();
1838 return fRc;
1839
1840 def attachHd(self, sHd, sController = "IDE Controller", iPort = 0, iDevice = 0, fImmutable = True, fForceResource = True):
1841 """
1842 Attaches a HD to a VM.
1843 Returns True on success and False on failure. Error information is logged.
1844 """
1845 # Input validation.
1846 if fForceResource and not self.oTstDrv.isResourceFile(sHd):
1847 reporter.fatal('"%s" is not in the resource set' % (sHd,));
1848 return None;
1849
1850 if not self.ensureControllerAttached(sController):
1851 return False;
1852
1853 # Find the HD, registering it if necessary (as immutable).
1854 if fForceResource:
1855 sFullName = self.oTstDrv.getFullResourceName(sHd);
1856 else:
1857 sFullName = sHd;
1858 try:
1859 oHd = self.oVBox.findHardDisk(sFullName);
1860 except:
1861 try:
1862 if self.fpApiVer >= 4.1:
1863 oHd = self.oVBox.openMedium(sFullName, vboxcon.DeviceType_HardDisk, vboxcon.AccessMode_ReadOnly, False);
1864 elif self.fpApiVer >= 4.0:
1865 oHd = self.oVBox.openMedium(sFullName, vboxcon.DeviceType_HardDisk, vboxcon.AccessMode_ReadOnly);
1866 else:
1867 oHd = self.oVBox.openHardDisk(sFullName, vboxcon.AccessMode_ReadOnly, False, "", False, "");
1868 except:
1869 reporter.errorXcpt('failed to open hd "%s"' % (sFullName));
1870 return False;
1871 try:
1872 if fImmutable:
1873 oHd.type = vboxcon.MediumType_Immutable;
1874 else:
1875 oHd.type = vboxcon.MediumType_Normal;
1876 except:
1877 if fImmutable:
1878 reporter.errorXcpt('failed to set hd "%s" immutable' % (sHd));
1879 else:
1880 reporter.errorXcpt('failed to set hd "%s" normal' % (sHd));
1881 return False;
1882
1883 # Attach it.
1884 fRc = True;
1885 try:
1886 if self.fpApiVer >= 4.0:
1887 self.o.machine.attachDevice(sController, iPort, iDevice, vboxcon.DeviceType_HardDisk, oHd);
1888 else:
1889 self.o.machine.attachDevice(sController, iPort, iDevice, vboxcon.DeviceType_HardDisk, oHd.id);
1890 except:
1891 reporter.errorXcpt('attachDevice("%s",%s,%s,HardDisk,"%s") failed on "%s"' \
1892 % (sController, iPort, iDevice, oHd.id, self.sName) );
1893 fRc = False;
1894 else:
1895 reporter.log('attached "%s" to %s' % (sHd, self.sName));
1896 self.oTstDrv.processPendingEvents();
1897 return fRc;
1898
1899 def createBaseHd(self, sHd, sFmt = "VDI", cb = 10*1024*1024*1024, cMsTimeout = 60000, tMediumVariant = None):
1900 """
1901 Creates a base HD.
1902 Returns Medium object on success and None on failure. Error information is logged.
1903 """
1904 if tMediumVariant is None:
1905 tMediumVariant = (vboxcon.MediumVariant_Standard, );
1906
1907 try:
1908 if self.fpApiVer >= 5.0:
1909 oHd = self.oVBox.createMedium(sFmt, sHd, vboxcon.AccessMode_ReadWrite, vboxcon.DeviceType_HardDisk);
1910 else:
1911 oHd = self.oVBox.createHardDisk(sFmt, sHd);
1912 oProgressXpcom = oHd.createBaseStorage(cb, tMediumVariant);
1913 oProgress = ProgressWrapper(oProgressXpcom, self.oVBoxMgr, self.oTstDrv, 'create base disk %s' % (sHd));
1914 oProgress.wait(cMsTimeout);
1915 oProgress.logResult();
1916 except:
1917 reporter.errorXcpt('failed to create base hd "%s"' % (sHd));
1918 oHd = None
1919
1920 return oHd;
1921
1922 def createDiffHd(self, oParentHd, sHd, sFmt = "VDI"):
1923 """
1924 Creates a differencing HD.
1925 Returns Medium object on success and None on failure. Error information is logged.
1926 """
1927 # Detect the proper format if requested
1928 if sFmt is None:
1929 try:
1930 oHdFmt = oParentHd.mediumFormat;
1931 lstCaps = self.oVBoxMgr.getArray(oHdFmt, 'capabilities');
1932 if vboxcon.MediumFormatCapabilities_Differencing in lstCaps:
1933 sFmt = oHdFmt.id;
1934 else:
1935 sFmt = 'VDI';
1936 except:
1937 reporter.errorXcpt('failed to get preferred diff format for "%s"' % (sHd));
1938 return None;
1939 try:
1940 if self.fpApiVer >= 5.0:
1941 oHd = self.oVBox.createMedium(sFmt, sHd, vboxcon.AccessMode_ReadWrite, vboxcon.DeviceType_HardDisk);
1942 else:
1943 oHd = self.oVBox.createHardDisk(sFmt, sHd);
1944 oProgressXpcom = oParentHd.createDiffStorage(oHd, (vboxcon.MediumVariant_Standard, ))
1945 oProgress = ProgressWrapper(oProgressXpcom, self.oVBoxMgr, self.oTstDrv, 'create diff disk %s' % (sHd));
1946 oProgress.wait();
1947 oProgress.logResult();
1948 except:
1949 reporter.errorXcpt('failed to create diff hd "%s"' % (sHd));
1950 oHd = None
1951
1952 return oHd;
1953
1954 def createAndAttachHd(self, sHd, sFmt = "VDI", sController = "IDE Controller", cb = 10*1024*1024*1024, # pylint: disable=too-many-arguments
1955 iPort = 0, iDevice = 0, fImmutable = True, cMsTimeout = 60000, tMediumVariant = None):
1956 """
1957 Creates and attaches a HD to a VM.
1958 Returns True on success and False on failure. Error information is logged.
1959 """
1960 if not self.ensureControllerAttached(sController):
1961 return False;
1962
1963 oHd = self.createBaseHd(sHd, sFmt, cb, cMsTimeout, tMediumVariant);
1964 if oHd is None:
1965 return False;
1966
1967 fRc = True;
1968 try:
1969 if fImmutable:
1970 oHd.type = vboxcon.MediumType_Immutable;
1971 else:
1972 oHd.type = vboxcon.MediumType_Normal;
1973 except:
1974 if fImmutable:
1975 reporter.errorXcpt('failed to set hd "%s" immutable' % (sHd));
1976 else:
1977 reporter.errorXcpt('failed to set hd "%s" normal' % (sHd));
1978 fRc = False;
1979
1980 # Attach it.
1981 if fRc is True:
1982 try:
1983 if self.fpApiVer >= 4.0:
1984 self.o.machine.attachDevice(sController, iPort, iDevice, vboxcon.DeviceType_HardDisk, oHd);
1985 else:
1986 self.o.machine.attachDevice(sController, iPort, iDevice, vboxcon.DeviceType_HardDisk, oHd.id);
1987 except:
1988 reporter.errorXcpt('attachDevice("%s",%s,%s,HardDisk,"%s") failed on "%s"' \
1989 % (sController, iPort, iDevice, oHd.id, self.sName) );
1990 fRc = False;
1991 else:
1992 reporter.log('attached "%s" to %s' % (sHd, self.sName));
1993
1994 # Delete disk in case of an error
1995 if fRc is False:
1996 try:
1997 oProgressCom = oHd.deleteStorage();
1998 except:
1999 reporter.errorXcpt('deleteStorage() for disk %s failed' % (sHd,));
2000 else:
2001 oProgress = ProgressWrapper(oProgressCom, self.oVBoxMgr, self.oTstDrv, 'delete disk %s' % (sHd));
2002 oProgress.wait();
2003 oProgress.logResult();
2004
2005 self.oTstDrv.processPendingEvents();
2006 return fRc;
2007
2008 def detachHd(self, sController = "IDE Controller", iPort = 0, iDevice = 0):
2009 """
2010 Detaches a HD, if attached, and returns a reference to it (IMedium).
2011
2012 In order to delete the detached medium, the caller must first save
2013 the changes made in this session.
2014
2015 Returns (fRc, oHd), where oHd is None unless fRc is True, and fRc is
2016 your standard success indicator. Error information is logged.
2017 """
2018
2019 # What's attached?
2020 try:
2021 oHd = self.o.machine.getMedium(sController, iPort, iDevice);
2022 except:
2023 if self.oVBoxMgr.xcptIsOurXcptKind() \
2024 and self.oVBoxMgr.xcptIsEqual(None, self.oVBoxMgr.constants.VBOX_E_OBJECT_NOT_FOUND):
2025 reporter.log('No HD attached (to %s %s:%s)' % (sController, iPort, iDevice));
2026 return (True, None);
2027 return (reporter.errorXcpt('Error getting media at port %s, device %s, on %s.'
2028 % (iPort, iDevice, sController)), None);
2029 # Detach it.
2030 try:
2031 self.o.machine.detachDevice(sController, iPort, iDevice);
2032 except:
2033 return (reporter.errorXcpt('detachDevice("%s",%s,%s) failed on "%s"' \
2034 % (sController, iPort, iDevice, self.sName) ), None);
2035 reporter.log('detached HD ("%s",%s,%s) from %s' % (sController, iPort, iDevice, self.sName));
2036 return (True, oHd);
2037
2038 def attachFloppy(self, sFloppy, sController = "Floppy Controller", iPort = 0, iDevice = 0):
2039 """
2040 Attaches a floppy image to a VM.
2041 Returns True on success and False on failure. Error information is logged.
2042 """
2043 # Input validation.
2044 ## @todo Fix this wrt to bootsector-xxx.img from the validationkit.zip.
2045 ##if not self.oTstDrv.isResourceFile(sFloppy):
2046 ## reporter.fatal('"%s" is not in the resource set' % (sFloppy));
2047 ## return None;
2048
2049 if not self.ensureControllerAttached(sController):
2050 return False;
2051
2052 # Find the floppy image, registering it if necessary (as immutable).
2053 sFullName = self.oTstDrv.getFullResourceName(sFloppy);
2054 try:
2055 oFloppy = self.oVBox.findFloppyImage(sFullName);
2056 except:
2057 try:
2058 if self.fpApiVer >= 4.1:
2059 oFloppy = self.oVBox.openMedium(sFullName, vboxcon.DeviceType_Floppy, vboxcon.AccessMode_ReadOnly, False);
2060 elif self.fpApiVer >= 4.0:
2061 oFloppy = self.oVBox.openMedium(sFullName, vboxcon.DeviceType_Floppy, vboxcon.AccessMode_ReadOnly);
2062 else:
2063 oFloppy = self.oVBox.openFloppyImage(sFullName, "");
2064 except:
2065 reporter.errorXcpt('failed to open floppy "%s"' % (sFullName));
2066 return False;
2067 ## @todo the following works but causes trouble below (asserts in main).
2068 #try:
2069 # oFloppy.type = vboxcon.MediumType_Immutable;
2070 #except:
2071 # reporter.errorXcpt('failed to make floppy "%s" immutable' % (sFullName));
2072 # return False;
2073
2074 # Attach it.
2075 fRc = True;
2076 try:
2077 if self.fpApiVer >= 4.0:
2078 self.o.machine.attachDevice(sController, iPort, iDevice, vboxcon.DeviceType_Floppy, oFloppy);
2079 else:
2080 self.o.machine.attachDevice(sController, iPort, iDevice, vboxcon.DeviceType_Floppy, oFloppy.id);
2081 except:
2082 reporter.errorXcpt('attachDevice("%s",%s,%s,Floppy,"%s") failed on "%s"' \
2083 % (sController, iPort, iDevice, oFloppy.id, self.sName) );
2084 fRc = False;
2085 else:
2086 reporter.log('attached "%s" to %s' % (sFloppy, self.sName));
2087 self.oTstDrv.processPendingEvents();
2088 return fRc;
2089
2090 def setupNic(self, sType, sXXX):
2091 """
2092 Sets up a NIC to a VM.
2093 Returns True on success and False on failure. Error information is logged.
2094 """
2095 if sType == "PCNet": enmType = vboxcon.NetworkAdapterType_Am79C973;
2096 elif sType == "PCNetOld": enmType = vboxcon.NetworkAdapterType_Am79C970A;
2097 elif sType == "E1000": enmType = vboxcon.NetworkAdapterType_I82545EM; # MT Server
2098 elif sType == "E1000Desk": enmType = vboxcon.NetworkAdapterType_I82540EM; # MT Desktop
2099 elif sType == "E1000Srv2": enmType = vboxcon.NetworkAdapterType_I82543GC; # T Server
2100 elif sType == "Virtio": enmType = vboxcon.NetworkAdapterType_Virtio;
2101 else:
2102 reporter.error('Invalid NIC type: "%s" (sXXX=%s)' % (sType, sXXX));
2103 return False;
2104 ## @todo Implement me!
2105 if enmType is not None: pass
2106 return True;
2107
2108 def setupAudio(self, eAudioControllerType, fEnable = True, eAudioDriverType = None):
2109 """
2110 Sets up audio.
2111
2112 :param eAudioControllerType: The audio controller type (vboxcon.AudioControllerType_XXX).
2113 :param fEnable: Whether to enable or disable the audio controller (default enable).
2114 :param eAudioDriverType: The audio driver type (vboxcon.AudioDriverType_XXX), picks something suitable
2115 if None is passed (default).
2116 """
2117 try: oAudioAdapter = self.o.machine.audioAdapter;
2118 except: return reporter.errorXcpt('Failed to get the audio adapter.');
2119
2120 try: oAudioAdapter.audioController = eAudioControllerType;
2121 except: return reporter.errorXcpt('Failed to set the audio controller to %s.' % (eAudioControllerType,));
2122
2123 if eAudioDriverType is None:
2124 sHost = utils.getHostOs()
2125 if sHost == 'darwin': eAudioDriverType = vboxcon.AudioDriverType_CoreAudio;
2126 elif sHost == 'win': eAudioDriverType = vboxcon.AudioDriverType_DirectSound;
2127 elif sHost == 'linux': eAudioDriverType = vboxcon.AudioDriverType_Pulse;
2128 elif sHost == 'solaris': eAudioDriverType = vboxcon.AudioDriverType_OSS;
2129 else:
2130 reporter.error('PORTME: Do not know which audio driver to pick for: %s!' % (sHost,));
2131 eAudioDriverType = vboxcon.AudioDriverType_Null;
2132
2133 try: oAudioAdapter.audioDriver = eAudioDriverType;
2134 except: return reporter.errorXcpt('Failed to set the audio driver to %s.' % (eAudioDriverType,))
2135
2136 try: oAudioAdapter.enabled = fEnable;
2137 except: return reporter.errorXcpt('Failed to set the "enabled" property to %s.' % (fEnable,));
2138
2139 reporter.log('set audio adapter type to %d, driver to %d, and enabled to %s'
2140 % (eAudioControllerType, eAudioDriverType, fEnable,));
2141 self.oTstDrv.processPendingEvents();
2142 return True;
2143
2144 def setupPreferredConfig(self): # pylint: disable=too-many-locals
2145 """
2146 Configures the VM according to the preferences of the guest type.
2147 """
2148 try:
2149 sOsTypeId = self.o.machine.OSTypeId;
2150 except:
2151 reporter.errorXcpt('failed to obtain the OSTypeId for "%s"' % (self.sName));
2152 return False;
2153
2154 try:
2155 oOsType = self.oVBox.getGuestOSType(sOsTypeId);
2156 except:
2157 reporter.errorXcpt('getGuestOSType("%s") failed for "%s"' % (sOsTypeId, self.sName));
2158 return False;
2159
2160 # get the attributes.
2161 try:
2162 #sFamilyId = oOsType.familyId;
2163 #f64Bit = oOsType.is64Bit;
2164 fIoApic = oOsType.recommendedIOAPIC;
2165 fVirtEx = oOsType.recommendedVirtEx;
2166 cMBRam = oOsType.recommendedRAM;
2167 cMBVRam = oOsType.recommendedVRAM;
2168 #cMBHdd = oOsType.recommendedHDD;
2169 eNicType = oOsType.adapterType;
2170 if self.fpApiVer >= 3.2:
2171 if self.fpApiVer >= 4.2:
2172 fPae = oOsType.recommendedPAE;
2173 fUsbHid = oOsType.recommendedUSBHID;
2174 fHpet = oOsType.recommendedHPET;
2175 eStorCtlType = oOsType.recommendedHDStorageController;
2176 else:
2177 fPae = oOsType.recommendedPae;
2178 fUsbHid = oOsType.recommendedUsbHid;
2179 fHpet = oOsType.recommendedHpet;
2180 eStorCtlType = oOsType.recommendedHdStorageController;
2181 eFirmwareType = oOsType.recommendedFirmware;
2182 else:
2183 fPae = False;
2184 fUsbHid = False;
2185 fHpet = False;
2186 eFirmwareType = -1;
2187 eStorCtlType = vboxcon.StorageControllerType_PIIX4;
2188 if self.fpApiVer >= 4.0:
2189 eAudioCtlType = oOsType.recommendedAudioController;
2190 except:
2191 reporter.errorXcpt('exception reading IGuestOSType(%s) attribute' % (sOsTypeId));
2192 self.oTstDrv.processPendingEvents();
2193 return False;
2194 self.oTstDrv.processPendingEvents();
2195
2196 # Do the setting. Continue applying settings on error in case the
2197 # caller ignores the return code
2198 fRc = True;
2199 if not self.enableIoApic(fIoApic): fRc = False;
2200 if not self.enableVirtEx(fVirtEx): fRc = False;
2201 if not self.enablePae(fPae): fRc = False;
2202 if not self.setRamSize(cMBRam): fRc = False;
2203 if not self.setVRamSize(cMBVRam): fRc = False;
2204 if not self.setNicType(eNicType, 0): fRc = False;
2205 if self.fpApiVer >= 3.2:
2206 if not self.setFirmwareType(eFirmwareType): fRc = False;
2207 if not self.enableUsbHid(fUsbHid): fRc = False;
2208 if not self.enableHpet(fHpet): fRc = False;
2209 if eStorCtlType in (vboxcon.StorageControllerType_PIIX3,
2210 vboxcon.StorageControllerType_PIIX4,
2211 vboxcon.StorageControllerType_ICH6,):
2212 if not self.setStorageControllerType(eStorCtlType, "IDE Controller"):
2213 fRc = False;
2214 if self.fpApiVer >= 4.0:
2215 if not self.setupAudio(eAudioCtlType): fRc = False;
2216
2217 return fRc;
2218
2219 def addUsbDeviceFilter(self, sName, sVendorId = None, sProductId = None, sRevision = None, # pylint: disable=too-many-arguments
2220 sManufacturer = None, sProduct = None, sSerialNumber = None,
2221 sPort = None, sRemote = None):
2222 """
2223 Creates a USB device filter and inserts it into the VM.
2224 Returns True on success.
2225 Returns False on failure (logged).
2226 """
2227 fRc = True;
2228
2229 try:
2230 oUsbDevFilter = self.o.machine.USBDeviceFilters.createDeviceFilter(sName);
2231 oUsbDevFilter.active = True;
2232 if sVendorId is not None:
2233 oUsbDevFilter.vendorId = sVendorId;
2234 if sProductId is not None:
2235 oUsbDevFilter.productId = sProductId;
2236 if sRevision is not None:
2237 oUsbDevFilter.revision = sRevision;
2238 if sManufacturer is not None:
2239 oUsbDevFilter.manufacturer = sManufacturer;
2240 if sProduct is not None:
2241 oUsbDevFilter.product = sProduct;
2242 if sSerialNumber is not None:
2243 oUsbDevFilter.serialnumber = sSerialNumber;
2244 if sPort is not None:
2245 oUsbDevFilter.port = sPort;
2246 if sRemote is not None:
2247 oUsbDevFilter.remote = sRemote;
2248 try:
2249 self.o.machine.USBDeviceFilters.insertDeviceFilter(0, oUsbDevFilter);
2250 except:
2251 reporter.errorXcpt('insertDeviceFilter(%s) failed on "%s"' \
2252 % (0, self.sName) );
2253 fRc = False;
2254 else:
2255 reporter.log('inserted USB device filter "%s" to %s' % (sName, self.sName));
2256 except:
2257 reporter.errorXcpt('createDeviceFilter("%s") failed on "%s"' \
2258 % (sName, self.sName) );
2259 fRc = False;
2260 return fRc;
2261
2262 def getGuestPropertyValue(self, sName):
2263 """
2264 Gets a guest property value.
2265 Returns the value on success, None on failure (logged).
2266 """
2267 try:
2268 sValue = self.o.machine.getGuestPropertyValue(sName);
2269 except:
2270 reporter.errorXcpt('IMachine::getGuestPropertyValue("%s") failed' % (sName));
2271 return None;
2272 return sValue;
2273
2274 def setGuestPropertyValue(self, sName, sValue):
2275 """
2276 Sets a guest property value.
2277 Returns the True on success, False on failure (logged).
2278 """
2279 try:
2280 self.o.machine.setGuestPropertyValue(sName, sValue);
2281 except:
2282 reporter.errorXcpt('IMachine::setGuestPropertyValue("%s","%s") failed' % (sName, sValue));
2283 return False;
2284 return True;
2285
2286 def delGuestPropertyValue(self, sName):
2287 """
2288 Deletes a guest property value.
2289 Returns the True on success, False on failure (logged).
2290 """
2291 try:
2292 oMachine = self.o.machine;
2293 if self.fpApiVer >= 4.2:
2294 oMachine.deleteGuestProperty(sName);
2295 else:
2296 oMachine.setGuestPropertyValue(sName, '');
2297 except:
2298 reporter.errorXcpt('Unable to delete guest property "%s"' % (sName,));
2299 return False;
2300 return True;
2301
2302 def setExtraData(self, sKey, sValue):
2303 """
2304 Sets extra data.
2305 Returns the True on success, False on failure (logged).
2306 """
2307 try:
2308 self.o.machine.setExtraData(sKey, sValue);
2309 except:
2310 reporter.errorXcpt('IMachine::setExtraData("%s","%s") failed' % (sKey, sValue));
2311 return False;
2312 return True;
2313
2314 def getExtraData(self, sKey):
2315 """
2316 Gets extra data.
2317 Returns value on success, None on failure.
2318 """
2319 try:
2320 sValue = self.o.machine.getExtraData(sKey)
2321 except:
2322 reporter.errorXcpt('IMachine::setExtraData("%s","%s") failed' % (sKey, sValue))
2323 return None
2324 return sValue
2325
2326 def setupTeleporter(self, fEnabled=True, uPort = 6500, sAddress = '', sPassword = ''):
2327 """
2328 Sets up the teleporter for the VM.
2329 Returns True on success, False on failure (logged).
2330 """
2331 try:
2332 self.o.machine.teleporterAddress = sAddress;
2333 self.o.machine.teleporterPort = uPort;
2334 self.o.machine.teleporterPassword = sPassword;
2335 self.o.machine.teleporterEnabled = fEnabled;
2336 except:
2337 reporter.errorXcpt('setupTeleporter(%s, %s, %s, %s)' % (fEnabled, sPassword, uPort, sAddress));
2338 return False;
2339 return True;
2340
2341 def enableTeleporter(self, fEnable=True):
2342 """
2343 Enables or disables the teleporter of the VM.
2344 Returns True on success, False on failure (logged).
2345 """
2346 try:
2347 self.o.machine.teleporterEnabled = fEnable;
2348 except:
2349 reporter.errorXcpt('IMachine::teleporterEnabled=%s failed' % (fEnable));
2350 return False;
2351 return True;
2352
2353 def teleport(self, sHostname = 'localhost', uPort = 6500, sPassword = 'password', cMsMaxDowntime = 250):
2354 """
2355 Wrapper around the IConsole::teleport() method.
2356 Returns a progress object on success, None on failure (logged).
2357 """
2358 reporter.log2('"%s"::teleport(%s,%s,%s,%s)...' % (self.sName, sHostname, uPort, sPassword, cMsMaxDowntime));
2359 try:
2360 oProgress = self.o.console.teleport(sHostname, uPort, sPassword, cMsMaxDowntime)
2361 except:
2362 reporter.errorXcpt('IConsole::teleport(%s,%s,%s,%s) failed' % (sHostname, uPort, sPassword, cMsMaxDowntime));
2363 return None;
2364 return ProgressWrapper(oProgress, self.oVBoxMgr, self.oTstDrv, 'teleport %s' % (self.sName,));
2365
2366 def getOsType(self):
2367 """
2368 Gets the IGuestOSType interface for the machine.
2369
2370 return IGuestOSType interface on success, None + errorXcpt on failure.
2371 No exceptions raised.
2372 """
2373 try:
2374 sOsTypeId = self.o.machine.OSTypeId;
2375 except:
2376 reporter.errorXcpt('failed to obtain the OSTypeId for "%s"' % (self.sName));
2377 return None;
2378
2379 try:
2380 oOsType = self.oVBox.getGuestOSType(sOsTypeId);
2381 except:
2382 reporter.errorXcpt('getGuestOSType("%s") failed for "%s"' % (sOsTypeId, self.sName));
2383 return None;
2384
2385 return oOsType;
2386
2387 def setOsType(self, sNewTypeId):
2388 """
2389 Changes the OS type.
2390
2391 returns True on success, False + errorXcpt on failure.
2392 No exceptions raised.
2393 """
2394 try:
2395 self.o.machine.OSTypeId = sNewTypeId;
2396 except:
2397 reporter.errorXcpt('failed to set the OSTypeId for "%s" to "%s"' % (self.sName, sNewTypeId));
2398 return False;
2399 return True;
2400
2401
2402 def setParavirtProvider(self, iProvider):
2403 """
2404 Sets a paravirtualisation provider.
2405 Returns the True on success, False on failure (logged).
2406 """
2407 try:
2408 self.o.machine.paravirtProvider = iProvider
2409 except:
2410 reporter.errorXcpt('Unable to set paravirtualisation provider "%s"' % (iProvider,))
2411 return False;
2412 return True;
2413
2414
2415 def setupSerialToRawFile(self, iSerialPort, sRawFile):
2416 """
2417 Enables the given serial port (zero based) and redirects it to sRawFile.
2418 Returns the True on success, False on failure (logged).
2419 """
2420 try:
2421 oPort = self.o.machine.getSerialPort(iSerialPort);
2422 except:
2423 fRc = reporter.errorXcpt('failed to get serial port #%u' % (iSerialPort,));
2424 else:
2425 try:
2426 oPort.path = sRawFile;
2427 except:
2428 fRc = reporter.errorXcpt('failed to set the "path" property on serial port #%u to "%s"'
2429 % (iSerialPort, sRawFile));
2430 else:
2431 try:
2432 oPort.hostMode = vboxcon.PortMode_RawFile;
2433 except:
2434 fRc = reporter.errorXcpt('failed to set the "hostMode" property on serial port #%u to PortMode_RawFile'
2435 % (iSerialPort,));
2436 else:
2437 try:
2438 oPort.enabled = True;
2439 except:
2440 fRc = reporter.errorXcpt('failed to set the "enable" property on serial port #%u to True'
2441 % (iSerialPort,));
2442 else:
2443 reporter.log('set SerialPort[%s].enabled/hostMode/path=True/RawFile/%s' % (iSerialPort, sRawFile,));
2444 fRc = True;
2445 self.oTstDrv.processPendingEvents();
2446 return fRc;
2447
2448
2449 def enableSerialPort(self, iSerialPort):
2450 """
2451 Enables the given serial port setting the initial port mode to disconnected.
2452 """
2453 try:
2454 oPort = self.o.machine.getSerialPort(iSerialPort);
2455 except:
2456 fRc = reporter.errorXcpt('failed to get serial port #%u' % (iSerialPort,));
2457 else:
2458 try:
2459 oPort.hostMode = vboxcon.PortMode_Disconnected;
2460 except:
2461 fRc = reporter.errorXcpt('failed to set the "hostMode" property on serial port #%u to PortMode_Disconnected'
2462 % (iSerialPort,));
2463 else:
2464 try:
2465 oPort.enabled = True;
2466 except:
2467 fRc = reporter.errorXcpt('failed to set the "enable" property on serial port #%u to True'
2468 % (iSerialPort,));
2469 else:
2470 reporter.log('set SerialPort[%s].enabled/hostMode/=True/Disconnected' % (iSerialPort,));
2471 fRc = True;
2472 self.oTstDrv.processPendingEvents();
2473 return fRc;
2474
2475
2476 def changeSerialPortAttachment(self, iSerialPort, ePortMode, sPath, fServer):
2477 """
2478 Changes the attachment of the given serial port to the attachment config given.
2479 """
2480 try:
2481 oPort = self.o.machine.getSerialPort(iSerialPort);
2482 except:
2483 fRc = reporter.errorXcpt('failed to get serial port #%u' % (iSerialPort,));
2484 else:
2485 try:
2486 # Change port mode to disconnected first so changes get picked up by a potentially running VM.
2487 oPort.hostMode = vboxcon.PortMode_Disconnected;
2488 except:
2489 fRc = reporter.errorXcpt('failed to set the "hostMode" property on serial port #%u to PortMode_Disconnected'
2490 % (iSerialPort,));
2491 else:
2492 try:
2493 oPort.path = sPath;
2494 oPort.server = fServer;
2495 oPort.hostMode = ePortMode;
2496 except:
2497 fRc = reporter.errorXcpt('failed to configure the serial port');
2498 else:
2499 reporter.log('set SerialPort[%s].hostMode/path/server=%s/%s/%s'
2500 % (iSerialPort, ePortMode, sPath, fServer));
2501 fRc = True;
2502 self.oTstDrv.processPendingEvents();
2503 return fRc;
2504
2505 #
2506 # IConsole wrappers.
2507 #
2508
2509 def powerOff(self, fFudgeOnFailure = True):
2510 """
2511 Powers off the VM.
2512
2513 Returns True on success.
2514 Returns False on IConsole::powerDown() failure.
2515 Returns None if the progress object returns failure.
2516 """
2517 #
2518 # Deregister event handler before we power off the VM, otherwise we're
2519 # racing for VM process termination and cause misleading spurious
2520 # error messages in the event handling code, because the event objects
2521 # disappear.
2522 #
2523 # Note! Doing this before powerDown to try prevent numerous smoketest
2524 # timeouts on XPCOM hosts.
2525 #
2526 self.deregisterEventHandlerForTask();
2527
2528
2529 # Try power if off.
2530 try:
2531 oProgress = self.o.console.powerDown();
2532 except:
2533 reporter.logXcpt('IConsole::powerDown failed on %s' % (self.sName));
2534 if fFudgeOnFailure:
2535 self.oTstDrv.waitOnDirectSessionClose(self.oVM, 5000); # fudge
2536 self.waitForTask(1000); # fudge
2537 return False;
2538
2539 # Wait on power off operation to complete.
2540 rc = self.oTstDrv.waitOnProgress(oProgress);
2541 if rc < 0:
2542 self.close();
2543 if fFudgeOnFailure:
2544 vbox.reportError(oProgress, 'powerDown for "%s" failed' % (self.sName));
2545 self.oTstDrv.waitOnDirectSessionClose(self.oVM, 5000); # fudge
2546 return None;
2547
2548 # Wait for the VM to really power off or we'll fail to open a new session to it.
2549 self.oTstDrv.waitOnDirectSessionClose(self.oVM, 5000); # fudge
2550 return self.waitForTask(30 * 1000); # fudge
2551
2552 def saveState(self, fPause = True):
2553 """
2554 Saves state of the VM.
2555
2556 Returns True on success.
2557 Returns False on IConsole::saveState() failure.
2558 Returns None if the progress object returns Failure.
2559 """
2560
2561 if fPause is True \
2562 and self.oVM.state is vboxcon.MachineState_Running:
2563 self.o.console.pause();
2564 if self.oVM.state is not vboxcon.MachineState_Paused:
2565 reporter.error('pause for "%s" failed' % (self.sName));
2566 # Try saving state.
2567 try:
2568 if self.fpApiVer >= 5.0:
2569 oProgress = self.o.machine.saveState()
2570 else:
2571 oProgress = self.o.console.saveState()
2572 except:
2573 reporter.logXcpt('IMachine::saveState failed on %s' % (self.sName));
2574 return False;
2575
2576 # Wait for saving state operation to complete.
2577 rc = self.oTstDrv.waitOnProgress(oProgress);
2578 if rc < 0:
2579 self.close();
2580 return None;
2581
2582 # Wait for the VM to really terminate or we'll fail to open a new session to it.
2583 self.oTstDrv.waitOnDirectSessionClose(self.oVM, 5000); # fudge
2584 return self.waitForTask(30 * 1000); # fudge
2585
2586 def discardSavedState(self, fRemove = True):
2587 """
2588 Discards saved state of the VM.
2589
2590 Returns True on success.
2591 Returns False on IConsole::discardSaveState() failure.
2592 """
2593
2594 try:
2595 if self.fpApiVer >= 5.0:
2596 self.o.machine.discardSavedState(fRemove)
2597 else:
2598 self.o.console.discardSavedState(fRemove)
2599 except:
2600 reporter.logXcpt('IMachine::discardSavedState failed on %s' % (self.sName))
2601 return False
2602 return True
2603
2604 def restoreSnapshot(self, oSnapshot, fFudgeOnFailure = True):
2605 """
2606 Restores the given snapshot.
2607
2608 Returns True on success.
2609 Returns False on IMachine::restoreSnapshot() failure.
2610 Returns None if the progress object returns failure.
2611 """
2612 try:
2613 if self.fpApiVer >= 5.0:
2614 oProgress = self.o.machine.restoreSnapshot(oSnapshot);
2615 else:
2616 oProgress = self.o.console.restoreSnapshot(oSnapshot);
2617 except:
2618 reporter.logXcpt('IMachine::restoreSnapshot failed on %s' % (self.sName));
2619 if fFudgeOnFailure:
2620 self.oTstDrv.waitOnDirectSessionClose(self.oVM, 5000); # fudge
2621 self.waitForTask(1000); # fudge
2622 return False;
2623
2624 rc = self.oTstDrv.waitOnProgress(oProgress);
2625 if rc < 0:
2626 self.close();
2627 if fFudgeOnFailure:
2628 vbox.reportError(oProgress, 'restoreSnapshot for "%s" failed' % (self.sName));
2629 return None;
2630
2631 return self.waitForTask(30 * 1000);
2632
2633 def deleteSnapshot(self, oSnapshot, fFudgeOnFailure = True, cMsTimeout = 30 * 1000):
2634 """
2635 Deletes the given snapshot merging the diff image into the base.
2636
2637 Returns True on success.
2638 Returns False on IMachine::deleteSnapshot() failure.
2639 """
2640 try:
2641 if self.fpApiVer >= 5.0:
2642 oProgressCom = self.o.machine.deleteSnapshot(oSnapshot);
2643 else:
2644 oProgressCom = self.o.console.deleteSnapshot(oSnapshot);
2645 oProgress = ProgressWrapper(oProgressCom, self.oVBoxMgr, self.oTstDrv, 'Delete Snapshot %s' % (oSnapshot));
2646 oProgress.wait(cMsTimeout);
2647 oProgress.logResult();
2648 except:
2649 reporter.logXcpt('IMachine::deleteSnapshot failed on %s' % (self.sName));
2650 if fFudgeOnFailure:
2651 self.oTstDrv.waitOnDirectSessionClose(self.oVM, 5000); # fudge
2652 self.waitForTask(1000); # fudge
2653 return False;
2654
2655 return True;
2656
2657 def takeSnapshot(self, sName, sDescription = '', fPause = True, fFudgeOnFailure = True, cMsTimeout = 30 * 1000):
2658 """
2659 Takes a snapshot with the given name
2660
2661 Returns True on success.
2662 Returns False on IMachine::takeSnapshot() or VM state change failure.
2663 """
2664 try:
2665 if fPause is True \
2666 and self.oVM.state is vboxcon.MachineState_Running:
2667 self.o.console.pause();
2668 if self.fpApiVer >= 5.0:
2669 (oProgressCom, _) = self.o.machine.takeSnapshot(sName, sDescription, True);
2670 else:
2671 oProgressCom = self.o.console.takeSnapshot(sName, sDescription);
2672 oProgress = ProgressWrapper(oProgressCom, self.oVBoxMgr, self.oTstDrv, 'Take Snapshot %s' % (sName));
2673 oProgress.wait(cMsTimeout);
2674 oProgress.logResult();
2675 except:
2676 reporter.logXcpt('IMachine::takeSnapshot failed on %s' % (self.sName));
2677 if fFudgeOnFailure:
2678 self.oTstDrv.waitOnDirectSessionClose(self.oVM, 5000); # fudge
2679 self.waitForTask(1000); # fudge
2680 return False;
2681
2682 if fPause is True \
2683 and self.oVM.state is vboxcon.MachineState_Paused:
2684 self.o.console.resume();
2685
2686 return True;
2687
2688 def findSnapshot(self, sName):
2689 """
2690 Returns the snapshot object with the given name
2691
2692 Returns snapshot object on success.
2693 Returns None if there is no snapshot with the given name.
2694 """
2695 return self.oVM.findSnapshot(sName);
2696
2697 def takeScreenshot(self, sFilename, iScreenId=0):
2698 """
2699 Take screenshot from the given display and save it to specified file.
2700
2701 Returns True on success
2702 Returns False on failure.
2703 """
2704 try:
2705 if self.fpApiVer >= 5.0:
2706 iWidth, iHeight, _, _, _, _ = self.o.console.display.getScreenResolution(iScreenId)
2707 aPngData = self.o.console.display.takeScreenShotToArray(iScreenId, iWidth, iHeight,
2708 vboxcon.BitmapFormat_PNG)
2709 else:
2710 iWidth, iHeight, _, _, _ = self.o.console.display.getScreenResolution(iScreenId)
2711 aPngData = self.o.console.display.takeScreenShotPNGToArray(iScreenId, iWidth, iHeight)
2712 except:
2713 reporter.logXcpt("Unable to take screenshot")
2714 return False
2715
2716 oFile = open(sFilename, 'wb')
2717 oFile.write(aPngData)
2718 oFile.close()
2719
2720 return True
2721
2722 def attachUsbDevice(self, sUuid, sCaptureFilename = None):
2723 """
2724 Attach given USB device UUID to the VM.
2725
2726 Returns True on success
2727 Returns False on failure.
2728 """
2729 fRc = True;
2730 try:
2731 if sCaptureFilename is None:
2732 self.o.console.attachUSBDevice(sUuid, '');
2733 else:
2734 self.o.console.attachUSBDevice(sUuid, sCaptureFilename);
2735 except:
2736 reporter.logXcpt('Unable to attach USB device %s' % (sUuid,));
2737 fRc = False;
2738
2739 return fRc;
2740
2741 def detachUsbDevice(self, sUuid):
2742 """
2743 Detach given USB device UUID from the VM.
2744
2745 Returns True on success
2746 Returns False on failure.
2747 """
2748 fRc = True;
2749 try:
2750 _ = self.o.console.detachUSBDevice(sUuid);
2751 except:
2752 reporter.logXcpt('Unable to detach USB device %s' % (sUuid,));
2753 fRc = False;
2754
2755 return fRc;
2756
2757
2758 #
2759 # IMachineDebugger wrappers.
2760 #
2761
2762 def queryOsKernelLog(self):
2763 """
2764 Tries to get the OS kernel log using the VM debugger interface.
2765
2766 Returns string containing the kernel log on success.
2767 Returns None on failure.
2768 """
2769 sOsKernelLog = None;
2770 try:
2771 self.o.console.debugger.loadPlugIn('all');
2772 except:
2773 reporter.logXcpt('Unable to load debugger plugins');
2774 else:
2775 try:
2776 sOsDetected = self.o.console.debugger.detectOS();
2777 except:
2778 reporter.logXcpt('Failed to detect the guest OS');
2779 else:
2780 try:
2781 sOsKernelLog = self.o.console.debugger.queryOSKernelLog(0);
2782 except:
2783 reporter.logXcpt('Unable to get the guest OS (%s) kernel log' % (sOsDetected,));
2784 return sOsKernelLog;
2785
2786 def queryDbgInfo(self, sItem, sArg = '', sDefault = None):
2787 """
2788 Simple wrapper around IMachineDebugger::info.
2789
2790 Returns string on success, sDefault on failure (logged).
2791 """
2792 try:
2793 return self.o.console.debugger.info(sItem, sArg);
2794 except:
2795 reporter.logXcpt('Unable to query "%s" with arg "%s"' % (sItem, sArg,));
2796 return sDefault;
2797
2798 def queryDbgInfoVgaText(self, sArg = 'all'):
2799 """
2800 Tries to get the 'info vgatext' output, provided we're in next mode.
2801
2802 Returns string containing text on success.
2803 Returns None on failure or not text mode.
2804 """
2805 sVgaText = None;
2806 try:
2807 sVgaText = self.o.console.debugger.info('vgatext', sArg);
2808 if sVgaText.startswith('Not in text mode!'):
2809 sVgaText = None;
2810 except:
2811 reporter.logXcpt('Unable to query vgatext with arg "%s"' % (sArg,));
2812 return sVgaText;
2813
2814 def queryDbgGuestStack(self, iCpu = 0):
2815 """
2816 Returns the guest stack for the given VCPU.
2817
2818 Returns string containing the guest stack for the selected VCPU on success.
2819 Returns None on failure.
2820 """
2821
2822 #
2823 # Load all plugins first and try to detect the OS so we can
2824 # get nicer stack traces.
2825 #
2826 try:
2827 self.o.console.debugger.loadPlugIn('all');
2828 except:
2829 reporter.logXcpt('Unable to load debugger plugins');
2830 else:
2831 try:
2832 sOsDetected = self.o.console.debugger.detectOS();
2833 _ = sOsDetected;
2834 except:
2835 reporter.logXcpt('Failed to detect the guest OS');
2836
2837 sGuestStack = None;
2838 try:
2839 sGuestStack = self.o.console.debugger.dumpGuestStack(iCpu);
2840 except:
2841 reporter.logXcpt('Unable to query guest stack for CPU %s' % (iCpu, ));
2842
2843 return sGuestStack;
2844
2845
2846 #
2847 # Other methods.
2848 #
2849
2850 def getPrimaryIp(self):
2851 """
2852 Tries to obtain the primary IP address of the guest via the guest
2853 properties.
2854
2855 Returns IP address on success.
2856 Returns empty string on failure.
2857 """
2858 sIpAddr = self.getGuestPropertyValue('/VirtualBox/GuestInfo/Net/0/V4/IP');
2859 if vbox.isIpAddrValid(sIpAddr):
2860 return sIpAddr;
2861 return '';
2862
2863 def getPid(self):
2864 """
2865 Gets the process ID for the direct session unless it's ourselves.
2866 """
2867 if self.uPid is None and self.o is not None and self.fRemoteSession:
2868 try:
2869 if self.fpApiVer >= 4.2:
2870 uPid = self.o.machine.sessionPID;
2871 else:
2872 uPid = self.o.machine.sessionPid;
2873 if uPid != os.getpid() and uPid != 0xffffffff:
2874 self.uPid = uPid;
2875 except Exception as oXcpt:
2876 if vbox.ComError.equal(oXcpt, vbox.ComError.E_UNEXPECTED):
2877 try:
2878 if self.fpApiVer >= 4.2:
2879 uPid = self.oVM.sessionPID;
2880 else:
2881 uPid = self.oVM.sessionPid;
2882 if uPid != os.getpid() and uPid != 0xffffffff:
2883 self.uPid = uPid;
2884 except:
2885 reporter.log2Xcpt();
2886 else:
2887 reporter.log2Xcpt();
2888 if self.uPid is not None:
2889 reporter.log2('getPid: %u' % (self.uPid,));
2890 self.fPidFile = self.oTstDrv.pidFileAdd(self.uPid, 'vm_%s' % (self.sName,), # Set-uid-to-root is similar to SUDO.
2891 fSudo = True);
2892 return self.uPid;
2893
2894 def addLogsToReport(self, cReleaseLogs = 1):
2895 """
2896 Retrieves and adds the release and debug logs to the test report.
2897 """
2898 fRc = True;
2899
2900 # Add each of the requested release logs to the report.
2901 for iLog in range(0, cReleaseLogs):
2902 try:
2903 if self.fpApiVer >= 3.2:
2904 sLogFile = self.oVM.queryLogFilename(iLog);
2905 elif iLog > 0:
2906 sLogFile = '%s/VBox.log' % (self.oVM.logFolder,);
2907 else:
2908 sLogFile = '%s/VBox.log.%u' % (self.oVM.logFolder, iLog);
2909 except:
2910 reporter.logXcpt('iLog=%s' % (iLog,));
2911 fRc = False;
2912 else:
2913 if sLogFile is not None and sLogFile != '': # the None bit is for a 3.2.0 bug.
2914 reporter.addLogFile(sLogFile, 'log/release/vm', '%s #%u' % (self.sName, iLog),
2915 sAltName = '%s-%s' % (self.sName, os.path.basename(sLogFile),));
2916
2917 # Now for the hardened windows startup log.
2918 try:
2919 sLogFile = os.path.join(self.oVM.logFolder, 'VBoxHardening.log');
2920 except:
2921 reporter.logXcpt();
2922 fRc = False;
2923 else:
2924 if os.path.isfile(sLogFile):
2925 reporter.addLogFile(sLogFile, 'log/release/vm', '%s hardening log' % (self.sName, ),
2926 sAltName = '%s-%s' % (self.sName, os.path.basename(sLogFile),));
2927
2928 # Now for the debug log.
2929 if self.sLogFile is not None and os.path.isfile(self.sLogFile):
2930 reporter.addLogFile(self.sLogFile, 'log/debug/vm', '%s debug' % (self.sName, ),
2931 sAltName = '%s-%s' % (self.sName, os.path.basename(self.sLogFile),));
2932
2933 return fRc;
2934
2935 def registerDerivedEventHandler(self, oSubClass, dArgs = None, fMustSucceed = True):
2936 """
2937 Create an instance of the given ConsoleEventHandlerBase sub-class and
2938 register it.
2939
2940 The new instance is returned on success. None is returned on error.
2941 """
2942
2943 # We need a console object.
2944 try:
2945 oConsole = self.o.console;
2946 except Exception as oXcpt:
2947 if fMustSucceed or vbox.ComError.notEqual(oXcpt, vbox.ComError.E_UNEXPECTED):
2948 reporter.errorXcpt('Failed to get ISession::console for "%s"' % (self.sName, ));
2949 return None;
2950
2951 # Add the base class arguments.
2952 dArgsCopy = dArgs.copy() if dArgs is not None else dict();
2953 dArgsCopy['oSession'] = self;
2954 dArgsCopy['oConsole'] = oConsole;
2955 sLogSuffix = 'on %s' % (self.sName,)
2956 return oSubClass.registerDerivedEventHandler(self.oVBoxMgr, self.fpApiVer, oSubClass, dArgsCopy,
2957 oConsole, 'IConsole', 'IConsoleCallback',
2958 fMustSucceed = fMustSucceed, sLogSuffix = sLogSuffix);
2959
2960 def enableVmmDevTestingPart(self, fEnabled, fEnableMMIO = False):
2961 """
2962 Enables the testing part of the VMMDev.
2963
2964 Returns True on success and False on failure. Error information is logged.
2965 """
2966 fRc = True;
2967 try:
2968 self.o.machine.setExtraData('VBoxInternal/Devices/VMMDev/0/Config/TestingEnabled',
2969 '1' if fEnabled else '');
2970 self.o.machine.setExtraData('VBoxInternal/Devices/VMMDev/0/Config/TestingMMIO',
2971 '1' if fEnableMMIO and fEnabled else '');
2972 except:
2973 reporter.errorXcpt('VM name "%s", fEnabled=%s' % (self.sName, fEnabled));
2974 fRc = False;
2975 else:
2976 reporter.log('set VMMDevTesting=%s for "%s"' % (fEnabled, self.sName));
2977 self.oTstDrv.processPendingEvents();
2978 return fRc;
2979
2980 #
2981 # Test eXecution Service methods.
2982 #
2983
2984 def txsConnectViaTcp(self, cMsTimeout = 10*60000, sIpAddr = None, fNatForwardingForTxs = False):
2985 """
2986 Connects to the TXS using TCP/IP as transport. If no IP or MAC is
2987 addresses are specified, we'll get the IP from the guest additions.
2988
2989 Returns a TxsConnectTask object on success, None + log on failure.
2990 """
2991 # If the VM is configured with a NAT interface, connect to local host.
2992 fReversedSetup = False;
2993 fUseNatForTxs = False;
2994 sMacAddr = None;
2995 oIDhcpServer = None;
2996 if sIpAddr is None:
2997 try:
2998 oNic = self.oVM.getNetworkAdapter(0);
2999 enmAttachmentType = oNic.attachmentType;
3000 if enmAttachmentType == vboxcon.NetworkAttachmentType_NAT:
3001 fUseNatForTxs = True;
3002 elif enmAttachmentType == vboxcon.NetworkAttachmentType_HostOnly and not sIpAddr:
3003 # Get the MAC address and find the DHCP server.
3004 sMacAddr = oNic.MACAddress;
3005 sHostOnlyNIC = oNic.hostOnlyInterface;
3006 oIHostOnlyIf = self.oVBox.host.findHostNetworkInterfaceByName(sHostOnlyNIC);
3007 sHostOnlyNet = oIHostOnlyIf.networkName;
3008 oIDhcpServer = self.oVBox.findDHCPServerByNetworkName(sHostOnlyNet);
3009 except:
3010 reporter.errorXcpt();
3011 return None;
3012
3013 if fUseNatForTxs:
3014 fReversedSetup = not fNatForwardingForTxs;
3015 sIpAddr = '127.0.0.1';
3016
3017 # Kick off the task.
3018 try:
3019 oTask = TxsConnectTask(self, cMsTimeout, sIpAddr, sMacAddr, oIDhcpServer, fReversedSetup,
3020 fnProcessEvents = self.oTstDrv.processPendingEvents);
3021 except:
3022 reporter.errorXcpt();
3023 oTask = None;
3024 return oTask;
3025
3026 def txsTryConnectViaTcp(self, cMsTimeout, sHostname, fReversed = False):
3027 """
3028 Attempts to connect to a TXS instance.
3029
3030 Returns True if a connection was established, False if not (only grave
3031 failures are logged as errors).
3032
3033 Note! The timeout is more of a guideline...
3034 """
3035
3036 if sHostname is None or sHostname.strip() == '':
3037 raise base.GenError('Empty sHostname is not implemented yet');
3038
3039 oTxsSession = txsclient.tryOpenTcpSession(cMsTimeout, sHostname, fReversedSetup = fReversed,
3040 cMsIdleFudge = cMsTimeout // 2,
3041 fnProcessEvents = self.oTstDrv.processPendingEvents);
3042 if oTxsSession is None:
3043 return False;
3044
3045 # Wait for the connect task to time out.
3046 self.oTstDrv.addTask(oTxsSession);
3047 self.oTstDrv.processPendingEvents();
3048 oRc = self.oTstDrv.waitForTasks(cMsTimeout);
3049 self.oTstDrv.removeTask(oTxsSession);
3050 if oRc != oTxsSession:
3051 if oRc is not None:
3052 reporter.log('oRc=%s, expected %s' % (oRc, oTxsSession));
3053 self.oTstDrv.processPendingEvents();
3054 oTxsSession.cancelTask(); # this is synchronous
3055 return False;
3056
3057 # Check the status.
3058 reporter.log2('TxsSession is ready, isSuccess() -> %s.' % (oTxsSession.isSuccess(),));
3059 if not oTxsSession.isSuccess():
3060 return False;
3061
3062 reporter.log2('Disconnecting from TXS...');
3063 return oTxsSession.syncDisconnect();
3064
3065
3066
3067class TxsConnectTask(TdTaskBase):
3068 """
3069 Class that takes care of connecting to a VM.
3070 """
3071
3072 class TxsConnectTaskVBoxCallback(vbox.VirtualBoxEventHandlerBase):
3073 """ Class for looking for IPv4 address changes on interface 0."""
3074 def __init__(self, dArgs):
3075 vbox.VirtualBoxEventHandlerBase.__init__(self, dArgs);
3076 self.oParentTask = dArgs['oParentTask'];
3077 self.sMachineId = dArgs['sMachineId'];
3078
3079 def onGuestPropertyChange(self, sMachineId, sName, sValue, sFlags):
3080 """Look for IP address."""
3081 reporter.log2('onGuestPropertyChange(,%s,%s,%s,%s)' % (sMachineId, sName, sValue, sFlags));
3082 if sMachineId == self.sMachineId \
3083 and sName == '/VirtualBox/GuestInfo/Net/0/V4/IP':
3084 oParentTask = self.oParentTask;
3085 if oParentTask:
3086 oParentTask._setIp(sValue); # pylint: disable=protected-access
3087
3088
3089 def __init__(self, oSession, cMsTimeout, sIpAddr, sMacAddr, oIDhcpServer, fReversedSetup, fnProcessEvents = None):
3090 TdTaskBase.__init__(self, utils.getCallerName(), fnProcessEvents = fnProcessEvents);
3091 self.cMsTimeout = cMsTimeout;
3092 self.fnProcessEvents = fnProcessEvents;
3093 self.sIpAddr = None;
3094 self.sNextIpAddr = None;
3095 self.sMacAddr = sMacAddr;
3096 self.oIDhcpServer = oIDhcpServer;
3097 self.fReversedSetup = fReversedSetup;
3098 self.oVBoxEventHandler = None;
3099 self.oTxsSession = None;
3100
3101 # Check that the input makes sense:
3102 if (sMacAddr is None) != (oIDhcpServer is None) \
3103 or (sMacAddr and fReversedSetup) \
3104 or (sMacAddr and sIpAddr):
3105 reporter.error('TxsConnectTask sMacAddr=%s oIDhcpServer=%s sIpAddr=%s fReversedSetup=%s'
3106 % (sMacAddr, oIDhcpServer, sIpAddr, fReversedSetup,));
3107 raise base.GenError();
3108
3109 reporter.log2('TxsConnectTask: sIpAddr=%s fReversedSetup=%s' % (sIpAddr, fReversedSetup))
3110 if fReversedSetup is True:
3111 self._openTcpSession(sIpAddr, fReversedSetup = True);
3112 elif sIpAddr is not None and sIpAddr.strip() != '':
3113 self._openTcpSession(sIpAddr, cMsIdleFudge = 5000);
3114 else:
3115 #
3116 # If we've got no IP address, register callbacks that listens for
3117 # the primary network adaptor of the VM to set a IPv4 guest prop.
3118 # Note! The order in which things are done here is kind of important.
3119 #
3120
3121 # 0. The caller zaps the property before starting the VM.
3122 #try:
3123 # oSession.delGuestPropertyValue('/VirtualBox/GuestInfo/Net/0/V4/IP');
3124 #except:
3125 # reporter.logXcpt();
3126
3127 # 1. Register the callback / event listener object.
3128 dArgs = {'oParentTask':self, 'sMachineId':oSession.o.machine.id};
3129 self.oVBoxEventHandler = oSession.oVBox.registerDerivedEventHandler(self.TxsConnectTaskVBoxCallback, dArgs);
3130
3131 # 2. Query the guest properties.
3132 try:
3133 sIpAddr = oSession.getGuestPropertyValue('/VirtualBox/GuestInfo/Net/0/V4/IP');
3134 except:
3135 reporter.errorXcpt('IMachine::getGuestPropertyValue("/VirtualBox/GuestInfo/Net/0/V4/IP") failed');
3136 self._deregisterEventHandler();
3137 raise;
3138 else:
3139 if sIpAddr is not None:
3140 self._setIp(sIpAddr);
3141
3142 #
3143 # If the network adapter of the VM is host-only we can talk poll IDHCPServer
3144 # for the guest IP, allowing us to detect it for VMs without guest additions.
3145 # This will when we're polled.
3146 #
3147 if sMacAddr is not None:
3148 assert self.oIDhcpServer is not None;
3149
3150
3151 # end __init__
3152
3153 def __del__(self):
3154 """ Make sure we deregister the callback. """
3155 self._deregisterEventHandler();
3156 return TdTaskBase.__del__(self);
3157
3158 def toString(self):
3159 return '<%s cMsTimeout=%s, sIpAddr=%s, sNextIpAddr=%s, sMacAddr=%s, fReversedSetup=%s,' \
3160 ' oTxsSession=%s oVBoxEventHandler=%s>' \
3161 % (TdTaskBase.toString(self), self.cMsTimeout, self.sIpAddr, self.sNextIpAddr, self.sMacAddr, self.fReversedSetup,
3162 self.oTxsSession, self.oVBoxEventHandler);
3163
3164 def _deregisterEventHandler(self):
3165 """Deregisters the event handler."""
3166 fRc = True;
3167 oVBoxEventHandler = self.oVBoxEventHandler;
3168 if oVBoxEventHandler is not None:
3169 self.oVBoxEventHandler = None;
3170 fRc = oVBoxEventHandler.unregister();
3171 oVBoxEventHandler.oParentTask = None; # Try avoid cylic deps.
3172 return fRc;
3173
3174 def _setIp(self, sIpAddr, fInitCall = False):
3175 """Called when we get an IP. Will create a TXS session and signal the task."""
3176 sIpAddr = sIpAddr.strip();
3177
3178 if sIpAddr is not None \
3179 and sIpAddr != '':
3180 if vbox.isIpAddrValid(sIpAddr) or fInitCall:
3181 try:
3182 for s in sIpAddr.split('.'):
3183 i = int(s);
3184 if str(i) != s:
3185 raise Exception();
3186 except:
3187 reporter.fatalXcpt();
3188 else:
3189 reporter.log('TxsConnectTask: opening session to ip "%s"' % (sIpAddr));
3190 self._openTcpSession(sIpAddr, cMsIdleFudge = 5000);
3191 return None;
3192
3193 reporter.log('TxsConnectTask: Ignoring Bad ip "%s"' % (sIpAddr));
3194 else:
3195 reporter.log2('TxsConnectTask: Ignoring empty ip "%s"' % (sIpAddr));
3196 return None;
3197
3198 def _openTcpSession(self, sIpAddr, uPort = None, fReversedSetup = False, cMsIdleFudge = 0):
3199 """
3200 Calls txsclient.openTcpSession and switches our task to reflect the
3201 state of the subtask.
3202 """
3203 self.oCv.acquire();
3204 if self.oTxsSession is None:
3205 reporter.log2('_openTcpSession: sIpAddr=%s, uPort=%d, fReversedSetup=%s' %
3206 (sIpAddr, uPort if uPort is not None else 0, fReversedSetup));
3207 self.sIpAddr = sIpAddr;
3208 self.oTxsSession = txsclient.openTcpSession(self.cMsTimeout, sIpAddr, uPort, fReversedSetup,
3209 cMsIdleFudge, fnProcessEvents = self.fnProcessEvents);
3210 self.oTxsSession.setTaskOwner(self);
3211 else:
3212 self.sNextIpAddr = sIpAddr;
3213 reporter.log2('_openTcpSession: sNextIpAddr=%s' % (sIpAddr,));
3214 self.oCv.release();
3215 return None;
3216
3217 def notifyAboutReadyTask(self, oTxsSession):
3218 """
3219 Called by the TXS session task when it's done.
3220
3221 We'll signal the task completed or retry depending on the result.
3222 """
3223
3224 self.oCv.acquire();
3225
3226 # Disassociate ourselves with the session (avoid cyclic ref)
3227 oTxsSession.setTaskOwner(None);
3228 fSuccess = oTxsSession.isSuccess();
3229 if self.oTxsSession is not None:
3230 if not fSuccess:
3231 self.oTxsSession = None;
3232 if fSuccess and self.fReversedSetup:
3233 self.sIpAddr = oTxsSession.oTransport.sHostname;
3234 else:
3235 fSuccess = False;
3236
3237 # Signal done, or retry?
3238 fDeregister = False;
3239 if fSuccess \
3240 or self.fReversedSetup \
3241 or self.getAgeAsMs() >= self.cMsTimeout:
3242 self.signalTaskLocked();
3243 fDeregister = True;
3244 else:
3245 sIpAddr = self.sNextIpAddr if self.sNextIpAddr is not None else self.sIpAddr;
3246 self._openTcpSession(sIpAddr, cMsIdleFudge = 5000);
3247
3248 self.oCv.release();
3249
3250 # If we're done, deregister the callback (w/o owning lock). It will
3251 if fDeregister:
3252 self._deregisterEventHandler();
3253 return True;
3254
3255 def _pollDhcpServer(self):
3256 """
3257 Polls the DHCP server by MAC address in host-only setups.
3258 """
3259
3260 if self.sIpAddr:
3261 return False;
3262
3263 if self.oIDhcpServer is None or not self.sMacAddr:
3264 return False;
3265
3266 try:
3267 (sIpAddr, sState, secIssued, secExpire) = self.oIDhcpServer.findLeaseByMAC(self.sMacAddr, 0);
3268 except:
3269 reporter.log4Xcpt('sMacAddr=%s' % (self.sMacAddr,));
3270 return False;
3271
3272 secNow = utils.secondsSinceUnixEpoch();
3273 reporter.log2('dhcp poll: secNow=%s secExpire=%s secIssued=%s sState=%s sIpAddr=%s'
3274 % (secNow, secExpire, secIssued, sState, sIpAddr,));
3275 if secNow > secExpire or sState != 'acked' or not sIpAddr:
3276 return False;
3277
3278 reporter.log('dhcp poll: sIpAddr=%s secExpire=%s (%s TTL) secIssued=%s (%s ago)'
3279 % (sIpAddr, secExpire, secExpire - secNow, secIssued, secNow - secIssued,));
3280 self._setIp(sIpAddr);
3281 return True;
3282
3283 #
3284 # Task methods
3285 #
3286
3287 def pollTask(self, fLocked = False):
3288 """
3289 Overridden pollTask method.
3290 """
3291 self._pollDhcpServer();
3292 return TdTaskBase.pollTask(self, fLocked);
3293
3294 #
3295 # Public methods
3296 #
3297
3298 def getResult(self):
3299 """
3300 Returns the connected TXS session object on success.
3301 Returns None on failure or if the task has not yet completed.
3302 """
3303 self.oCv.acquire();
3304 oTxsSession = self.oTxsSession;
3305 self.oCv.release();
3306
3307 if oTxsSession is not None and not oTxsSession.isSuccess():
3308 oTxsSession = None;
3309 return oTxsSession;
3310
3311 def cancelTask(self):
3312 """ Cancels the task. """
3313 self._deregisterEventHandler(); # (make sure to avoid cyclic fun)
3314 self.oCv.acquire();
3315 if not self.fSignalled:
3316 oTxsSession = self.oTxsSession;
3317 if oTxsSession is not None:
3318 self.oCv.release();
3319 oTxsSession.setTaskOwner(None);
3320 oTxsSession.cancelTask();
3321 oTxsSession.waitForTask(1000);
3322 self.oCv.acquire();
3323 self.signalTaskLocked();
3324 self.oCv.release();
3325 return True;
3326
3327
3328
3329class AdditionsStatusTask(TdTaskBase):
3330 """
3331 Class that takes care of waiting till the guest additions are in a given state.
3332 """
3333
3334 class AdditionsStatusTaskCallback(vbox.EventHandlerBase):
3335 """ Class for looking for IPv4 address changes on interface 0."""
3336 def __init__(self, dArgs):
3337 self.oParentTask = dArgs['oParentTask'];
3338 vbox.EventHandlerBase.__init__(self, dArgs, self.oParentTask.oSession.fpApiVer,
3339 'AdditionsStatusTaskCallback/%s' % (self.oParentTask.oSession.sName,));
3340
3341 def handleEvent(self, oEvt):
3342 try:
3343 enmType = oEvt.type;
3344 except:
3345 reporter.errorXcpt();
3346 else:
3347 reporter.log2('AdditionsStatusTaskCallback:handleEvent: enmType=%s' % (enmType,));
3348 if enmType == vboxcon.VBoxEventType_OnGuestAdditionsStatusChanged:
3349 oParentTask = self.oParentTask;
3350 if oParentTask:
3351 oParentTask.pollTask();
3352
3353 # end
3354
3355
3356 def __init__(self, oSession, oIGuest, cMsTimeout = 120000, aenmWaitForRunLevels = None, aenmWaitForActive = None,
3357 aenmWaitForInactive = None):
3358 """
3359 aenmWaitForRunLevels - List of run level values to wait for (success if one matches).
3360 aenmWaitForActive - List facilities (type values) that must be active.
3361 aenmWaitForInactive - List facilities (type values) that must be inactive.
3362
3363 The default is to wait for AdditionsRunLevelType_Userland if all three lists
3364 are unspecified or empty.
3365 """
3366 TdTaskBase.__init__(self, utils.getCallerName());
3367 self.oSession = oSession # type: vboxwrappers.SessionWrapper
3368 self.oIGuest = oIGuest;
3369 self.cMsTimeout = cMsTimeout;
3370 self.fSucceeded = False;
3371 self.oVBoxEventHandler = None;
3372 self.aenmWaitForRunLevels = aenmWaitForRunLevels if aenmWaitForRunLevels else [];
3373 self.aenmWaitForActive = aenmWaitForActive if aenmWaitForActive else [];
3374 self.aenmWaitForInactive = aenmWaitForInactive if aenmWaitForInactive else [];
3375
3376 # Provide a sensible default if nothing is given.
3377 if not self.aenmWaitForRunLevels and not self.aenmWaitForActive and not self.aenmWaitForInactive:
3378 self.aenmWaitForRunLevels = [vboxcon.AdditionsRunLevelType_Userland,];
3379
3380 # Register the event handler on hosts which has it:
3381 if oSession.fpApiVer >= 6.1 or hasattr(vboxcon, 'VBoxEventType_OnGuestAdditionsStatusChanged'):
3382 aenmEvents = (vboxcon.VBoxEventType_OnGuestAdditionsStatusChanged,);
3383 dArgs = {
3384 'oParentTask': self,
3385 };
3386 self.oVBoxEventHandler = vbox.EventHandlerBase.registerDerivedEventHandler(oSession.oVBoxMgr,
3387 oSession.fpApiVer,
3388 self.AdditionsStatusTaskCallback,
3389 dArgs,
3390 oIGuest,
3391 'IGuest',
3392 'AdditionsStatusTaskCallback',
3393 aenmEvents = aenmEvents);
3394 reporter.log2('AdditionsStatusTask: %s' % (self.toString(), ));
3395
3396 def __del__(self):
3397 """ Make sure we deregister the callback. """
3398 self._deregisterEventHandler();
3399 self.oIGuest = None;
3400 return TdTaskBase.__del__(self);
3401
3402 def toString(self):
3403 return '<%s cMsTimeout=%s, fSucceeded=%s, aenmWaitForRunLevels=%s, aenmWaitForActive=%s, aenmWaitForInactive=%s, ' \
3404 'oVBoxEventHandler=%s>' \
3405 % (TdTaskBase.toString(self), self.cMsTimeout, self.fSucceeded, self.aenmWaitForRunLevels, self.aenmWaitForActive,
3406 self.aenmWaitForInactive, self.oVBoxEventHandler,);
3407
3408 def _deregisterEventHandler(self):
3409 """Deregisters the event handler."""
3410 fRc = True;
3411 oVBoxEventHandler = self.oVBoxEventHandler;
3412 if oVBoxEventHandler is not None:
3413 self.oVBoxEventHandler = None;
3414 fRc = oVBoxEventHandler.unregister();
3415 oVBoxEventHandler.oParentTask = None; # Try avoid cylic deps.
3416 return fRc;
3417
3418 def _poll(self):
3419 """
3420 Internal worker for pollTask() that returns the new signalled state.
3421 """
3422
3423 #
3424 # Check if any of the runlevels we wait for have been reached:
3425 #
3426 if self.aenmWaitForRunLevels:
3427 try:
3428 enmRunLevel = self.oIGuest.additionsRunLevel;
3429 except:
3430 reporter.errorXcpt();
3431 return True;
3432 if enmRunLevel not in self.aenmWaitForRunLevels:
3433 reporter.log2('AdditionsStatusTask/poll: enmRunLevel=%s not in %s' % (enmRunLevel, self.aenmWaitForRunLevels,));
3434 return False;
3435 reporter.log2('AdditionsStatusTask/poll: enmRunLevel=%s matched %s!' % (enmRunLevel, self.aenmWaitForRunLevels,));
3436
3437
3438 #
3439 # Check for the facilities that must all be active.
3440 #
3441 for enmFacility in self.aenmWaitForActive:
3442 try:
3443 (enmStatus, _) = self.oIGuest.getFacilityStatus(enmFacility);
3444 except:
3445 reporter.errorXcpt('enmFacility=%s' % (enmFacility,));
3446 return True;
3447 if enmStatus != vboxcon.AdditionsFacilityStatus_Active:
3448 reporter.log2('AdditionsStatusTask/poll: enmFacility=%s not active: %s' % (enmFacility, enmStatus,));
3449 return False;
3450
3451 #
3452 # Check for the facilities that must all be inactive or terminated.
3453 #
3454 for enmFacility in self.aenmWaitForInactive:
3455 try:
3456 (enmStatus, _) = self.oIGuest.getFacilityStatus(enmFacility);
3457 except:
3458 reporter.errorXcpt('enmFacility=%s' % (enmFacility,));
3459 return True;
3460 if enmStatus not in (vboxcon.AdditionsFacilityStatus_Inactive,
3461 vboxcon.AdditionsFacilityStatus_Terminated):
3462 reporter.log2('AdditionsStatusTask/poll: enmFacility=%s not inactive: %s' % (enmFacility, enmStatus,));
3463 return False;
3464
3465
3466 reporter.log('AdditionsStatusTask: Poll succeeded, signalling...');
3467 self.fSucceeded = True;
3468 return True;
3469
3470
3471 #
3472 # Task methods
3473 #
3474
3475 def pollTask(self, fLocked = False):
3476 """
3477 Overridden pollTask method.
3478 """
3479 if not fLocked:
3480 self.lockTask();
3481
3482 fDeregister = False;
3483 fRc = self.fSignalled;
3484 if not fRc:
3485 fRc = self._poll();
3486 if fRc or self.getAgeAsMs() >= self.cMsTimeout:
3487 self.signalTaskLocked();
3488 fDeregister = True;
3489
3490 if not fLocked:
3491 self.unlockTask();
3492
3493 # If we're done, deregister the event callback (w/o owning lock).
3494 if fDeregister:
3495 self._deregisterEventHandler();
3496 return fRc;
3497
3498 def getResult(self):
3499 """
3500 Returns true if the we succeeded.
3501 Returns false if not. If the task is signalled already, then we
3502 encountered a problem while polling.
3503 """
3504 return self.fSucceeded;
3505
3506 def cancelTask(self):
3507 """
3508 Cancels the task.
3509 Just to actively disengage the event handler.
3510 """
3511 self._deregisterEventHandler();
3512 return True;
3513
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