VirtualBox

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

最後變更 在這個檔案從79915是 79912,由 vboxsync 提交於 6 年 前

ValKit/vboxwrappers.py: Try create a new host-only interface is no suitable one is found. [fixes] bugref:9151

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 137.6 KB
 
1# -*- coding: utf-8 -*-
2# $Id: vboxwrappers.py 79912 2019-07-21 15:41:29Z 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.alldomusa.eu.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: 79912 $"
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
1441 elif eAttachmentType == vboxcon.NetworkAttachmentType_HostOnly:
1442 try:
1443 aoHostNics = self.oVBoxMgr.getArray(self.oVBox.host, 'networkInterfaces');
1444 for oHostNic in aoHostNics:
1445 if oHostNic.interfaceType == vboxcon.HostNetworkInterfaceType_HostOnly:
1446 if oHostNic.status == vboxcon.HostNetworkInterfaceStatus_Up:
1447 sRetName = oHostNic.name;
1448 break;
1449 if sRetName == '':
1450 sRetName = oHostNic.name;
1451 except:
1452 reporter.errorXcpt();
1453 if sRetName == '':
1454 # Create a new host-only interface.
1455 reporter.log("Creating host only NIC ...");
1456 try:
1457 (oIProgress, oIHostOnly) = self.oVBox.host.createHostOnlyNetworkInterface();
1458 oProgress = ProgressWrapper(oIProgress, self.oVBoxMgr, self.oTstDrv, 'Create host only NIC');
1459 oProgress.wait();
1460 if oProgress.logResult() is False:
1461 return '';
1462 sRetName = oIHostOnly.name;
1463 except:
1464 reporter.errorXcpt();
1465 return '';
1466 reporter.log("Created host only NIC: '%s'" % (sRetName,));
1467
1468 elif eAttachmentType == vboxcon.NetworkAttachmentType_Internal:
1469 sRetName = 'VBoxTest';
1470
1471 elif eAttachmentType == vboxcon.NetworkAttachmentType_NAT:
1472 sRetName = '';
1473
1474 else: ## @todo Support NetworkAttachmentType_NATNetwork
1475 reporter.error('eAttachmentType=%s is not known' % (eAttachmentType));
1476 return sRetName;
1477
1478 def setNicAttachment(self, eAttachmentType, sName = None, iNic = 0):
1479 """
1480 Sets the attachment type of the specified NIC.
1481 Returns True on success and False on failure. Error information is logged.
1482 """
1483 try:
1484 oNic = self.o.machine.getNetworkAdapter(iNic);
1485 except:
1486 reporter.errorXcpt('getNetworkAdapter(%s) failed for "%s"' % (iNic, self.sName));
1487 return False;
1488
1489 try:
1490 if eAttachmentType is not None:
1491 try:
1492 if self.fpApiVer >= 4.1:
1493 oNic.attachmentType = eAttachmentType;
1494 else:
1495 if eAttachmentType == vboxcon.NetworkAttachmentType_NAT:
1496 oNic.attachToNAT();
1497 elif eAttachmentType == vboxcon.NetworkAttachmentType_Bridged:
1498 oNic.attachToBridgedInterface();
1499 elif eAttachmentType == vboxcon.NetworkAttachmentType_Internal:
1500 oNic.attachToInternalNetwork();
1501 elif eAttachmentType == vboxcon.NetworkAttachmentType_HostOnly:
1502 oNic.attachToHostOnlyInterface();
1503 else:
1504 raise base.GenError("eAttachmentType=%s is invalid" % (eAttachmentType));
1505 except:
1506 reporter.errorXcpt('failed to set the attachment type on slot %s to %s for VM "%s"' \
1507 % (iNic, eAttachmentType, self.sName));
1508 return False;
1509 else:
1510 try:
1511 eAttachmentType = oNic.attachmentType;
1512 except:
1513 reporter.errorXcpt('failed to get the attachment type on slot %s for VM "%s"' % (iNic, self.sName));
1514 return False;
1515 finally:
1516 self.oTstDrv.processPendingEvents();
1517
1518 if sName is not None:
1519 # Resolve the special 'default' name.
1520 if sName == 'default':
1521 sName = self.getDefaultNicName(eAttachmentType);
1522
1523 # The name translate to different attributes depending on the
1524 # attachment type.
1525 try:
1526 if eAttachmentType == vboxcon.NetworkAttachmentType_Bridged:
1527 ## @todo check this out on windows, may have to do a
1528 # translation of the name there or smth IIRC.
1529 try:
1530 if self.fpApiVer >= 4.1:
1531 oNic.bridgedInterface = sName;
1532 else:
1533 oNic.hostInterface = sName;
1534 except:
1535 reporter.errorXcpt('failed to set the hostInterface property on slot %s to "%s" for VM "%s"'
1536 % (iNic, sName, self.sName,));
1537 return False;
1538 elif eAttachmentType == vboxcon.NetworkAttachmentType_HostOnly:
1539 try:
1540 if self.fpApiVer >= 4.1:
1541 oNic.hostOnlyInterface = sName;
1542 else:
1543 oNic.hostInterface = sName;
1544 except:
1545 reporter.errorXcpt('failed to set the internalNetwork property on slot %s to "%s" for VM "%s"'
1546 % (iNic, sName, self.sName,));
1547 return False;
1548 elif eAttachmentType == vboxcon.NetworkAttachmentType_Internal:
1549 try:
1550 oNic.internalNetwork = sName;
1551 except:
1552 reporter.errorXcpt('failed to set the internalNetwork property on slot %s to "%s" for VM "%s"'
1553 % (iNic, sName, self.sName,));
1554 return False;
1555 elif eAttachmentType == vboxcon.NetworkAttachmentType_NAT:
1556 try:
1557 oNic.NATNetwork = sName;
1558 except:
1559 reporter.errorXcpt('failed to set the NATNetwork property on slot %s to "%s" for VM "%s"'
1560 % (iNic, sName, self.sName,));
1561 return False;
1562 finally:
1563 self.oTstDrv.processPendingEvents();
1564
1565 if not self.setupNatForwardingForTxs(iNic):
1566 return False;
1567 reporter.log('set NIC type on slot %s to %s for VM "%s"' % (iNic, eAttachmentType, self.sName));
1568 return True;
1569
1570 def setNicMacAddress(self, sMacAddr, iNic = 0):
1571 """
1572 Sets the MAC address of the specified NIC.
1573
1574 The sMacAddr parameter is a string supplying the tail end of the MAC
1575 address, missing quads are supplied from a constant byte (2), the IPv4
1576 address of the host, and the NIC number.
1577
1578 Returns True on success and False on failure. Error information is logged.
1579 """
1580
1581 # Resolve missing MAC address prefix by feeding in the host IP address bytes.
1582 cchMacAddr = len(sMacAddr);
1583 if 0 < cchMacAddr < 12:
1584 sHostIP = netutils.getPrimaryHostIp();
1585 abHostIP = socket.inet_aton(sHostIP);
1586 if sys.version_info[0] < 3:
1587 abHostIP = (ord(abHostIP[0]), ord(abHostIP[1]), ord(abHostIP[2]), ord(abHostIP[3]));
1588
1589 if abHostIP[0] == 127 \
1590 or (abHostIP[0] == 169 and abHostIP[1] == 254) \
1591 or (abHostIP[0] == 192 and abHostIP[1] == 168 and abHostIP[2] == 56):
1592 return reporter.error('host IP for "%s" is %s, most likely not unique.' % (netutils.getHostnameFqdn(), sHostIP,));
1593
1594 sDefaultMac = '%02X%02X%02X%02X%02X%02X' % (0x02, abHostIP[0], abHostIP[1], abHostIP[2], abHostIP[3], iNic);
1595 sMacAddr = sDefaultMac[0:(12 - cchMacAddr)] + sMacAddr;
1596
1597 # Get the NIC object and try set it address.
1598 try:
1599 oNic = self.o.machine.getNetworkAdapter(iNic);
1600 except:
1601 return reporter.errorXcpt('getNetworkAdapter(%s) failed for "%s"' % (iNic, self.sName,));
1602
1603 try:
1604 oNic.MACAddress = sMacAddr;
1605 except:
1606 return reporter.errorXcpt('failed to set the MAC address on slot %s to "%s" for VM "%s"'
1607 % (iNic, sMacAddr, self.sName));
1608
1609 reporter.log('set MAC address on slot %s to %s for VM "%s"' % (iNic, sMacAddr, self.sName,));
1610 return True;
1611
1612 def setRamSize(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.memorySize = cMB;
1620 except:
1621 reporter.errorXcpt('failed to set the RAM size of "%s" to %s' % (self.sName, cMB));
1622 fRc = False;
1623 else:
1624 reporter.log('set the RAM size of "%s" to %s' % (self.sName, cMB));
1625 self.oTstDrv.processPendingEvents();
1626 return fRc;
1627
1628 def setVRamSize(self, cMB):
1629 """
1630 Set the RAM size of the VM.
1631 Returns True on success and False on failure. Error information is logged.
1632 """
1633 fRc = True;
1634 try:
1635 self.o.machine.VRAMSize = cMB;
1636 except:
1637 reporter.errorXcpt('failed to set the VRAM size of "%s" to %s' % (self.sName, cMB));
1638 fRc = False;
1639 else:
1640 reporter.log('set the VRAM size of "%s" to %s' % (self.sName, cMB));
1641 self.oTstDrv.processPendingEvents();
1642 return fRc;
1643
1644 def setCpuCount(self, cCpus):
1645 """
1646 Set the number of CPUs.
1647 Returns True on success and False on failure. Error information is logged.
1648 """
1649 fRc = True;
1650 try:
1651 self.o.machine.CPUCount = cCpus;
1652 except:
1653 reporter.errorXcpt('failed to set the CPU count of "%s" to %s' % (self.sName, cCpus));
1654 fRc = False;
1655 else:
1656 reporter.log('set the CPU count of "%s" to %s' % (self.sName, cCpus));
1657 self.oTstDrv.processPendingEvents();
1658 return fRc;
1659
1660 def getCpuCount(self):
1661 """
1662 Returns the number of CPUs.
1663 Returns the number of CPUs on success and 0 on failure. Error information is logged.
1664 """
1665 cCpus = 0;
1666 try:
1667 cCpus = self.o.machine.CPUCount;
1668 except:
1669 reporter.errorXcpt('failed to get the CPU count of "%s"' % (self.sName,));
1670
1671 self.oTstDrv.processPendingEvents();
1672 return cCpus;
1673
1674 def ensureControllerAttached(self, sController):
1675 """
1676 Makes sure the specified controller is attached to the VM, attaching it
1677 if necessary.
1678 """
1679 try:
1680 try:
1681 self.o.machine.getStorageControllerByName(sController);
1682 except:
1683 (eBus, eType) = _ControllerNameToBusAndType(sController);
1684 try:
1685 oCtl = self.o.machine.addStorageController(sController, eBus);
1686 except:
1687 reporter.errorXcpt('addStorageController("%s",%s) failed on "%s"' % (sController, eBus, self.sName) );
1688 return False;
1689 else:
1690 try:
1691 oCtl.controllerType = eType;
1692 reporter.log('added storage controller "%s" (bus %s, type %s) to %s'
1693 % (sController, eBus, eType, self.sName));
1694 except:
1695 reporter.errorXcpt('controllerType = %s on ("%s" / %s) failed on "%s"'
1696 % (eType, sController, eBus, self.sName) );
1697 return False;
1698 finally:
1699 self.oTstDrv.processPendingEvents();
1700 return True;
1701
1702 def setStorageControllerPortCount(self, sController, iPortCount):
1703 """
1704 Set maximum ports count for storage controller
1705 """
1706 try:
1707 oCtl = self.o.machine.getStorageControllerByName(sController)
1708 oCtl.portCount = iPortCount
1709 self.oTstDrv.processPendingEvents()
1710 reporter.log('set controller "%s" port count to value %d' % (sController, iPortCount))
1711 return True
1712 except:
1713 reporter.log('unable to set storage controller "%s" ports count to %d' % (sController, iPortCount))
1714
1715 return False
1716
1717 def setStorageControllerHostIoCache(self, sController, fUseHostIoCache):
1718 """
1719 Set maximum ports count for storage controller
1720 """
1721 try:
1722 oCtl = self.o.machine.getStorageControllerByName(sController);
1723 oCtl.useHostIOCache = fUseHostIoCache;
1724 self.oTstDrv.processPendingEvents();
1725 reporter.log('set controller "%s" host I/O cache setting to %r' % (sController, fUseHostIoCache));
1726 return True;
1727 except:
1728 reporter.log('unable to set storage controller "%s" host I/O cache setting to %r' % (sController, fUseHostIoCache));
1729
1730 return False;
1731
1732 def setBootOrder(self, iPosition, eType):
1733 """
1734 Set guest boot order type
1735 @param iPosition boot order position
1736 @param eType device type (vboxcon.DeviceType_HardDisk,
1737 vboxcon.DeviceType_DVD, vboxcon.DeviceType_Floppy)
1738 """
1739 try:
1740 self.o.machine.setBootOrder(iPosition, eType)
1741 except:
1742 return reporter.errorXcpt('Unable to set boot order.')
1743
1744 reporter.log('Set boot order [%d] for device %s' % (iPosition, str(eType)))
1745 self.oTstDrv.processPendingEvents();
1746
1747 return True
1748
1749 def setStorageControllerType(self, eType, sController = "IDE Controller"):
1750 """
1751 Similar to ensureControllerAttached, except it will change the type.
1752 """
1753 try:
1754 oCtl = self.o.machine.getStorageControllerByName(sController);
1755 except:
1756 (eBus, _) = _ControllerNameToBusAndType(sController);
1757 try:
1758 oCtl = self.o.machine.addStorageController(sController, eBus);
1759 reporter.log('added storage controller "%s" (bus %s) to %s' % (sController, eBus, self.sName));
1760 except:
1761 reporter.errorXcpt('addStorageController("%s",%s) failed on "%s"' % (sController, eBus, self.sName) );
1762 return False;
1763 try:
1764 oCtl.controllerType = eType;
1765 except:
1766 reporter.errorXcpt('failed to set controller type of "%s" on "%s" to %s' % (sController, self.sName, eType) );
1767 return False;
1768 reporter.log('set controller type of "%s" on "%s" to %s' % (sController, self.sName, eType) );
1769 self.oTstDrv.processPendingEvents();
1770 return True;
1771
1772 def attachDvd(self, sImage = None, sController = "IDE Controller", iPort = 1, iDevice = 0):
1773 """
1774 Attaches a DVD drive to a VM, optionally with an ISO inserted.
1775 Returns True on success and False on failure. Error information is logged.
1776 """
1777 # Input validation.
1778 if sImage is not None and not self.oTstDrv.isResourceFile(sImage)\
1779 and not os.path.isabs(sImage): ## fixme - testsuite unzip ++
1780 reporter.fatal('"%s" is not in the resource set' % (sImage));
1781 return None;
1782
1783 if not self.ensureControllerAttached(sController):
1784 return False;
1785
1786 # Find/register the image if specified.
1787 oImage = None;
1788 sImageUuid = "";
1789 if sImage is not None:
1790 sFullName = self.oTstDrv.getFullResourceName(sImage)
1791 try:
1792 oImage = self.oVBox.findDVDImage(sFullName);
1793 except:
1794 try:
1795 if self.fpApiVer >= 4.1:
1796 oImage = self.oVBox.openMedium(sFullName, vboxcon.DeviceType_DVD, vboxcon.AccessMode_ReadOnly, False);
1797 elif self.fpApiVer >= 4.0:
1798 oImage = self.oVBox.openMedium(sFullName, vboxcon.DeviceType_DVD, vboxcon.AccessMode_ReadOnly);
1799 else:
1800 oImage = self.oVBox.openDVDImage(sFullName, "");
1801 except vbox.ComException as oXcpt:
1802 if oXcpt.errno != -1:
1803 reporter.errorXcpt('failed to open DVD image "%s" xxx' % (sFullName));
1804 else:
1805 reporter.errorXcpt('failed to open DVD image "%s" yyy' % (sFullName));
1806 return False;
1807 except:
1808 reporter.errorXcpt('failed to open DVD image "%s"' % (sFullName));
1809 return False;
1810 try:
1811 sImageUuid = oImage.id;
1812 except:
1813 reporter.errorXcpt('failed to get the UUID of "%s"' % (sFullName));
1814 return False;
1815
1816 # Attach the DVD.
1817 fRc = True;
1818 try:
1819 if self.fpApiVer >= 4.0:
1820 self.o.machine.attachDevice(sController, iPort, iDevice, vboxcon.DeviceType_DVD, oImage);
1821 else:
1822 self.o.machine.attachDevice(sController, iPort, iDevice, vboxcon.DeviceType_DVD, sImageUuid);
1823 except:
1824 reporter.errorXcpt('attachDevice("%s",%s,%s,HardDisk,"%s") failed on "%s"' \
1825 % (sController, iPort, iDevice, sImageUuid, self.sName) );
1826 fRc = False;
1827 else:
1828 reporter.log('attached DVD to %s, image="%s"' % (self.sName, sImage));
1829 self.oTstDrv.processPendingEvents();
1830 return fRc;
1831
1832 def attachHd(self, sHd, sController = "IDE Controller", iPort = 0, iDevice = 0, fImmutable = True, fForceResource = True):
1833 """
1834 Attaches a HD to a VM.
1835 Returns True on success and False on failure. Error information is logged.
1836 """
1837 # Input validation.
1838 if fForceResource and not self.oTstDrv.isResourceFile(sHd):
1839 reporter.fatal('"%s" is not in the resource set' % (sHd,));
1840 return None;
1841
1842 if not self.ensureControllerAttached(sController):
1843 return False;
1844
1845 # Find the HD, registering it if necessary (as immutable).
1846 if fForceResource:
1847 sFullName = self.oTstDrv.getFullResourceName(sHd);
1848 else:
1849 sFullName = sHd;
1850 try:
1851 oHd = self.oVBox.findHardDisk(sFullName);
1852 except:
1853 try:
1854 if self.fpApiVer >= 4.1:
1855 oHd = self.oVBox.openMedium(sFullName, vboxcon.DeviceType_HardDisk, vboxcon.AccessMode_ReadOnly, False);
1856 elif self.fpApiVer >= 4.0:
1857 oHd = self.oVBox.openMedium(sFullName, vboxcon.DeviceType_HardDisk, vboxcon.AccessMode_ReadOnly);
1858 else:
1859 oHd = self.oVBox.openHardDisk(sFullName, vboxcon.AccessMode_ReadOnly, False, "", False, "");
1860 except:
1861 reporter.errorXcpt('failed to open hd "%s"' % (sFullName));
1862 return False;
1863 try:
1864 if fImmutable:
1865 oHd.type = vboxcon.MediumType_Immutable;
1866 else:
1867 oHd.type = vboxcon.MediumType_Normal;
1868 except:
1869 if fImmutable:
1870 reporter.errorXcpt('failed to set hd "%s" immutable' % (sHd));
1871 else:
1872 reporter.errorXcpt('failed to set hd "%s" normal' % (sHd));
1873 return False;
1874
1875 # Attach it.
1876 fRc = True;
1877 try:
1878 if self.fpApiVer >= 4.0:
1879 self.o.machine.attachDevice(sController, iPort, iDevice, vboxcon.DeviceType_HardDisk, oHd);
1880 else:
1881 self.o.machine.attachDevice(sController, iPort, iDevice, vboxcon.DeviceType_HardDisk, oHd.id);
1882 except:
1883 reporter.errorXcpt('attachDevice("%s",%s,%s,HardDisk,"%s") failed on "%s"' \
1884 % (sController, iPort, iDevice, oHd.id, self.sName) );
1885 fRc = False;
1886 else:
1887 reporter.log('attached "%s" to %s' % (sHd, self.sName));
1888 self.oTstDrv.processPendingEvents();
1889 return fRc;
1890
1891 def createBaseHd(self, sHd, sFmt = "VDI", cb = 10*1024*1024*1024, cMsTimeout = 60000, tMediumVariant = None):
1892 """
1893 Creates a base HD.
1894 Returns Medium object on success and None on failure. Error information is logged.
1895 """
1896 if tMediumVariant is None:
1897 tMediumVariant = (vboxcon.MediumVariant_Standard, );
1898
1899 try:
1900 if self.fpApiVer >= 5.0:
1901 oHd = self.oVBox.createMedium(sFmt, sHd, vboxcon.AccessMode_ReadWrite, vboxcon.DeviceType_HardDisk);
1902 else:
1903 oHd = self.oVBox.createHardDisk(sFmt, sHd);
1904 oProgressXpcom = oHd.createBaseStorage(cb, tMediumVariant);
1905 oProgress = ProgressWrapper(oProgressXpcom, self.oVBoxMgr, self.oTstDrv, 'create base disk %s' % (sHd));
1906 oProgress.wait(cMsTimeout);
1907 oProgress.logResult();
1908 except:
1909 reporter.errorXcpt('failed to create base hd "%s"' % (sHd));
1910 oHd = None
1911
1912 return oHd;
1913
1914 def createDiffHd(self, oParentHd, sHd, sFmt = "VDI"):
1915 """
1916 Creates a differencing HD.
1917 Returns Medium object on success and None on failure. Error information is logged.
1918 """
1919 # Detect the proper format if requested
1920 if sFmt is None:
1921 try:
1922 oHdFmt = oParentHd.mediumFormat;
1923 lstCaps = self.oVBoxMgr.getArray(oHdFmt, 'capabilities');
1924 if vboxcon.MediumFormatCapabilities_Differencing in lstCaps:
1925 sFmt = oHdFmt.id;
1926 else:
1927 sFmt = 'VDI';
1928 except:
1929 reporter.errorXcpt('failed to get preferred diff format for "%s"' % (sHd));
1930 return None;
1931 try:
1932 if self.fpApiVer >= 5.0:
1933 oHd = self.oVBox.createMedium(sFmt, sHd, vboxcon.AccessMode_ReadWrite, vboxcon.DeviceType_HardDisk);
1934 else:
1935 oHd = self.oVBox.createHardDisk(sFmt, sHd);
1936 oProgressXpcom = oParentHd.createDiffStorage(oHd, (vboxcon.MediumVariant_Standard, ))
1937 oProgress = ProgressWrapper(oProgressXpcom, self.oVBoxMgr, self.oTstDrv, 'create diff disk %s' % (sHd));
1938 oProgress.wait();
1939 oProgress.logResult();
1940 except:
1941 reporter.errorXcpt('failed to create diff hd "%s"' % (sHd));
1942 oHd = None
1943
1944 return oHd;
1945
1946 def createAndAttachHd(self, sHd, sFmt = "VDI", sController = "IDE Controller", cb = 10*1024*1024*1024, # pylint: disable=too-many-arguments
1947 iPort = 0, iDevice = 0, fImmutable = True, cMsTimeout = 60000, tMediumVariant = None):
1948 """
1949 Creates and attaches a HD to a VM.
1950 Returns True on success and False on failure. Error information is logged.
1951 """
1952 if not self.ensureControllerAttached(sController):
1953 return False;
1954
1955 oHd = self.createBaseHd(sHd, sFmt, cb, cMsTimeout, tMediumVariant);
1956 if oHd is None:
1957 return False;
1958
1959 fRc = True;
1960 try:
1961 if fImmutable:
1962 oHd.type = vboxcon.MediumType_Immutable;
1963 else:
1964 oHd.type = vboxcon.MediumType_Normal;
1965 except:
1966 if fImmutable:
1967 reporter.errorXcpt('failed to set hd "%s" immutable' % (sHd));
1968 else:
1969 reporter.errorXcpt('failed to set hd "%s" normal' % (sHd));
1970 fRc = False;
1971
1972 # Attach it.
1973 if fRc is True:
1974 try:
1975 if self.fpApiVer >= 4.0:
1976 self.o.machine.attachDevice(sController, iPort, iDevice, vboxcon.DeviceType_HardDisk, oHd);
1977 else:
1978 self.o.machine.attachDevice(sController, iPort, iDevice, vboxcon.DeviceType_HardDisk, oHd.id);
1979 except:
1980 reporter.errorXcpt('attachDevice("%s",%s,%s,HardDisk,"%s") failed on "%s"' \
1981 % (sController, iPort, iDevice, oHd.id, self.sName) );
1982 fRc = False;
1983 else:
1984 reporter.log('attached "%s" to %s' % (sHd, self.sName));
1985
1986 # Delete disk in case of an error
1987 if fRc is False:
1988 try:
1989 oProgressCom = oHd.deleteStorage();
1990 except:
1991 reporter.errorXcpt('deleteStorage() for disk %s failed' % (sHd,));
1992 else:
1993 oProgress = ProgressWrapper(oProgressCom, self.oVBoxMgr, self.oTstDrv, 'delete disk %s' % (sHd));
1994 oProgress.wait();
1995 oProgress.logResult();
1996
1997 self.oTstDrv.processPendingEvents();
1998 return fRc;
1999
2000 def detachHd(self, sController = "IDE Controller", iPort = 0, iDevice = 0):
2001 """
2002 Detaches a HD, if attached, and returns a reference to it (IMedium).
2003
2004 In order to delete the detached medium, the caller must first save
2005 the changes made in this session.
2006
2007 Returns (fRc, oHd), where oHd is None unless fRc is True, and fRc is
2008 your standard success indicator. Error information is logged.
2009 """
2010
2011 # What's attached?
2012 try:
2013 oHd = self.o.machine.getMedium(sController, iPort, iDevice);
2014 except:
2015 if self.oVBoxMgr.xcptIsOurXcptKind() \
2016 and self.oVBoxMgr.xcptIsEqual(None, self.oVBoxMgr.constants.VBOX_E_OBJECT_NOT_FOUND):
2017 reporter.log('No HD attached (to %s %s:%s)' % (sController, iPort, iDevice));
2018 return (True, None);
2019 return (reporter.errorXcpt('Error getting media at port %s, device %s, on %s.'
2020 % (iPort, iDevice, sController)), None);
2021 # Detach it.
2022 try:
2023 self.o.machine.detachDevice(sController, iPort, iDevice);
2024 except:
2025 return (reporter.errorXcpt('detachDevice("%s",%s,%s) failed on "%s"' \
2026 % (sController, iPort, iDevice, self.sName) ), None);
2027 reporter.log('detached HD ("%s",%s,%s) from %s' % (sController, iPort, iDevice, self.sName));
2028 return (True, oHd);
2029
2030 def attachFloppy(self, sFloppy, sController = "Floppy Controller", iPort = 0, iDevice = 0):
2031 """
2032 Attaches a floppy image to a VM.
2033 Returns True on success and False on failure. Error information is logged.
2034 """
2035 # Input validation.
2036 ## @todo Fix this wrt to bootsector-xxx.img from the validationkit.zip.
2037 ##if not self.oTstDrv.isResourceFile(sFloppy):
2038 ## reporter.fatal('"%s" is not in the resource set' % (sFloppy));
2039 ## return None;
2040
2041 if not self.ensureControllerAttached(sController):
2042 return False;
2043
2044 # Find the floppy image, registering it if necessary (as immutable).
2045 sFullName = self.oTstDrv.getFullResourceName(sFloppy);
2046 try:
2047 oFloppy = self.oVBox.findFloppyImage(sFullName);
2048 except:
2049 try:
2050 if self.fpApiVer >= 4.1:
2051 oFloppy = self.oVBox.openMedium(sFullName, vboxcon.DeviceType_Floppy, vboxcon.AccessMode_ReadOnly, False);
2052 elif self.fpApiVer >= 4.0:
2053 oFloppy = self.oVBox.openMedium(sFullName, vboxcon.DeviceType_Floppy, vboxcon.AccessMode_ReadOnly);
2054 else:
2055 oFloppy = self.oVBox.openFloppyImage(sFullName, "");
2056 except:
2057 reporter.errorXcpt('failed to open floppy "%s"' % (sFullName));
2058 return False;
2059 ## @todo the following works but causes trouble below (asserts in main).
2060 #try:
2061 # oFloppy.type = vboxcon.MediumType_Immutable;
2062 #except:
2063 # reporter.errorXcpt('failed to make floppy "%s" immutable' % (sFullName));
2064 # return False;
2065
2066 # Attach it.
2067 fRc = True;
2068 try:
2069 if self.fpApiVer >= 4.0:
2070 self.o.machine.attachDevice(sController, iPort, iDevice, vboxcon.DeviceType_Floppy, oFloppy);
2071 else:
2072 self.o.machine.attachDevice(sController, iPort, iDevice, vboxcon.DeviceType_Floppy, oFloppy.id);
2073 except:
2074 reporter.errorXcpt('attachDevice("%s",%s,%s,Floppy,"%s") failed on "%s"' \
2075 % (sController, iPort, iDevice, oFloppy.id, self.sName) );
2076 fRc = False;
2077 else:
2078 reporter.log('attached "%s" to %s' % (sFloppy, self.sName));
2079 self.oTstDrv.processPendingEvents();
2080 return fRc;
2081
2082 def setupNic(self, sType, sXXX):
2083 """
2084 Sets up a NIC to a VM.
2085 Returns True on success and False on failure. Error information is logged.
2086 """
2087 if sType == "PCNet": enmType = vboxcon.NetworkAdapterType_Am79C973;
2088 elif sType == "PCNetOld": enmType = vboxcon.NetworkAdapterType_Am79C970A;
2089 elif sType == "E1000": enmType = vboxcon.NetworkAdapterType_I82545EM; # MT Server
2090 elif sType == "E1000Desk": enmType = vboxcon.NetworkAdapterType_I82540EM; # MT Desktop
2091 elif sType == "E1000Srv2": enmType = vboxcon.NetworkAdapterType_I82543GC; # T Server
2092 elif sType == "Virtio": enmType = vboxcon.NetworkAdapterType_Virtio;
2093 else:
2094 reporter.error('Invalid NIC type: "%s" (sXXX=%s)' % (sType, sXXX));
2095 return False;
2096 ## @todo Implement me!
2097 if enmType is not None: pass
2098 return True;
2099
2100 def setupAudio(self, eAudioControllerType, fEnable = True, eAudioDriverType = None):
2101 """
2102 Sets up audio.
2103
2104 :param eAudioControllerType: The audio controller type (vboxcon.AudioControllerType_XXX).
2105 :param fEnable: Whether to enable or disable the audio controller (default enable).
2106 :param eAudioDriverType: The audio driver type (vboxcon.AudioDriverType_XXX), picks something suitable
2107 if None is passed (default).
2108 """
2109 try: oAudioAdapter = self.o.machine.audioAdapter;
2110 except: return reporter.errorXcpt('Failed to get the audio adapter.');
2111
2112 try: oAudioAdapter.audioController = eAudioControllerType;
2113 except: return reporter.errorXcpt('Failed to set the audio controller to %s.' % (eAudioControllerType,));
2114
2115 if eAudioDriverType is None:
2116 sHost = utils.getHostOs()
2117 if sHost == 'darwin': eAudioDriverType = vboxcon.AudioDriverType_CoreAudio;
2118 elif sHost == 'win': eAudioDriverType = vboxcon.AudioDriverType_DirectSound;
2119 elif sHost == 'linux': eAudioDriverType = vboxcon.AudioDriverType_Pulse;
2120 elif sHost == 'solaris': eAudioDriverType = vboxcon.AudioDriverType_OSS;
2121 else:
2122 reporter.error('PORTME: Do not know which audio driver to pick for: %s!' % (sHost,));
2123 eAudioDriverType = vboxcon.AudioDriverType_Null;
2124
2125 try: oAudioAdapter.audioDriver = eAudioDriverType;
2126 except: return reporter.errorXcpt('Failed to set the audio driver to %s.' % (eAudioDriverType,))
2127
2128 try: oAudioAdapter.enabled = fEnable;
2129 except: return reporter.errorXcpt('Failed to set the "enabled" property to %s.' % (fEnable,));
2130
2131 reporter.log('set audio adapter type to %d, driver to %d, and enabled to %s'
2132 % (eAudioControllerType, eAudioDriverType, fEnable,));
2133 self.oTstDrv.processPendingEvents();
2134 return True;
2135
2136 def setupPreferredConfig(self): # pylint: disable=too-many-locals
2137 """
2138 Configures the VM according to the preferences of the guest type.
2139 """
2140 try:
2141 sOsTypeId = self.o.machine.OSTypeId;
2142 except:
2143 reporter.errorXcpt('failed to obtain the OSTypeId for "%s"' % (self.sName));
2144 return False;
2145
2146 try:
2147 oOsType = self.oVBox.getGuestOSType(sOsTypeId);
2148 except:
2149 reporter.errorXcpt('getGuestOSType("%s") failed for "%s"' % (sOsTypeId, self.sName));
2150 return False;
2151
2152 # get the attributes.
2153 try:
2154 #sFamilyId = oOsType.familyId;
2155 #f64Bit = oOsType.is64Bit;
2156 fIoApic = oOsType.recommendedIOAPIC;
2157 fVirtEx = oOsType.recommendedVirtEx;
2158 cMBRam = oOsType.recommendedRAM;
2159 cMBVRam = oOsType.recommendedVRAM;
2160 #cMBHdd = oOsType.recommendedHDD;
2161 eNicType = oOsType.adapterType;
2162 if self.fpApiVer >= 3.2:
2163 if self.fpApiVer >= 4.2:
2164 fPae = oOsType.recommendedPAE;
2165 fUsbHid = oOsType.recommendedUSBHID;
2166 fHpet = oOsType.recommendedHPET;
2167 eStorCtlType = oOsType.recommendedHDStorageController;
2168 else:
2169 fPae = oOsType.recommendedPae;
2170 fUsbHid = oOsType.recommendedUsbHid;
2171 fHpet = oOsType.recommendedHpet;
2172 eStorCtlType = oOsType.recommendedHdStorageController;
2173 eFirmwareType = oOsType.recommendedFirmware;
2174 else:
2175 fPae = False;
2176 fUsbHid = False;
2177 fHpet = False;
2178 eFirmwareType = -1;
2179 eStorCtlType = vboxcon.StorageControllerType_PIIX4;
2180 if self.fpApiVer >= 4.0:
2181 eAudioCtlType = oOsType.recommendedAudioController;
2182 except:
2183 reporter.errorXcpt('exception reading IGuestOSType(%s) attribute' % (sOsTypeId));
2184 self.oTstDrv.processPendingEvents();
2185 return False;
2186 self.oTstDrv.processPendingEvents();
2187
2188 # Do the setting. Continue applying settings on error in case the
2189 # caller ignores the return code
2190 fRc = True;
2191 if not self.enableIoApic(fIoApic): fRc = False;
2192 if not self.enableVirtEx(fVirtEx): fRc = False;
2193 if not self.enablePae(fPae): fRc = False;
2194 if not self.setRamSize(cMBRam): fRc = False;
2195 if not self.setVRamSize(cMBVRam): fRc = False;
2196 if not self.setNicType(eNicType, 0): fRc = False;
2197 if self.fpApiVer >= 3.2:
2198 if not self.setFirmwareType(eFirmwareType): fRc = False;
2199 if not self.enableUsbHid(fUsbHid): fRc = False;
2200 if not self.enableHpet(fHpet): fRc = False;
2201 if eStorCtlType in (vboxcon.StorageControllerType_PIIX3,
2202 vboxcon.StorageControllerType_PIIX4,
2203 vboxcon.StorageControllerType_ICH6,):
2204 if not self.setStorageControllerType(eStorCtlType, "IDE Controller"):
2205 fRc = False;
2206 if self.fpApiVer >= 4.0:
2207 if not self.setupAudio(eAudioCtlType): fRc = False;
2208
2209 return fRc;
2210
2211 def addUsbDeviceFilter(self, sName, sVendorId = None, sProductId = None, sRevision = None, # pylint: disable=too-many-arguments
2212 sManufacturer = None, sProduct = None, sSerialNumber = None,
2213 sPort = None, sRemote = None):
2214 """
2215 Creates a USB device filter and inserts it into the VM.
2216 Returns True on success.
2217 Returns False on failure (logged).
2218 """
2219 fRc = True;
2220
2221 try:
2222 oUsbDevFilter = self.o.machine.USBDeviceFilters.createDeviceFilter(sName);
2223 oUsbDevFilter.active = True;
2224 if sVendorId is not None:
2225 oUsbDevFilter.vendorId = sVendorId;
2226 if sProductId is not None:
2227 oUsbDevFilter.productId = sProductId;
2228 if sRevision is not None:
2229 oUsbDevFilter.revision = sRevision;
2230 if sManufacturer is not None:
2231 oUsbDevFilter.manufacturer = sManufacturer;
2232 if sProduct is not None:
2233 oUsbDevFilter.product = sProduct;
2234 if sSerialNumber is not None:
2235 oUsbDevFilter.serialnumber = sSerialNumber;
2236 if sPort is not None:
2237 oUsbDevFilter.port = sPort;
2238 if sRemote is not None:
2239 oUsbDevFilter.remote = sRemote;
2240 try:
2241 self.o.machine.USBDeviceFilters.insertDeviceFilter(0, oUsbDevFilter);
2242 except:
2243 reporter.errorXcpt('insertDeviceFilter(%s) failed on "%s"' \
2244 % (0, self.sName) );
2245 fRc = False;
2246 else:
2247 reporter.log('inserted USB device filter "%s" to %s' % (sName, self.sName));
2248 except:
2249 reporter.errorXcpt('createDeviceFilter("%s") failed on "%s"' \
2250 % (sName, self.sName) );
2251 fRc = False;
2252 return fRc;
2253
2254 def getGuestPropertyValue(self, sName):
2255 """
2256 Gets a guest property value.
2257 Returns the value on success, None on failure (logged).
2258 """
2259 try:
2260 sValue = self.o.machine.getGuestPropertyValue(sName);
2261 except:
2262 reporter.errorXcpt('IMachine::getGuestPropertyValue("%s") failed' % (sName));
2263 return None;
2264 return sValue;
2265
2266 def setGuestPropertyValue(self, sName, sValue):
2267 """
2268 Sets a guest property value.
2269 Returns the True on success, False on failure (logged).
2270 """
2271 try:
2272 self.o.machine.setGuestPropertyValue(sName, sValue);
2273 except:
2274 reporter.errorXcpt('IMachine::setGuestPropertyValue("%s","%s") failed' % (sName, sValue));
2275 return False;
2276 return True;
2277
2278 def delGuestPropertyValue(self, sName):
2279 """
2280 Deletes a guest property value.
2281 Returns the True on success, False on failure (logged).
2282 """
2283 try:
2284 oMachine = self.o.machine;
2285 if self.fpApiVer >= 4.2:
2286 oMachine.deleteGuestProperty(sName);
2287 else:
2288 oMachine.setGuestPropertyValue(sName, '');
2289 except:
2290 reporter.errorXcpt('Unable to delete guest property "%s"' % (sName,));
2291 return False;
2292 return True;
2293
2294 def setExtraData(self, sKey, sValue):
2295 """
2296 Sets extra data.
2297 Returns the True on success, False on failure (logged).
2298 """
2299 try:
2300 self.o.machine.setExtraData(sKey, sValue);
2301 except:
2302 reporter.errorXcpt('IMachine::setExtraData("%s","%s") failed' % (sKey, sValue));
2303 return False;
2304 return True;
2305
2306 def getExtraData(self, sKey):
2307 """
2308 Gets extra data.
2309 Returns value on success, None on failure.
2310 """
2311 try:
2312 sValue = self.o.machine.getExtraData(sKey)
2313 except:
2314 reporter.errorXcpt('IMachine::setExtraData("%s","%s") failed' % (sKey, sValue))
2315 return None
2316 return sValue
2317
2318 def setupTeleporter(self, fEnabled=True, uPort = 6500, sAddress = '', sPassword = ''):
2319 """
2320 Sets up the teleporter for the VM.
2321 Returns True on success, False on failure (logged).
2322 """
2323 try:
2324 self.o.machine.teleporterAddress = sAddress;
2325 self.o.machine.teleporterPort = uPort;
2326 self.o.machine.teleporterPassword = sPassword;
2327 self.o.machine.teleporterEnabled = fEnabled;
2328 except:
2329 reporter.errorXcpt('setupTeleporter(%s, %s, %s, %s)' % (fEnabled, sPassword, uPort, sAddress));
2330 return False;
2331 return True;
2332
2333 def enableTeleporter(self, fEnable=True):
2334 """
2335 Enables or disables the teleporter of the VM.
2336 Returns True on success, False on failure (logged).
2337 """
2338 try:
2339 self.o.machine.teleporterEnabled = fEnable;
2340 except:
2341 reporter.errorXcpt('IMachine::teleporterEnabled=%s failed' % (fEnable));
2342 return False;
2343 return True;
2344
2345 def teleport(self, sHostname = 'localhost', uPort = 6500, sPassword = 'password', cMsMaxDowntime = 250):
2346 """
2347 Wrapper around the IConsole::teleport() method.
2348 Returns a progress object on success, None on failure (logged).
2349 """
2350 reporter.log2('"%s"::teleport(%s,%s,%s,%s)...' % (self.sName, sHostname, uPort, sPassword, cMsMaxDowntime));
2351 try:
2352 oProgress = self.o.console.teleport(sHostname, uPort, sPassword, cMsMaxDowntime)
2353 except:
2354 reporter.errorXcpt('IConsole::teleport(%s,%s,%s,%s) failed' % (sHostname, uPort, sPassword, cMsMaxDowntime));
2355 return None;
2356 return ProgressWrapper(oProgress, self.oVBoxMgr, self.oTstDrv, 'teleport %s' % (self.sName,));
2357
2358 def getOsType(self):
2359 """
2360 Gets the IGuestOSType interface for the machine.
2361
2362 return IGuestOSType interface on success, None + errorXcpt on failure.
2363 No exceptions raised.
2364 """
2365 try:
2366 sOsTypeId = self.o.machine.OSTypeId;
2367 except:
2368 reporter.errorXcpt('failed to obtain the OSTypeId for "%s"' % (self.sName));
2369 return None;
2370
2371 try:
2372 oOsType = self.oVBox.getGuestOSType(sOsTypeId);
2373 except:
2374 reporter.errorXcpt('getGuestOSType("%s") failed for "%s"' % (sOsTypeId, self.sName));
2375 return None;
2376
2377 return oOsType;
2378
2379 def setOsType(self, sNewTypeId):
2380 """
2381 Changes the OS type.
2382
2383 returns True on success, False + errorXcpt on failure.
2384 No exceptions raised.
2385 """
2386 try:
2387 self.o.machine.OSTypeId = sNewTypeId;
2388 except:
2389 reporter.errorXcpt('failed to set the OSTypeId for "%s" to "%s"' % (self.sName, sNewTypeId));
2390 return False;
2391 return True;
2392
2393
2394 def setParavirtProvider(self, iProvider):
2395 """
2396 Sets a paravirtualisation provider.
2397 Returns the True on success, False on failure (logged).
2398 """
2399 try:
2400 self.o.machine.paravirtProvider = iProvider
2401 except:
2402 reporter.errorXcpt('Unable to set paravirtualisation provider "%s"' % (iProvider,))
2403 return False;
2404 return True;
2405
2406
2407 def setupSerialToRawFile(self, iSerialPort, sRawFile):
2408 """
2409 Enables the given serial port (zero based) and redirects it to sRawFile.
2410 Returns the True on success, False on failure (logged).
2411 """
2412 try:
2413 oPort = self.o.machine.getSerialPort(iSerialPort);
2414 except:
2415 fRc = reporter.errorXcpt('failed to get serial port #%u' % (iSerialPort,));
2416 else:
2417 try:
2418 oPort.path = sRawFile;
2419 except:
2420 fRc = reporter.errorXcpt('failed to set the "path" property on serial port #%u to "%s"'
2421 % (iSerialPort, sRawFile));
2422 else:
2423 try:
2424 oPort.hostMode = vboxcon.PortMode_RawFile;
2425 except:
2426 fRc = reporter.errorXcpt('failed to set the "hostMode" property on serial port #%u to PortMode_RawFile'
2427 % (iSerialPort,));
2428 else:
2429 try:
2430 oPort.enabled = True;
2431 except:
2432 fRc = reporter.errorXcpt('failed to set the "enable" property on serial port #%u to True'
2433 % (iSerialPort,));
2434 else:
2435 reporter.log('set SerialPort[%s].enabled/hostMode/path=True/RawFile/%s' % (iSerialPort, sRawFile,));
2436 fRc = True;
2437 self.oTstDrv.processPendingEvents();
2438 return fRc;
2439
2440
2441 def enableSerialPort(self, iSerialPort):
2442 """
2443 Enables the given serial port setting the initial port mode to disconnected.
2444 """
2445 try:
2446 oPort = self.o.machine.getSerialPort(iSerialPort);
2447 except:
2448 fRc = reporter.errorXcpt('failed to get serial port #%u' % (iSerialPort,));
2449 else:
2450 try:
2451 oPort.hostMode = vboxcon.PortMode_Disconnected;
2452 except:
2453 fRc = reporter.errorXcpt('failed to set the "hostMode" property on serial port #%u to PortMode_Disconnected'
2454 % (iSerialPort,));
2455 else:
2456 try:
2457 oPort.enabled = True;
2458 except:
2459 fRc = reporter.errorXcpt('failed to set the "enable" property on serial port #%u to True'
2460 % (iSerialPort,));
2461 else:
2462 reporter.log('set SerialPort[%s].enabled/hostMode/=True/Disconnected' % (iSerialPort,));
2463 fRc = True;
2464 self.oTstDrv.processPendingEvents();
2465 return fRc;
2466
2467
2468 def changeSerialPortAttachment(self, iSerialPort, ePortMode, sPath, fServer):
2469 """
2470 Changes the attachment of the given serial port to the attachment config given.
2471 """
2472 try:
2473 oPort = self.o.machine.getSerialPort(iSerialPort);
2474 except:
2475 fRc = reporter.errorXcpt('failed to get serial port #%u' % (iSerialPort,));
2476 else:
2477 try:
2478 # Change port mode to disconnected first so changes get picked up by a potentially running VM.
2479 oPort.hostMode = vboxcon.PortMode_Disconnected;
2480 except:
2481 fRc = reporter.errorXcpt('failed to set the "hostMode" property on serial port #%u to PortMode_Disconnected'
2482 % (iSerialPort,));
2483 else:
2484 try:
2485 oPort.path = sPath;
2486 oPort.server = fServer;
2487 oPort.hostMode = ePortMode;
2488 except:
2489 fRc = reporter.errorXcpt('failed to configure the serial port');
2490 else:
2491 reporter.log('set SerialPort[%s].hostMode/path/server=%s/%s/%s'
2492 % (iSerialPort, ePortMode, sPath, fServer));
2493 fRc = True;
2494 self.oTstDrv.processPendingEvents();
2495 return fRc;
2496
2497 #
2498 # IConsole wrappers.
2499 #
2500
2501 def powerOff(self, fFudgeOnFailure = True):
2502 """
2503 Powers off the VM.
2504
2505 Returns True on success.
2506 Returns False on IConsole::powerDown() failure.
2507 Returns None if the progress object returns failure.
2508 """
2509 #
2510 # Deregister event handler before we power off the VM, otherwise we're
2511 # racing for VM process termination and cause misleading spurious
2512 # error messages in the event handling code, because the event objects
2513 # disappear.
2514 #
2515 # Note! Doing this before powerDown to try prevent numerous smoketest
2516 # timeouts on XPCOM hosts.
2517 #
2518 self.deregisterEventHandlerForTask();
2519
2520
2521 # Try power if off.
2522 try:
2523 oProgress = self.o.console.powerDown();
2524 except:
2525 reporter.logXcpt('IConsole::powerDown failed on %s' % (self.sName));
2526 if fFudgeOnFailure:
2527 self.oTstDrv.waitOnDirectSessionClose(self.oVM, 5000); # fudge
2528 self.waitForTask(1000); # fudge
2529 return False;
2530
2531 # Wait on power off operation to complete.
2532 rc = self.oTstDrv.waitOnProgress(oProgress);
2533 if rc < 0:
2534 self.close();
2535 if fFudgeOnFailure:
2536 vbox.reportError(oProgress, 'powerDown for "%s" failed' % (self.sName));
2537 self.oTstDrv.waitOnDirectSessionClose(self.oVM, 5000); # fudge
2538 return None;
2539
2540 # Wait for the VM to really power off or we'll fail to open a new session to it.
2541 self.oTstDrv.waitOnDirectSessionClose(self.oVM, 5000); # fudge
2542 return self.waitForTask(30 * 1000); # fudge
2543
2544 def saveState(self, fPause = True):
2545 """
2546 Saves state of the VM.
2547
2548 Returns True on success.
2549 Returns False on IConsole::saveState() failure.
2550 Returns None if the progress object returns Failure.
2551 """
2552
2553 if fPause is True \
2554 and self.oVM.state is vboxcon.MachineState_Running:
2555 self.o.console.pause();
2556 if self.oVM.state is not vboxcon.MachineState_Paused:
2557 reporter.error('pause for "%s" failed' % (self.sName));
2558 # Try saving state.
2559 try:
2560 if self.fpApiVer >= 5.0:
2561 oProgress = self.o.machine.saveState()
2562 else:
2563 oProgress = self.o.console.saveState()
2564 except:
2565 reporter.logXcpt('IMachine::saveState failed on %s' % (self.sName));
2566 return False;
2567
2568 # Wait for saving state operation to complete.
2569 rc = self.oTstDrv.waitOnProgress(oProgress);
2570 if rc < 0:
2571 self.close();
2572 return None;
2573
2574 # Wait for the VM to really terminate or we'll fail to open a new session to it.
2575 self.oTstDrv.waitOnDirectSessionClose(self.oVM, 5000); # fudge
2576 return self.waitForTask(30 * 1000); # fudge
2577
2578 def discardSavedState(self, fRemove = True):
2579 """
2580 Discards saved state of the VM.
2581
2582 Returns True on success.
2583 Returns False on IConsole::discardSaveState() failure.
2584 """
2585
2586 try:
2587 if self.fpApiVer >= 5.0:
2588 self.o.machine.discardSavedState(fRemove)
2589 else:
2590 self.o.console.discardSavedState(fRemove)
2591 except:
2592 reporter.logXcpt('IMachine::discardSavedState failed on %s' % (self.sName))
2593 return False
2594 return True
2595
2596 def restoreSnapshot(self, oSnapshot, fFudgeOnFailure = True):
2597 """
2598 Restores the given snapshot.
2599
2600 Returns True on success.
2601 Returns False on IMachine::restoreSnapshot() failure.
2602 Returns None if the progress object returns failure.
2603 """
2604 try:
2605 if self.fpApiVer >= 5.0:
2606 oProgress = self.o.machine.restoreSnapshot(oSnapshot);
2607 else:
2608 oProgress = self.o.console.restoreSnapshot(oSnapshot);
2609 except:
2610 reporter.logXcpt('IMachine::restoreSnapshot failed on %s' % (self.sName));
2611 if fFudgeOnFailure:
2612 self.oTstDrv.waitOnDirectSessionClose(self.oVM, 5000); # fudge
2613 self.waitForTask(1000); # fudge
2614 return False;
2615
2616 rc = self.oTstDrv.waitOnProgress(oProgress);
2617 if rc < 0:
2618 self.close();
2619 if fFudgeOnFailure:
2620 vbox.reportError(oProgress, 'restoreSnapshot for "%s" failed' % (self.sName));
2621 return None;
2622
2623 return self.waitForTask(30 * 1000);
2624
2625 def deleteSnapshot(self, oSnapshot, fFudgeOnFailure = True, cMsTimeout = 30 * 1000):
2626 """
2627 Deletes the given snapshot merging the diff image into the base.
2628
2629 Returns True on success.
2630 Returns False on IMachine::deleteSnapshot() failure.
2631 """
2632 try:
2633 if self.fpApiVer >= 5.0:
2634 oProgressCom = self.o.machine.deleteSnapshot(oSnapshot);
2635 else:
2636 oProgressCom = self.o.console.deleteSnapshot(oSnapshot);
2637 oProgress = ProgressWrapper(oProgressCom, self.oVBoxMgr, self.oTstDrv, 'Delete Snapshot %s' % (oSnapshot));
2638 oProgress.wait(cMsTimeout);
2639 oProgress.logResult();
2640 except:
2641 reporter.logXcpt('IMachine::deleteSnapshot failed on %s' % (self.sName));
2642 if fFudgeOnFailure:
2643 self.oTstDrv.waitOnDirectSessionClose(self.oVM, 5000); # fudge
2644 self.waitForTask(1000); # fudge
2645 return False;
2646
2647 return True;
2648
2649 def takeSnapshot(self, sName, sDescription = '', fPause = True, fFudgeOnFailure = True, cMsTimeout = 30 * 1000):
2650 """
2651 Takes a snapshot with the given name
2652
2653 Returns True on success.
2654 Returns False on IMachine::takeSnapshot() or VM state change failure.
2655 """
2656 try:
2657 if fPause is True \
2658 and self.oVM.state is vboxcon.MachineState_Running:
2659 self.o.console.pause();
2660 if self.fpApiVer >= 5.0:
2661 (oProgressCom, _) = self.o.machine.takeSnapshot(sName, sDescription, True);
2662 else:
2663 oProgressCom = self.o.console.takeSnapshot(sName, sDescription);
2664 oProgress = ProgressWrapper(oProgressCom, self.oVBoxMgr, self.oTstDrv, 'Take Snapshot %s' % (sName));
2665 oProgress.wait(cMsTimeout);
2666 oProgress.logResult();
2667 except:
2668 reporter.logXcpt('IMachine::takeSnapshot failed on %s' % (self.sName));
2669 if fFudgeOnFailure:
2670 self.oTstDrv.waitOnDirectSessionClose(self.oVM, 5000); # fudge
2671 self.waitForTask(1000); # fudge
2672 return False;
2673
2674 if fPause is True \
2675 and self.oVM.state is vboxcon.MachineState_Paused:
2676 self.o.console.resume();
2677
2678 return True;
2679
2680 def findSnapshot(self, sName):
2681 """
2682 Returns the snapshot object with the given name
2683
2684 Returns snapshot object on success.
2685 Returns None if there is no snapshot with the given name.
2686 """
2687 return self.oVM.findSnapshot(sName);
2688
2689 def takeScreenshot(self, sFilename, iScreenId=0):
2690 """
2691 Take screenshot from the given display and save it to specified file.
2692
2693 Returns True on success
2694 Returns False on failure.
2695 """
2696 try:
2697 if self.fpApiVer >= 5.0:
2698 iWidth, iHeight, _, _, _, _ = self.o.console.display.getScreenResolution(iScreenId)
2699 aPngData = self.o.console.display.takeScreenShotToArray(iScreenId, iWidth, iHeight,
2700 vboxcon.BitmapFormat_PNG)
2701 else:
2702 iWidth, iHeight, _, _, _ = self.o.console.display.getScreenResolution(iScreenId)
2703 aPngData = self.o.console.display.takeScreenShotPNGToArray(iScreenId, iWidth, iHeight)
2704 except:
2705 reporter.logXcpt("Unable to take screenshot")
2706 return False
2707
2708 oFile = open(sFilename, 'wb')
2709 oFile.write(aPngData)
2710 oFile.close()
2711
2712 return True
2713
2714 def attachUsbDevice(self, sUuid, sCaptureFilename = None):
2715 """
2716 Attach given USB device UUID to the VM.
2717
2718 Returns True on success
2719 Returns False on failure.
2720 """
2721 fRc = True;
2722 try:
2723 if sCaptureFilename is None:
2724 self.o.console.attachUSBDevice(sUuid, '');
2725 else:
2726 self.o.console.attachUSBDevice(sUuid, sCaptureFilename);
2727 except:
2728 reporter.logXcpt('Unable to attach USB device %s' % (sUuid,));
2729 fRc = False;
2730
2731 return fRc;
2732
2733 def detachUsbDevice(self, sUuid):
2734 """
2735 Detach given USB device UUID from the VM.
2736
2737 Returns True on success
2738 Returns False on failure.
2739 """
2740 fRc = True;
2741 try:
2742 _ = self.o.console.detachUSBDevice(sUuid);
2743 except:
2744 reporter.logXcpt('Unable to detach USB device %s' % (sUuid,));
2745 fRc = False;
2746
2747 return fRc;
2748
2749
2750 #
2751 # IMachineDebugger wrappers.
2752 #
2753
2754 def queryOsKernelLog(self):
2755 """
2756 Tries to get the OS kernel log using the VM debugger interface.
2757
2758 Returns string containing the kernel log on success.
2759 Returns None on failure.
2760 """
2761 sOsKernelLog = None;
2762 try:
2763 self.o.console.debugger.loadPlugIn('all');
2764 except:
2765 reporter.logXcpt('Unable to load debugger plugins');
2766 else:
2767 try:
2768 sOsDetected = self.o.console.debugger.detectOS();
2769 except:
2770 reporter.logXcpt('Failed to detect the guest OS');
2771 else:
2772 try:
2773 sOsKernelLog = self.o.console.debugger.queryOSKernelLog(0);
2774 except:
2775 reporter.logXcpt('Unable to get the guest OS (%s) kernel log' % (sOsDetected,));
2776 return sOsKernelLog;
2777
2778 def queryDbgInfo(self, sItem, sArg = '', sDefault = None):
2779 """
2780 Simple wrapper around IMachineDebugger::info.
2781
2782 Returns string on success, sDefault on failure (logged).
2783 """
2784 try:
2785 return self.o.console.debugger.info(sItem, sArg);
2786 except:
2787 reporter.logXcpt('Unable to query "%s" with arg "%s"' % (sItem, sArg,));
2788 return sDefault;
2789
2790 def queryDbgInfoVgaText(self, sArg = 'all'):
2791 """
2792 Tries to get the 'info vgatext' output, provided we're in next mode.
2793
2794 Returns string containing text on success.
2795 Returns None on failure or not text mode.
2796 """
2797 sVgaText = None;
2798 try:
2799 sVgaText = self.o.console.debugger.info('vgatext', sArg);
2800 if sVgaText.startswith('Not in text mode!'):
2801 sVgaText = None;
2802 except:
2803 reporter.logXcpt('Unable to query vgatext with arg "%s"' % (sArg,));
2804 return sVgaText;
2805
2806 def queryDbgGuestStack(self, iCpu = 0):
2807 """
2808 Returns the guest stack for the given VCPU.
2809
2810 Returns string containing the guest stack for the selected VCPU on success.
2811 Returns None on failure.
2812 """
2813
2814 #
2815 # Load all plugins first and try to detect the OS so we can
2816 # get nicer stack traces.
2817 #
2818 try:
2819 self.o.console.debugger.loadPlugIn('all');
2820 except:
2821 reporter.logXcpt('Unable to load debugger plugins');
2822 else:
2823 try:
2824 sOsDetected = self.o.console.debugger.detectOS();
2825 _ = sOsDetected;
2826 except:
2827 reporter.logXcpt('Failed to detect the guest OS');
2828
2829 sGuestStack = None;
2830 try:
2831 sGuestStack = self.o.console.debugger.dumpGuestStack(iCpu);
2832 except:
2833 reporter.logXcpt('Unable to query guest stack for CPU %s' % (iCpu, ));
2834
2835 return sGuestStack;
2836
2837
2838 #
2839 # Other methods.
2840 #
2841
2842 def getPrimaryIp(self):
2843 """
2844 Tries to obtain the primary IP address of the guest via the guest
2845 properties.
2846
2847 Returns IP address on success.
2848 Returns empty string on failure.
2849 """
2850 sIpAddr = self.getGuestPropertyValue('/VirtualBox/GuestInfo/Net/0/V4/IP');
2851 if vbox.isIpAddrValid(sIpAddr):
2852 return sIpAddr;
2853 return '';
2854
2855 def getPid(self):
2856 """
2857 Gets the process ID for the direct session unless it's ourselves.
2858 """
2859 if self.uPid is None and self.o is not None and self.fRemoteSession:
2860 try:
2861 if self.fpApiVer >= 4.2:
2862 uPid = self.o.machine.sessionPID;
2863 else:
2864 uPid = self.o.machine.sessionPid;
2865 if uPid != os.getpid() and uPid != 0xffffffff:
2866 self.uPid = uPid;
2867 except Exception as oXcpt:
2868 if vbox.ComError.equal(oXcpt, vbox.ComError.E_UNEXPECTED):
2869 try:
2870 if self.fpApiVer >= 4.2:
2871 uPid = self.oVM.sessionPID;
2872 else:
2873 uPid = self.oVM.sessionPid;
2874 if uPid != os.getpid() and uPid != 0xffffffff:
2875 self.uPid = uPid;
2876 except:
2877 reporter.log2Xcpt();
2878 else:
2879 reporter.log2Xcpt();
2880 if self.uPid is not None:
2881 reporter.log2('getPid: %u' % (self.uPid,));
2882 self.fPidFile = self.oTstDrv.pidFileAdd(self.uPid, 'vm_%s' % (self.sName,), # Set-uid-to-root is similar to SUDO.
2883 fSudo = True);
2884 return self.uPid;
2885
2886 def addLogsToReport(self, cReleaseLogs = 1):
2887 """
2888 Retrieves and adds the release and debug logs to the test report.
2889 """
2890 fRc = True;
2891
2892 # Add each of the requested release logs to the report.
2893 for iLog in range(0, cReleaseLogs):
2894 try:
2895 if self.fpApiVer >= 3.2:
2896 sLogFile = self.oVM.queryLogFilename(iLog);
2897 elif iLog > 0:
2898 sLogFile = '%s/VBox.log' % (self.oVM.logFolder,);
2899 else:
2900 sLogFile = '%s/VBox.log.%u' % (self.oVM.logFolder, iLog);
2901 except:
2902 reporter.logXcpt('iLog=%s' % (iLog,));
2903 fRc = False;
2904 else:
2905 if sLogFile is not None and sLogFile != '': # the None bit is for a 3.2.0 bug.
2906 reporter.addLogFile(sLogFile, 'log/release/vm', '%s #%u' % (self.sName, iLog),
2907 sAltName = '%s-%s' % (self.sName, os.path.basename(sLogFile),));
2908
2909 # Now for the hardened windows startup log.
2910 try:
2911 sLogFile = os.path.join(self.oVM.logFolder, 'VBoxHardening.log');
2912 except:
2913 reporter.logXcpt();
2914 fRc = False;
2915 else:
2916 if os.path.isfile(sLogFile):
2917 reporter.addLogFile(sLogFile, 'log/release/vm', '%s hardening log' % (self.sName, ),
2918 sAltName = '%s-%s' % (self.sName, os.path.basename(sLogFile),));
2919
2920 # Now for the debug log.
2921 if self.sLogFile is not None and os.path.isfile(self.sLogFile):
2922 reporter.addLogFile(self.sLogFile, 'log/debug/vm', '%s debug' % (self.sName, ),
2923 sAltName = '%s-%s' % (self.sName, os.path.basename(self.sLogFile),));
2924
2925 return fRc;
2926
2927 def registerDerivedEventHandler(self, oSubClass, dArgs = None, fMustSucceed = True):
2928 """
2929 Create an instance of the given ConsoleEventHandlerBase sub-class and
2930 register it.
2931
2932 The new instance is returned on success. None is returned on error.
2933 """
2934
2935 # We need a console object.
2936 try:
2937 oConsole = self.o.console;
2938 except Exception as oXcpt:
2939 if fMustSucceed or vbox.ComError.notEqual(oXcpt, vbox.ComError.E_UNEXPECTED):
2940 reporter.errorXcpt('Failed to get ISession::console for "%s"' % (self.sName, ));
2941 return None;
2942
2943 # Add the base class arguments.
2944 dArgsCopy = dArgs.copy() if dArgs is not None else dict();
2945 dArgsCopy['oSession'] = self;
2946 dArgsCopy['oConsole'] = oConsole;
2947 sLogSuffix = 'on %s' % (self.sName,)
2948 return oSubClass.registerDerivedEventHandler(self.oVBoxMgr, self.fpApiVer, oSubClass, dArgsCopy,
2949 oConsole, 'IConsole', 'IConsoleCallback',
2950 fMustSucceed = fMustSucceed, sLogSuffix = sLogSuffix);
2951
2952 def enableVmmDevTestingPart(self, fEnabled, fEnableMMIO = False):
2953 """
2954 Enables the testing part of the VMMDev.
2955
2956 Returns True on success and False on failure. Error information is logged.
2957 """
2958 fRc = True;
2959 try:
2960 self.o.machine.setExtraData('VBoxInternal/Devices/VMMDev/0/Config/TestingEnabled',
2961 '1' if fEnabled else '');
2962 self.o.machine.setExtraData('VBoxInternal/Devices/VMMDev/0/Config/TestingMMIO',
2963 '1' if fEnableMMIO and fEnabled else '');
2964 except:
2965 reporter.errorXcpt('VM name "%s", fEnabled=%s' % (self.sName, fEnabled));
2966 fRc = False;
2967 else:
2968 reporter.log('set VMMDevTesting=%s for "%s"' % (fEnabled, self.sName));
2969 self.oTstDrv.processPendingEvents();
2970 return fRc;
2971
2972 #
2973 # Test eXecution Service methods.
2974 #
2975
2976 def txsConnectViaTcp(self, cMsTimeout = 10*60000, sIpAddr = None, fNatForwardingForTxs = False):
2977 """
2978 Connects to the TXS using TCP/IP as transport. If no IP or MAC is
2979 addresses are specified, we'll get the IP from the guest additions.
2980
2981 Returns a TxsConnectTask object on success, None + log on failure.
2982 """
2983 # If the VM is configured with a NAT interface, connect to local host.
2984 fReversedSetup = False;
2985 fUseNatForTxs = False;
2986 sMacAddr = None;
2987 oIDhcpServer = None;
2988 if sIpAddr is None:
2989 try:
2990 oNic = self.oVM.getNetworkAdapter(0);
2991 enmAttachmentType = oNic.attachmentType;
2992 if enmAttachmentType == vboxcon.NetworkAttachmentType_NAT:
2993 fUseNatForTxs = True;
2994 elif enmAttachmentType == vboxcon.NetworkAttachmentType_HostOnly and not sIpAddr:
2995 # Get the MAC address and find the DHCP server.
2996 sMacAddr = oNic.MACAddress;
2997 sHostOnlyNIC = oNic.hostOnlyInterface;
2998 oIHostOnlyIf = self.oVBox.host.findHostNetworkInterfaceByName(sHostOnlyNIC);
2999 sHostOnlyNet = oIHostOnlyIf.networkName;
3000 oIDhcpServer = self.oVBox.findDHCPServerByNetworkName(sHostOnlyNet);
3001 except:
3002 reporter.errorXcpt();
3003 return None;
3004
3005 if fUseNatForTxs:
3006 fReversedSetup = not fNatForwardingForTxs;
3007 sIpAddr = '127.0.0.1';
3008
3009 # Kick off the task.
3010 try:
3011 oTask = TxsConnectTask(self, cMsTimeout, sIpAddr, sMacAddr, oIDhcpServer, fReversedSetup,
3012 fnProcessEvents = self.oTstDrv.processPendingEvents);
3013 except:
3014 reporter.errorXcpt();
3015 oTask = None;
3016 return oTask;
3017
3018 def txsTryConnectViaTcp(self, cMsTimeout, sHostname, fReversed = False):
3019 """
3020 Attempts to connect to a TXS instance.
3021
3022 Returns True if a connection was established, False if not (only grave
3023 failures are logged as errors).
3024
3025 Note! The timeout is more of a guideline...
3026 """
3027
3028 if sHostname is None or sHostname.strip() == '':
3029 raise base.GenError('Empty sHostname is not implemented yet');
3030
3031 oTxsSession = txsclient.tryOpenTcpSession(cMsTimeout, sHostname, fReversedSetup = fReversed,
3032 cMsIdleFudge = cMsTimeout // 2,
3033 fnProcessEvents = self.oTstDrv.processPendingEvents);
3034 if oTxsSession is None:
3035 return False;
3036
3037 # Wait for the connect task to time out.
3038 self.oTstDrv.addTask(oTxsSession);
3039 self.oTstDrv.processPendingEvents();
3040 oRc = self.oTstDrv.waitForTasks(cMsTimeout);
3041 self.oTstDrv.removeTask(oTxsSession);
3042 if oRc != oTxsSession:
3043 if oRc is not None:
3044 reporter.log('oRc=%s, expected %s' % (oRc, oTxsSession));
3045 self.oTstDrv.processPendingEvents();
3046 oTxsSession.cancelTask(); # this is synchronous
3047 return False;
3048
3049 # Check the status.
3050 reporter.log2('TxsSession is ready, isSuccess() -> %s.' % (oTxsSession.isSuccess(),));
3051 if not oTxsSession.isSuccess():
3052 return False;
3053
3054 reporter.log2('Disconnecting from TXS...');
3055 return oTxsSession.syncDisconnect();
3056
3057
3058
3059class TxsConnectTask(TdTaskBase):
3060 """
3061 Class that takes care of connecting to a VM.
3062 """
3063
3064 class TxsConnectTaskVBoxCallback(vbox.VirtualBoxEventHandlerBase):
3065 """ Class for looking for IPv4 address changes on interface 0."""
3066 def __init__(self, dArgs):
3067 vbox.VirtualBoxEventHandlerBase.__init__(self, dArgs);
3068 self.oParentTask = dArgs['oParentTask'];
3069 self.sMachineId = dArgs['sMachineId'];
3070
3071 def onGuestPropertyChange(self, sMachineId, sName, sValue, sFlags):
3072 """Look for IP address."""
3073 reporter.log2('onGuestPropertyChange(,%s,%s,%s,%s)' % (sMachineId, sName, sValue, sFlags));
3074 if sMachineId == self.sMachineId \
3075 and sName == '/VirtualBox/GuestInfo/Net/0/V4/IP':
3076 oParentTask = self.oParentTask;
3077 if oParentTask:
3078 oParentTask._setIp(sValue); # pylint: disable=protected-access
3079
3080
3081 def __init__(self, oSession, cMsTimeout, sIpAddr, sMacAddr, oIDhcpServer, fReversedSetup, fnProcessEvents = None):
3082 TdTaskBase.__init__(self, utils.getCallerName(), fnProcessEvents = fnProcessEvents);
3083 self.cMsTimeout = cMsTimeout;
3084 self.fnProcessEvents = fnProcessEvents;
3085 self.sIpAddr = None;
3086 self.sNextIpAddr = None;
3087 self.sMacAddr = sMacAddr;
3088 self.oIDhcpServer = oIDhcpServer;
3089 self.fReversedSetup = fReversedSetup;
3090 self.oVBoxEventHandler = None;
3091 self.oTxsSession = None;
3092
3093 # Check that the input makes sense:
3094 if (sMacAddr is None) != (oIDhcpServer is None) \
3095 or (sMacAddr and fReversedSetup) \
3096 or (sMacAddr and sIpAddr):
3097 reporter.error('TxsConnectTask sMacAddr=%s oIDhcpServer=%s sIpAddr=%s fReversedSetup=%s'
3098 % (sMacAddr, oIDhcpServer, sIpAddr, fReversedSetup,));
3099 raise base.GenError();
3100
3101 reporter.log2('TxsConnectTask: sIpAddr=%s fReversedSetup=%s' % (sIpAddr, fReversedSetup))
3102 if fReversedSetup is True:
3103 self._openTcpSession(sIpAddr, fReversedSetup = True);
3104 elif sIpAddr is not None and sIpAddr.strip() != '':
3105 self._openTcpSession(sIpAddr, cMsIdleFudge = 5000);
3106 else:
3107 #
3108 # If we've got no IP address, register callbacks that listens for
3109 # the primary network adaptor of the VM to set a IPv4 guest prop.
3110 # Note! The order in which things are done here is kind of important.
3111 #
3112
3113 # 0. The caller zaps the property before starting the VM.
3114 #try:
3115 # oSession.delGuestPropertyValue('/VirtualBox/GuestInfo/Net/0/V4/IP');
3116 #except:
3117 # reporter.logXcpt();
3118
3119 # 1. Register the callback / event listener object.
3120 dArgs = {'oParentTask':self, 'sMachineId':oSession.o.machine.id};
3121 self.oVBoxEventHandler = oSession.oVBox.registerDerivedEventHandler(self.TxsConnectTaskVBoxCallback, dArgs);
3122
3123 # 2. Query the guest properties.
3124 try:
3125 sIpAddr = oSession.getGuestPropertyValue('/VirtualBox/GuestInfo/Net/0/V4/IP');
3126 except:
3127 reporter.errorXcpt('IMachine::getGuestPropertyValue("/VirtualBox/GuestInfo/Net/0/V4/IP") failed');
3128 self._deregisterEventHandler();
3129 raise;
3130 else:
3131 if sIpAddr is not None:
3132 self._setIp(sIpAddr);
3133
3134 #
3135 # If the network adapter of the VM is host-only we can talk poll IDHCPServer
3136 # for the guest IP, allowing us to detect it for VMs without guest additions.
3137 # This will when we're polled.
3138 #
3139 if sMacAddr is not None:
3140 assert self.oIDhcpServer is not None;
3141
3142
3143 # end __init__
3144
3145 def __del__(self):
3146 """ Make sure we deregister the callback. """
3147 self._deregisterEventHandler();
3148 return TdTaskBase.__del__(self);
3149
3150 def toString(self):
3151 return '<%s cMsTimeout=%s, sIpAddr=%s, sNextIpAddr=%s, sMacAddr=%s, fReversedSetup=%s,' \
3152 ' oTxsSession=%s oVBoxEventHandler=%s>' \
3153 % (TdTaskBase.toString(self), self.cMsTimeout, self.sIpAddr, self.sNextIpAddr, self.sMacAddr, self.fReversedSetup,
3154 self.oTxsSession, self.oVBoxEventHandler);
3155
3156 def _deregisterEventHandler(self):
3157 """Deregisters the event handler."""
3158 fRc = True;
3159 oVBoxEventHandler = self.oVBoxEventHandler;
3160 if oVBoxEventHandler is not None:
3161 self.oVBoxEventHandler = None;
3162 fRc = oVBoxEventHandler.unregister();
3163 oVBoxEventHandler.oParentTask = None; # Try avoid cylic deps.
3164 return fRc;
3165
3166 def _setIp(self, sIpAddr, fInitCall = False):
3167 """Called when we get an IP. Will create a TXS session and signal the task."""
3168 sIpAddr = sIpAddr.strip();
3169
3170 if sIpAddr is not None \
3171 and sIpAddr != '':
3172 if vbox.isIpAddrValid(sIpAddr) or fInitCall:
3173 try:
3174 for s in sIpAddr.split('.'):
3175 i = int(s);
3176 if str(i) != s:
3177 raise Exception();
3178 except:
3179 reporter.fatalXcpt();
3180 else:
3181 reporter.log('TxsConnectTask: opening session to ip "%s"' % (sIpAddr));
3182 self._openTcpSession(sIpAddr, cMsIdleFudge = 5000);
3183 return None;
3184
3185 reporter.log('TxsConnectTask: Ignoring Bad ip "%s"' % (sIpAddr));
3186 else:
3187 reporter.log2('TxsConnectTask: Ignoring empty ip "%s"' % (sIpAddr));
3188 return None;
3189
3190 def _openTcpSession(self, sIpAddr, uPort = None, fReversedSetup = False, cMsIdleFudge = 0):
3191 """
3192 Calls txsclient.openTcpSession and switches our task to reflect the
3193 state of the subtask.
3194 """
3195 self.oCv.acquire();
3196 if self.oTxsSession is None:
3197 reporter.log2('_openTcpSession: sIpAddr=%s, uPort=%d, fReversedSetup=%s' %
3198 (sIpAddr, uPort if uPort is not None else 0, fReversedSetup));
3199 self.sIpAddr = sIpAddr;
3200 self.oTxsSession = txsclient.openTcpSession(self.cMsTimeout, sIpAddr, uPort, fReversedSetup,
3201 cMsIdleFudge, fnProcessEvents = self.fnProcessEvents);
3202 self.oTxsSession.setTaskOwner(self);
3203 else:
3204 self.sNextIpAddr = sIpAddr;
3205 reporter.log2('_openTcpSession: sNextIpAddr=%s' % (sIpAddr,));
3206 self.oCv.release();
3207 return None;
3208
3209 def notifyAboutReadyTask(self, oTxsSession):
3210 """
3211 Called by the TXS session task when it's done.
3212
3213 We'll signal the task completed or retry depending on the result.
3214 """
3215
3216 self.oCv.acquire();
3217
3218 # Disassociate ourselves with the session (avoid cyclic ref)
3219 oTxsSession.setTaskOwner(None);
3220 fSuccess = oTxsSession.isSuccess();
3221 if self.oTxsSession is not None:
3222 if not fSuccess:
3223 self.oTxsSession = None;
3224 if fSuccess and self.fReversedSetup:
3225 self.sIpAddr = oTxsSession.oTransport.sHostname;
3226 else:
3227 fSuccess = False;
3228
3229 # Signal done, or retry?
3230 fDeregister = False;
3231 if fSuccess \
3232 or self.fReversedSetup \
3233 or self.getAgeAsMs() >= self.cMsTimeout:
3234 self.signalTaskLocked();
3235 fDeregister = True;
3236 else:
3237 sIpAddr = self.sNextIpAddr if self.sNextIpAddr is not None else self.sIpAddr;
3238 self._openTcpSession(sIpAddr, cMsIdleFudge = 5000);
3239
3240 self.oCv.release();
3241
3242 # If we're done, deregister the callback (w/o owning lock). It will
3243 if fDeregister:
3244 self._deregisterEventHandler();
3245 return True;
3246
3247 def _pollDhcpServer(self):
3248 """
3249 Polls the DHCP server by MAC address in host-only setups.
3250 """
3251
3252 if self.sIpAddr:
3253 return False;
3254
3255 if self.oIDhcpServer is None or not self.sMacAddr:
3256 return False;
3257
3258 try:
3259 (sIpAddr, sState, secIssued, secExpire) = self.oIDhcpServer.findLeaseByMAC(self.sMacAddr, 0);
3260 except:
3261 reporter.log2Xcpt('sMacAddr=%s' % (self.sMacAddr,));
3262 return False;
3263
3264 secNow = utils.secondsSinceUnixEpoch();
3265 reporter.log2('dhcp poll: secNow=%s secExpire=%s secIssued=%s sState=%s sIpAddr=%s'
3266 % (secNow, secExpire, secIssued, sState, sIpAddr,));
3267 if secNow > secExpire or sState != 'acked' or not sIpAddr:
3268 return False;
3269
3270 reporter.log('dhcp poll: sIpAddr=%s secExpire=%s (%s TTL) secIssued=%s (%s ago)'
3271 % (sIpAddr, secExpire, secExpire - secNow, secIssued, secNow - secIssued,));
3272 self._setIp(sIpAddr);
3273 return True;
3274
3275 #
3276 # Task methods
3277 #
3278
3279 def pollTask(self, fLocked = False):
3280 """
3281 Overridden pollTask method.
3282 """
3283 self._pollDhcpServer();
3284 return TdTaskBase.pollTask(self, fLocked);
3285
3286 #
3287 # Public methods
3288 #
3289
3290 def getResult(self):
3291 """
3292 Returns the connected TXS session object on success.
3293 Returns None on failure or if the task has not yet completed.
3294 """
3295 self.oCv.acquire();
3296 oTxsSession = self.oTxsSession;
3297 self.oCv.release();
3298
3299 if oTxsSession is not None and not oTxsSession.isSuccess():
3300 oTxsSession = None;
3301 return oTxsSession;
3302
3303 def cancelTask(self):
3304 """ Cancels the task. """
3305 self._deregisterEventHandler(); # (make sure to avoid cyclic fun)
3306 self.oCv.acquire();
3307 if not self.fSignalled:
3308 oTxsSession = self.oTxsSession;
3309 if oTxsSession is not None:
3310 self.oCv.release();
3311 oTxsSession.setTaskOwner(None);
3312 oTxsSession.cancelTask();
3313 oTxsSession.waitForTask(1000);
3314 self.oCv.acquire();
3315 self.signalTaskLocked();
3316 self.oCv.release();
3317 return True;
3318
3319
3320
3321class AdditionsStatusTask(TdTaskBase):
3322 """
3323 Class that takes care of waiting till the guest additions are in a given state.
3324 """
3325
3326 class AdditionsStatusTaskCallback(vbox.EventHandlerBase):
3327 """ Class for looking for IPv4 address changes on interface 0."""
3328 def __init__(self, dArgs):
3329 self.oParentTask = dArgs['oParentTask'];
3330 vbox.EventHandlerBase.__init__(self, dArgs, self.oParentTask.oSession.fpApiVer,
3331 'AdditionsStatusTaskCallback/%s' % (self.oParentTask.oSession.sName,));
3332
3333 def handleEvent(self, oEvt):
3334 try:
3335 enmType = oEvt.type;
3336 except:
3337 reporter.errorXcpt();
3338 else:
3339 reporter.log2('AdditionsStatusTaskCallback:handleEvent: enmType=%s' % (enmType,));
3340 if enmType == vboxcon.VBoxEventType_OnGuestAdditionsStatusChanged:
3341 oParentTask = self.oParentTask;
3342 if oParentTask:
3343 oParentTask.pollTask();
3344
3345 # end
3346
3347
3348 def __init__(self, oSession, oIGuest, cMsTimeout = 120000, aenmWaitForRunLevels = None, aenmWaitForActive = None,
3349 aenmWaitForInactive = None):
3350 """
3351 aenmWaitForRunLevels - List of run level values to wait for (success if one matches).
3352 aenmWaitForActive - List facilities (type values) that must be active.
3353 aenmWaitForInactive - List facilities (type values) that must be inactive.
3354
3355 The default is to wait for AdditionsRunLevelType_Userland if all three lists
3356 are unspecified or empty.
3357 """
3358 TdTaskBase.__init__(self, utils.getCallerName());
3359 self.oSession = oSession # type: vboxwrappers.SessionWrapper
3360 self.oIGuest = oIGuest;
3361 self.cMsTimeout = cMsTimeout;
3362 self.fSucceeded = False;
3363 self.oVBoxEventHandler = None;
3364 self.aenmWaitForRunLevels = aenmWaitForRunLevels if aenmWaitForRunLevels else [];
3365 self.aenmWaitForActive = aenmWaitForActive if aenmWaitForActive else [];
3366 self.aenmWaitForInactive = aenmWaitForInactive if aenmWaitForInactive else [];
3367
3368 # Provide a sensible default if nothing is given.
3369 if not self.aenmWaitForRunLevels and not self.aenmWaitForActive and not self.aenmWaitForInactive:
3370 self.aenmWaitForRunLevels = [vboxcon.AdditionsRunLevelType_Userland,];
3371
3372 # Register the event handler on hosts which has it:
3373 if oSession.fpApiVer >= 6.1 or hasattr(vboxcon, 'VBoxEventType_OnGuestAdditionsStatusChanged'):
3374 aenmEvents = (vboxcon.VBoxEventType_OnGuestAdditionsStatusChanged,);
3375 dArgs = {
3376 'oParentTask': self,
3377 };
3378 self.oVBoxEventHandler = vbox.EventHandlerBase.registerDerivedEventHandler(oSession.oVBoxMgr,
3379 oSession.fpApiVer,
3380 self.AdditionsStatusTaskCallback,
3381 dArgs,
3382 oIGuest,
3383 'IGuest',
3384 'AdditionsStatusTaskCallback',
3385 aenmEvents = aenmEvents);
3386 reporter.log2('AdditionsStatusTask: %s' % (self.toString(), ));
3387
3388 def __del__(self):
3389 """ Make sure we deregister the callback. """
3390 self._deregisterEventHandler();
3391 self.oIGuest = None;
3392 return TdTaskBase.__del__(self);
3393
3394 def toString(self):
3395 return '<%s cMsTimeout=%s, fSucceeded=%s, aenmWaitForRunLevels=%s, aenmWaitForActive=%s, aenmWaitForInactive=%s, ' \
3396 'oVBoxEventHandler=%s>' \
3397 % (TdTaskBase.toString(self), self.cMsTimeout, self.fSucceeded, self.aenmWaitForRunLevels, self.aenmWaitForActive,
3398 self.aenmWaitForInactive, self.oVBoxEventHandler,);
3399
3400 def _deregisterEventHandler(self):
3401 """Deregisters the event handler."""
3402 fRc = True;
3403 oVBoxEventHandler = self.oVBoxEventHandler;
3404 if oVBoxEventHandler is not None:
3405 self.oVBoxEventHandler = None;
3406 fRc = oVBoxEventHandler.unregister();
3407 oVBoxEventHandler.oParentTask = None; # Try avoid cylic deps.
3408 return fRc;
3409
3410 def _poll(self):
3411 """
3412 Internal worker for pollTask() that returns the new signalled state.
3413 """
3414
3415 #
3416 # Check if any of the runlevels we wait for have been reached:
3417 #
3418 if self.aenmWaitForRunLevels:
3419 try:
3420 enmRunLevel = self.oIGuest.additionsRunLevel;
3421 except:
3422 reporter.errorXcpt();
3423 return True;
3424 if enmRunLevel not in self.aenmWaitForRunLevels:
3425 reporter.log2('AdditionsStatusTask/poll: enmRunLevel=%s not in %s' % (enmRunLevel, self.aenmWaitForRunLevels,));
3426 return False;
3427 reporter.log2('AdditionsStatusTask/poll: enmRunLevel=%s matched %s!' % (enmRunLevel, self.aenmWaitForRunLevels,));
3428
3429
3430 #
3431 # Check for the facilities that must all be active.
3432 #
3433 for enmFacility in self.aenmWaitForActive:
3434 try:
3435 (enmStatus, _) = self.oIGuest.getFacilityStatus(enmFacility);
3436 except:
3437 reporter.errorXcpt('enmFacility=%s' % (enmFacility,));
3438 return True;
3439 if enmStatus != vboxcon.AdditionsFacilityStatus_Active:
3440 reporter.log2('AdditionsStatusTask/poll: enmFacility=%s not active: %s' % (enmFacility, enmStatus,));
3441 return False;
3442
3443 #
3444 # Check for the facilities that must all be inactive or terminated.
3445 #
3446 for enmFacility in self.aenmWaitForInactive:
3447 try:
3448 (enmStatus, _) = self.oIGuest.getFacilityStatus(enmFacility);
3449 except:
3450 reporter.errorXcpt('enmFacility=%s' % (enmFacility,));
3451 return True;
3452 if enmStatus not in (vboxcon.AdditionsFacilityStatus_Inactive,
3453 vboxcon.AdditionsFacilityStatus_Terminated):
3454 reporter.log2('AdditionsStatusTask/poll: enmFacility=%s not inactive: %s' % (enmFacility, enmStatus,));
3455 return False;
3456
3457
3458 reporter.log('AdditionsStatusTask: Poll succeeded, signalling...');
3459 self.fSucceeded = True;
3460 return True;
3461
3462
3463 #
3464 # Task methods
3465 #
3466
3467 def pollTask(self, fLocked = False):
3468 """
3469 Overridden pollTask method.
3470 """
3471 if not fLocked:
3472 self.lockTask();
3473
3474 fDeregister = False;
3475 fRc = self.fSignalled;
3476 if not fRc:
3477 fRc = self._poll();
3478 if fRc or self.getAgeAsMs() >= self.cMsTimeout:
3479 self.signalTaskLocked();
3480 fDeregister = True;
3481
3482 if not fLocked:
3483 self.unlockTask();
3484
3485 # If we're done, deregister the event callback (w/o owning lock).
3486 if fDeregister:
3487 self._deregisterEventHandler();
3488 return fRc;
3489
3490 def getResult(self):
3491 """
3492 Returns true if the we succeeded.
3493 Returns false if not. If the task is signalled already, then we
3494 encountered a problem while polling.
3495 """
3496 return self.fSucceeded;
3497
3498 def cancelTask(self):
3499 """
3500 Cancels the task.
3501 Just to actively disengage the event handler.
3502 """
3503 self._deregisterEventHandler();
3504 return True;
3505
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette