Пример #1
0
    def check_version(self, node_id=None, timeout=2, strict=False):
        """Attempt to guess the broker version"""
        if node_id is None:
            node_id = self.least_loaded_node()

        def connect(node_id):
            timeout_at = time.time() + timeout
            # brokers < 0.9 do not return any broker metadata if there are no topics
            # so we're left with a single bootstrap connection
            while not self.ready(node_id):
                if time.time() >= timeout_at:
                    raise Errors.NodeNotReadyError(node_id)
                time.sleep(0.025)

            # Monkeypatch the connection request timeout
            # Generally this timeout should not get triggered
            # but in case it does, we want it to be reasonably short
            self._conns[node_id].config['request_timeout_ms'] = timeout * 1000

        # kafka kills the connection when it doesnt recognize an API request
        # so we can send a test request and then follow immediately with a
        # vanilla MetadataRequest. If the server did not recognize the first
        # request, both will be failed with a ConnectionError that wraps
        # socket.error (32, 54, or 104)
        import socket
        from .protocol.admin import ListGroupsRequest
        from .protocol.commit import (OffsetFetchRequest_v0,
                                      GroupCoordinatorRequest)
        from .protocol.metadata import MetadataRequest

        # Socket errors are logged as exceptions and can alarm users. Mute them
        from logging import Filter

        class ConnFilter(Filter):
            def filter(self, record):
                if record.funcName in ('recv', 'send'):
                    return False
                return True

        log_filter = ConnFilter()

        test_cases = [
            ('0.9', ListGroupsRequest()),
            ('0.8.2', GroupCoordinatorRequest('kafka-python-default-group')),
            ('0.8.1', OffsetFetchRequest_v0('kafka-python-default-group', [])),
            ('0.8.0', MetadataRequest([])),
        ]

        logging.getLogger('kafka.conn').addFilter(log_filter)
        for version, request in test_cases:
            connect(node_id)
            f = self.send(node_id, request)
            time.sleep(0.1)  # HACK: sleeping to wait for socket to send bytes
            metadata = self.send(node_id, MetadataRequest([]))
            self.poll(future=f)
            self.poll(future=metadata)

            assert f.is_done, 'Future is not done? Please file bug report'

            if f.succeeded():
                log.info('Broker version identifed as %s', version)
                break

            # Only enable strict checking to verify that we understand failure
            # modes. For most users, the fact that the request failed should be
            # enough to rule out a particular broker version.
            if strict:
                # If the socket flush hack did not work (which should force the
                # connection to close and fail all pending requests), then we
                # get a basic Request Timeout. Thisisn
                if isinstance(f.exception, Errors.RequestTimedOutError):
                    pass
                elif six.PY2:
                    assert isinstance(f.exception.args[0], socket.error)
                    assert f.exception.args[0].errno in (32, 54, 104)
                else:
                    assert isinstance(f.exception.args[0], ConnectionError)
            log.info("Broker is not v%s -- it did not recognize %s", version,
                     request.__class__.__name__)
        else:

            raise Errors.UnrecognizedBrokerVersion()

        logging.getLogger('kafka.conn').removeFilter(log_filter)
        self._conns[node_id].config['request_timeout_ms'] = self.config[
            'request_timeout_ms']
        return version
Пример #2
0
    def check_version(self, node_id=None):
        """Attempt to guess the broker version"""
        if node_id is None:
            node_id = self.least_loaded_node()

        def connect():
            timeout = time.time() + 10
            # brokers < 0.9 do not return any broker metadata if there are no topics
            # so we're left with a single bootstrap connection
            while not self.ready(node_id):
                if time.time() >= timeout:
                    raise Errors.NodeNotReadyError(node_id)
                time.sleep(0.025)

        # kafka kills the connection when it doesnt recognize an API request
        # so we can send a test request and then follow immediately with a
        # vanilla MetadataRequest. If the server did not recognize the first
        # request, both will be failed with a ConnectionError that wraps
        # socket.error (32, 54, or 104)
        import socket
        from .protocol.admin import ListGroupsRequest
        from .protocol.commit import (OffsetFetchRequest_v0,
                                      GroupCoordinatorRequest)
        from .protocol.metadata import MetadataRequest

        # Socket errors are logged as exceptions and can alarm users. Mute them
        from logging import Filter

        class ConnFilter(Filter):
            def filter(self, record):
                if record.funcName in ('recv', 'send'):
                    return False
                return True

        log_filter = ConnFilter()

        test_cases = [
            ('0.9', ListGroupsRequest()),
            ('0.8.2', GroupCoordinatorRequest('kafka-python-default-group')),
            ('0.8.1', OffsetFetchRequest_v0('kafka-python-default-group', [])),
            ('0.8.0', MetadataRequest([])),
        ]

        logging.getLogger('kafka.conn').addFilter(log_filter)
        for version, request in test_cases:
            connect()
            f = self.send(node_id, request)
            time.sleep(0.1)  # HACK: sleeping to wait for socket to send bytes
            metadata = self.send(node_id, MetadataRequest([]))
            self.poll(future=f)
            self.poll(future=metadata)

            assert f.is_done

            if f.succeeded():
                log.info('Broker version identifed as %s', version)
                break

            if six.PY2:
                assert isinstance(f.exception.args[0], socket.error)
                assert f.exception.args[0].errno in (32, 54, 104)
            else:
                assert isinstance(f.exception.args[0], ConnectionError)
            log.info("Broker is not v%s -- it did not recognize %s", version,
                     request.__class__.__name__)
            continue

        else:
            raise Errors.UnrecognizedBrokerVersion()

        logging.getLogger('kafka.conn').removeFilter(log_filter)
        return version