コード例 #1
0
    def doReboot(self):
        """
        Worker common to _cmdReboot and _doUpgrade that performs a system reboot.
        """
        # !! Not more exceptions beyond this point !!
        testboxcommons.log('Rebooting');

        # Stop anything that might be executing at this point.
        oCurTask = self._getCurTask();
        if oCurTask is not None:
            oCurTask.terminate();
            oCurTask.wait(self.kcSecStopBeforeRebootTimeout);

        # Invoke shutdown command line utility.
        sOs = utils.getHostOs();
        asCmd2 = None;
        if sOs == 'win':
            asCmd = ['shutdown', '/r', '/t', '0'];
        elif sOs == 'os2':
            asCmd = ['setboot', '/B'];
        elif sOs in ('solaris',):
            asCmd = ['/usr/sbin/reboot', '-p'];
            asCmd2 = ['/usr/sbin/reboot']; # Hack! S10 doesn't have -p, but don't know how to reliably detect S10.
        else:
            asCmd = ['/sbin/shutdown', '-r', 'now'];
        try:
            utils.sudoProcessOutputChecked(asCmd);
        except Exception, oXcpt:
            if asCmd2 is not None:
                try:
                    utils.sudoProcessOutputChecked(asCmd2);
                except Exception, oXcpt:
                    testboxcommons.log('Error executing reboot command "%s" as well as "%s": %s' % (asCmd, asCmd2, oXcpt));
                    return False;
コード例 #2
0
    def _logInternal(self, sMessage, fPrefix = True, fFlushCheck = False):
        """
        Internal logging.
        Won't flush the backlog, returns a flush indicator so the caller can
        do it instead.
        """
        if fPrefix:
            try:
                oNow = datetime.utcnow();
                sTs = '%02u:%02u:%02u.%06u ' % (oNow.hour, oNow.minute, oNow.second, oNow.microsecond);
            except Exception as oXcpt:
                sTs = 'oXcpt=%s ' % (oXcpt);
            sFullMsg = sTs + sMessage;
        else:
            sFullMsg = sMessage;

        self._oBackLogLock.acquire();
        self._asBackLog.append(sFullMsg);
        cchBackLog = self._cchBackLog + len(sFullMsg) + 1;
        self._cchBackLog = cchBackLog;
        secTsBackLogFlush = self._secTsBackLogFlush;
        self._oBackLogLock.release();

        testboxcommons.log(sFullMsg);
        return fFlushCheck \
            and (   cchBackLog >= self.kcchMaxBackLog \
                 or utils.timestampSecond() - secTsBackLogFlush >= self.kcSecBackLogFlush);
コード例 #3
0
    def _maybeSignOn(self):
        """
        Check if Test Box parameters were changed
        and do sign-in in case of positive result
        """

        # Skip sign-on check if background command is currently in
        # running state (avoid infinite signing on).
        if self._oCommand.isRunning():
            return None;

        # Refresh sign-on parameters, changes triggers sign-on.
        fNeedSignOn = (True if not self._fSignedOn or self._fNeedReSignOn else False)
        for item in self._ddSignOnParams:
            if self._ddSignOnParams[item][self.FN] is None:
                continue

            sOldValue = self._ddSignOnParams[item][self.VALUE]
            self._ddSignOnParams[item][self.VALUE] = self._ddSignOnParams[item][self.FN]()
            if sOldValue != self._ddSignOnParams[item][self.VALUE]:
                fNeedSignOn = True
                testboxcommons.log('Detected %s parameter change: %s -> %s' %
                                   (item, sOldValue, self._ddSignOnParams[item][self.VALUE]))

        if fNeedSignOn:
            self._doSignOn();
        return None;
コード例 #4
0
ファイル: testboxconnection.py プロジェクト: mcenirm/vbox
    def __init__(self, oResponse):
        """
        Convert the HTTPResponse to a dictionary, raising TestBoxException on
        malformed response.
        """
        if oResponse is not None:
            # Read the whole response (so we can log it).
            sBody = oResponse.read();

            # Check the content type.
            sContentType = oResponse.getheader('Content-Type');
            if sContentType is None  or  sContentType != 'application/x-www-form-urlencoded; charset=utf-8':
                testboxcommons.log('SERVER RESPONSE: Content-Type: %s' % (sContentType,));
                testboxcommons.log('SERVER RESPONSE: %s' % (sBody.rstrip(),))
                raise testboxcommons.TestBoxException('Invalid server response type: "%s"' % (sContentType,));

            # Parse the body (this should be the exact reverse of what
            # TestBoxConnection.postRequestRaw).
            ##testboxcommons.log2('SERVER RESPONSE: "%s"' % (sBody,))
            self._dResponse = urlparse.parse_qs(sBody, strict_parsing=True);

            # Convert the dictionary from 'field:values' to 'field:value'. Fail
            # if a field has more than one value (i.e. given more than once).
            for sField in self._dResponse:
                if len(self._dResponse[sField]) != 1:
                    raise testboxcommons.TestBoxException('The field "%s" appears more than once in the server response' \
                                                          % (sField,));
                self._dResponse[sField] = self._dResponse[sField][0]
        else:
            # Special case, dummy response object.
            self._dResponse = dict();
コード例 #5
0
    def __init__(self, oResponse):
        """
        Convert the HTTPResponse to a dictionary, raising TestBoxException on
        malformed response.
        """
        if oResponse is not None:
            # Read the whole response (so we can log it).
            sBody = oResponse.read()
            sBody = sBody.decode('utf-8')

            # Check the content type.
            sContentType = oResponse.getheader('Content-Type')
            if sContentType is None or sContentType != 'application/x-www-form-urlencoded; charset=utf-8':
                testboxcommons.log('SERVER RESPONSE: Content-Type: %s' %
                                   (sContentType, ))
                testboxcommons.log('SERVER RESPONSE: %s' % (sBody.rstrip(), ))
                raise testboxcommons.TestBoxException(
                    'Invalid server response type: "%s"' % (sContentType, ))

            # Parse the body (this should be the exact reverse of what
            # TestBoxConnection.postRequestRaw).
            ##testboxcommons.log2('SERVER RESPONSE: "%s"' % (sBody,))
            self._dResponse = urlparse.parse_qs(sBody, strict_parsing=True)

            # Convert the dictionary from 'field:values' to 'field:value'. Fail
            # if a field has more than one value (i.e. given more than once).
            for sField in self._dResponse:
                if len(self._dResponse[sField]) != 1:
                    raise testboxcommons.TestBoxException('The field "%s" appears more than once in the server response' \
                                                          % (sField,))
                self._dResponse[sField] = self._dResponse[sField][0]
        else:
            # Special case, dummy response object.
            self._dResponse = dict()
コード例 #6
0
    def _logInternal(self, sMessage, fPrefix = True, fFlushCheck = False):
        """
        Internal logging.
        Won't flush the backlog, returns a flush indicator so the caller can
        do it instead.
        """
        if fPrefix:
            try:
                oNow = datetime.utcnow();
                sTs = '%02u:%02u:%02u.%06u ' % (oNow.hour, oNow.minute, oNow.second, oNow.microsecond);
            except Exception as oXcpt:
                sTs = 'oXcpt=%s ' % (oXcpt);
            sFullMsg = sTs + sMessage;
        else:
            sFullMsg = sMessage;

        self._oBackLogLock.acquire();
        self._asBackLog.append(sFullMsg);
        cchBackLog = self._cchBackLog + len(sFullMsg) + 1;
        self._cchBackLog = cchBackLog;
        secTsBackLogFlush = self._secTsBackLogFlush;
        self._oBackLogLock.release();

        testboxcommons.log(sFullMsg);
        return fFlushCheck \
            and (   cchBackLog >= self.kcchMaxBackLog \
                 or utils.timestampSecond() - secTsBackLogFlush >= self.kcSecBackLogFlush);
コード例 #7
0
    def _maybeSignOn(self):
        """
        Check if Test Box parameters were changed
        and do sign-in in case of positive result
        """

        # Skip sign-on check if background command is currently in
        # running state (avoid infinite signing on).
        if self._oCommand.isRunning():
            return None;

        # Refresh sign-on parameters, changes triggers sign-on.
        fNeedSignOn = (True if not self._fSignedOn or self._fNeedReSignOn else False)
        for item in self._ddSignOnParams:
            if self._ddSignOnParams[item][self.FN] is None:
                continue

            sOldValue = self._ddSignOnParams[item][self.VALUE]
            self._ddSignOnParams[item][self.VALUE] = self._ddSignOnParams[item][self.FN]()
            if sOldValue != self._ddSignOnParams[item][self.VALUE]:
                fNeedSignOn = True
                testboxcommons.log('Detected %s parameter change: %s -> %s' %
                                   (item, sOldValue, self._ddSignOnParams[item][self.VALUE]))

        if fNeedSignOn:
            self._doSignOn();
        return None;
コード例 #8
0
 def _cmdSpecial(self, oResponse, oConnection):
     """
     Reserved for future fun.
     """
     oConnection.sendReplyAndClose(constants.tbreq.COMMAND_NOTSUP, constants.tbresp.CMD_SPECIAL);
     testboxcommons.log('Special command %s not supported...' % (oResponse,));
     return False;
コード例 #9
0
 def _cmdSpecial(self, oResponse, oConnection):
     """
     Reserved for future fun.
     """
     oConnection.sendReplyAndClose(constants.tbreq.COMMAND_NOTSUP,
                                   constants.tbresp.CMD_SPECIAL)
     testboxcommons.log('Special command %s not supported...' %
                        (oResponse, ))
     return False
コード例 #10
0
    def _logFlush(self, oGivenConnection=None):
        """
        Flushes the log to the test manager.

        No exceptions.
        """
        fRc = True
        self._oBackLogFlushLock.acquire()

        # Grab the current back log.
        self._oBackLogLock.acquire()
        asBackLog = self._asBackLog
        self._asBackLog = []
        self._cchBackLog = 0
        self._secTsBackLogFlush = utils.timestampSecond()
        self._oBackLogLock.release()

        # If there is anything to flush, flush it.
        if asBackLog:
            sBody = ''
            for sLine in asBackLog:
                sBody += sLine + '\n'

            oConnection = None
            try:
                if oGivenConnection is None:
                    oConnection = self._oTestBoxScript.openTestManagerConnection(
                    )
                    oConnection.postRequest(
                        constants.tbreq.LOG_MAIN,
                        {constants.tbreq.LOG_PARAM_BODY: sBody})
                    oConnection.close()
                else:
                    oGivenConnection.postRequest(
                        constants.tbreq.LOG_MAIN,
                        {constants.tbreq.LOG_PARAM_BODY: sBody})
            except Exception as oXcpt:
                testboxcommons.log('_logFlush error: %s' % (oXcpt, ))
                if len(sBody) < self.kcchMaxBackLog * 4:
                    self._oBackLogLock.acquire()
                    asBackLog.extend(self._asBackLog)
                    self._asBackLog = asBackLog
                    # Don't restore _cchBackLog as there is no point in retrying immediately.
                    self._oBackLogLock.release()
                if oConnection is not None:  # Be kind to apache.
                    try:
                        oConnection.close()
                    except:
                        pass
                fRc = False

        self._oBackLogFlushLock.release()
        return fRc
