VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/testdriver/vboxinstaller.py@ 53563

Last change on this file since 53563 was 53561, checked in by vboxsync, 10 years ago

not my day :-/

  • Property svn:eol-style set to LF
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 33.0 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4"""
5VirtualBox Installer Wrapper Driver.
6
7This installs VirtualBox, starts a sub driver which does the real testing,
8and then uninstall VirtualBox afterwards. This reduces the complexity of the
9other VBox test drivers.
10"""
11
12__copyright__ = \
13"""
14Copyright (C) 2010-2014 Oracle Corporation
15
16This file is part of VirtualBox Open Source Edition (OSE), as
17available from http://www.virtualbox.org. This file is free software;
18you can redistribute it and/or modify it under the terms of the GNU
19General Public License (GPL) as published by the Free Software
20Foundation, in version 2 as it comes in the "COPYING" file of the
21VirtualBox OSE distribution. VirtualBox OSE is distributed in the
22hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
23
24The contents of this file may alternatively be used under the terms
25of the Common Development and Distribution License Version 1.0
26(CDDL) only, as it comes in the "COPYING.CDDL" file of the
27VirtualBox OSE distribution, in which case the provisions of the
28CDDL are applicable instead of those of the GPL.
29
30You may elect to license modified versions of this file under the
31terms and conditions of either the GPL or the CDDL or both.
32"""
33__version__ = "$Revision: 53561 $"
34
35
36# Standard Python imports.
37import os
38import sys
39import re
40import socket
41import tempfile
42import time
43
44# Only the main script needs to modify the path.
45try: __file__
46except: __file__ = sys.argv[0];
47g_ksValidationKitDir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)));
48sys.path.append(g_ksValidationKitDir);
49
50# Validation Kit imports.
51from common import utils, webutils;
52from testdriver import reporter;
53from testdriver.base import TestDriverBase;
54
55
56
57class VBoxInstallerTestDriver(TestDriverBase):
58 """
59 Implementation of a top level test driver.
60 """
61
62
63 ## State file indicating that we've skipped installation.
64 ksVar_Skipped = 'vboxinstaller-skipped';
65
66
67 def __init__(self):
68 TestDriverBase.__init__(self);
69 self._asSubDriver = []; # The sub driver and it's arguments.
70 self._asBuildUrls = []; # The URLs passed us on the command line.
71 self._asBuildFiles = []; # The downloaded file names.
72 self._fAutoInstallPuelExtPack = True;
73
74 #
75 # Base method we override
76 #
77
78 def showUsage(self):
79 rc = TestDriverBase.showUsage(self);
80 # 0 1 2 3 4 5 6 7 8
81 # 012345678901234567890123456789012345678901234567890123456789012345678901234567890
82 reporter.log('');
83 reporter.log('vboxinstaller Options:');
84 reporter.log(' --vbox-build <url[,url2[,..]]>');
85 reporter.log(' Comma separated list of URL to file to download and install or/and');
86 reporter.log(' unpack. URLs without a schema are assumed to be files on the');
87 reporter.log(' build share and will be copied off it.');
88 reporter.log(' --no-puel-extpack');
89 reporter.log(' Indicates that the PUEL extension pack should not be installed if found.');
90 reporter.log(' The default is to install it if found in the vbox-build.');
91 reporter.log(' --');
92 reporter.log(' Indicates the end of our parameters and the start of the sub');
93 reporter.log(' testdriver and its arguments.');
94 return rc;
95
96 def parseOption(self, asArgs, iArg):
97 """
98 Parse our arguments.
99 """
100 if asArgs[iArg] == '--':
101 # End of our parameters and start of the sub driver invocation.
102 iArg = self.requireMoreArgs(1, asArgs, iArg);
103 assert len(self._asSubDriver) == 0;
104 self._asSubDriver = asArgs[iArg:];
105 self._asSubDriver[0] = self._asSubDriver[0].replace('/', os.path.sep);
106 iArg = len(asArgs) - 1;
107 elif asArgs[iArg] == '--vbox-build':
108 # List of files to copy/download and install.
109 iArg = self.requireMoreArgs(1, asArgs, iArg);
110 self._asBuildUrls = asArgs[iArg].split(',');
111 elif asArgs[iArg] == '--no-puel-extpack':
112 self._fAutoInstallPuelExtPack = False;
113 elif asArgs[iArg] == '--puel-extpack':
114 self._fAutoInstallPuelExtPack = True;
115 else:
116 return TestDriverBase.parseOption(self, asArgs, iArg);
117 return iArg + 1;
118
119 def completeOptions(self):
120 #
121 # Check that we've got what we need.
122 #
123 if len(self._asBuildUrls) == 0:
124 reporter.error('No build files specfiied ("--vbox-build file1[,file2[...]]")');
125 return False;
126 if len(self._asSubDriver) == 0:
127 reporter.error('No sub testdriver specified. (" -- test/stuff/tdStuff1.py args")');
128 return False;
129
130 #
131 # Construct _asBuildFiles as an array parallel to _asBuildUrls.
132 #
133 for sUrl in self._asBuildUrls:
134 sDstFile = os.path.join(self.sScratchPath, webutils.getFilename(sUrl));
135 self._asBuildFiles.append(sDstFile);
136
137 return TestDriverBase.completeOptions(self);
138
139 def actionExtract(self):
140 reporter.error('vboxinstall does not support extracting resources, you have to do that using the sub testdriver.');
141 return False;
142
143 def actionCleanupBefore(self):
144 """
145 Kills all VBox process we see.
146
147 This is only supposed to execute on a testbox so we don't need to go
148 all complicated wrt other users.
149 """
150 return self._killAllVBoxProcesses();
151
152 def actionConfig(self):
153 """
154 Install VBox and pass on the configure request to the sub testdriver.
155 """
156 fRc = self._installVBox();
157 if fRc is None: self._persistentVarSet(self.ksVar_Skipped, 'true');
158 else: self._persistentVarUnset(self.ksVar_Skipped);
159
160 ## @todo vbox.py still has bugs preventing us from invoking it seperately with each action.
161 if fRc is True and 'execute' not in self.asActions and 'all' not in self.asActions:
162 fRc = self._executeSubDriver([ 'verify', ]);
163 if fRc is True and 'execute' not in self.asActions and 'all' not in self.asActions:
164 fRc = self._executeSubDriver([ 'config', ]);
165 return fRc;
166
167 def actionExecute(self):
168 """
169 Execute the sub testdriver.
170 """
171 return self._executeSubDriver(self.asActions);
172
173 def actionCleanupAfter(self):
174 """
175 Forward this to the sub testdriver, then uninstall VBox.
176 """
177 fRc = True;
178 if 'execute' not in self.asActions and 'all' not in self.asActions:
179 fRc = self._executeSubDriver([ 'cleanup-after', ]);
180
181 if not self._killAllVBoxProcesses():
182 fRc = False;
183
184 if not self._uninstallVBox(self._persistentVarExists(self.ksVar_Skipped)):
185 fRc = False;
186
187 if utils.getHostOs() == 'darwin':
188 self._darwinUnmountDmg(fIgnoreError = True); # paranoia
189
190 if not TestDriverBase.actionCleanupAfter(self):
191 fRc = False;
192
193 return fRc;
194
195
196 def actionAbort(self):
197 """
198 Forward this to the sub testdriver first, then do the default pid file
199 based cleanup and finally swipe the scene with the heavy artillery.
200 """
201 fRc1 = self._executeSubDriver([ 'abort', ]);
202 fRc2 = TestDriverBase.actionAbort(self);
203 fRc3 = self._killAllVBoxProcesses();
204 return fRc1 and fRc2 and fRc3;
205
206
207 #
208 # Persistent variables.
209 #
210 ## @todo integrate into the base driver. Persisten accross scratch wipes?
211
212 def __persistentVarCalcName(self, sVar):
213 """Returns the (full) filename for the given persistent variable."""
214 assert re.match(r'^[a-zA-Z0-9_-]*$', sVar) is not None;
215 return os.path.join(self.sScratchPath, 'persistent-%s.var' % (sVar,));
216
217 def _persistentVarSet(self, sVar, sValue = ''):
218 """
219 Sets a persistent variable.
220
221 Returns True on success, False + reporter.error on failure.
222
223 May raise exception if the variable name is invalid or something
224 unexpected happens.
225 """
226 sFull = self.__persistentVarCalcName(sVar);
227 try:
228 oFile = open(sFull, 'w');
229 if len(sValue) > 0:
230 oFile.write(sValue.encode('utf-8'));
231 oFile.close();
232 except:
233 reporter.errorXcpt('Error creating "%s"' % (sFull,));
234 return False;
235 return True;
236
237 def _persistentVarUnset(self, sVar):
238 """
239 Unsets a persistent variable.
240
241 Returns True on success, False + reporter.error on failure.
242
243 May raise exception if the variable name is invalid or something
244 unexpected happens.
245 """
246 sFull = self.__persistentVarCalcName(sVar);
247 if os.path.exists(sFull):
248 try:
249 os.unlink(sFull);
250 except:
251 reporter.errorXcpt('Error unlinking "%s"' % (sFull,));
252 return False;
253 return True;
254
255 def _persistentVarExists(self, sVar):
256 """
257 Checks if a persistent variable exists.
258
259 Returns true/false.
260
261 May raise exception if the variable name is invalid or something
262 unexpected happens.
263 """
264 return os.path.exists(self.__persistentVarCalcName(sVar));
265
266 def _persistentVarGet(self, sVar):
267 """
268 Gets the value of a persistent variable.
269
270 Returns variable value on success.
271 Returns None if the variable doesn't exist or if an
272 error (reported) occured.
273
274 May raise exception if the variable name is invalid or something
275 unexpected happens.
276 """
277 sFull = self.__persistentVarCalcName(sVar);
278 if not os.path.exists(sFull):
279 return None;
280 try:
281 oFile = open(sFull, 'r');
282 sValue = oFile.read().decode('utf-8');
283 oFile.close();
284 except:
285 reporter.errorXcpt('Error creating "%s"' % (sFull,));
286 return None;
287 return sValue;
288
289
290 #
291 # Helpers.
292 #
293
294 def _killAllVBoxProcesses(self):
295 """
296 Kills all virtual box related processes we find in the system.
297 """
298
299 for iIteration in range(22):
300 # Gather processes to kill.
301 aoTodo = [];
302 for oProcess in utils.processListAll():
303 sBase = oProcess.getBaseImageNameNoExeSuff();
304 if sBase is None:
305 continue;
306 sBase = sBase.lower();
307 if sBase in [ 'vboxsvc', 'virtualbox', 'virtualboxvm', 'vboxheadless', 'vboxmanage', 'vboxsdl', 'vboxwebsrv',
308 'vboxautostart', 'vboxballoonctrl', 'vboxbfe', 'vboxextpackhelperapp', 'vboxnetdhcp',
309 'vboxnetadpctl', 'vboxtestogl', 'vboxtunctl', 'vboxvmmpreload', 'vboxxpcomipcd', 'vmCreator', ]:
310 aoTodo.append(oProcess);
311 if iIteration in [0, 21] and sBase in [ 'windbg', 'gdb', 'gdb-i386-apple-darwin', ]:
312 reporter.log('Warning: debugger running: %s (%s)' % (oProcess.iPid, sBase,));
313 if len(aoTodo) == 0:
314 return True;
315
316 # Kill.
317 for oProcess in aoTodo:
318 reporter.log('Loop #%d - Killing %s (%s)'
319 % (iIteration, oProcess.iPid, oProcess.sImage if oProcess.sName is None else oProcess.sName,));
320 utils.processKill(oProcess.iPid); # No mercy.
321
322 # Check if they're all dead like they should be.
323 time.sleep(0.1);
324 for oProcess in aoTodo:
325 if utils.processExists(oProcess.iPid):
326 time.sleep(2);
327 break;
328
329 return False;
330
331 def _executeSync(self, asArgs):
332 """
333 Executes a child process synchronously.
334 Returns True if the process executed successfully and returned 0,
335 otherwise False is returned.
336 """
337 reporter.log('Executing: %s' % (asArgs, ));
338 reporter.flushall();
339 try:
340 iRc = utils.processCall(asArgs, shell = False, close_fds = False);
341 except:
342 reporter.errorXcpt();
343 return False;
344 reporter.log('Exit code: %s (%s)' % (iRc, asArgs));
345 return iRc is 0;
346
347 def _sudoExecuteSync(self, asArgs):
348 """
349 Executes a sudo child process synchronously.
350 Returns a tuple [True, 0] if the process executed successfully
351 and returned 0, otherwise [False, rc] is returned.
352 """
353 reporter.log('Executing [sudo]: %s' % (asArgs, ));
354 reporter.flushall();
355 iRc = 0;
356 try:
357 iRc = utils.sudoProcessCall(asArgs, shell = False, close_fds = False);
358 except:
359 reporter.errorXcpt();
360 return (False, 0);
361 reporter.log('Exit code [sudo]: %s (%s)' % (iRc, asArgs));
362 return (iRc is 0, iRc);
363
364 def _executeSubDriver(self, asActions):
365 """
366 Execute the sub testdriver with the specified action.
367 """
368 asArgs = list(self._asSubDriver)
369 asArgs.append('--no-wipe-clean');
370 asArgs.extend(asActions);
371 return self._executeSync(asArgs);
372
373 def _maybeUnpackArchive(self, sMaybeArchive, fNonFatal = False):
374 """
375 Attempts to unpack the given build file.
376 Updates _asBuildFiles.
377 Returns True/False. No exceptions.
378 """
379 asMembers = utils.unpackFile(sMaybeArchive, self.sScratchPath, reporter.log,
380 reporter.log if fNonFatal else reporter.error);
381 if asMembers is None:
382 return False;
383 self._asBuildFiles.extend(asMembers);
384 return True;
385
386
387 def _installVBox(self):
388 """
389 Download / copy the build files into the scratch area and install them.
390 """
391 reporter.testStart('Installing VirtualBox');
392 reporter.log('CWD=%s' % (os.getcwd(),)); # curious
393
394 #
395 # Download the build files.
396 #
397 for i in range(len(self._asBuildUrls)):
398 if webutils.downloadFile(self._asBuildUrls[i], self._asBuildFiles[i],
399 self.sBuildPath, reporter.log, reporter.log) is not True:
400 reporter.testDone(fSkipped = True);
401 return None; # Failed to get binaries, probably deleted. Skip the test run.
402
403 #
404 # Unpack anything we know what is and append it to the build files
405 # list. This allows us to use VBoxAll*.tar.gz files.
406 #
407 for sFile in list(self._asBuildFiles):
408 if self._maybeUnpackArchive(sFile, fNonFatal = True) is not True:
409 reporter.testDone(fSkipped = True);
410 return None; # Failed to unpack. Probably local error, like busy
411 # DLLs on windows, no reason for failing the build.
412
413 #
414 # Go to system specific installation code.
415 #
416 sHost = utils.getHostOs()
417 if sHost == 'darwin': fRc = self._installVBoxOnDarwin();
418 elif sHost == 'linux': fRc = self._installVBoxOnLinux();
419 elif sHost == 'solaris': fRc = self._installVBoxOnSolaris();
420 elif sHost == 'win': fRc = self._installVBoxOnWindows();
421 else:
422 reporter.error('Unsupported host "%s".' % (sHost,));
423 if fRc is False:
424 reporter.testFailure('Installation error.');
425
426 #
427 # Install the extension pack.
428 #
429 if fRc is True and self._fAutoInstallPuelExtPack:
430 fRc = self._installExtPack();
431 if fRc is False:
432 reporter.testFailure('Extension pack installation error.');
433
434 # Some debugging...
435 try:
436 cMbFreeSpace = utils.getDiskUsage(self.sScratchPath);
437 reporter.log('Disk usage after VBox install: %d MB available at %s' % (cMbFreeSpace, self.sScratchPath,));
438 except:
439 reporter.logXcpt('Unable to get disk free space. Ignored. Continuing.');
440
441 reporter.testDone();
442 return fRc;
443
444 def _uninstallVBox(self, fIgnoreError = False):
445 """
446 Uninstall VirtualBox.
447 """
448 reporter.testStart('Uninstalling VirtualBox');
449
450 sHost = utils.getHostOs()
451 if sHost == 'darwin': fRc = self._uninstallVBoxOnDarwin();
452 elif sHost == 'linux': fRc = self._uninstallVBoxOnLinux();
453 elif sHost == 'solaris': fRc = self._uninstallVBoxOnSolaris();
454 elif sHost == 'win': fRc = self._uninstallVBoxOnWindows();
455 else:
456 reporter.error('Unsupported host "%s".' % (sHost,));
457 if fRc is False and not fIgnoreError:
458 reporter.testFailure('Uninstallation failed.');
459
460 fRc2 = self._uninstallAllExtPacks();
461 if not fRc2 and fRc:
462 fRc = fRc2;
463
464 reporter.testDone(fSkipped = (fRc is None));
465 return fRc;
466
467 def _findFile(self, sRegExp, fMandatory = False):
468 """
469 Returns the first build file that matches the given regular expression
470 (basename only).
471
472 Returns None if no match was found, logging it as an error if
473 fMandatory is set.
474 """
475 oRegExp = re.compile(sRegExp);
476
477 for sFile in self._asBuildFiles:
478 if oRegExp.match(os.path.basename(sFile)) and os.path.exists(sFile):
479 return sFile;
480
481 if fMandatory:
482 reporter.error('Failed to find a file matching "%s" in %s.' % (sRegExp, self._asBuildFiles,));
483 return None;
484
485 def _waitForTestManagerConnectivity(self, cSecTimeout):
486 """
487 Check and wait for network connectivity to the test manager.
488
489 This is used with the windows installation and uninstallation since
490 these usually disrupts network connectivity when installing the filter
491 driver. If we proceed to quickly, we might finish the test at a time
492 when we cannot report to the test manager and thus end up with an
493 abandonded test error.
494 """
495 cSecElapsed = 0;
496 secStart = utils.timestampSecond();
497 while reporter.checkTestManagerConnection() is False:
498 cSecElapsed = utils.timestampSecond() - secStart;
499 if cSecElapsed >= cSecTimeout:
500 reporter.log('_waitForTestManagerConnectivity: Giving up after %u secs.' % (cSecTimeout,));
501 return False;
502 time.sleep(2);
503
504 if cSecElapsed > 0:
505 reporter.log('_waitForTestManagerConnectivity: Waited %s secs.' % (cSecTimeout,));
506 return True;
507
508
509 #
510 # Darwin (Mac OS X).
511 #
512
513 def _darwinDmgPath(self):
514 """ Returns the path to the DMG mount."""
515 return os.path.join(self.sScratchPath, 'DmgMountPoint');
516
517 def _darwinUnmountDmg(self, fIgnoreError):
518 """
519 Umount any DMG on at the default mount point.
520 """
521 sMountPath = self._darwinDmgPath();
522 if not os.path.exists(sMountPath):
523 return True;
524
525 # Unmount.
526 fRc = self._executeSync(['hdiutil', 'detach', sMountPath ]);
527 if not fRc and not fIgnoreError:
528 reporter.error('Failed to unmount DMG at %s' % sMountPath);
529
530 # Remove dir.
531 try:
532 os.rmdir(sMountPath);
533 except:
534 if not fIgnoreError:
535 reporter.errorXcpt('Failed to remove directory %s' % sMountPath);
536 return fRc;
537
538 def _darwinMountDmg(self, sDmg):
539 """
540 Mount the DMG at the default mount point.
541 """
542 self._darwinUnmountDmg(fIgnoreError = True)
543
544 sMountPath = self._darwinDmgPath();
545 if not os.path.exists(sMountPath):
546 try:
547 os.mkdir(sMountPath, 0755);
548 except:
549 reporter.logXcpt();
550 return False;
551
552 return self._executeSync(['hdiutil', 'attach', '-readonly', '-mount', 'required', '-mountpoint', sMountPath, sDmg, ]);
553
554 def _installVBoxOnDarwin(self):
555 """ Installs VBox on Mac OS X."""
556 sDmg = self._findFile('^VirtualBox-.*\\.dmg$');
557 if sDmg is None:
558 return False;
559
560 # Mount the DMG.
561 fRc = self._darwinMountDmg(sDmg);
562 if fRc is not True:
563 return False;
564
565 # Uninstall any previous vbox version first.
566 sUninstaller = os.path.join(self._darwinDmgPath(), 'VirtualBox_Uninstall.tool');
567 fRc, _ = self._sudoExecuteSync([sUninstaller, '--unattended',]);
568 if fRc is True:
569
570 # Install the package.
571 sPkg = os.path.join(self._darwinDmgPath(), 'VirtualBox.pkg');
572 fRc, _ = self._sudoExecuteSync(['installer', '-verbose', '-dumplog', '-pkg', sPkg, '-target', '/']);
573
574 # Unmount the DMG and we're done.
575 if not self._darwinUnmountDmg(fIgnoreError = False):
576 fRc = False;
577 return fRc;
578
579 def _uninstallVBoxOnDarwin(self):
580 """ Uninstalls VBox on Mac OS X."""
581
582 # Is VirtualBox installed? If not, don't try uninstall it.
583 sVBox = self._getVBoxInstallPath(fFailIfNotFound = False);
584 if sVBox is None:
585 return True;
586
587 # Find the dmg.
588 sDmg = self._findFile('^VirtualBox-.*\\.dmg$');
589 if sDmg is None:
590 return False;
591 if not os.path.exists(sDmg):
592 return True;
593
594 # Mount the DMG.
595 fRc = self._darwinMountDmg(sDmg);
596 if fRc is not True:
597 return False;
598
599 # Execute the uninstaller.
600 sUninstaller = os.path.join(self._darwinDmgPath(), 'VirtualBox_Uninstall.tool');
601 fRc, _ = self._sudoExecuteSync([sUninstaller, '--unattended',]);
602
603 # Unmount the DMG and we're done.
604 if not self._darwinUnmountDmg(fIgnoreError = False):
605 fRc = False;
606 return fRc;
607
608 #
609 # GNU/Linux
610 #
611
612 def _installVBoxOnLinux(self):
613 """ Installs VBox on Linux."""
614 sRun = self._findFile('^VirtualBox-.*\\.run$');
615 if sRun is None:
616 return False;
617 utils.chmodPlusX(sRun);
618
619 # Install the new one.
620 fRc, _ = self._sudoExecuteSync([sRun,]);
621 return fRc;
622
623 def _uninstallVBoxOnLinux(self):
624 """ Uninstalls VBox on Linux."""
625
626 # Is VirtualBox installed? If not, don't try uninstall it.
627 sVBox = self._getVBoxInstallPath(fFailIfNotFound = False);
628 if sVBox is None:
629 return True;
630
631 # Find the .run file and use it.
632 sRun = self._findFile('^VirtualBox-.*\\.run$', fMandatory = False);
633 if sRun is not None:
634 utils.chmodPlusX(sRun);
635 fRc, _ = self._sudoExecuteSync([sRun, 'uninstall']);
636 return fRc;
637
638 # Try the installed uninstaller.
639 for sUninstaller in [os.path.join(sVBox, 'uninstall.sh'), '/opt/VirtualBox/uninstall.sh', ]:
640 if os.path.isfile(sUninstaller):
641 reporter.log('Invoking "%s"...' % (sUninstaller,));
642 fRc, _ = self._sudoExecuteSync([sUninstaller, 'uninstall']);
643 return fRc;
644
645 reporter.log('Did not find any VirtualBox install to uninstall.');
646 return True;
647
648
649 #
650 # Solaris
651 #
652
653 def _generateAutoResponseOnSolaris(self):
654 """
655 Generates an autoresponse file on solaris, returning the name.
656 None is return on failure.
657 """
658 sPath = os.path.join(self.sScratchPath, 'SolarisAutoResponse');
659 oFile = utils.openNoInherit(sPath, 'wt');
660 oFile.write('basedir=default\n'
661 'runlevel=nocheck\n'
662 'conflict=quit\n'
663 'setuid=nocheck\n'
664 'action=nocheck\n'
665 'partial=quit\n'
666 'instance=unique\n'
667 'idepend=quit\n'
668 'rdepend=quit\n'
669 'space=quit\n'
670 'mail=\n');
671 oFile.close();
672 return sPath;
673
674 def _installVBoxOnSolaris(self):
675 """ Installs VBox on Solaris."""
676 sPkg = self._findFile('^VirtualBox-.*\\.pkg$', fMandatory = False);
677 if sPkg is None:
678 sTar = self._findFile('^VirtualBox-.*-SunOS-.*\\.tar.gz$', fMandatory = False);
679 if sTar is not None:
680 if self._maybeUnpackArchive(sTar) is not True:
681 return False;
682 sPkg = self._findFile('^VirtualBox-.*\\.pkg$', fMandatory = True);
683 sRsp = self._findFile('^autoresponse$', fMandatory = True);
684 if sPkg is None or sRsp is None:
685 return False;
686
687 # Uninstall first (ignore result).
688 self._uninstallVBoxOnSolaris();
689
690 # Install the new one.
691 fRc, _ = self._sudoExecuteSync(['pkgadd', '-d', sPkg, '-n', '-a', sRsp, 'SUNWvbox']);
692 return fRc;
693
694 def _uninstallVBoxOnSolaris(self):
695 """ Uninstalls VBox on Solaris."""
696 reporter.flushall();
697 if utils.processCall(['pkginfo', '-q', 'SUNWvbox']) != 0:
698 return True;
699 sRsp = self._generateAutoResponseOnSolaris();
700 fRc, _ = self._sudoExecuteSync(['pkgrm', '-n', '-a', sRsp, 'SUNWvbox']);
701 return fRc;
702
703 #
704 # Windows
705 #
706
707 def _installVBoxOnWindows(self):
708 """ Installs VBox on Windows."""
709 sExe = self._findFile('^VirtualBox-.*-(MultiArch|Win).exe$');
710 if sExe is None:
711 return False;
712
713 # Uninstall any previous vbox version first.
714 fRc = self._uninstallVBoxOnWindows();
715 if fRc is not True:
716 return None; # There shouldn't be anything to uninstall, and if there is, it's not our fault.
717
718 # Install the new one.
719 asArgs = [sExe, '-vvvv', '--silent', '--logging'];
720 asArgs.extend(['--msiparams', 'REBOOT=ReallySuppress']);
721 sVBoxInstallPath = os.environ.get('VBOX_INSTALL_PATH', None);
722 if sVBoxInstallPath is not None:
723 asArgs.extend(['INSTALLDIR="%s"' % (sVBoxInstallPath,)]);
724 fRc2, iRc = self._sudoExecuteSync(asArgs);
725 if fRc2 is False:
726 if iRc == 3010: # ERROR_SUCCESS_REBOOT_REQUIRED
727 reporter.log('Note: Installer required a reboot to complete installation');
728 # Optional, don't fail.
729 else:
730 fRc = False;
731 sLogFile = os.path.join(tempfile.gettempdir(), 'VirtualBox', 'VBoxInstallLog.txt');
732 if sLogFile is not None \
733 and os.path.isfile(sLogFile):
734 reporter.addLogFile(sLogFile, 'log/installer', "Verbose MSI installation log file");
735 self._waitForTestManagerConnectivity(30);
736 return fRc;
737
738 def _uninstallVBoxOnWindows(self):
739 """
740 Uninstalls VBox on Windows, all installations we find to be on the safe side...
741 """
742
743 import win32com.client; # pylint: disable=F0401
744 win32com.client.gencache.EnsureModule('{000C1092-0000-0000-C000-000000000046}', 1033, 1, 0);
745 oInstaller = win32com.client.Dispatch('WindowsInstaller.Installer',
746 resultCLSID = '{000C1090-0000-0000-C000-000000000046}')
747
748 # Search installed products for VirtualBox.
749 asProdCodes = [];
750 for sProdCode in oInstaller.Products:
751 try:
752 sProdName = oInstaller.ProductInfo(sProdCode, "ProductName");
753 except:
754 reporter.logXcpt();
755 continue;
756 #reporter.log('Info: %s=%s' % (sProdCode, sProdName));
757 if sProdName.startswith('Oracle VM VirtualBox') \
758 or sProdName.startswith('Sun VirtualBox'):
759 asProdCodes.append([sProdCode, sProdName]);
760
761 # Before we start uninstalling anything, just ruthlessly kill any
762 # msiexec process we might find hanging around.
763 cKilled = 0;
764 for oProcess in utils.processListAll():
765 sBase = oProcess.getBaseImageNameNoExeSuff();
766 if sBase is not None and sBase.lower() in [ 'msiexec', ]:
767 reporter.log('Killing MSI process: %s (%s)' % (oProcess.iPid, sBase));
768 utils.processKill(oProcess.iPid);
769 cKilled += 1;
770 if cKilled > 0:
771 time.sleep(16); # fudge.
772
773 # Do the uninstalling.
774 fRc = True;
775 sLogFile = os.path.join(self.sScratchPath, 'VBoxUninstallLog.txt');
776 for sProdCode, sProdName in asProdCodes:
777 reporter.log('Uninstalling %s (%s)...' % (sProdName, sProdCode));
778 fRc2, iRc = self._sudoExecuteSync(['msiexec', '/uninstall', sProdCode, '/quiet', '/passive', '/norestart',
779 '/L*v', '%s' % (sLogFile), ]);
780 if fRc2 is False:
781 if iRc == 3010: # ERROR_SUCCESS_REBOOT_REQUIRED
782 reporter.log('Note: Uninstaller required a reboot to complete uninstallation');
783 # Optional, don't fail.
784 else:
785 fRc = False;
786 reporter.addLogFile(sLogFile, 'log/uninstaller', "Verbose MSI uninstallation log file");
787
788 # TEMPORARY HACK - START
789 sHostName = socket.getfqdn();
790 if fRc and not sHostName.startswith('testboxwin3') \
791 and utils.getHostOsVersion() in ['8', '8.1', '9', '2008Server', '2008ServerR2', '2012Server']:
792 reporter.log('Peforming extra NDIS cleanup...');
793 sMagicScript = os.path.abspath(os.path.join(g_ksValidationKitDir, 'testdriver', 'win-vbox-net-uninstall.ps1'));
794 fRc2, _ = self._sudoExecuteSync(['powershell.exe', '-Command', 'set-executionpolicy unrestricted']);
795 if not fRc2:
796 reporter.log('set-executionpolicy failed.');
797 self._sudoExecuteSync(['powershell.exe', '-Command', 'get-executionpolicy']);
798 fRc2, _ = self._sudoExecuteSync(['powershell.exe', '-File', sMagicScript]);
799 if not fRc2:
800 reporter.log('NDIS cleanup failed.');
801 # TEMPORARY HACK - END
802
803 self._waitForTestManagerConnectivity(30);
804 if fRc is False and os.path.isfile(sLogFile):
805 reporter.addLogFile(sLogFile, 'log/uninstaller');
806 return fRc;
807
808
809 #
810 # Extension pack.
811 #
812
813 def _getVBoxInstallPath(self, fFailIfNotFound):
814 """ Returns the default VBox installation path. """
815 sHost = utils.getHostOs();
816 if sHost == 'win':
817 sProgFiles = os.environ.get('ProgramFiles', 'C:\\Program Files');
818 asLocs = [
819 os.path.join(sProgFiles, 'Oracle', 'VirtualBox'),
820 os.path.join(sProgFiles, 'OracleVM', 'VirtualBox'),
821 os.path.join(sProgFiles, 'Sun', 'VirtualBox'),
822 ];
823 elif sHost == 'linux' or sHost == 'solaris':
824 asLocs = [ '/opt/VirtualBox', '/opt/VirtualBox-3.2', '/opt/VirtualBox-3.1', '/opt/VirtualBox-3.0'];
825 elif sHost == 'darwin':
826 asLocs = [ '/Applications/VirtualBox.app/Contents/MacOS' ];
827 else:
828 asLocs = [ '/opt/VirtualBox' ];
829 if 'VBOX_INSTALL_PATH' in os.environ:
830 asLocs.insert(0, os.environ.get('VBOX_INSTALL_PATH', None));
831
832 for sLoc in asLocs:
833 if os.path.isdir(sLoc):
834 return sLoc;
835 if fFailIfNotFound:
836 reporter.error('Failed to locate VirtualBox installation: %s' % (asLocs,));
837 else:
838 reporter.log2('Failed to locate VirtualBox installation: %s' % (asLocs,));
839 return None;
840
841 def _installExtPack(self):
842 """ Installs the extension pack. """
843 sVBox = self._getVBoxInstallPath(fFailIfNotFound = True);
844 if sVBox is None:
845 return False;
846 sExtPackDir = os.path.join(sVBox, 'ExtensionPacks');
847
848 if self._uninstallAllExtPacks() is not True:
849 return False;
850
851 sExtPack = self._findFile('Oracle_VM_VirtualBox_Extension_Pack.vbox-extpack');
852 if sExtPack is None:
853 sExtPack = self._findFile('Oracle_VM_VirtualBox_Extension_Pack.*.vbox-extpack');
854 if sExtPack is None:
855 return True;
856
857 sDstDir = os.path.join(sExtPackDir, 'Oracle_VM_VirtualBox_Extension_Pack');
858 reporter.log('Installing extension pack "%s" to "%s"...' % (sExtPack, sExtPackDir));
859 fRc, _ = self._sudoExecuteSync([ self.getBinTool('vts_tar'),
860 '--extract',
861 '--verbose',
862 '--gzip',
863 '--file', sExtPack,
864 '--directory', sDstDir,
865 '--file-mode-and-mask', '0644',
866 '--file-mode-or-mask', '0644',
867 '--dir-mode-and-mask', '0755',
868 '--dir-mode-or-mask', '0755',
869 '--owner', '0',
870 '--group', '0',
871 ]);
872 return fRc;
873
874 def _uninstallAllExtPacks(self):
875 """ Uninstalls all extension packs. """
876 sVBox = self._getVBoxInstallPath(fFailIfNotFound = False);
877 if sVBox is None:
878 return True;
879
880 sExtPackDir = os.path.join(sVBox, 'ExtensionPacks');
881 if not os.path.exists(sExtPackDir):
882 return True;
883
884 fRc, _ = self._sudoExecuteSync([self.getBinTool('vts_rm'), '-Rfv', '--', sExtPackDir]);
885 return fRc;
886
887
888
889if __name__ == '__main__':
890 sys.exit(VBoxInstallerTestDriver().main(sys.argv));
891
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