VirtualBox

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

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

testdriver: Hack to work around what seems like missing processing during syncUploadFile in tdAddGuestCtrl.py/prepareGuestForTesting. bugref:9151 bugref:9320 bug

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