コード例 #11
0
def _doUpgradeRemoveOldStuff(sUpgradeDir, asMembers):
    """
    Clean up all obsolete files and directories.
    Returns True (shouldn't fail or raise any exceptions).
    """

    try:
        shutil.rmtree(sUpgradeDir, ignore_errors=True)
    except:
        pass

    asKnownFiles = []
    asKnownDirs = []
    for sMember in asMembers:
        sMember = sMember[len('testboxscript/'):]
        if sMember == '':
            continue
        if sMember[-1] == '/':
            asKnownDirs.append(
                os.path.normpath(
                    os.path.join(g_ksValidationKitDir, sMember[:-1])))
        else:
            asKnownFiles.append(
                os.path.normpath(os.path.join(g_ksValidationKitDir, sMember)))

    for sDirPath, asDirs, asFiles in os.walk(g_ksValidationKitDir,
                                             topdown=False):
        for sDir in asDirs:
            sFull = os.path.normpath(os.path.join(sDirPath, sDir))
            if sFull not in asKnownDirs:
                testboxcommons.log2('Info: Removing obsolete directory "%s"' %
                                    (sFull, ))
                try:
                    os.rmdir(sFull)
                except Exception as oXcpt:
                    testboxcommons.log(
                        'Warning: failed to rmdir obsolete dir "%s": %s' %
                        (sFull, oXcpt))

        for sFile in asFiles:
            sFull = os.path.normpath(os.path.join(sDirPath, sFile))
            if sFull not in asKnownFiles:
                testboxcommons.log2('Info: Removing obsolete file "%s"' %
                                    (sFull, ))
                try:
                    os.unlink(sFull)
                except Exception as oXcpt:
                    testboxcommons.log(
                        'Warning: failed to unlink obsolete file "%s": %s' %
                        (sFull, oXcpt))
    return True
コード例 #12
0
    def dispatch(self):
        """
        Receive orders from Test Manager and execute them
        """

        (self._idTestBox, self._sTestBoxName,
         self._fSignedOn) = self._oCommand.resumeIncompleteCommand()
        self._fNeedReSignOn = self._fSignedOn
        if self._fSignedOn:
            os.environ['TESTBOX_ID'] = str(self._idTestBox)
            os.environ['TESTBOX_NAME'] = self._sTestBoxName

        while True:
            # Make sure we're signed on before trying to do anything.
            self._maybeSignOn()
            while not self._fSignedOn:
                iFactor = 1 if self._cSignOnAttempts < 100 else 4
                time.sleep(
                    random.randint(self.kcSecMinSignOnDelay * iFactor,
                                   self.kcSecMaxSignOnDelay * iFactor))
                self._maybeSignOn()

            # Retrieve and handle command from the TM.
            (oResponse,
             oConnection) = TestBoxConnection.requestCommandWithConnection(
                 self._oOptions.sTestManagerUrl, self._idTestBox,
                 self._sTestBoxUuid, self._oCommand.isRunning())
            if oResponse is not None:
                self._oCommand.handleCommand(oResponse, oConnection)
            if oConnection is not None:
                if oConnection.isConnected():
                    self._oCommand.flushLogOnConnection(oConnection)
                oConnection.close()

            # Automatically reboot if scratch init fails.
            if self._cReinitScratchErrors > 8 and self.reinitScratch(
                    cRetries=3) is False:
                testboxcommons.log(
                    'Scratch does not initialize cleanly after %d attempts, rebooting...'
                    % (self._cReinitScratchErrors, ))
                self._oCommand.doReboot()

            # delay a wee bit before looping.
            ## @todo We shouldn't bother the server too frequently.  We should try combine the test reporting done elsewhere
            # with the command retrieval done here.  I believe tinderclient.pl is capable of doing that.
            iFactor = 1
            if self._cReinitScratchErrors > 0:
                iFactor = 4
            time.sleep(
                random.randint(self.kcSecMinDelay * iFactor,
                               self.kcSecMaxDelay * iFactor))
コード例 #13
0
    def handleCommand(self, oResponse, oConnection):
        """
        Handles a command from the test manager.

        Some commands will close the connection, others (generally the simple
        ones) wont, leaving the caller the option to use it for log flushing.

        Returns success indicator.
        Raises no exception.
        """
        try:
            sCmdName = oResponse.getStringChecked(
                constants.tbresp.ALL_PARAM_RESULT)
        except Exception as oXcpt:
            oConnection.close()
            return False

        # Do we know the command?
        fRc = False
        if sCmdName in self._dfnCommands:
            testboxcommons.log(sCmdName)
            try:
                # Execute the handler.
                fRc = self._dfnCommands[sCmdName](oResponse, oConnection)
            except Exception as oXcpt:
                # NACK the command if an exception is raised during parameter validation.
                testboxcommons.log1Xcpt('Exception executing "%s": %s' %
                                        (sCmdName, oXcpt))
                if oConnection.isConnected():
                    try:
                        oConnection.sendReplyAndClose(
                            constants.tbreq.COMMAND_NACK, sCmdName)
                    except Exception as oXcpt2:
                        testboxcommons.log('Failed to NACK "%s": %s' %
                                           (sCmdName, oXcpt2))
        elif sCmdName in [
                constants.tbresp.STATUS_DEAD, constants.tbresp.STATUS_NACK
        ]:
            testboxcommons.log('Received status instead of command: %s' %
                               (sCmdName, ))
        else:
            # NOTSUP the unknown command.
            testboxcommons.log('Received unknown command: %s' % (sCmdName, ))
            try:
                oConnection.sendReplyAndClose(constants.tbreq.COMMAND_NOTSUP,
                                              sCmdName)
            except Exception as oXcpt:
                testboxcommons.log('Failed to NOTSUP "%s": %s' %
                                   (sCmdName, oXcpt))
        return fRc
コード例 #14
0
def _doUpgradeTestRun(sUpgradeDir):
    """
    Do a testrun of the new script, to make sure it doesn't fail with
    to run in any way because of old python, missing import or generally
    busted upgrade.
    Returns True/False.
    """
    asArgs = [
        os.path.join(sUpgradeDir, 'testboxscript', 'testboxscript',
                     'testboxscript.py'), '--version'
    ]
    testboxcommons.log('Testing the new testbox script (%s)...' %
                       (asArgs[0], ))
    if sys.executable is not None and len(sys.executable) > 0:
        asArgs.insert(0, sys.executable)
    oChild = subprocess.Popen(asArgs,
                              shell=False,
                              stdout=subprocess.PIPE,
                              stderr=subprocess.STDOUT)

    asBuf = []
    oThread = threading.Thread(target=_doUpgradeThreadProc,
                               args=(oChild.stdout, asBuf))
    oThread.daemon = True
    oThread.start()
    oThread.join(30)

    iStatus = oChild.poll()
    if iStatus is None:
        testboxcommons.log('Checking the new testboxscript timed out.')
        oChild.terminate()
        oThread.join(5)
        return False
    if iStatus is not TBS_EXITCODE_SYNTAX:
        testboxcommons.log('The new testboxscript returned %d instead of %d during check.' \
                           % (iStatus, TBS_EXITCODE_SYNTAX))
        return False

    sOutput = ''.join(asBuf)
    sOutput = sOutput.strip()
    try:
        iNewVersion = int(sOutput)
    except:
        testboxcommons.log(
            'The new testboxscript returned an unparseable version string: "%s"!'
            % (sOutput, ))
        return False
    testboxcommons.log('New script version: %s' % (iNewVersion, ))
    return True
コード例 #15
0
ファイル: testboxupgrade.py プロジェクト: Ratio2/vbox
def _doUpgradeTestRun(sUpgradeDir):
    """
    Do a testrun of the new script, to make sure it doesn't fail with
    to run in any way because of old python, missing import or generally
    busted upgrade.
    Returns True/False.
    """
    asArgs = [os.path.join(sUpgradeDir, 'testboxscript', 'testboxscript', 'testboxscript.py'), '--version' ];
    testboxcommons.log('Testing the new testbox script (%s)...' % (asArgs[0],));
    if sys.executable:
        asArgs.insert(0, sys.executable);
    oChild = subprocess.Popen(asArgs, shell = False,                                        # pylint: disable=consider-using-with
                              stdout=subprocess.PIPE, stderr=subprocess.STDOUT);

    asBuf = []
    oThread = threading.Thread(target=_doUpgradeThreadProc, args=(oChild.stdout, asBuf));
    oThread.daemon = True;
    oThread.start();
    oThread.join(30);

    # Give child up to 5 seconds to terminate after producing output.
    if sys.version_info[0] >= 3 and sys.version_info[1] >= 3:
        oChild.wait(5); # pylint: disable=too-many-function-args
    else:
        for _ in range(50):
            iStatus = oChild.poll();
            if iStatus is None:
                break;
            time.sleep(0.1);
    iStatus = oChild.poll();
    if iStatus is None:
        testboxcommons.log('Checking the new testboxscript timed out.');
        oChild.terminate();
        oThread.join(5);
        return False;
    if iStatus is not TBS_EXITCODE_SYNTAX:
        testboxcommons.log('The new testboxscript returned %d instead of %d during check.' \
                           % (iStatus, TBS_EXITCODE_SYNTAX));
        return False;

    sOutput = b''.join(asBuf).decode('utf-8');
    sOutput = sOutput.strip();
    try:
        iNewVersion = int(sOutput);
    except:
        testboxcommons.log('The new testboxscript returned an unparseable version string: "%s"!' % (sOutput,));
        return False;
    testboxcommons.log('New script version: %s' % (iNewVersion,));
    return True;
コード例 #16
0
    def _logFlush(self, oGivenConnection = None):
        """
        Flushes the log to the test manager.

        No exceptions.
        """
        fRc = True;
        self._oBackLogFlushLock.acquire();

        # Grab the current back log.
        self._oBackLogLock.acquire();
        asBackLog = self._asBackLog;
        self._asBackLog  = [];
        self._cchBackLog = 0;
        self._secTsBackLogFlush = utils.timestampSecond();
        self._oBackLogLock.release();

        # If there is anything to flush, flush it.
        if asBackLog:
            sBody = '';
            for sLine in asBackLog:
                sBody += sLine + '\n';

            oConnection = None;
            try:
                if oGivenConnection is None:
                    oConnection = self._oTestBoxScript.openTestManagerConnection();
                    oConnection.postRequest(constants.tbreq.LOG_MAIN, {constants.tbreq.LOG_PARAM_BODY: sBody});
                    oConnection.close();
                else:
                    oGivenConnection.postRequest(constants.tbreq.LOG_MAIN, {constants.tbreq.LOG_PARAM_BODY: sBody});
            except Exception as oXcpt:
                testboxcommons.log('_logFlush error: %s' % (oXcpt,));
                if len(sBody) < self.kcchMaxBackLog * 4:
                    self._oBackLogLock.acquire();
                    asBackLog.extend(self._asBackLog);
                    self._asBackLog = asBackLog;
                    # Don't restore _cchBackLog as there is no point in retrying immediately.
                    self._oBackLogLock.release();
                if oConnection is not None: # Be kind to apache.
                    try:    oConnection.close();
                    except: pass;
                fRc = False;

        self._oBackLogFlushLock.release();
        return fRc;
