Ejemplo n.º 1
0
 def _receive_all(self, timeout, logger):
     """
     Read as much as possible before catch SessionTimeoutException
     :param timeout:
     :param logger:
     :return:
     :rtype: str
     """
     if not timeout:
         timeout = self._timeout
     start_time = time.time()
     read_buffer = ''
     while True:
         try:
             read_buffer += self._receive(0.1, logger)
         except (SessionReadTimeout, SessionReadEmptyData):
             if read_buffer:
                 return read_buffer
             elif time.time() - start_time > timeout:
                 raise ExpectedSessionException(self.__class__.__name__,
                                                'Socket closed by timeout')
Ejemplo n.º 2
0
    def reconnect(self, prompt, logger, timeout=None):
        """Recconnect implementation.

        :param prompt:
        :param logger:
        :param timeout:
        :return:
        """
        logger.debug("Reconnect")
        timeout = timeout or self._reconnect_timeout

        call_time = time.time()
        while time.time() - call_time < timeout:
            try:
                self.disconnect()
                return self.connect(prompt, logger)
            except Exception as e:
                logger.debug(e)
        raise ExpectedSessionException(
            self.__class__.__name__,
            "Reconnect unsuccessful, timeout exceeded, see logs for more details",
        )
Ejemplo n.º 3
0
    def hardware_expect(self,
                        command,
                        expected_string,
                        logger,
                        action_map=None,
                        error_map=None,
                        timeout=None,
                        retries=None,
                        check_action_loop_detector=True,
                        empty_loop_timeout=None,
                        remove_command_from_output=True,
                        **optional_args):
        """Get response form the device and compare it to action_map, error_map and expected_string patterns,
        perform actions specified in action_map if any, and return output.
        Raise Exception if receive empty response from device within a minute

        :param command: command to send
        :param expected_string: expected string
        :param expect_map: dict with {re_str: action} to trigger some action on received string
        :param error_map: expected error list
        :param timeout: session timeout
        :param retries: maximal retries count
        :param remove_command_from_output: In some switches the output string includes the command which was called.
            The flag used to verify whether the the command string removed from the output string.
        :return:
        """

        if not action_map:
            action_map = OrderedDict()

        if not error_map:
            error_map = OrderedDict()

        retries = retries or self._max_loop_retries
        empty_loop_timeout = empty_loop_timeout or self._empty_loop_timeout

        if command is not None:
            self._clear_buffer(self._clear_buffer_timeout, logger)

            logger.debug('Command: {}'.format(command))
            self.send_line(command, logger)

        if not expected_string:
            raise ExpectedSessionException(
                self.__class__.__name__,
                'List of expected messages can\'t be empty!')

        # Loop until one of the expressions is matched or MAX_RETRIES
        # nothing is expected (usually used for exit)
        output_list = list()
        output_str = ''
        retries_count = 0
        is_correct_exit = False

        action_loop_detector = ActionLoopDetector(
            self._loop_detector_max_action_loops,
            self._loop_detector_max_combination_length)

        while retries == 0 or retries_count < retries:

            # try:
            # read_buffer = self._receive(timeout, logger)
            # read all data from buffer
            read_buffer = self._receive_all(timeout, logger)
            # except socket.timeout:
            #     read_buffer = None

            if read_buffer:
                read_buffer = normalize_buffer(read_buffer)
                logger.info(read_buffer)
                output_str += read_buffer
                # if option remove_command_from_output is set to True, look for command in output buffer,
                #  remove it in case of found
                if command and remove_command_from_output:
                    command_pattern = '^.*' + command + '.*\\n'
                    if re.search(command_pattern, output_str):
                        output_str = re.sub(command_pattern, '', output_str)
                        remove_command_from_output = False
                retries_count = 0
            else:
                retries_count += 1
                time.sleep(empty_loop_timeout)
                continue

            if re.search(expected_string, output_str, re.DOTALL):
                # logger.debug('Expected str: {}'.format(expected_string))
                output_list.append(output_str)
                is_correct_exit = True

            for action_key in action_map:
                result_match = re.search(action_key, output_str, re.DOTALL)
                if result_match:
                    output_list.append(output_str)

                    if check_action_loop_detector:
                        if action_loop_detector.loops_detected(action_key):
                            logger.error('Loops detected')
                            raise SessionLoopDetectorException(
                                self.__class__.__name__,
                                'Expected actions loops detected')
                    logger.debug('Action key: {}'.format(action_key))
                    action_map[action_key](self, logger)
                    output_str = ''
                    break

            if is_correct_exit:
                break

        if not is_correct_exit:
            raise SessionLoopLimitException(
                self.__class__.__name__,
                'Session Loop limit exceeded, {} loops'.format(retries_count))

        result_output = ''.join(output_list)

        for error_string in error_map:
            result_match = re.search(error_string, result_output, re.DOTALL)
            if result_match:
                raise CommandExecutionException(
                    self.__class__.__name__,
                    'Session returned \'{}\''.format(error_map[error_string]))

        # Read buffer to the end. Useful when expected_string isn't last in buffer
        result_output += self._clear_buffer(self._clear_buffer_timeout, logger)
        return result_output
