VirtualBox

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

Last change on this file since 57181 was 56722, checked in by vboxsync, 9 years ago

vboxinstaller.py: Propagate skipped status from sub-driver.

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

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