VirtualBox

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

Last change on this file since 87004 was 86502, checked in by vboxsync, 4 years ago

ValKit/vboxwrappers.py: Drop the ISession reference when VBoxSVC closed our direct session for us, we'll end up retry closing it during garbage collection, which is totally pointless. bugref:9841

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