コード例 #17
0
    def _doUpgrade(self, oResponse, oConnection, fReboot):
        """
        Common worker for _cmdUpgrade and _cmdUpgradeAndReboot.
        Will sys.exit on success!
        """

        #
        # The server specifies a ZIP archive with the new scripts. It's ASSUMED
        # that the zip is of selected files at g_ksValidationKitDir in SVN.  It's
        # further ASSUMED that we're executing from
        #
        sZipUrl = oResponse.getStringChecked(
            constants.tbresp.UPGRADE_PARAM_URL)
        oResponse.checkParameterCount(2)

        if utils.isRunningFromCheckout():
            raise TestBoxException(
                'Cannot upgrade when running from the tree!')
        oConnection.sendAckAndClose(constants.tbresp.CMD_UPGRADE_AND_REBOOT if
                                    fReboot else constants.tbresp.CMD_UPGRADE)

        testboxcommons.log('Upgrading...')

        #
        # Download the file and install it.
        #
        sDstFile = os.path.join(g_ksTestScriptDir, 'VBoxTestBoxScript.zip')
        if os.path.exists(sDstFile):
            os.unlink(sDstFile)
        fRc = webutils.downloadFile(sZipUrl, sDstFile,
                                    self._oTestBoxScript.getPathBuilds(),
                                    testboxcommons.log)
        if fRc is not True:
            return False

        if upgradeFromZip(sDstFile) is not True:
            return False

        #
        # Restart the system or the script (we have a parent script which
        # respawns us when we quit).
        #
        if fReboot:
            self.doReboot()
        sys.exit(TBS_EXITCODE_NEED_UPGRADE)
        return False
コード例 #18
0
    def dispatch(self):
        """
        Receive orders from Test Manager and execute them
        """

        (self._idTestBox, self._sTestBoxName, self._fSignedOn) = self._oCommand.resumeIncompleteCommand();
        self._fNeedReSignOn = self._fSignedOn;
        if self._fSignedOn:
            os.environ['TESTBOX_ID']   = str(self._idTestBox);
            os.environ['TESTBOX_NAME'] = self._sTestBoxName;

        while True:
            # Make sure we're signed on before trying to do anything.
            self._maybeSignOn();
            while not self._fSignedOn:
                iFactor = 1 if self._cSignOnAttempts < 100 else 4;
                time.sleep(random.randint(self.kcSecMinSignOnDelay * iFactor, self.kcSecMaxSignOnDelay * iFactor));
                self._maybeSignOn();

            # Retrieve and handle command from the TM.
            (oResponse, oConnection) = TestBoxConnection.requestCommandWithConnection(self._oOptions.sTestManagerUrl,
                                                                                      self._idTestBox,
                                                                                      self._sTestBoxUuid,
                                                                                      self._oCommand.isRunning());
            if oResponse is not None:
                self._oCommand.handleCommand(oResponse, oConnection);
            if oConnection is not None:
                if oConnection.isConnected():
                    self._oCommand.flushLogOnConnection(oConnection);
                oConnection.close();

            # Automatically reboot if scratch init fails.
            if self._cReinitScratchErrors > 8 and self.reinitScratch() is False:
                testboxcommons.log('Scratch does not initialize cleanly after %d attempts, rebooting...'
                                   % ( self._cReinitScratchErrors, ));
                self._oCommand.doReboot();

            # delay a wee bit before looping.
            ## @todo We shouldn't bother the server too frequently.  We should try combine the test reporting done elsewhere
            # with the command retrieval done here.  I believe tinderclient.pl is capable of doing that.
            iFactor = 1;
            if self._cReinitScratchErrors > 0:
                iFactor = 4;
            time.sleep(random.randint(self.kcSecMinDelay * iFactor, self.kcSecMaxDelay * iFactor));
コード例 #19
0
    def _doSignOn(self):
        """
        Worker for _maybeSignOn that does the actual signing on.
        """
        assert not self._oCommand.isRunning();

        # Reset the siged-on state.
        testboxcommons.log('Signing-on...')
        self._fSignedOn = False
        self._idTestBox = None
        self._cSignOnAttempts += 1;

        # Assemble SIGN-ON request parameters and send the request.
        dParams = {};
        for sParam in self._ddSignOnParams:
            dParams[sParam] = self._ddSignOnParams[sParam][self.VALUE];
        oResponse = TestBoxConnection.sendSignOn(self._oOptions.sTestManagerUrl, dParams);

        # Check response.
        try:
            sResult = oResponse.getStringChecked(constants.tbresp.ALL_PARAM_RESULT);
            if sResult != constants.tbresp.STATUS_ACK:
                raise TestBoxException('Result is %s' % (sResult,));
            oResponse.checkParameterCount(3);
            idTestBox    = oResponse.getIntChecked(constants.tbresp.SIGNON_PARAM_ID, 1, 0x7ffffffe);
            sTestBoxName = oResponse.getStringChecked(constants.tbresp.SIGNON_PARAM_NAME);
        except TestBoxException as err:
            testboxcommons.log('Failed to sign-on: %s' % (str(err),))
            testboxcommons.log('Server response: %s' % (oResponse.toString(),));
            return False;

        # Successfully signed on, update the state.
        self._fSignedOn       = True;
        self._fNeedReSignOn   = False;
        self._cSignOnAttempts = 0;
        self._idTestBox       = idTestBox;
        self._sTestBoxName    = sTestBoxName;

        # Update the environment.
        os.environ['TESTBOX_ID']            = str(self._idTestBox);
        os.environ['TESTBOX_NAME']          = sTestBoxName;
        os.environ['TESTBOX_CPU_COUNT']     = self.getSignOnParam(constants.tbreq.SIGNON_PARAM_CPU_COUNT);
        os.environ['TESTBOX_MEM_SIZE']      = self.getSignOnParam(constants.tbreq.SIGNON_PARAM_MEM_SIZE);
        os.environ['TESTBOX_SCRATCH_SIZE']  = self.getSignOnParam(constants.tbreq.SIGNON_PARAM_SCRATCH_SIZE);

        testboxcommons.log('Successfully signed-on with Test Box ID #%s and given the name "%s"' \
                           % (self._idTestBox, self._sTestBoxName));

        # Set up the scratch area.
        self.reinitScratch(fUseTheForce = self._fFirstSignOn, cRetries = 2);

        self._fFirstSignOn = False;
        return True;
コード例 #20
0
def _doUpgradeRemoveOldStuff(sUpgradeDir, asMembers):
    """
    Clean up all obsolete files and directories.
    Returns True (shouldn't fail or raise any exceptions).
    """

    try:
        shutil.rmtree(sUpgradeDir, ignore_errors = True);
    except:
        pass;

    asKnownFiles = [];
    asKnownDirs  = [];
    for sMember in asMembers:
        sMember = sMember[len('testboxscript/'):];
        if sMember == '':
            continue;
        if sMember[-1] == '/':
            asKnownDirs.append(os.path.normpath(os.path.join(g_ksValidationKitDir, sMember[:-1])));
        else:
            asKnownFiles.append(os.path.normpath(os.path.join(g_ksValidationKitDir, sMember)));

    for sDirPath, asDirs, asFiles in os.walk(g_ksValidationKitDir, topdown=False):
        for sDir in asDirs:
            sFull = os.path.normpath(os.path.join(sDirPath, sDir));
            if sFull not in asKnownDirs:
                testboxcommons.log2('Info: Removing obsolete directory "%s"' % (sFull,));
                try:
                    os.rmdir(sFull);
                except Exception as oXcpt:
                    testboxcommons.log('Warning: failed to rmdir obsolete dir "%s": %s' % (sFull, oXcpt));

        for sFile in asFiles:
            sFull = os.path.normpath(os.path.join(sDirPath, sFile));
            if sFull not in asKnownFiles:
                testboxcommons.log2('Info: Removing obsolete file "%s"' % (sFull,));
                try:
                    os.unlink(sFull);
                except Exception as oXcpt:
                    testboxcommons.log('Warning: failed to unlink obsolete file "%s": %s' % (sFull, oXcpt));
    return True;
コード例 #21
0
    def handleCommand(self, oResponse, oConnection):
        """
        Handles a command from the test manager.

        Some commands will close the connection, others (generally the simple
        ones) wont, leaving the caller the option to use it for log flushing.

        Returns success indicator.
        Raises no exception.
        """
        try:
            sCmdName = oResponse.getStringChecked(constants.tbresp.ALL_PARAM_RESULT);
        except Exception as oXcpt:
            oConnection.close();
            return False;

        # Do we know the command?
        fRc = False;
        if sCmdName in self._dfnCommands:
            testboxcommons.log(sCmdName);
            try:
                # Execute the handler.
                fRc = self._dfnCommands[sCmdName](oResponse, oConnection)
            except Exception as oXcpt:
                # NACK the command if an exception is raised during parameter validation.
                testboxcommons.log1Xcpt('Exception executing "%s": %s' % (sCmdName, oXcpt));
                if oConnection.isConnected():
                    try:
                        oConnection.sendReplyAndClose(constants.tbreq.COMMAND_NACK, sCmdName);
                    except Exception as oXcpt2:
                        testboxcommons.log('Failed to NACK "%s": %s' % (sCmdName, oXcpt2));
        elif sCmdName in [constants.tbresp.STATUS_DEAD, constants.tbresp.STATUS_NACK]:
            testboxcommons.log('Received status instead of command: %s' % (sCmdName, ));
        else:
            # NOTSUP the unknown command.
            testboxcommons.log('Received unknown command: %s' % (sCmdName, ));
            try:
                oConnection.sendReplyAndClose(constants.tbreq.COMMAND_NOTSUP, sCmdName);
            except Exception as oXcpt:
                testboxcommons.log('Failed to NOTSUP "%s": %s' % (sCmdName, oXcpt));
        return fRc;
コード例 #22
0
    def _doUpgrade(self, oResponse, oConnection, fReboot):
        """
        Common worker for _cmdUpgrade and _cmdUpgradeAndReboot.
        Will sys.exit on success!
        """

        #
        # The server specifies a ZIP archive with the new scripts. It's ASSUMED
        # that the zip is of selected files at g_ksValidationKitDir in SVN.  It's
        # further ASSUMED that we're executing from
        #
        sZipUrl = oResponse.getStringChecked(constants.tbresp.UPGRADE_PARAM_URL)
        oResponse.checkParameterCount(2);

        if utils.isRunningFromCheckout():
            raise TestBoxException('Cannot upgrade when running from the tree!');
        oConnection.sendAckAndClose(constants.tbresp.CMD_UPGRADE_AND_REBOOT if fReboot else constants.tbresp.CMD_UPGRADE);

        testboxcommons.log('Upgrading...');

        #
        # Download the file and install it.
        #
        sDstFile = os.path.join(g_ksTestScriptDir, 'VBoxTestBoxScript.zip');
        if os.path.exists(sDstFile):
            os.unlink(sDstFile);
        fRc = webutils.downloadFile(sZipUrl, sDstFile, self._oTestBoxScript.getPathBuilds(), testboxcommons.log);
        if fRc is not True:
            return False;

        if upgradeFromZip(sDstFile) is not True:
            return False;

        #
        # Restart the system or the script (we have a parent script which
        # respawns us when we quit).
        #
        if fReboot:
            self.doReboot();
        sys.exit(TBS_EXITCODE_NEED_UPGRADE);
        return False;                   # shuts up pylint (it will probably complain later when it learns DECL_NO_RETURN).
