VirtualBox

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

Last change on this file since 79142 was 79087, checked in by vboxsync, 6 years ago

ValKit: New pylint version - cleanup in progress.

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