Ejemplo n.º 4
0
    def hardware_expect(self,
                        command,
                        expected_string,
                        logger,
                        action_map=None,
                        error_map=None,
                        timeout=None,
                        retries=None,
                        check_action_loop_detector=True,
                        empty_loop_timeout=None,
                        remove_command_from_output=True,
                        **optional_args):
        """Get response from the device.

        Compare it to action_map, error_map and expected_string patterns,
        perform actions specified in action_map if any, and return output.
        Raise Exception if receive empty response from device within a minute

        :param command: command to send
        :param expected_string: expected string
        :param logger: logger
        :param action_map: dict with {re_str: action} to trigger some action
            on received string
        :param error_map: expected error map with subclass of CommandExecutionException
            or str
        :type error_map: dict[str, CommandExecutionException|str]
        :param timeout: session timeout
        :param retries: maximal retries count
        :param remove_command_from_output: In some switches the output string includes
            the command which was called. The flag used to verify whether the the
            command string removed from the output string.
        :return:
        :rtype: str
        """
        if not action_map:
            action_map = OrderedDict()

        if not error_map:
            error_map = OrderedDict()

        retries = retries or self._max_loop_retries
        empty_loop_timeout = empty_loop_timeout or self._empty_loop_timeout

        if command is not None:
            self._clear_buffer(self._clear_buffer_timeout, logger)

            logger.debug("Command: {}".format(command))
            self.send_line(command, logger)

        if not expected_string:
            raise ExpectedSessionException(
                self.__class__.__name__,
                "List of expected messages can't be empty!")

        # Loop until one of the expressions is matched or MAX_RETRIES
        # nothing is expected (usually used for exit)
        output_list = []
        output_str = ""
        retries_count = 0
        is_correct_exit = False

        action_loop_detector = ActionLoopDetector(
            self._loop_detector_max_action_loops,
            self._loop_detector_max_combination_length,
        )
        while retries == 0 or retries_count < retries:

            read_buffer = self._receive_all(timeout, logger)

            if read_buffer:
                read_buffer = normalize_buffer(read_buffer)
                logger.debug(read_buffer)
                output_str += read_buffer
                # if option remove_command_from_output is set to True, look for command
                # in output buffer, remove it in case of found
                if command and remove_command_from_output:
                    command_pattern = self._generate_command_pattern(command)
                    if re.search(command_pattern,
                                 output_str,
                                 flags=re.MULTILINE):
                        output_str = re.sub(command_pattern,
                                            "",
                                            output_str,
                                            count=1,
                                            flags=re.MULTILINE)
                        remove_command_from_output = False
                retries_count = 0
            else:
                retries_count += 1
                time.sleep(empty_loop_timeout)
                continue

            if self.match_prompt(expected_string, output_str, logger):
                output_list.append(output_str)
                is_correct_exit = True

            for action_key in action_map:
                result_match = re.search(action_key, output_str, re.DOTALL)
                if result_match:
                    output_list.append(output_str)

                    if check_action_loop_detector:
                        if action_loop_detector.loops_detected(action_key):
                            logger.error("Loops detected")
                            raise SessionLoopDetectorException(
                                self.__class__.__name__,
                                "Expected actions loops detected",
                            )
                    logger.debug("Action key: {}".format(action_key))
                    action_map[action_key](self, logger)
                    output_str = ""
                    break

            if is_correct_exit:
                break

        if not is_correct_exit:
            raise SessionLoopLimitException(
                self.__class__.__name__,
                "Session Loop limit exceeded, {} loops".format(retries_count),
            )

        result_output = "".join(output_list)

        for error_pattern, error in error_map.items():
            result_match = re.search(error_pattern, result_output, re.DOTALL)

            if result_match:
                if isinstance(error, CommandExecutionException):
                    raise error
                else:
                    raise CommandExecutionException(
                        "Session returned '{}'".format(error))

        # Read buffer to the end. Useful when expected_string isn't last in buffer
        result_output += self._clear_buffer(self._clear_buffer_timeout, logger)
        return result_output