VirtualBox

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

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

ValidationKit: fix copy/pasto

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