コード例 #23
0
def _doUpgradeTestRun(sUpgradeDir):
    """
    Do a testrun of the new script, to make sure it doesn't fail with
    to run in any way because of old python, missing import or generally
    busted upgrade.
    Returns True/False.
    """
    asArgs = [os.path.join(sUpgradeDir, "testboxscript", "testboxscript", "testboxscript.py"), "--version"]
    testboxcommons.log("Testing the new testbox script (%s)..." % (asArgs[0],))
    if sys.executable is not None and len(sys.executable) > 0:
        asArgs.insert(0, sys.executable)
    oChild = subprocess.Popen(asArgs, shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

    asBuf = []
    oThread = threading.Thread(target=_doUpgradeThreadProc, args=(oChild.stdout, asBuf))
    oThread.daemon = True
    oThread.start()
    oThread.join(30)

    iStatus = oChild.poll()
    if iStatus is None:
        testboxcommons.log("Checking the new testboxscript timed out.")
        oChild.terminate()
        oThread.join(5)
        return False
    if iStatus is not TBS_EXITCODE_SYNTAX:
        testboxcommons.log(
            "The new testboxscript returned %d instead of %d during check." % (iStatus, TBS_EXITCODE_SYNTAX)
        )
        return False

    sOutput = "".join(asBuf)
    sOutput = sOutput.strip()
    try:
        iNewVersion = int(sOutput)
    except:
        testboxcommons.log('The new testboxscript returned an unparseable version string: "%s"!' % (sOutput,))
        return False
    testboxcommons.log("New script version: %s" % (iNewVersion,))
    return True
コード例 #24
0
    def doReboot(self):
        """
        Worker common to _cmdReboot and _doUpgrade that performs a system reboot.
        """
        # !! Not more exceptions beyond this point !!
        testboxcommons.log('Rebooting')

        # Stop anything that might be executing at this point.
        oCurTask = self._getCurTask()
        if oCurTask is not None:
            oCurTask.terminate()
            oCurTask.wait(self.kcSecStopBeforeRebootTimeout)

        # Invoke shutdown command line utility.
        sOs = utils.getHostOs()
        asCmd2 = None
        if sOs == 'win':
            asCmd = [
                'shutdown', '/r', '/t', '0', '/c',
                '"ValidationKit triggered reboot"', '/d', '4:1'
            ]
        elif sOs == 'os2':
            asCmd = ['setboot', '/B']
        elif sOs in ('solaris', ):
            asCmd = ['/usr/sbin/reboot', '-p']
            asCmd2 = ['/usr/sbin/reboot']
            # Hack! S10 doesn't have -p, but don't know how to reliably detect S10.
        else:
            asCmd = ['/sbin/shutdown', '-r', 'now']
        try:
            utils.sudoProcessOutputChecked(asCmd)
        except Exception, oXcpt:
            if asCmd2 is not None:
                try:
                    utils.sudoProcessOutputChecked(asCmd2)
                except Exception, oXcpt:
                    testboxcommons.log(
                        'Error executing reboot command "%s" as well as "%s": %s'
                        % (asCmd, asCmd2, oXcpt))
                    return False
コード例 #25
0
def _doUpgradeCheckZip(oZip):
    """
    Check that the essential files are there.
    Returns list of members on success, None on failure.
    """
    asMembers = oZip.namelist()
    if   ('testboxscript/testboxscript/testboxscript.py'      not in asMembers) \
      or ('testboxscript/testboxscript/testboxscript_real.py' not in asMembers):
        testboxcommons.log('Missing one or both testboxscripts (members: %s)' %
                           (asMembers, ))
        return None

    for sMember in asMembers:
        if not sMember.startswith('testboxscript/'):
            testboxcommons.log(
                'zip file contains member outside testboxscript/: "%s"' %
                (sMember, ))
            return None
        if sMember.find('/../') > 0 or sMember.endswith('/..'):
            testboxcommons.log(
                'zip file contains member with escape sequence: "%s"' %
                (sMember, ))
            return None

    return asMembers
コード例 #26
0
    def _doSignOn(self):
        """
        Worker for _maybeSignOn that does the actual signing on.
        """
        assert not self._oCommand.isRunning();

        # Reset the siged-on state.
        testboxcommons.log('Signing-on...')
        self._fSignedOn = False
        self._idTestBox = None
        self._cSignOnAttempts += 1;

        # Assemble SIGN-ON request parameters and send the request.
        dParams = {};
        for sParam in self._ddSignOnParams:
            dParams[sParam] = self._ddSignOnParams[sParam][self.VALUE];
        oResponse = TestBoxConnection.sendSignOn(self._oOptions.sTestManagerUrl, dParams);

        # Check response.
        try:
            sResult = oResponse.getStringChecked(constants.tbresp.ALL_PARAM_RESULT);
            if sResult != constants.tbresp.STATUS_ACK:
                raise TestBoxException('Result is %s' % (sResult,));
            oResponse.checkParameterCount(3);
            idTestBox    = oResponse.getIntChecked(constants.tbresp.SIGNON_PARAM_ID, 1, 0x7ffffffe);
            sTestBoxName = oResponse.getStringChecked(constants.tbresp.SIGNON_PARAM_NAME);
        except TestBoxException, err:
            testboxcommons.log('Failed to sign-on: %s' % (str(err),))
            testboxcommons.log('Server response: %s' % (oResponse.toString(),));
            return False;
コード例 #27
0
    def _doSignOn(self):
        """
        Worker for _maybeSignOn that does the actual signing on.
        """
        assert not self._oCommand.isRunning();

        # Reset the siged-on state.
        testboxcommons.log('Signing-on...')
        self._fSignedOn = False
        self._idTestBox = None
        self._cSignOnAttempts += 1;

        # Assemble SIGN-ON request parameters and send the request.
        dParams = {};
        for sParam in self._ddSignOnParams:
            dParams[sParam] = self._ddSignOnParams[sParam][self.VALUE];
        oResponse = TestBoxConnection.sendSignOn(self._oOptions.sTestManagerUrl, dParams);

        # Check response.
        try:
            sResult = oResponse.getStringChecked(constants.tbresp.ALL_PARAM_RESULT);
            if sResult != constants.tbresp.STATUS_ACK:
                raise TestBoxException('Result is %s' % (sResult,));
            oResponse.checkParameterCount(3);
            idTestBox    = oResponse.getIntChecked(constants.tbresp.SIGNON_PARAM_ID, 1, 0x7ffffffe);
            sTestBoxName = oResponse.getStringChecked(constants.tbresp.SIGNON_PARAM_NAME);
        except TestBoxException, err:
            testboxcommons.log('Failed to sign-on: %s' % (str(err),))
            testboxcommons.log('Server response: %s' % (oResponse.toString(),));
            return False;
コード例 #28
0
def _doUpgradeTestRun(sUpgradeDir):
    """
    Do a testrun of the new script, to make sure it doesn't fail with
    to run in any way because of old python, missing import or generally
    busted upgrade.
    Returns True/False.
    """
    asArgs = [os.path.join(sUpgradeDir, 'testboxscript', 'testboxscript', 'testboxscript.py'), '--version' ];
    testboxcommons.log('Testing the new testbox script (%s)...' % (asArgs[0],));
    if sys.executable:
        asArgs.insert(0, sys.executable);
    oChild = subprocess.Popen(asArgs, shell = False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT);

    asBuf = []
    oThread = threading.Thread(target=_doUpgradeThreadProc, args=(oChild.stdout, asBuf));
    oThread.daemon = True;
    oThread.start();
    oThread.join(30);

    iStatus = oChild.poll();
    if iStatus is None:
        testboxcommons.log('Checking the new testboxscript timed out.');
        oChild.terminate();
        oThread.join(5);
        return False;
    if iStatus is not TBS_EXITCODE_SYNTAX:
        testboxcommons.log('The new testboxscript returned %d instead of %d during check.' \
                           % (iStatus, TBS_EXITCODE_SYNTAX));
        return False;

    sOutput = ''.join(asBuf);
    sOutput = sOutput.strip();
    try:
        iNewVersion = int(sOutput);
    except:
        testboxcommons.log('The new testboxscript returned an unparseable version string: "%s"!' % (sOutput,));
        return False;
    testboxcommons.log('New script version: %s' % (iNewVersion,));
    return True;
コード例 #29
0
def upgradeFromZip(sZipFile):
    """
    Upgrade the testboxscript install using the specified zip file.
    Returns True/False.
    """

    # A little precaution.
    if utils.isRunningFromCheckout():
        testboxcommons.log('Use "svn up" to "upgrade" your source tree!')
        return False

    #
    # Prepare.
    #
    # Note! Don't bother cleaning up files and dirs in the error paths,
    #       they'll be restricted to the one zip and the one upgrade dir.
    #       We'll remove them next time we upgrade.
    #
    oZip = zipfile.ZipFile(sZipFile, 'r')
    asMembers = _doUpgradeCheckZip(oZip)
    if asMembers is None:
        return False

    sUpgradeDir = os.path.join(g_ksTestScriptDir, 'upgrade')
    testboxcommons.log('Unzipping "%s" to "%s"...' % (sZipFile, sUpgradeDir))
    if _doUpgradeUnzipAndCheck(oZip, sUpgradeDir, asMembers) is not True:
        return False
    oZip.close()

    if _doUpgradeTestRun(sUpgradeDir) is not True:
        return False

    #
    # Execute.
    #
    if _doUpgradeApply(sUpgradeDir, asMembers) is not True:
        return False
    _doUpgradeRemoveOldStuff(sUpgradeDir, asMembers)
    return True
コード例 #30
0
def upgradeFromZip(sZipFile):
    """
    Upgrade the testboxscript install using the specified zip file.
    Returns True/False.
    """

    # A little precaution.
    if utils.isRunningFromCheckout():
        testboxcommons.log('Use "svn up" to "upgrade" your source tree!')
        return False

    #
    # Prepare.
    #
    # Note! Don't bother cleaning up files and dirs in the error paths,
    #       they'll be restricted to the one zip and the one upgrade dir.
    #       We'll remove them next time we upgrade.
    #
    oZip = zipfile.ZipFile(sZipFile, "r")
    asMembers = _doUpgradeCheckZip(oZip)
    if asMembers is None:
        return False

    sUpgradeDir = os.path.join(g_ksTestScriptDir, "upgrade")
    testboxcommons.log('Unzipping "%s" to "%s"...' % (sZipFile, sUpgradeDir))
    if _doUpgradeUnzipAndCheck(oZip, sUpgradeDir, asMembers) is not True:
        return False
    oZip.close()

    if _doUpgradeTestRun(sUpgradeDir) is not True:
        return False

    #
    # Execute.
    #
    if _doUpgradeApply(sUpgradeDir, asMembers) is not True:
        return False
    _doUpgradeRemoveOldStuff(sUpgradeDir, asMembers)
    return True
コード例 #31
0
def _doUpgradeApply(sUpgradeDir, asMembers):
    """
    # Apply the directories and files from the upgrade.
    returns True/False/Exception.
    """

    #
    # Create directories first since that's least intrusive.
    #
    for sMember in asMembers:
        if sMember[-1] == '/':
            sMember = sMember[len('testboxscript/'):]
            if sMember != '':
                sFull = os.path.join(g_ksValidationKitDir, sMember)
                if not os.path.isdir(sFull):
                    os.makedirs(sFull, 0755)

    #
    # Move the files into place.
    #
    fRc = True
    asOldFiles = []
    for sMember in asMembers:
        if sMember[-1] != '/':
            sSrc = os.path.join(sUpgradeDir, sMember)
            sDst = os.path.join(g_ksValidationKitDir,
                                sMember[len('testboxscript/'):])

            # Move the old file out of the way first.
            sDstRm = None
            if os.path.exists(sDst):
                testboxcommons.log2('Info: Installing "%s"' % (sDst, ))
                sDstRm = '%s-delete-me-%s' % (
                    sDst,
                    uuid.uuid4(),
                )
                try:
                    os.rename(sDst, sDstRm)
                except Exception, oXcpt:
                    testboxcommons.log(
                        'Error: failed to rename (old) "%s" to "%s": %s' %
                        (sDst, sDstRm, oXcpt))
                    try:
                        shutil.copy(sDst, sDstRm)
                    except Exception, oXcpt:
                        testboxcommons.log(
                            'Error: failed to copy (old) "%s" to "%s": %s' %
                            (sDst, sDstRm, oXcpt))
                        break
                    try:
                        os.unlink(sDst)
                    except Exception, oXcpt:
                        testboxcommons.log(
                            'Error: failed to unlink (old) "%s": %s' %
                            (sDst, oXcpt))
                        break
コード例 #32
0
def _doUpgradeApply(sUpgradeDir, asMembers):
    """
    # Apply the directories and files from the upgrade.
    returns True/False/Exception.
    """

    #
    # Create directories first since that's least intrusive.
    #
    for sMember in asMembers:
        if sMember[-1] == "/":
            sMember = sMember[len("testboxscript/") :]
            if sMember != "":
                sFull = os.path.join(g_ksValidationKitDir, sMember)
                if not os.path.isdir(sFull):
                    os.makedirs(sFull, 0755)

    #
    # Move the files into place.
    #
    fRc = True
    asOldFiles = []
    for sMember in asMembers:
        if sMember[-1] != "/":
            sSrc = os.path.join(sUpgradeDir, sMember)
            sDst = os.path.join(g_ksValidationKitDir, sMember[len("testboxscript/") :])

            # Move the old file out of the way first.
            sDstRm = None
            if os.path.exists(sDst):
                testboxcommons.log2('Info: Installing "%s"' % (sDst,))
                sDstRm = "%s-delete-me-%s" % (sDst, uuid.uuid4())
                try:
                    os.rename(sDst, sDstRm)
                except Exception, oXcpt:
                    testboxcommons.log('Error: failed to rename (old) "%s" to "%s": %s' % (sDst, sDstRm, oXcpt))
                    try:
                        shutil.copy(sDst, sDstRm)
                    except Exception, oXcpt:
                        testboxcommons.log('Error: failed to copy (old) "%s" to "%s": %s' % (sDst, sDstRm, oXcpt))
                        break
                    try:
                        os.unlink(sDst)
                    except Exception, oXcpt:
                        testboxcommons.log('Error: failed to unlink (old) "%s": %s' % (sDst, oXcpt))
                        break
コード例 #33
0
ファイル: testboxupgrade.py プロジェクト: mcenirm/vbox
def _doUpgradeCheckZip(oZip):
    """
    Check that the essential files are there.
    Returns list of members on success, None on failure.
    """
    asMembers = oZip.namelist();
    if   ('testboxscript/testboxscript/testboxscript.py'      not in asMembers) \
      or ('testboxscript/testboxscript/testboxscript_real.py' not in asMembers):
        testboxcommons.log('Missing one or both testboxscripts (members: %s)' % (asMembers,));
        return None;

    for sMember in asMembers:
        if not sMember.startswith('testboxscript/'):
            testboxcommons.log('zip file contains member outside testboxscript/: "%s"' % (sMember,));
            return None;
        if sMember.find('/../') > 0 or sMember.endswith('/..'):
            testboxcommons.log('zip file contains member with escape sequence: "%s"' % (sMember,));
            return None;

    return asMembers;
コード例 #34
0
def _doUpgradeUnzipAndCheck(oZip, sUpgradeDir, asMembers):
    """
    Unzips the files into sUpdateDir, does chmod(755) on all files and
    checks that there are no symlinks or special files.
    Returns True/False.
    """
    #
    # Extract the files.
    #
    if os.path.exists(sUpgradeDir):
        shutil.rmtree(sUpgradeDir)
    for sMember in asMembers:
        if sMember.endswith('/'):
            os.makedirs(
                os.path.join(sUpgradeDir, sMember.replace('/', os.path.sep)),
                0o775)
        else:
            oZip.extract(sMember, sUpgradeDir)

    #
    # Make all files executable and make sure only owner can write to them.
    # While at it, also check that there are only files and directory, no
    # symbolic links or special stuff.
    #
    for sMember in asMembers:
        sFull = os.path.join(sUpgradeDir, sMember)
        if sMember.endswith('/'):
            if not os.path.isdir(sFull):
                testboxcommons.log('Not directory: "%s"' % sFull)
                return False
        else:
            if not os.path.isfile(sFull):
                testboxcommons.log('Not regular file: "%s"' % sFull)
                return False
            try:
                os.chmod(sFull, 0o755)
            except Exception as oXcpt:
                testboxcommons.log('warning chmod error on %s: %s' %
                                   (sFull, oXcpt))
    return True
コード例 #35
0
def _doUpgradeUnzipAndCheck(oZip, sUpgradeDir, asMembers):
    """
    Unzips the files into sUpdateDir, does chmod(755) on all files and
    checks that there are no symlinks or special files.
    Returns True/False.
    """
    #
    # Extract the files.
    #
    if os.path.exists(sUpgradeDir):
        shutil.rmtree(sUpgradeDir);
    for sMember in asMembers:
        if sMember.endswith('/'):
            os.makedirs(os.path.join(sUpgradeDir, sMember.replace('/', os.path.sep)), 0o775);
        else:
            oZip.extract(sMember, sUpgradeDir);

    #
    # Make all files executable and make sure only owner can write to them.
    # While at it, also check that there are only files and directory, no
    # symbolic links or special stuff.
    #
    for sMember in asMembers:
        sFull = os.path.join(sUpgradeDir, sMember);
        if sMember.endswith('/'):
            if not os.path.isdir(sFull):
                testboxcommons.log('Not directory: "%s"' % sFull);
                return False;
        else:
            if not os.path.isfile(sFull):
                testboxcommons.log('Not regular file: "%s"' % sFull);
                return False;
            try:
                os.chmod(sFull, 0o755);
            except Exception as oXcpt:
                testboxcommons.log('warning chmod error on %s: %s' % (sFull, oXcpt));
    return True;
コード例 #36
0
                        break
                    try:
                        os.unlink(sDst)
                    except Exception, oXcpt:
                        testboxcommons.log(
                            'Error: failed to unlink (old) "%s": %s' %
                            (sDst, oXcpt))
                        break

            # Move/copy the new one into place.
            testboxcommons.log2('Info: Installing "%s"' % (sDst, ))
            try:
                os.rename(sSrc, sDst)
            except Exception, oXcpt:
                testboxcommons.log(
                    'Warning: failed to rename (new) "%s" to "%s": %s' %
                    (sSrc, sDst, oXcpt))
                try:
                    shutil.copy(sSrc, sDst)
                except:
                    testboxcommons.log(
                        'Error: failed to copy (new) "%s" to "%s": %s' %
                        (sSrc, sDst, oXcpt))
                    fRc = False
                    break

    #
    # Roll back on failure.
    #
    if fRc is not True:
        testboxcommons.log('Attempting to roll back old files...')
コード例 #37
0
    def __init__(self, oOptions):
        """
        Initialize internals
        """
        self._oOptions        = oOptions;
        self._sTestBoxHelper  = None;

        # Signed-on state
        self._cSignOnAttempts = 0;
        self._fSignedOn       = False;
        self._fNeedReSignOn   = False;
        self._fFirstSignOn    = True;
        self._idTestBox       = None;
        self._sTestBoxName    = '';
        self._sTestBoxUuid    = self.ksNullUuid; # convenience, assigned below.

        # Command processor.
        self._oCommand = TestBoxCommand(self);

        #
        # Scratch dir setup.  Use /var/tmp instead of /tmp because we may need
        # many many GBs for some test scenarios and /tmp can be backed by swap
        # or be a fast+small disk of some kind, while /var/tmp is normally
        # larger, if slower.  /var/tmp is generally not cleaned up on reboot,
        # /tmp often is, this would break host panic / triple-fault detection.
        #
        if self._oOptions.sScratchRoot is None:
            if utils.getHostOs() in ('win', 'os2', 'haiku', 'dos'):
                # We need *lots* of space, so avoid /tmp as it may be a memory
                # file system backed by the swap file, or worse.
                self._oOptions.sScratchRoot = tempfile.gettempdir();
            else:
                self._oOptions.sScratchRoot = '/var/tmp';
            sSubDir = 'testbox';
            try:
                sSubDir = '%s-%u' % (sSubDir, os.getuid()); # pylint: disable=E1101
            except:
                pass;
            self._oOptions.sScratchRoot = os.path.join(self._oOptions.sScratchRoot, sSubDir);

        self._sScratchSpill   = os.path.join(self._oOptions.sScratchRoot, 'scratch');
        self._sScratchScripts = os.path.join(self._oOptions.sScratchRoot, 'scripts');
        self._sScratchState   = os.path.join(self._oOptions.sScratchRoot, 'state');   # persistant storage.

        for sDir in [self._oOptions.sScratchRoot, self._sScratchSpill, self._sScratchScripts, self._sScratchState]:
            if not os.path.isdir(sDir):
                os.makedirs(sDir, 0700);

        # We count consecutive reinitScratch failures and will reboot the
        # testbox after a while in the hope that it will correct the issue.
        self._cReinitScratchErrors = 0;

        #
        # Mount builds and test resources if requested.
        #
        self.mountShares();

        #
        # Sign-on parameters: Packed into list of records of format:
        # { <Parameter ID>: { <Current value>, <Check function> } }
        #
        self._ddSignOnParams = \
        {
            constants.tbreq.ALL_PARAM_TESTBOX_UUID:        { self.VALUE: self._getHostSystemUuid(),    self.FN: None },
            constants.tbreq.SIGNON_PARAM_OS:               { self.VALUE: utils.getHostOs(),            self.FN: None },
            constants.tbreq.SIGNON_PARAM_OS_VERSION:       { self.VALUE: utils.getHostOsVersion(),     self.FN: None },
            constants.tbreq.SIGNON_PARAM_CPU_ARCH:         { self.VALUE: utils.getHostArch(),          self.FN: None },
            constants.tbreq.SIGNON_PARAM_CPU_VENDOR:       { self.VALUE: self._getHostCpuVendor(),     self.FN: None },
            constants.tbreq.SIGNON_PARAM_CPU_NAME:         { self.VALUE: self._getHostCpuName(),       self.FN: None },
            constants.tbreq.SIGNON_PARAM_CPU_REVISION:     { self.VALUE: self._getHostCpuRevision(),   self.FN: None },
            constants.tbreq.SIGNON_PARAM_HAS_HW_VIRT:      { self.VALUE: self._hasHostHwVirt(),        self.FN: None },
            constants.tbreq.SIGNON_PARAM_HAS_NESTED_PAGING:{ self.VALUE: self._hasHostNestedPaging(),  self.FN: None },
            constants.tbreq.SIGNON_PARAM_HAS_64_BIT_GUEST: { self.VALUE: self._can64BitGuest(),        self.FN: None },
            constants.tbreq.SIGNON_PARAM_HAS_IOMMU:        { self.VALUE: self._hasHostIoMmu(),         self.FN: None },
            #constants.tbreq.SIGNON_PARAM_WITH_RAW_MODE:    { self.VALUE: self._withRawModeSupport(),   self.FN: None },
            constants.tbreq.SIGNON_PARAM_SCRIPT_REV:       { self.VALUE: self._getScriptRev(),         self.FN: None },
            constants.tbreq.SIGNON_PARAM_REPORT:           { self.VALUE: self._getHostReport(),        self.FN: None },
            constants.tbreq.SIGNON_PARAM_PYTHON_VERSION:   { self.VALUE: self._getPythonHexVersion(),  self.FN: None },
            constants.tbreq.SIGNON_PARAM_CPU_COUNT:        { self.VALUE: None,     self.FN: multiprocessing.cpu_count },
            constants.tbreq.SIGNON_PARAM_MEM_SIZE:         { self.VALUE: None,     self.FN: self._getHostMemSize },
            constants.tbreq.SIGNON_PARAM_SCRATCH_SIZE:     { self.VALUE: None,     self.FN: self._getFreeScratchSpace },
        }
        for sItem in self._ddSignOnParams:
            if self._ddSignOnParams[sItem][self.FN] is not None:
                self._ddSignOnParams[sItem][self.VALUE] = self._ddSignOnParams[sItem][self.FN]()

        testboxcommons.log('Starting Test Box script (%s)' % __version__)
        testboxcommons.log('Test Manager URL: %s' % self._oOptions.sTestManagerUrl,)
        testboxcommons.log('Scratch root path: %s' % self._oOptions.sScratchRoot,)
        for sItem in self._ddSignOnParams:
            testboxcommons.log('Sign-On value %18s: %s' % (sItem, self._ddSignOnParams[sItem][self.VALUE]));

        #
        # The System UUID is the primary identification of the machine, so
        # refuse to cooperate if it's NULL.
        #
        self._sTestBoxUuid = self.getSignOnParam(constants.tbreq.ALL_PARAM_TESTBOX_UUID);
        if self._sTestBoxUuid == self.ksNullUuid:
            raise TestBoxScriptException('Couldn\'t determine the System UUID, please use --system-uuid to specify it.');

        #
        # Export environment variables, clearing any we don't know yet.
        #
        for sEnvVar in self._oOptions.asEnvVars:
            iEqual = sEnvVar.find('=');
            if iEqual == -1:    # No '=', remove it.
                if sEnvVar in os.environ:
                    del os.environ[sEnvVar];
            elif iEqual > 0:    # Set it.
                os.environ[sEnvVar[:iEqual]] = sEnvVar[iEqual+1:];
            else:               # Starts with '=', bad user.
                raise TestBoxScriptException('Invalid -E argument: "%s"' % (sEnvVar,));

        os.environ['TESTBOX_PATH_BUILDS']       = self._oOptions.sBuildsPath;
        os.environ['TESTBOX_PATH_RESOURCES']    = self._oOptions.sTestRsrcPath;
        os.environ['TESTBOX_PATH_SCRATCH']      = self._sScratchSpill;
        os.environ['TESTBOX_PATH_SCRIPTS']      = self._sScratchScripts;
        os.environ['TESTBOX_PATH_UPLOAD']       = self._sScratchSpill; ## @todo drop the UPLOAD dir?
        os.environ['TESTBOX_HAS_HW_VIRT']       = self.getSignOnParam(constants.tbreq.SIGNON_PARAM_HAS_HW_VIRT);
        os.environ['TESTBOX_HAS_NESTED_PAGING'] = self.getSignOnParam(constants.tbreq.SIGNON_PARAM_HAS_NESTED_PAGING);
        os.environ['TESTBOX_HAS_IOMMU']         = self.getSignOnParam(constants.tbreq.SIGNON_PARAM_HAS_IOMMU);
        os.environ['TESTBOX_SCRIPT_REV']        = self.getSignOnParam(constants.tbreq.SIGNON_PARAM_SCRIPT_REV);
        os.environ['TESTBOX_CPU_COUNT']         = self.getSignOnParam(constants.tbreq.SIGNON_PARAM_CPU_COUNT);
        os.environ['TESTBOX_MEM_SIZE']          = self.getSignOnParam(constants.tbreq.SIGNON_PARAM_MEM_SIZE);
        os.environ['TESTBOX_SCRATCH_SIZE']      = self.getSignOnParam(constants.tbreq.SIGNON_PARAM_SCRATCH_SIZE);
        #TODO: os.environ['TESTBOX_WITH_RAW_MODE']     = self.getSignOnParam(constants.tbreq.SIGNON_PARAM_WITH_RAW_MODE);
        os.environ['TESTBOX_WITH_RAW_MODE']     = self._withRawModeSupport();
        os.environ['TESTBOX_MANAGER_URL']       = self._oOptions.sTestManagerUrl;
        os.environ['TESTBOX_UUID']              = self._sTestBoxUuid;
        os.environ['TESTBOX_REPORTER']          = 'remote';
        os.environ['TESTBOX_NAME']              = '';
        os.environ['TESTBOX_ID']                = '';
        os.environ['TESTBOX_TEST_SET_ID']       = '';
        os.environ['TESTBOX_TIMEOUT']           = '0';
        os.environ['TESTBOX_TIMEOUT_ABS']       = '0';

        if utils.getHostOs() is 'win':
            os.environ['COMSPEC']            = os.path.join(os.environ['SystemRoot'], 'System32', 'cmd.exe');
コード例 #38
0
                        shutil.copy(sDst, sDstRm)
                    except Exception, oXcpt:
                        testboxcommons.log('Error: failed to copy (old) "%s" to "%s": %s' % (sDst, sDstRm, oXcpt))
                        break
                    try:
                        os.unlink(sDst)
                    except Exception, oXcpt:
                        testboxcommons.log('Error: failed to unlink (old) "%s": %s' % (sDst, oXcpt))
                        break

            # Move/copy the new one into place.
            testboxcommons.log2('Info: Installing "%s"' % (sDst,))
            try:
                os.rename(sSrc, sDst)
            except Exception, oXcpt:
                testboxcommons.log('Warning: failed to rename (new) "%s" to "%s": %s' % (sSrc, sDst, oXcpt))
                try:
                    shutil.copy(sSrc, sDst)
                except:
                    testboxcommons.log('Error: failed to copy (new) "%s" to "%s": %s' % (sSrc, sDst, oXcpt))
                    fRc = False
                    break

    #
    # Roll back on failure.
    #
    if fRc is not True:
        testboxcommons.log("Attempting to roll back old files...")
        for sDstRm in asOldFiles:
            sDst = sDstRm[: sDstRm.rfind("-delete-me")]
            testboxcommons.log2('Info: Rolling back "%s" (%s)' % (sDst, os.path.basename(sDstRm)))
コード例 #39
0
ファイル: testboxtasks.py プロジェクト: mcenirm/vbox
                oNow = datetime.utcnow();
                sTs = '%02u:%02u:%02u.%06u ' % (oNow.hour, oNow.minute, oNow.second, oNow.microsecond);
            except Exception, oXcpt:
                sTs = 'oXcpt=%s ' % (oXcpt);
            sFullMsg = sTs + sMessage;
        else:
            sFullMsg = sMessage;

        self._oBackLogLock.acquire();
        self._asBackLog.append(sFullMsg);
        cchBackLog = self._cchBackLog + len(sFullMsg) + 1;
        self._cchBackLog = cchBackLog;
        secTsBackLogFlush = self._secTsBackLogFlush;
        self._oBackLogLock.release();

        testboxcommons.log(sFullMsg);
        return fFlushCheck \
            and (   cchBackLog >= self.kcchMaxBackLog \
                 or utils.timestampSecond() - secTsBackLogFlush >= self.kcSecBackLogFlush);

    def _log(self, sMessage):
        """
        General logging function, will flush.
        """
        if self._logInternal(sMessage, fFlushCheck = True):
            self._logFlush();
        return True;

    def _reportDone(self, sResult):
        """
        Report EXEC job done to the test manager.
コード例 #40
0
        Some commands will close the connection, others (generally the simple
        ones) wont, leaving the caller the option to use it for log flushing.

        Returns success indicator.
        Raises no exception.
        """
        try:
            sCmdName = oResponse.getStringChecked(constants.tbresp.ALL_PARAM_RESULT);
        except Exception, oXcpt:
            oConnection.close();
            return False;

        # Do we know the command?
        fRc = False;
        if sCmdName in self._dfnCommands:
            testboxcommons.log(sCmdName);
            try:
                # Execute the handler.
                fRc = self._dfnCommands[sCmdName](oResponse, oConnection)
            except Exception, oXcpt:
                # NACK the command if an exception is raised during parameter validation.
                testboxcommons.log1Xcpt('Exception executing "%s": %s' % (sCmdName, oXcpt));
                if oConnection.isConnected():
                    try:
                        oConnection.sendReplyAndClose(constants.tbreq.COMMAND_NACK, sCmdName);
                    except Exception, oXcpt2:
                        testboxcommons.log('Failed to NACK "%s": %s' % (sCmdName, oXcpt2));
        elif sCmdName in [constants.tbresp.STATUS_DEAD, constants.tbresp.STATUS_NACK]:
            testboxcommons.log('Received status in stead of command: %s' % (sCmdName, ));
        else:
            # NOTSUP the unknown command.
コード例 #41
0
        # Successfully signed on, update the state.
        self._fSignedOn       = True;
        self._fNeedReSignOn   = False;
        self._cSignOnAttempts = 0;
        self._idTestBox       = idTestBox;
        self._sTestBoxName    = sTestBoxName;

        # Update the environment.
        os.environ['TESTBOX_ID']            = str(self._idTestBox);
        os.environ['TESTBOX_NAME']          = sTestBoxName;
        os.environ['TESTBOX_CPU_COUNT']     = self.getSignOnParam(constants.tbreq.SIGNON_PARAM_CPU_COUNT);
        os.environ['TESTBOX_MEM_SIZE']      = self.getSignOnParam(constants.tbreq.SIGNON_PARAM_MEM_SIZE);
        os.environ['TESTBOX_SCRATCH_SIZE']  = self.getSignOnParam(constants.tbreq.SIGNON_PARAM_SCRATCH_SIZE);

        testboxcommons.log('Successfully signed-on with Test Box ID #%s and given the name "%s"' \
                           % (self._idTestBox, self._sTestBoxName));

        # Set up the scratch area.
        self.reinitScratch(fUseTheForce = self._fFirstSignOn, cRetries = 2);

        self._fFirstSignOn = False;
        return True;

    def _maybeSignOn(self):
        """
        Check if Test Box parameters were changed
        and do sign-in in case of positive result
        """

        # Skip sign-on check if background command is currently in
        # running state (avoid infinite signing on).
コード例 #42
0
def _doUpgradeApply(sUpgradeDir, asMembers):
    """
    # Apply the directories and files from the upgrade.
    returns True/False/Exception.
    """

    #
    # Create directories first since that's least intrusive.
    #
    for sMember in asMembers:
        if sMember[-1] == '/':
            sMember = sMember[len('testboxscript/'):]
            if sMember != '':
                sFull = os.path.join(g_ksValidationKitDir, sMember)
                if not os.path.isdir(sFull):
                    os.makedirs(sFull, 0o755)

    #
    # Move the files into place.
    #
    fRc = True
    asOldFiles = []
    for sMember in asMembers:
        if sMember[-1] != '/':
            sSrc = os.path.join(sUpgradeDir, sMember)
            sDst = os.path.join(g_ksValidationKitDir,
                                sMember[len('testboxscript/'):])

            # Move the old file out of the way first.
            sDstRm = None
            if os.path.exists(sDst):
                testboxcommons.log2('Info: Installing "%s"' % (sDst, ))
                sDstRm = '%s-delete-me-%s' % (
                    sDst,
                    uuid.uuid4(),
                )
                try:
                    os.rename(sDst, sDstRm)
                except Exception as oXcpt:
                    testboxcommons.log(
                        'Error: failed to rename (old) "%s" to "%s": %s' %
                        (sDst, sDstRm, oXcpt))
                    try:
                        shutil.copy(sDst, sDstRm)
                    except Exception as oXcpt:
                        testboxcommons.log(
                            'Error: failed to copy (old) "%s" to "%s": %s' %
                            (sDst, sDstRm, oXcpt))
                        break
                    try:
                        os.unlink(sDst)
                    except Exception as oXcpt:
                        testboxcommons.log(
                            'Error: failed to unlink (old) "%s": %s' %
                            (sDst, oXcpt))
                        break

            # Move/copy the new one into place.
            testboxcommons.log2('Info: Installing "%s"' % (sDst, ))
            try:
                os.rename(sSrc, sDst)
            except Exception as oXcpt:
                testboxcommons.log(
                    'Warning: failed to rename (new) "%s" to "%s": %s' %
                    (sSrc, sDst, oXcpt))
                try:
                    shutil.copy(sSrc, sDst)
                except:
                    testboxcommons.log(
                        'Error: failed to copy (new) "%s" to "%s": %s' %
                        (sSrc, sDst, oXcpt))
                    fRc = False
                    break

    #
    # Roll back on failure.
    #
    if fRc is not True:
        testboxcommons.log('Attempting to roll back old files...')
        for sDstRm in asOldFiles:
            sDst = sDstRm[:sDstRm.rfind('-delete-me')]
            testboxcommons.log2('Info: Rolling back "%s" (%s)' %
                                (sDst, os.path.basename(sDstRm)))
            try:
                shutil.move(sDstRm, sDst)
            except:
                testboxcommons.log(
                    'Error: failed to rollback "%s" onto "%s": %s' %
                    (sDstRm, sDst, oXcpt))
        return False
    return True
コード例 #43
0
                oNow = datetime.utcnow();
                sTs = '%02u:%02u:%02u.%06u ' % (oNow.hour, oNow.minute, oNow.second, oNow.microsecond);
            except Exception, oXcpt:
                sTs = 'oXcpt=%s ' % (oXcpt);
            sFullMsg = sTs + sMessage;
        else:
            sFullMsg = sMessage;

        self._oBackLogLock.acquire();
        self._asBackLog.append(sFullMsg);
        cchBackLog = self._cchBackLog + len(sFullMsg) + 1;
        self._cchBackLog = cchBackLog;
        secTsBackLogFlush = self._secTsBackLogFlush;
        self._oBackLogLock.release();

        testboxcommons.log(sFullMsg);
        return fFlushCheck \
            and (   cchBackLog >= self.kcchMaxBackLog \
                 or utils.timestampSecond() - secTsBackLogFlush >= self.kcSecBackLogFlush);

    def _log(self, sMessage):
        """
        General logging function, will flush.
        """
        if self._logInternal(sMessage, fFlushCheck = True):
            self._logFlush();
        return True;

    def _reportDone(self, sResult):
        """
        Report EXEC job done to the test manager.
コード例 #44
0
class TestBoxCommand(object):
    """
    Implementation of Test Box command.
    """

    ## The time to wait on the current task to abort.
    kcSecStopTimeout = 360
    ## The time to wait on the current task to abort before rebooting.
    kcSecStopBeforeRebootTimeout = 360

    def __init__(self, oTestBoxScript):
        """
        Class instance init
        """
        self._oTestBoxScript = oTestBoxScript
        self._oCurTaskLock = threading.RLock()
        self._oCurTask = None

        # List of available commands and their handlers
        self._dfnCommands    = \
        {
            constants.tbresp.CMD_IDLE:                 self._cmdIdle,
            constants.tbresp.CMD_WAIT:                 self._cmdWait,
            constants.tbresp.CMD_EXEC:                 self._cmdExec,
            constants.tbresp.CMD_ABORT:                self._cmdAbort,
            constants.tbresp.CMD_REBOOT:               self._cmdReboot,
            constants.tbresp.CMD_UPGRADE:              self._cmdUpgrade,
            constants.tbresp.CMD_UPGRADE_AND_REBOOT:   self._cmdUpgradeAndReboot,
            constants.tbresp.CMD_SPECIAL:              self._cmdSpecial,
        }

    def _cmdIdle(self, oResponse, oConnection):
        """
        Idle response, no ACK.
        """
        oResponse.checkParameterCount(1)

        # The dispatch loop will delay for us, so nothing to do here.
        _ = oConnection
        # Leave the connection open.
        return True

    def _cmdWait(self, oResponse, oConnection):
        """
        Gang scheduling wait response, no ACK.
        """
        oResponse.checkParameterCount(1)

        # The dispatch loop will delay for us, so nothing to do here.
        _ = oConnection
        # Leave the connection open.
        return True

    def _cmdExec(self, oResponse, oConnection):
        """
        Execute incoming command
        """

        # Check if required parameters given and make a little sense.
        idResult = oResponse.getIntChecked(
            constants.tbresp.EXEC_PARAM_RESULT_ID, 1)
        sScriptZips = oResponse.getStringChecked(
            constants.tbresp.EXEC_PARAM_SCRIPT_ZIPS)
        sScriptCmdLine = oResponse.getStringChecked(
            constants.tbresp.EXEC_PARAM_SCRIPT_CMD_LINE)
        cSecTimeout = oResponse.getIntChecked(
            constants.tbresp.EXEC_PARAM_TIMEOUT, 30)
        oResponse.checkParameterCount(5)

        sScriptFile = utils.argsGetFirst(sScriptCmdLine)
        if sScriptFile is None:
            raise TestBoxException('Bad script command line: "%s"' %
                                   (sScriptCmdLine, ))
        if len(os.path.basename(sScriptFile)) < len('t.py'):
            raise TestBoxException('Script file name too short: "%s"' %
                                   (sScriptFile, ))
        if len(sScriptZips) < len('x.zip'):
            raise TestBoxException('Script zip name too short: "%s"' %
                                   (sScriptFile, ))

        # One task at the time.
        if self.isRunning():
            raise TestBoxException('Already running other command')

        # Don't bother running the task without the shares mounted.
        self._oTestBoxScript.mountShares()
        # Raises exception on failure.

        # Kick off the task and ACK the command.
        self._oCurTaskLock.acquire()
        try:
            self._oCurTask = TestBoxExecTask(self._oTestBoxScript,
                                             idResult=idResult,
                                             sScriptZips=sScriptZips,
                                             sScriptCmdLine=sScriptCmdLine,
                                             cSecTimeout=cSecTimeout)
        finally:
            self._oCurTaskLock.release()
        oConnection.sendAckAndClose(constants.tbresp.CMD_EXEC)
        return True

    def _cmdAbort(self, oResponse, oConnection):
        """
        Abort background task
        """
        oResponse.checkParameterCount(1)
        oConnection.sendAck(constants.tbresp.CMD_ABORT)

        oCurTask = self._getCurTask()
        if oCurTask is not None:
            oCurTask.terminate()
            oCurTask.flushLogOnConnection(oConnection)
            oConnection.close()
            oCurTask.wait(self.kcSecStopTimeout)

        return True

    def doReboot(self):
        """
        Worker common to _cmdReboot and _doUpgrade that performs a system reboot.
        """
        # !! Not more exceptions beyond this point !!
        testboxcommons.log('Rebooting')

        # Stop anything that might be executing at this point.
        oCurTask = self._getCurTask()
        if oCurTask is not None:
            oCurTask.terminate()
            oCurTask.wait(self.kcSecStopBeforeRebootTimeout)

        # Invoke shutdown command line utility.
        sOs = utils.getHostOs()
        asCmd2 = None
        if sOs == 'win':
            asCmd = ['shutdown', '/r', '/t', '0']
        elif sOs == 'os2':
            asCmd = ['setboot', '/B']
        elif sOs in ('solaris', ):
            asCmd = ['/usr/sbin/reboot', '-p']
            asCmd2 = ['/usr/sbin/reboot']
            # Hack! S10 doesn't have -p, but don't know how to reliably detect S10.
        else:
            asCmd = ['/sbin/shutdown', '-r', 'now']
        try:
            utils.sudoProcessOutputChecked(asCmd)
        except Exception, oXcpt:
            if asCmd2 is not None:
                try:
                    utils.sudoProcessOutputChecked(asCmd2)
                except Exception, oXcpt:
                    testboxcommons.log(
                        'Error executing reboot command "%s" as well as "%s": %s'
                        % (asCmd, asCmd2, oXcpt))
                    return False
            testboxcommons.log('Error executing reboot command "%s": %s' %
                               (asCmd, oXcpt))
            return False
コード例 #45
0
    def __init__(self, oOptions):
        """
        Initialize internals
        """
        self._oOptions        = oOptions;
        self._sTestBoxHelper  = None;

        # Signed-on state
        self._cSignOnAttempts = 0;
        self._fSignedOn       = False;
        self._fNeedReSignOn   = False;
        self._fFirstSignOn    = True;
        self._idTestBox       = None;
        self._sTestBoxName    = '';
        self._sTestBoxUuid    = self.ksNullUuid; # convenience, assigned below.

        # Command processor.
        self._oCommand = TestBoxCommand(self);

        #
        # Scratch dir setup.  Use /var/tmp instead of /tmp because we may need
        # many many GBs for some test scenarios and /tmp can be backed by swap
        # or be a fast+small disk of some kind, while /var/tmp is normally
        # larger, if slower.  /var/tmp is generally not cleaned up on reboot,
        # /tmp often is, this would break host panic / triple-fault detection.
        #
        if self._oOptions.sScratchRoot is None:
            if utils.getHostOs() in ('win', 'os2', 'haiku', 'dos'):
                # We need *lots* of space, so avoid /tmp as it may be a memory
                # file system backed by the swap file, or worse.
                self._oOptions.sScratchRoot = tempfile.gettempdir();
            else:
                self._oOptions.sScratchRoot = '/var/tmp';
            sSubDir = 'testbox';
            try:
                sSubDir = '%s-%u' % (sSubDir, os.getuid()); # pylint: disable=E1101
            except:
                pass;
            self._oOptions.sScratchRoot = os.path.join(self._oOptions.sScratchRoot, sSubDir);

        self._sScratchSpill   = os.path.join(self._oOptions.sScratchRoot, 'scratch');
        self._sScratchScripts = os.path.join(self._oOptions.sScratchRoot, 'scripts');
        self._sScratchState   = os.path.join(self._oOptions.sScratchRoot, 'state');   # persistant storage.

        for sDir in [self._oOptions.sScratchRoot, self._sScratchSpill, self._sScratchScripts, self._sScratchState]:
            if not os.path.isdir(sDir):
                os.makedirs(sDir, 0700);

        # We count consecutive reinitScratch failures and will reboot the
        # testbox after a while in the hope that it will correct the issue.
        self._cReinitScratchErrors = 0;

        #
        # Mount builds and test resources if requested.
        #
        self.mountShares();

        #
        # Sign-on parameters: Packed into list of records of format:
        # { <Parameter ID>: { <Current value>, <Check function> } }
        #
        self._ddSignOnParams = \
        {
            constants.tbreq.ALL_PARAM_TESTBOX_UUID:        { self.VALUE: self._getHostSystemUuid(),    self.FN: None },
            constants.tbreq.SIGNON_PARAM_OS:               { self.VALUE: utils.getHostOs(),            self.FN: None },
            constants.tbreq.SIGNON_PARAM_OS_VERSION:       { self.VALUE: utils.getHostOsVersion(),     self.FN: None },
            constants.tbreq.SIGNON_PARAM_CPU_ARCH:         { self.VALUE: utils.getHostArch(),          self.FN: None },
            constants.tbreq.SIGNON_PARAM_CPU_VENDOR:       { self.VALUE: self._getHostCpuVendor(),     self.FN: None },
            constants.tbreq.SIGNON_PARAM_CPU_NAME:         { self.VALUE: self._getHostCpuName(),       self.FN: None },
            constants.tbreq.SIGNON_PARAM_CPU_REVISION:     { self.VALUE: self._getHostCpuRevision(),   self.FN: None },
            constants.tbreq.SIGNON_PARAM_HAS_HW_VIRT:      { self.VALUE: self._hasHostHwVirt(),        self.FN: None },
            constants.tbreq.SIGNON_PARAM_HAS_NESTED_PAGING:{ self.VALUE: self._hasHostNestedPaging(),  self.FN: None },
            constants.tbreq.SIGNON_PARAM_HAS_64_BIT_GUEST: { self.VALUE: self._can64BitGuest(),        self.FN: None },
            constants.tbreq.SIGNON_PARAM_HAS_IOMMU:        { self.VALUE: self._hasHostIoMmu(),         self.FN: None },
            #constants.tbreq.SIGNON_PARAM_WITH_RAW_MODE:    { self.VALUE: self._withRawModeSupport(),   self.FN: None },
            constants.tbreq.SIGNON_PARAM_SCRIPT_REV:       { self.VALUE: self._getScriptRev(),         self.FN: None },
            constants.tbreq.SIGNON_PARAM_REPORT:           { self.VALUE: self._getHostReport(),        self.FN: None },
            constants.tbreq.SIGNON_PARAM_PYTHON_VERSION:   { self.VALUE: self._getPythonHexVersion(),  self.FN: None },
            constants.tbreq.SIGNON_PARAM_CPU_COUNT:        { self.VALUE: None,     self.FN: multiprocessing.cpu_count },
            constants.tbreq.SIGNON_PARAM_MEM_SIZE:         { self.VALUE: None,     self.FN: self._getHostMemSize },
            constants.tbreq.SIGNON_PARAM_SCRATCH_SIZE:     { self.VALUE: None,     self.FN: self._getFreeScratchSpace },
        }
        for sItem in self._ddSignOnParams:
            if self._ddSignOnParams[sItem][self.FN] is not None:
                self._ddSignOnParams[sItem][self.VALUE] = self._ddSignOnParams[sItem][self.FN]()

        testboxcommons.log('Starting Test Box script (%s)' % (self._getScriptRev(),));
        testboxcommons.log('Test Manager URL: %s' % self._oOptions.sTestManagerUrl,)
        testboxcommons.log('Scratch root path: %s' % self._oOptions.sScratchRoot,)
        for sItem in self._ddSignOnParams:
            testboxcommons.log('Sign-On value %18s: %s' % (sItem, self._ddSignOnParams[sItem][self.VALUE]));

        #
        # The System UUID is the primary identification of the machine, so
        # refuse to cooperate if it's NULL.
        #
        self._sTestBoxUuid = self.getSignOnParam(constants.tbreq.ALL_PARAM_TESTBOX_UUID);
        if self._sTestBoxUuid == self.ksNullUuid:
            raise TestBoxScriptException('Couldn\'t determine the System UUID, please use --system-uuid to specify it.');

        #
        # Export environment variables, clearing any we don't know yet.
        #
        for sEnvVar in self._oOptions.asEnvVars:
            iEqual = sEnvVar.find('=');
            if iEqual == -1:    # No '=', remove it.
                if sEnvVar in os.environ:
                    del os.environ[sEnvVar];
            elif iEqual > 0:    # Set it.
                os.environ[sEnvVar[:iEqual]] = sEnvVar[iEqual+1:];
            else:               # Starts with '=', bad user.
                raise TestBoxScriptException('Invalid -E argument: "%s"' % (sEnvVar,));

        os.environ['TESTBOX_PATH_BUILDS']       = self._oOptions.sBuildsPath;
        os.environ['TESTBOX_PATH_RESOURCES']    = self._oOptions.sTestRsrcPath;
        os.environ['TESTBOX_PATH_SCRATCH']      = self._sScratchSpill;
        os.environ['TESTBOX_PATH_SCRIPTS']      = self._sScratchScripts;
        os.environ['TESTBOX_PATH_UPLOAD']       = self._sScratchSpill; ## @todo drop the UPLOAD dir?
        os.environ['TESTBOX_HAS_HW_VIRT']       = self.getSignOnParam(constants.tbreq.SIGNON_PARAM_HAS_HW_VIRT);
        os.environ['TESTBOX_HAS_NESTED_PAGING'] = self.getSignOnParam(constants.tbreq.SIGNON_PARAM_HAS_NESTED_PAGING);
        os.environ['TESTBOX_HAS_IOMMU']         = self.getSignOnParam(constants.tbreq.SIGNON_PARAM_HAS_IOMMU);
        os.environ['TESTBOX_SCRIPT_REV']        = self.getSignOnParam(constants.tbreq.SIGNON_PARAM_SCRIPT_REV);
        os.environ['TESTBOX_CPU_COUNT']         = self.getSignOnParam(constants.tbreq.SIGNON_PARAM_CPU_COUNT);
        os.environ['TESTBOX_MEM_SIZE']          = self.getSignOnParam(constants.tbreq.SIGNON_PARAM_MEM_SIZE);
        os.environ['TESTBOX_SCRATCH_SIZE']      = self.getSignOnParam(constants.tbreq.SIGNON_PARAM_SCRATCH_SIZE);
        #TODO: os.environ['TESTBOX_WITH_RAW_MODE']     = self.getSignOnParam(constants.tbreq.SIGNON_PARAM_WITH_RAW_MODE);
        os.environ['TESTBOX_WITH_RAW_MODE']     = str(self._withRawModeSupport());
        os.environ['TESTBOX_MANAGER_URL']       = self._oOptions.sTestManagerUrl;
        os.environ['TESTBOX_UUID']              = self._sTestBoxUuid;
        os.environ['TESTBOX_REPORTER']          = 'remote';
        os.environ['TESTBOX_NAME']              = '';
        os.environ['TESTBOX_ID']                = '';
        os.environ['TESTBOX_TEST_SET_ID']       = '';
        os.environ['TESTBOX_TIMEOUT']           = '0';
        os.environ['TESTBOX_TIMEOUT_ABS']       = '0';

        if utils.getHostOs() == 'win':
            os.environ['COMSPEC']            = os.path.join(os.environ['SystemRoot'], 'System32', 'cmd.exe');
コード例 #46
0
        # Successfully signed on, update the state.
        self._fSignedOn       = True;
        self._fNeedReSignOn   = False;
        self._cSignOnAttempts = 0;
        self._idTestBox       = idTestBox;
        self._sTestBoxName    = sTestBoxName;

        # Update the environment.
        os.environ['TESTBOX_ID']            = str(self._idTestBox);
        os.environ['TESTBOX_NAME']          = sTestBoxName;
        os.environ['TESTBOX_CPU_COUNT']     = self.getSignOnParam(constants.tbreq.SIGNON_PARAM_CPU_COUNT);
        os.environ['TESTBOX_MEM_SIZE']      = self.getSignOnParam(constants.tbreq.SIGNON_PARAM_MEM_SIZE);
        os.environ['TESTBOX_SCRATCH_SIZE']  = self.getSignOnParam(constants.tbreq.SIGNON_PARAM_SCRATCH_SIZE);

        testboxcommons.log('Successfully signed-on with Test Box ID #%s and given the name "%s"' \
                           % (self._idTestBox, self._sTestBoxName));

        # Set up the scratch area.
        self.reinitScratch(fUseTheForce = self._fFirstSignOn);

        self._fFirstSignOn = False;
        return True;

    def _maybeSignOn(self):
        """
        Check if Test Box parameters were changed
        and do sign-in in case of positive result
        """

        # Skip sign-on check if background command is currently in
        # running state (avoid infinite signing on).
コード例 #47
0
def _doUpgradeApply(sUpgradeDir, asMembers):
    """
    # Apply the directories and files from the upgrade.
    returns True/False/Exception.
    """

    #
    # Create directories first since that's least intrusive.
    #
    for sMember in asMembers:
        if sMember[-1] == '/':
            sMember = sMember[len('testboxscript/'):];
            if sMember != '':
                sFull = os.path.join(g_ksValidationKitDir, sMember);
                if not os.path.isdir(sFull):
                    os.makedirs(sFull, 0o755);

    #
    # Move the files into place.
    #
    fRc = True;
    asOldFiles = [];
    for sMember in asMembers:
        if sMember[-1] != '/':
            sSrc = os.path.join(sUpgradeDir, sMember);
            sDst = os.path.join(g_ksValidationKitDir, sMember[len('testboxscript/'):]);

            # Move the old file out of the way first.
            sDstRm = None;
            if os.path.exists(sDst):
                testboxcommons.log2('Info: Installing "%s"' % (sDst,));
                sDstRm = '%s-delete-me-%s' % (sDst, uuid.uuid4(),);
                try:
                    os.rename(sDst, sDstRm);
                except Exception as oXcpt:
                    testboxcommons.log('Error: failed to rename (old) "%s" to "%s": %s' % (sDst, sDstRm, oXcpt));
                    try:
                        shutil.copy(sDst, sDstRm);
                    except Exception as oXcpt:
                        testboxcommons.log('Error: failed to copy (old) "%s" to "%s": %s' % (sDst, sDstRm, oXcpt));
                        break;
                    try:
                        os.unlink(sDst);
                    except Exception as oXcpt:
                        testboxcommons.log('Error: failed to unlink (old) "%s": %s' % (sDst, oXcpt));
                        break;

            # Move/copy the new one into place.
            testboxcommons.log2('Info: Installing "%s"' % (sDst,));
            try:
                os.rename(sSrc, sDst);
            except Exception as oXcpt:
                testboxcommons.log('Warning: failed to rename (new) "%s" to "%s": %s' % (sSrc, sDst, oXcpt));
                try:
                    shutil.copy(sSrc, sDst);
                except:
                    testboxcommons.log('Error: failed to copy (new) "%s" to "%s": %s' % (sSrc, sDst, oXcpt));
                    fRc = False;
                    break;

    #
    # Roll back on failure.
    #
    if fRc is not True:
        testboxcommons.log('Attempting to roll back old files...');
        for sDstRm in asOldFiles:
            sDst = sDstRm[:sDstRm.rfind('-delete-me')];
            testboxcommons.log2('Info: Rolling back "%s" (%s)' % (sDst, os.path.basename(sDstRm)));
            try:
                shutil.move(sDstRm, sDst);
            except:
                testboxcommons.log('Error: failed to rollback "%s" onto "%s": %s' % (sDstRm, sDst, oXcpt));
        return False;
    return True;
コード例 #48
0
        ones) wont, leaving the caller the option to use it for log flushing.

        Returns success indicator.
        Raises no exception.
        """
        try:
            sCmdName = oResponse.getStringChecked(
                constants.tbresp.ALL_PARAM_RESULT)
        except Exception, oXcpt:
            oConnection.close()
            return False

        # Do we know the command?
        fRc = False
        if sCmdName in self._dfnCommands:
            testboxcommons.log(sCmdName)
            try:
                # Execute the handler.
                fRc = self._dfnCommands[sCmdName](oResponse, oConnection)
            except Exception, oXcpt:
                # NACK the command if an exception is raised during parameter validation.
                testboxcommons.log1Xcpt('Exception executing "%s": %s' %
                                        (sCmdName, oXcpt))
                if oConnection.isConnected():
                    try:
                        oConnection.sendReplyAndClose(
                            constants.tbreq.COMMAND_NACK, sCmdName)
                    except Exception, oXcpt2:
                        testboxcommons.log('Failed to NACK "%s": %s' %
                                           (sCmdName, oXcpt2))
        elif sCmdName in [