VirtualBox

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

Last change on this file was 108981, checked in by vboxsync, 3 weeks ago

ValidationKit/testdriver/vboxwrappers.py: Ensure the proper port count is set when attachiing a device to a given storage controller [fix]

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

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