VirtualBox

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

Last change on this file since 79066 was 79056, checked in by vboxsync, 6 years ago

ValKit/tdGuestOsUnattendedInst1: Added option for installing guest additions and implemented waiting for them to come online. bugref:9151

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