VirtualBox

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

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

Validation Kit: run network cleanup script before install, not after uninstall; exclude testboxharp2

  • Property svn:eol-style set to LF
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 33.2 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: 53771 $"
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 # TEMPORARY HACK - START
714 # It seems that running the NDIS cleanup script upon uninstallation is not
715 # a good idea, so let's run it before installing VirtualBox.
716 sHostName = socket.getfqdn();
717 if fRc and not sHostName.startswith('testboxwin3') \
718 and not sHostName.startswith('testboxharp2') \
719 and utils.getHostOsVersion() in ['8', '8.1', '9', '2008Server', '2008ServerR2', '2012Server']:
720 reporter.log('Peforming extra NDIS cleanup...');
721 sMagicScript = os.path.abspath(os.path.join(g_ksValidationKitDir, 'testdriver', 'win-vbox-net-uninstall.ps1'));
722 fRc2, _ = self._sudoExecuteSync(['powershell.exe', '-Command', 'set-executionpolicy unrestricted']);
723 if not fRc2:
724 reporter.log('set-executionpolicy failed.');
725 self._sudoExecuteSync(['powershell.exe', '-Command', 'get-executionpolicy']);
726 fRc2, _ = self._sudoExecuteSync(['powershell.exe', '-File', sMagicScript]);
727 if not fRc2:
728 reporter.log('NDIS cleanup failed.');
729 # TEMPORARY HACK - END
730
731 # Uninstall any previous vbox version first.
732 fRc = self._uninstallVBoxOnWindows();
733 if fRc is not True:
734 return None; # There shouldn't be anything to uninstall, and if there is, it's not our fault.
735
736 # Install the new one.
737 asArgs = [sExe, '-vvvv', '--silent', '--logging'];
738 asArgs.extend(['--msiparams', 'REBOOT=ReallySuppress']);
739 sVBoxInstallPath = os.environ.get('VBOX_INSTALL_PATH', None);
740 if sVBoxInstallPath is not None:
741 asArgs.extend(['INSTALLDIR="%s"' % (sVBoxInstallPath,)]);
742 fRc2, iRc = self._sudoExecuteSync(asArgs);
743 if fRc2 is False:
744 if iRc == 3010: # ERROR_SUCCESS_REBOOT_REQUIRED
745 reporter.log('Note: Installer required a reboot to complete installation');
746 # Optional, don't fail.
747 else:
748 fRc = False;
749 sLogFile = os.path.join(tempfile.gettempdir(), 'VirtualBox', 'VBoxInstallLog.txt');
750 if sLogFile is not None \
751 and os.path.isfile(sLogFile):
752 reporter.addLogFile(sLogFile, 'log/installer', "Verbose MSI installation log file");
753 self._waitForTestManagerConnectivity(30);
754 return fRc;
755
756 def _uninstallVBoxOnWindows(self):
757 """
758 Uninstalls VBox on Windows, all installations we find to be on the safe side...
759 """
760
761 import win32com.client; # pylint: disable=F0401
762 win32com.client.gencache.EnsureModule('{000C1092-0000-0000-C000-000000000046}', 1033, 1, 0);
763 oInstaller = win32com.client.Dispatch('WindowsInstaller.Installer',
764 resultCLSID = '{000C1090-0000-0000-C000-000000000046}')
765
766 # Search installed products for VirtualBox.
767 asProdCodes = [];
768 for sProdCode in oInstaller.Products:
769 try:
770 sProdName = oInstaller.ProductInfo(sProdCode, "ProductName");
771 except:
772 reporter.logXcpt();
773 continue;
774 #reporter.log('Info: %s=%s' % (sProdCode, sProdName));
775 if sProdName.startswith('Oracle VM VirtualBox') \
776 or sProdName.startswith('Sun VirtualBox'):
777 asProdCodes.append([sProdCode, sProdName]);
778
779 # Before we start uninstalling anything, just ruthlessly kill any
780 # msiexec process we might find hanging around.
781 cKilled = 0;
782 for oProcess in utils.processListAll():
783 sBase = oProcess.getBaseImageNameNoExeSuff();
784 if sBase is not None and sBase.lower() in [ 'msiexec', ]:
785 reporter.log('Killing MSI process: %s (%s)' % (oProcess.iPid, sBase));
786 utils.processKill(oProcess.iPid);
787 cKilled += 1;
788 if cKilled > 0:
789 time.sleep(16); # fudge.
790
791 # Do the uninstalling.
792 fRc = True;
793 sLogFile = os.path.join(self.sScratchPath, 'VBoxUninstallLog.txt');
794 for sProdCode, sProdName in asProdCodes:
795 reporter.log('Uninstalling %s (%s)...' % (sProdName, sProdCode));
796 fRc2, iRc = self._sudoExecuteSync(['msiexec', '/uninstall', sProdCode, '/quiet', '/passive', '/norestart',
797 '/L*v', '%s' % (sLogFile), ]);
798 if fRc2 is False:
799 if iRc == 3010: # ERROR_SUCCESS_REBOOT_REQUIRED
800 reporter.log('Note: Uninstaller required a reboot to complete uninstallation');
801 # Optional, don't fail.
802 else:
803 fRc = False;
804 reporter.addLogFile(sLogFile, 'log/uninstaller', "Verbose MSI uninstallation log file");
805
806 self._waitForTestManagerConnectivity(30);
807 if fRc is False and os.path.isfile(sLogFile):
808 reporter.addLogFile(sLogFile, 'log/uninstaller');
809 return fRc;
810
811
812 #
813 # Extension pack.
814 #
815
816 def _getVBoxInstallPath(self, fFailIfNotFound):
817 """ Returns the default VBox installation path. """
818 sHost = utils.getHostOs();
819 if sHost == 'win':
820 sProgFiles = os.environ.get('ProgramFiles', 'C:\\Program Files');
821 asLocs = [
822 os.path.join(sProgFiles, 'Oracle', 'VirtualBox'),
823 os.path.join(sProgFiles, 'OracleVM', 'VirtualBox'),
824 os.path.join(sProgFiles, 'Sun', 'VirtualBox'),
825 ];
826 elif sHost == 'linux' or sHost == 'solaris':
827 asLocs = [ '/opt/VirtualBox', '/opt/VirtualBox-3.2', '/opt/VirtualBox-3.1', '/opt/VirtualBox-3.0'];
828 elif sHost == 'darwin':
829 asLocs = [ '/Applications/VirtualBox.app/Contents/MacOS' ];
830 else:
831 asLocs = [ '/opt/VirtualBox' ];
832 if 'VBOX_INSTALL_PATH' in os.environ:
833 asLocs.insert(0, os.environ.get('VBOX_INSTALL_PATH', None));
834
835 for sLoc in asLocs:
836 if os.path.isdir(sLoc):
837 return sLoc;
838 if fFailIfNotFound:
839 reporter.error('Failed to locate VirtualBox installation: %s' % (asLocs,));
840 else:
841 reporter.log2('Failed to locate VirtualBox installation: %s' % (asLocs,));
842 return None;
843
844 def _installExtPack(self):
845 """ Installs the extension pack. """
846 sVBox = self._getVBoxInstallPath(fFailIfNotFound = True);
847 if sVBox is None:
848 return False;
849 sExtPackDir = os.path.join(sVBox, 'ExtensionPacks');
850
851 if self._uninstallAllExtPacks() is not True:
852 return False;
853
854 sExtPack = self._findFile('Oracle_VM_VirtualBox_Extension_Pack.vbox-extpack');
855 if sExtPack is None:
856 sExtPack = self._findFile('Oracle_VM_VirtualBox_Extension_Pack.*.vbox-extpack');
857 if sExtPack is None:
858 return True;
859
860 sDstDir = os.path.join(sExtPackDir, 'Oracle_VM_VirtualBox_Extension_Pack');
861 reporter.log('Installing extension pack "%s" to "%s"...' % (sExtPack, sExtPackDir));
862 fRc, _ = self._sudoExecuteSync([ self.getBinTool('vts_tar'),
863 '--extract',
864 '--verbose',
865 '--gzip',
866 '--file', sExtPack,
867 '--directory', sDstDir,
868 '--file-mode-and-mask', '0644',
869 '--file-mode-or-mask', '0644',
870 '--dir-mode-and-mask', '0755',
871 '--dir-mode-or-mask', '0755',
872 '--owner', '0',
873 '--group', '0',
874 ]);
875 return fRc;
876
877 def _uninstallAllExtPacks(self):
878 """ Uninstalls all extension packs. """
879 sVBox = self._getVBoxInstallPath(fFailIfNotFound = False);
880 if sVBox is None:
881 return True;
882
883 sExtPackDir = os.path.join(sVBox, 'ExtensionPacks');
884 if not os.path.exists(sExtPackDir):
885 return True;
886
887 fRc, _ = self._sudoExecuteSync([self.getBinTool('vts_rm'), '-Rfv', '--', sExtPackDir]);
888 return fRc;
889
890
891
892if __name__ == '__main__':
893 sys.exit(VBoxInstallerTestDriver().main(sys.argv));
894
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