VirtualBox

Changeset 78831 in vbox for trunk/src/VBox/ValidationKit


Ignore:
Timestamp:
May 28, 2019 4:12:03 PM (6 years ago)
Author:
vboxsync
Message:

vboxtestvms.py: Trying to distill out a new base class for test VMs.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/ValidationKit/testdriver/vboxtestvms.py

    r78824 r78831  
    8787# Table translating from VM name core to a more detailed guest info.
    8888# pylint: disable=C0301
     89## @todo what's the difference between the first two columns again?
    8990g_aaNameToDetails = \
    9091[
     
    191192
    192193
     194
     195class BaseTestVm(object):
     196    """
     197    Base class ofr Test VMs.
     198    """
     199
     200    def __init__(self, # pylint: disable=R0913
     201                 sVmName,                                   # type: str
     202                 fGrouping = 0,                             # type: int
     203                 oSet = None,                               # type: TestVmSet
     204                 sKind = None,                              # type: str
     205                 acCpusSup = None,                          # type: List[int]
     206                 asVirtModesSup = None,                     # type: List[str]
     207                 asParavirtModesSup = None,                 # type: List[str]
     208                 fRandomPvPModeCrap = False,                # type: bool
     209                 fVmmDevTestingPart = None,                 # type: bool
     210                 fVmmDevTestingMmio = False,                # type: bool
     211                 ):
     212        self.oSet                    = oSet;
     213        self.sVmName                 = sVmName;
     214        self.fGrouping               = fGrouping;
     215        self.sKind                   = sKind;               # Guest OS type.
     216        self.acCpusSup               = acCpusSup;
     217        self.asVirtModesSup          = asVirtModesSup;
     218        self.asParavirtModesSup      = asParavirtModesSup;
     219        self.asParavirtModesSupOrg   = asParavirtModesSup;  # HACK ALERT! Trick to make the 'effing random mess not get in the
     220                                                            # way of actively selecting virtualization modes.
     221
     222        self.fSkip                   = False;               # All VMs are included in the configured set by default.
     223        self.fSnapshotRestoreCurrent = False;               # Whether to restore execution on the current snapshot.
     224
     225        self.fVmmDevTestingPart      = fVmmDevTestingPart;
     226        self.fVmmDevTestingMmio      = fVmmDevTestingMmio;
     227        self.fCom1RawFile            = False;
     228        self.sCom1RawFile            = None;                # Set by createVmInner and getReconfiguredVm if fCom1RawFile is set.
     229
     230        # Derived stuff:
     231        self.aInfo                   = None;
     232        self.sGuestOsType            = None;                # ksGuestOsTypeXxxx value, API GuestOS Type is in the sKind member.
     233        self._guessStuff(fRandomPvPModeCrap);
     234
     235    def _mkCanonicalGuestOSType(self, sType):
     236        """
     237        Convert guest OS type into constant representation.
     238        Raise exception if specified @param sType is unknown.
     239        """
     240        if sType.lower().startswith('darwin'):
     241            return g_ksGuestOsTypeDarwin
     242        if sType.lower().startswith('bsd'):
     243            return g_ksGuestOsTypeFreeBSD
     244        if sType.lower().startswith('dos'):
     245            return g_ksGuestOsTypeDOS
     246        if sType.lower().startswith('linux'):
     247            return g_ksGuestOsTypeLinux
     248        if sType.lower().startswith('os2'):
     249            return g_ksGuestOsTypeOS2
     250        if sType.lower().startswith('solaris'):
     251            return g_ksGuestOsTypeSolaris
     252        if sType.lower().startswith('windows'):
     253            return g_ksGuestOsTypeWindows
     254        raise base.GenError(sWhat="unknown guest OS kind: %s" % str(sType))
     255
     256    def _guessStuff(self, fRandomPvPModeCrap):
     257        """
     258        Used by the constructor to guess stuff.
     259        """
     260
     261        sNm     = self.sVmName.lower().strip();
     262        asSplit = sNm.replace('-', ' ').split(' ');
     263
     264        if self.sKind is None:
     265            # From name.
     266            for aInfo in g_aaNameToDetails:
     267                if _intersects(asSplit, aInfo[g_iRegEx]):
     268                    self.aInfo        = aInfo;
     269                    self.sGuestOsType = self._mkCanonicalGuestOSType(aInfo[g_iGuestOsType])
     270                    self.sKind        = aInfo[g_iKind];
     271                    break;
     272            if self.sKind is None:
     273                reporter.fatal('The OS of test VM "%s" cannot be guessed' % (self.sVmName,));
     274
     275            # Check for 64-bit, if required and supported.
     276            if (self.aInfo[g_iFlags] & g_kiArchMask) == g_k32_64  and  _intersects(asSplit, ['64', 'amd64']):
     277                self.sKind = self.sKind + '_64';
     278        else:
     279            # Lookup the kind.
     280            for aInfo in g_aaNameToDetails:
     281                if self.sKind == aInfo[g_iKind]:
     282                    self.aInfo = aInfo;
     283                    break;
     284            if self.aInfo is None:
     285                reporter.fatal('The OS of test VM "%s" with sKind="%s" cannot be guessed' % (self.sVmName, self.sKind));
     286
     287        # Translate sKind into sGuest OS Type.
     288        if self.sGuestOsType is None:
     289            if self.aInfo is not None:
     290                self.sGuestOsType = self._mkCanonicalGuestOSType(self.aInfo[g_iGuestOsType])
     291            elif self.sKind.find("Windows") >= 0:
     292                self.sGuestOsType = g_ksGuestOsTypeWindows
     293            elif self.sKind.find("Linux") >= 0:
     294                self.sGuestOsType = g_ksGuestOsTypeLinux;
     295            elif self.sKind.find("Solaris") >= 0:
     296                self.sGuestOsType = g_ksGuestOsTypeSolaris;
     297            elif self.sKind.find("DOS") >= 0:
     298                self.sGuestOsType = g_ksGuestOsTypeDOS;
     299            else:
     300                reporter.fatal('The OS of test VM "%s", sKind="%s" cannot be guessed' % (self.sVmName, self.sKind));
     301
     302        # Restrict modes and such depending on the OS.
     303        if self.asVirtModesSup is None:
     304            self.asVirtModesSup = list(g_asVirtModes);
     305            if   self.sGuestOsType in (g_ksGuestOsTypeOS2, g_ksGuestOsTypeDarwin) \
     306              or self.sKind.find('_64') > 0 \
     307              or (self.aInfo is not None and (self.aInfo[g_iFlags] & g_kiNoRaw)):
     308                self.asVirtModesSup = [sVirtMode for sVirtMode in self.asVirtModesSup if sVirtMode != 'raw'];
     309            # TEMPORARY HACK - START
     310            sHostName = os.environ.get("COMPUTERNAME", None);
     311            if sHostName:   sHostName = sHostName.lower();
     312            else:           sHostName = socket.getfqdn(); # Horribly slow on windows without IPv6 DNS/whatever.
     313            if sHostName.startswith('testboxpile1'):
     314                self.asVirtModesSup = [sVirtMode for sVirtMode in self.asVirtModesSup if sVirtMode != 'raw'];
     315            # TEMPORARY HACK - END
     316
     317        # Restrict the CPU count depending on the OS and/or percieved SMP readiness.
     318        if self.acCpusSup is None:
     319            if _intersects(asSplit, ['uni']):
     320                self.acCpusSup = [1];
     321            elif self.aInfo is not None:
     322                self.acCpusSup = [i for i in range(self.aInfo[g_iMinCpu], self.aInfo[g_iMaxCpu]) ];
     323            else:
     324                self.acCpusSup = [1];
     325
     326        # Figure relevant PV modes based on the OS.
     327        if self.asParavirtModesSup is None:
     328            self.asParavirtModesSup = g_kdaParavirtProvidersSupported[self.sGuestOsType];
     329            ## @todo Remove this hack as soon as we've got around to explictly configure test variations
     330            ## on the server side. Client side random is interesting but not the best option.
     331            self.asParavirtModesSupOrg = self.asParavirtModesSup;
     332            if fRandomPvPModeCrap:
     333                random.seed();
     334                self.asParavirtModesSup = (random.choice(self.asParavirtModesSup),);
     335
     336        return True;
     337
     338    def _generateRawPortFilename(self, oTestDrv, sInfix, sSuffix):
     339        """ Generates a raw port filename. """
     340        random.seed();
     341        sRandom = ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(10));
     342        return os.path.join(oTestDrv.sScratchPath, self.sVmName + sInfix + sRandom + sSuffix);
     343
     344    def _createVmTail(self, oTestDrv, eNic0AttachType, sDvdImage):
     345        """
     346        Returns same as vbox.TestDriver.createTestVM.
     347        """
     348        _ = oTestDrv; _ = eNic0AttachType; _ = sDvdImage;
     349        return reporter.error('Base class _createVmTail must not be called!');
     350
     351    def _childVmReconfig(self, oTestDrv, oVM, oSession):
     352        """
     353        Hook into getReconfiguredVm() for children.
     354        """
     355        _ = oTestDrv; _ = oVM; _ = oSession;
     356        return True;
     357
     358
     359    #
     360    # Public interface.
     361    #
     362
     363    def getMissingResources(self, sTestRsrc):
     364        """
     365        Returns a list of missing resources (paths, stuff) that the VM needs.
     366        """
     367        _ = sTestRsrc;
     368        return [];
     369
     370    def createVm(self, oTestDrv, eNic0AttachType = None, sDvdImage = None):
     371        """
     372        Creates the VM with defaults and the few tweaks as per the arguments.
     373
     374        Returns same as vbox.TestDriver.createTestVM.
     375        """
     376        reporter.log2('');
     377        reporter.log2('Creating %s...' % (self.sVmName,))
     378
     379        if self.fCom1RawFile:
     380            self.sCom1RawFile = self._generateRawPortFilename(oTestDrv, '-com1-', '.out');
     381
     382        return self._createVmTail(oTestDrv, eNic0AttachType, sDvdImage);
     383
     384    def getReconfiguredVm(self, oTestDrv, cCpus, sVirtMode, sParavirtMode = None):
     385        """
     386        actionExecute worker that finds and reconfigure a test VM.
     387
     388        Returns (fRc, oVM) where fRc is True, None or False and oVM is a
     389        VBox VM object that is only present when rc is True.
     390        """
     391
     392        fRc = False;
     393        oVM = oTestDrv.getVmByName(self.sVmName);
     394        if oVM is not None:
     395            if self.fSnapshotRestoreCurrent is True:
     396                fRc = True;
     397            else:
     398                fHostSupports64bit = oTestDrv.hasHostLongMode();
     399                if self.is64bitRequired() and not fHostSupports64bit:
     400                    fRc = None; # Skip the test.
     401                elif self.isViaIncompatible() and oTestDrv.isHostCpuVia():
     402                    fRc = None; # Skip the test.
     403                elif self.isShanghaiIncompatible() and oTestDrv.isHostCpuShanghai():
     404                    fRc = None; # Skip the test.
     405                elif self.isP4Incompatible() and oTestDrv.isHostCpuP4():
     406                    fRc = None; # Skip the test.
     407                else:
     408                    oSession = oTestDrv.openSession(oVM);
     409                    if oSession is not None:
     410                        fRc =         oSession.enableVirtEx(sVirtMode != 'raw');
     411                        fRc = fRc and oSession.enableNestedPaging(sVirtMode == 'hwvirt-np');
     412                        fRc = fRc and oSession.setCpuCount(cCpus);
     413                        if cCpus > 1:
     414                            fRc = fRc and oSession.enableIoApic(True);
     415
     416                        if sParavirtMode is not None and oSession.fpApiVer >= 5.0:
     417                            adParavirtProviders = {
     418                                g_ksParavirtProviderNone   : vboxcon.ParavirtProvider_None,
     419                                g_ksParavirtProviderDefault: vboxcon.ParavirtProvider_Default,
     420                                g_ksParavirtProviderLegacy : vboxcon.ParavirtProvider_Legacy,
     421                                g_ksParavirtProviderMinimal: vboxcon.ParavirtProvider_Minimal,
     422                                g_ksParavirtProviderHyperV : vboxcon.ParavirtProvider_HyperV,
     423                                g_ksParavirtProviderKVM    : vboxcon.ParavirtProvider_KVM,
     424                            };
     425                            fRc = fRc and oSession.setParavirtProvider(adParavirtProviders[sParavirtMode]);
     426
     427                        fCfg64Bit = self.is64bitRequired() or (self.is64bit() and fHostSupports64bit and sVirtMode != 'raw');
     428                        fRc = fRc and oSession.enableLongMode(fCfg64Bit);
     429                        if fCfg64Bit: # This is to avoid GUI pedantic warnings in the GUI. Sigh.
     430                            oOsType = oSession.getOsType();
     431                            if oOsType is not None:
     432                                if oOsType.is64Bit and sVirtMode == 'raw':
     433                                    assert(oOsType.id[-3:] == '_64');
     434                                    fRc = fRc and oSession.setOsType(oOsType.id[:-3]);
     435                                elif not oOsType.is64Bit and sVirtMode != 'raw':
     436                                    fRc = fRc and oSession.setOsType(oOsType.id + '_64');
     437
     438                        # New serial raw file.
     439                        if fRc and self.fCom1RawFile:
     440                            self.sCom1RawFile = self._generateRawPortFilename(oTestDrv, '-com1-', '.out');
     441                            utils.noxcptDeleteFile(self.sCom1RawFile);
     442                            fRc = oSession.setupSerialToRawFile(0, self.sCom1RawFile);
     443
     444                        # Make life simpler for child classes.
     445                        if fRc:
     446                            fRc = self._childVmReconfig(oTestDrv, oVM, oSession);
     447
     448                        fRc = fRc and oSession.saveSettings();
     449                        if not oSession.close():
     450                            fRc = False;
     451            if fRc is True:
     452                return (True, oVM);
     453        return (fRc, None);
     454
     455    def getNonCanonicalGuestOsType(self):
     456        """
     457        Gets the non-canonical OS type (self.sGuestOsType is canonical).
     458        """
     459        return self.sKind; #self.aInfo[g_iGuestOsType];
     460
     461    def isWindows(self):
     462        """ Checks if it's a Windows VM. """
     463        return self.sGuestOsType == g_ksGuestOsTypeWindows;
     464
     465    def isOS2(self):
     466        """ Checks if it's an OS/2 VM. """
     467        return self.sGuestOsType == g_ksGuestOsTypeOS2;
     468
     469    def isLinux(self):
     470        """ Checks if it's an Linux VM. """
     471        return self.sGuestOsType == g_ksGuestOsTypeLinux;
     472
     473    def is64bit(self):
     474        """ Checks if it's a 64-bit VM. """
     475        return self.sKind.find('_64') >= 0;
     476
     477    def is64bitRequired(self):
     478        """ Check if 64-bit is required or not. """
     479        return (self.aInfo[g_iFlags] & g_k64) != 0;
     480
     481    def isLoggedOntoDesktop(self):
     482        """ Checks if the test VM is logging onto a graphical desktop by default. """
     483        if self.isWindows():
     484            return True;
     485        if self.isOS2():
     486            return True;
     487        if self.sVmName.find('-desktop'):
     488            return True;
     489        return False;
     490
     491    def isViaIncompatible(self):
     492        """
     493        Identifies VMs that doesn't work on VIA.
     494
     495        Returns True if NOT supported on VIA, False if it IS supported.
     496        """
     497        # Oracle linux doesn't like VIA in our experience
     498        if self.aInfo[g_iKind] in ['Oracle', 'Oracle_64']:
     499            return True;
     500        # OS/2: "The system detected an internal processing error at location
     501        # 0168:fff1da1f - 000e:ca1f. 0a8606fd
     502        if self.isOS2():
     503            return True;
     504        # Windows NT4 before SP4 won't work because of cmpxchg8b not being
     505        # detected, leading to a STOP 3e(80,0,0,0).
     506        if self.aInfo[g_iKind] == 'WindowsNT4':
     507            if self.sVmName.find('sp') < 0:
     508                return True; # no service pack.
     509            if   self.sVmName.find('sp0') >= 0 \
     510              or self.sVmName.find('sp1') >= 0 \
     511              or self.sVmName.find('sp2') >= 0 \
     512              or self.sVmName.find('sp3') >= 0:
     513                return True;
     514        # XP x64 on a physical VIA box hangs exactly like a VM.
     515        if self.aInfo[g_iKind] in ['WindowsXP_64', 'Windows2003_64']:
     516            return True;
     517        # Vista 64 throws BSOD 0x5D (UNSUPPORTED_PROCESSOR)
     518        if self.aInfo[g_iKind] in ['WindowsVista_64']:
     519            return True;
     520        # Solaris 11 hangs on VIA, tested on a physical box (testboxvqc)
     521        if self.aInfo[g_iKind] in ['Solaris11_64']:
     522            return True;
     523        return False;
     524
     525    def isShanghaiIncompatible(self):
     526        """
     527        Identifies VMs that doesn't work on Shanghai.
     528
     529        Returns True if NOT supported on Shanghai, False if it IS supported.
     530        """
     531        # For now treat it just like VIA, to be adjusted later
     532        return self.isViaIncompatible()
     533
     534    def isP4Incompatible(self):
     535        """
     536        Identifies VMs that doesn't work on Pentium 4 / Pentium D.
     537
     538        Returns True if NOT supported on P4, False if it IS supported.
     539        """
     540        # Stupid 1 kHz timer. Too much for antique CPUs.
     541        if self.sVmName.find('rhel5') >= 0:
     542            return True;
     543        # Due to the boot animation the VM takes forever to boot.
     544        if self.aInfo[g_iKind] == 'Windows2000':
     545            return True;
     546        return False;
     547
     548    def isHostCpuAffectedByUbuntuNewAmdBug(self, oTestDrv):
     549        """
     550        Checks if the host OS is affected by older ubuntu installers being very
     551        picky about which families of AMD CPUs it would run on.
     552
     553        The installer checks for family 15, later 16, later 20, and in 11.10
     554        they remove the family check for AMD CPUs.
     555        """
     556        if not oTestDrv.isHostCpuAmd():
     557            return False;
     558        try:
     559            (uMaxExt, _, _, _) = oTestDrv.oVBox.host.getProcessorCPUIDLeaf(0, 0x80000000, 0);
     560            (uFamilyModel, _, _, _) = oTestDrv.oVBox.host.getProcessorCPUIDLeaf(0, 0x80000001, 0);
     561        except:
     562            reporter.logXcpt();
     563            return False;
     564        if uMaxExt < 0x80000001 or uMaxExt > 0x8000ffff:
     565            return False;
     566
     567        uFamily = (uFamilyModel >> 8) & 0xf
     568        if uFamily == 0xf:
     569            uFamily = ((uFamilyModel >> 20) & 0x7f) + 0xf;
     570        ## @todo Break this down into which old ubuntu release supports exactly
     571        ##       which AMD family, if we care.
     572        if uFamily <= 15:
     573            return False;
     574        reporter.log('Skipping "%s" because host CPU is a family %u AMD, which may cause trouble for the guest OS installer.'
     575                     % (self.sVmName, uFamily,));
     576        return True;
     577
     578
     579## @todo Inherit from BaseTestVm
    193580class TestVm(object):
    194581    """
Note: See TracChangeset for help on using the changeset viewer.

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