Exemplo n.º 1
0
    def set(self, *args):
        """
        Perform SNMP GET request
        :param oid: string or list of oids
        :returns: eigther result scalar or dict of name -> value
        """
        @tornado.gen.coroutine
        def run():
            try:
                self.result = yield snmp_set(
                    address=self.script.credentials["address"],
                    varbinds=varbinds,
                    community=str(self.script.credentials["snmp_rw"]),
                    tos=self.script.tos,
                    ioloop=self.get_ioloop(),
                    udp_socket=self.get_socket(),
                )
            except SNMPError as e:
                if e.code == TIMED_OUT:
                    raise self.TimeOutError()
                else:
                    raise

        if len(args) == 1:
            varbinds = args
        elif len(args) == 2:
            varbinds = [(args[0], args[1])]
        else:
            raise ValueError("Invalid varbinds")
        if "snmp_ro" not in self.script.credentials:
            raise SNMPError(code=ERR_SNMP_BAD_COMMUNITY)
        self.get_ioloop().run_sync(run)
        r, self.result = self.result, None
        return r
Exemplo n.º 2
0
Arquivo: base.py Projeto: nbashev/noc
    def count(self, oid, filter=None, version=None):
        """
        Iterate MIB subtree and count matching instances
        :param oid: OID
        :param filter: Callable accepting oid and value and returning boolean
        """
        async def run():
            try:
                r = await snmp_count(
                    address=self.script.credentials["address"],
                    oid=oid,
                    community=str(self.script.credentials["snmp_ro"]),
                    bulk=self.script.has_snmp_bulk(),
                    filter=filter,
                    tos=self.script.tos,
                    udp_socket=self.get_socket(),
                    version=version,
                    rate_limit=self.rate_limit,
                )
                return r
            except SNMPError as e:
                if e.code == TIMED_OUT:
                    raise self.TimeOutError()
                else:
                    raise

        if "snmp_ro" not in self.script.credentials:
            raise SNMPError(code=ERR_SNMP_BAD_COMMUNITY)
        version = self._get_snmp_version(version)
        return run_sync(run, close_all=False)
Exemplo n.º 3
0
Arquivo: base.py Projeto: nbashev/noc
    def set(self, *args):
        """
        Perform SNMP GET request
        :param oid: string or list of oids
        :returns: eigther result scalar or dict of name -> value
        """
        async def run():
            try:
                r = await snmp_set(
                    address=self.script.credentials["address"],
                    varbinds=varbinds,
                    community=str(self.script.credentials["snmp_rw"]),
                    tos=self.script.tos,
                    udp_socket=self.get_socket(),
                    rate_limit=self.rate_limit,
                )
                return r
            except SNMPError as e:
                if e.code == TIMED_OUT:
                    raise self.TimeOutError()
                else:
                    raise

        if len(args) == 1:
            varbinds = args
        elif len(args) == 2:
            varbinds = [(args[0], args[1])]
        else:
            raise ValueError("Invalid varbinds")
        if "snmp_ro" not in self.script.credentials:
            raise SNMPError(code=ERR_SNMP_BAD_COMMUNITY)
        return run_sync(run, close_all=False)
Exemplo n.º 4
0
async def snmp_set(
    address,
    varbinds,
    port=161,
    community="public",
    version=SNMP_v2c,
    timeout=10,
    tos=None,
    udp_socket=None,
    rate_limit: Optional[AsyncRateLimit] = None,
):
    """
    Perform SNMP set request and returns Future to be used
    inside async coroutine
    """
    logger.debug("[%s] SNMP SET %s", address, varbinds)
    # Send GET PDU
    pdu = set_pdu(community=community, varbinds=varbinds, version=version)
    if rate_limit:
        await rate_limit.wait()
    # Wait for result
    with UDPSocketContext(udp_socket, tos=tos) as sock:
        try:
            data, addr = await asyncio.wait_for(
                sock.send_and_receive(pdu, (address, port)), timeout)
        except asyncio.TimeoutError:
            raise SNMPError(code=TIMED_OUT, oid=varbinds[0][0])
        except socket.gaierror as e:
            logger.debug("[%s] Cannot resolve address: %s", address, e)
            raise SNMPError(code=UNREACHABLE, oid=varbinds[0][0])
        except OSError as e:
            logger.debug("[%s] Socket error: %s", address, e)
            raise SNMPError(code=UNREACHABLE, oid=varbinds[0][0])
        try:
            resp = parse_get_response(data)
        except ValueError:
            raise SNMPError(code=BER_ERROR, oid=varbinds[0][0])
        if resp.error_status != NO_ERROR:
            oid = None
            if resp.error_index and resp.varbinds:
                oid = resp.varbinds[resp.error_index - 1][0]
            logger.debug("[%s] SNMP error: %s %s", address, oid,
                         resp.error_status)
            raise SNMPError(code=resp.error_status, oid=oid)
        else:
            logger.debug("[%s] SET result: OK", address)
            return True
Exemplo n.º 5
0
Arquivo: base.py Projeto: nbashev/noc
    def getnext(
        self,
        oid,
        community_suffix=None,
        filter=None,
        cached=False,
        only_first=False,
        bulk=None,
        max_repetitions=None,
        version=None,
        max_retries=0,
        timeout=10,
        raw_varbinds=False,
        display_hints=None,
    ):
        async def run():
            try:
                r = await snmp_getnext(
                    address=self.script.credentials["address"],
                    oid=oid,
                    community=str(self.script.credentials["snmp_ro"]),
                    bulk=self.script.has_snmp_bulk() if bulk is None else bulk,
                    max_repetitions=max_repetitions,
                    filter=filter,
                    only_first=only_first,
                    tos=self.script.tos,
                    udp_socket=self.get_socket(),
                    version=version,
                    max_retries=max_retries,
                    timeout=timeout,
                    raw_varbinds=raw_varbinds,
                    display_hints=display_hints,
                    response_parser=self.script.profile.
                    get_snmp_response_parser(self.script),
                    rate_limit=self.rate_limit,
                )
                return r
            except SNMPError as e:
                if e.code == TIMED_OUT:
                    raise self.TimeOutError()
                else:
                    raise

        if "snmp_ro" not in self.script.credentials:
            raise SNMPError(code=ERR_SNMP_BAD_COMMUNITY)
        if display_hints is None:
            display_hints = self._get_display_hints()
        version = self._get_snmp_version(version)
        return run_sync(run, close_all=False)
Exemplo n.º 6
0
Arquivo: base.py Projeto: nbashev/noc
    def get(self,
            oids,
            cached=False,
            version=None,
            raw_varbinds=False,
            display_hints=None):
        """
        Perform SNMP GET request
        :param oid: string or list of oids
        :param cached: True if get results can be cached during session
        :param raw_varbinds: Return value in BER encoding
        :param display_hints: Dict of  oid -> render_function. See BaseProfile.snmp_display_hints for details
        :returns: eigther result scalar or dict of name -> value
        """
        async def run():
            try:
                r = await snmp_get(
                    address=self.script.credentials["address"],
                    oids=oids,
                    community=str(self.script.credentials["snmp_ro"]),
                    tos=self.script.tos,
                    udp_socket=self.get_socket(),
                    version=version,
                    raw_varbinds=raw_varbinds,
                    display_hints=display_hints,
                    response_parser=self.script.profile.
                    get_snmp_response_parser(self.script),
                    rate_limit=self.rate_limit,
                )
                self.timeouts = self.timeouts_limit
                return r
            except SNMPError as e:
                if e.code == TIMED_OUT:
                    if self.timeouts_limit:
                        self.timeouts -= 1
                        if not self.timeouts:
                            raise self.FatalTimeoutError()
                    raise self.TimeOutError()
                else:
                    raise

        if "snmp_ro" not in self.script.credentials:
            raise SNMPError(code=ERR_SNMP_BAD_COMMUNITY)
        if display_hints is None:
            display_hints = self._get_display_hints()
        version = self._get_snmp_version(version)
        return run_sync(run, close_all=False)
Exemplo n.º 7
0
    def getnext(
        self,
        oid,
        community_suffix=None,
        filter=None,
        cached=False,
        only_first=False,
        bulk=None,
        max_repetitions=None,
        version=None,
        max_retries=0,
        timeout=10,
        raw_varbinds=False,
    ):
        @tornado.gen.coroutine
        def run():
            try:
                self.result = yield snmp_getnext(
                    address=self.script.credentials["address"],
                    oid=oid,
                    community=str(self.script.credentials["snmp_ro"]),
                    bulk=self.script.has_snmp_bulk() if bulk is None else bulk,
                    max_repetitions=max_repetitions,
                    filter=filter,
                    only_first=only_first,
                    tos=self.script.tos,
                    ioloop=self.get_ioloop(),
                    udp_socket=self.get_socket(),
                    version=version,
                    max_retries=max_retries,
                    timeout=timeout,
                    raw_varbinds=raw_varbinds,
                )
            except SNMPError as e:
                if e.code == TIMED_OUT:
                    raise self.TimeOutError()
                else:
                    raise

        if "snmp_ro" not in self.script.credentials:
            raise SNMPError(code=ERR_SNMP_BAD_COMMUNITY)
        version = self._get_snmp_version(version)
        self.get_ioloop().run_sync(run)
        r, self.result = self.result, None
        return r
Exemplo n.º 8
0
    def get(self, oids, cached=False, version=None, raw_varbinds=False):
        """
        Perform SNMP GET request
        :param oid: string or list of oids
        :param cached: True if get results can be cached during session
        :param raw_varbinds: Return value in BER encoding
        :returns: eigther result scalar or dict of name -> value
        """
        @tornado.gen.coroutine
        def run():
            try:
                self.result = yield snmp_get(
                    address=self.script.credentials["address"],
                    oids=oids,
                    community=str(self.script.credentials["snmp_ro"]),
                    tos=self.script.tos,
                    ioloop=self.get_ioloop(),
                    udp_socket=self.get_socket(),
                    version=version,
                    raw_varbinds=raw_varbinds,
                )
                self.timeouts = self.timeouts_limit
            except SNMPError as e:
                if e.code == TIMED_OUT:
                    if self.timeouts_limit:
                        self.timeouts -= 1
                        if not self.timeouts:
                            raise self.FatalTimeoutError()
                    raise self.TimeOutError()
                else:
                    raise

        if "snmp_ro" not in self.script.credentials:
            raise SNMPError(code=ERR_SNMP_BAD_COMMUNITY)
        version = self._get_snmp_version(version)
        self.get_ioloop().run_sync(run)
        r, self.result = self.result, None
        return r
Exemplo n.º 9
0
async def snmp_get(
    address,
    oids,
    port=161,
    community="public",
    version=SNMP_v2c,
    timeout=10,
    tos=None,
    udp_socket: Optional[UDPSocket] = None,
    raw_varbinds=False,
    display_hints=None,
    response_parser: Optional[_ResponseParser] = None,
    rate_limit: Optional[AsyncRateLimit] = None,
):
    """
    Perform SNMP get request and returns Future to be used
    inside async coroutine
    """
    oid_map = {}
    if isinstance(oids, str):
        oids = [oids]
    elif isinstance(oids, dict):
        oid_map = {oids[k]: k for k in oids}
        oids = list(oids.values())
    else:
        raise ValueError("oids must be either string or dict")
    logger.debug("[%s] SNMP GET %s", address, oids)
    parser = _get_parser(response_parser, raw_varbinds)
    # Send GET PDU
    pdu = get_pdu(community=community, oids=oids, version=version)
    if rate_limit:
        await rate_limit.wait()
    with UDPSocketContext(udp_socket, tos=tos) as sock:
        try:
            data, addr = await asyncio.wait_for(
                sock.send_and_receive(pdu, (address, port)), timeout)
        except asyncio.TimeoutError:
            raise SNMPError(code=TIMED_OUT, oid=oids[0])
        except socket.gaierror as e:
            logger.debug("[%s] Cannot resolve address: %s", address, e)
            raise SNMPError(code=UNREACHABLE, oid=oids[0])
        except OSError as e:
            logger.debug("[%s] Socket error: %s", address, e)
            raise SNMPError(code=UNREACHABLE, oid=oids[0])
        try:
            resp = parser(data, display_hints)
        except ValueError:
            # Broken response
            raise SNMPError(code=BER_ERROR, oid=oids[0])
        if resp.error_status == NO_ERROR:
            # Success
            if oid_map:
                result = {}
                for k, v in resp.varbinds:
                    if k in oid_map:
                        result[oid_map[k]] = v
                    else:
                        logger.error("[%s] Invalid oid %s returned in reply",
                                     address, k)
            else:
                result = resp.varbinds[0][1]
            logger.debug("[%s] GET result: %r", address, result)
            return result
        elif resp.error_status == NO_SUCH_NAME and len(oids) > 1:
            # One or more invalid oids
            b_idx = resp.error_index - 1
            logger.debug("[%s] Invalid oid %s detected, trying to exclude",
                         address, resp.varbinds[b_idx][0])
            result = {}
            oid_parts = []
            if b_idx:
                # Oids before b_idx are probable correct
                oid_parts += [[vb[0] for vb in resp.varbinds[:b_idx]]]
            if b_idx < len(resp.varbinds) - 1:
                # Some oids after b_idx may be correct
                oid_parts += [[vb[0] for vb in resp.varbinds[b_idx + 1:]]]
            for new_oids in oid_parts:
                try:
                    new_result = await snmp_get(
                        address=address,
                        oids={k: k
                              for k in new_oids},
                        port=port,
                        community=community,
                        version=version,
                        timeout=timeout,
                        tos=tos,
                        udp_socket=sock,
                    )
                except SNMPError as e:
                    if e.code == NO_SUCH_NAME and len(new_oids) == 1:
                        # Ignore NO_SUCH_VALUE for last oid in list
                        new_result = {}
                    else:
                        raise
                for k in new_result:
                    if k in oid_map:
                        result[oid_map[k]] = new_result[k]
                    else:
                        logger.info("[%s] Invalid oid %s returned in reply",
                                    address, k)
            if result:
                logger.debug("[%s] GET result: %r", address, result)
                return result
            else:
                # All oids excluded as broken
                logger.debug("[%s] All oids are broken", address)
                raise SNMPError(code=NO_SUCH_NAME, oid=oids[0])
        else:
            oid = None
            if resp.error_index and resp.varbinds:
                if resp.error_index & 0x8000:
                    # Some broken SNMP servers (i.e. Huawei) returns
                    # negative error index. Try to negotiate silently
                    oid = resp.varbinds[min(65536 - resp.error_index,
                                            len(resp.varbinds) - 1)][0]
                else:
                    oid = resp.varbinds[resp.error_index - 1][0]
            logger.debug("[%s] SNMP error: %s %s", address, oid,
                         resp.error_status)
            raise SNMPError(code=resp.error_status, oid=oid)
Exemplo n.º 10
0
async def snmp_getnext(
    address: str,
    oid: str,
    port: int = 161,
    community: str = "public",
    version: int = SNMP_v2c,
    timeout: float = 10,
    bulk: bool = False,
    filter: Optional[Callable[[bytes, Any], bool]] = None,
    max_repetitions: int = BULK_MAX_REPETITIONS,
    only_first: bool = False,
    tos: Optional[int] = None,
    udp_socket: Optional[UDPSocket] = None,
    max_retries: int = 0,
    raw_varbinds: bool = False,
    display_hints: Optional[Dict[str,
                                 Optional[Callable[[str, bytes],
                                                   Union[str,
                                                         bytes]]]]] = None,
    response_parser: Optional[_ResponseParser] = None,
    rate_limit: Optional[AsyncRateLimit] = None,
):
    """
    Perform SNMP GETNEXT/BULK request and returns Future to be used
    inside async coroutine
    """
    def true(x, y):
        return True

    logger.debug("[%s] SNMP GETNEXT %s", address, oid)
    if not filter:
        filter = true
    poid = oid + "."
    result = []
    parser = _get_parser(response_parser, raw_varbinds)
    with UDPSocketContext(udp_socket, tos=tos) as sock:
        first_oid = None
        last_oid = None
        while True:
            if rate_limit:
                await rate_limit.wait()
            # Get PDU
            if bulk:
                pdu = getbulk_pdu(
                    community,
                    oid,
                    max_repetitions=max_repetitions or BULK_MAX_REPETITIONS,
                    version=version,
                )
            else:
                pdu = getnext_pdu(community, oid, version=version)
            # Send request and wait for response
            try:
                data, addr = await asyncio.wait_for(
                    sock.send_and_receive(pdu, (address, port)), timeout)
            except asyncio.TimeoutError:
                if not max_retries:
                    raise SNMPError(code=TIMED_OUT, oid=oid)
                max_retries -= 1
                continue
            except socket.gaierror as e:
                logger.debug("[%s] Cannot resolve address: %s", address, e)
                raise SNMPError(code=UNREACHABLE, oid=oid)
            except OSError as e:
                logger.debug("[%s] Socket error: %s", address, e)
                raise SNMPError(code=UNREACHABLE, oid=oid)
            # Parse response
            try:
                resp = parser(data, display_hints)
            except ValueError:
                raise SNMPError(code=BER_ERROR, oid=oid)
            if resp.error_status == NO_SUCH_NAME:
                # NULL result
                break
            elif resp.error_status == END_OID_TREE:
                # End OID Tree
                return result
            elif resp.error_status != NO_ERROR:
                # Error
                raise SNMPError(code=resp.error_status, oid=oid)
            elif not raw_varbinds:
                # Success value
                for oid, v in resp.varbinds:
                    if oid == first_oid:
                        logger.warning("[%s] GETNEXT Oid wrap detected",
                                       address)
                        return result
                    elif oid.startswith(poid) and not (
                            only_first and result) and oid != last_oid:
                        # Next value
                        if filter(oid, v):
                            result += [(oid, v)]
                        last_oid = oid
                        first_oid = first_oid or oid
                    else:
                        logger.debug("[%s] GETNEXT result: %s", address,
                                     result)
                        return result
            else:
                # Raw varbinds
                for oid, v in resp.varbinds:
                    s_oid = smart_text(oid)
                    if s_oid.startswith(poid) and not (
                            only_first and result) and oid != last_oid:
                        # Next value
                        if filter(s_oid, v):
                            result += [(oid, v)]
                        last_oid = oid
                        first_oid = first_oid or oid
                    else:
                        logger.debug("[%s] GETNEXT result: %s", address,
                                     result)
                        return result
Exemplo n.º 11
0
async def snmp_count(
    address,
    oid,
    port=161,
    community="public",
    version=SNMP_v2c,
    timeout=10,
    bulk=False,
    filter=None,
    max_repetitions=BULK_MAX_REPETITIONS,
    tos=None,
    udp_socket: Optional[UDPSocket] = None,
    rate_limit: Optional[AsyncRateLimit] = None,
):
    """
    Perform SNMP get request and returns Future to be used
    inside async coroutine
    """
    def true(x, y):
        return true

    logger.debug("[%s] SNMP COUNT %s", address, oid)
    if not filter:
        filter = true
    poid = oid + "."
    result = 0
    with UDPSocketContext(udp_socket, tos=tos) as sock:
        while True:
            if rate_limit:
                await rate_limit.wait()
            # Get PDU
            if bulk:
                pdu = getbulk_pdu(community,
                                  oid,
                                  max_repetitions=max_repetitions,
                                  version=version)
            else:
                pdu = getnext_pdu(community, oid, version=version)
            # Send request and wait for response
            try:
                data, addr = await asyncio.wait_for(
                    sock.send_and_receive(pdu, (address, port)), timeout)
            except asyncio.TimeoutError:
                raise SNMPError(code=TIMED_OUT, oid=oid)
            except socket.gaierror as e:
                logger.debug("[%s] Cannot resolve address: %s", address, e)
                raise SNMPError(code=UNREACHABLE, oid=oid)
            except OSError as e:
                logger.debug("[%s] Socket error: %s", address, e)
                raise SNMPError(code=UNREACHABLE, oid=oid)
            # Parse response
            try:
                resp = parse_get_response(data)
            except ValueError:
                raise SNMPError(code=BER_ERROR, oid=oid)
            if resp.error_status == NO_SUCH_NAME:
                # NULL result
                break
            elif resp.error_status != NO_ERROR:
                # Error
                raise SNMPError(code=resp.error_status, oid=oid)
            else:
                # Success value
                for oid, v in resp.varbinds:
                    if oid.startswith(poid):
                        # Next value
                        if filter(oid, v):
                            result += 1
                    else:
                        logger.debug("[%s] COUNT result: %s", address, result)
                        sock.close()
                        return result
Exemplo n.º 12
0
Arquivo: snmp.py Projeto: skripkar/noc
def snmp_get(address,
             oids,
             port=161,
             community="public",
             version=SNMP_v2c,
             timeout=10,
             tos=None,
             ioloop=None,
             udp_socket=None,
             raw_varbinds=False):
    """
    Perform SNMP get request and returns Future to be used
    inside @tornado.gen.coroutine
    """
    oid_map = {}
    if isinstance(oids, six.string_types):
        oids = [oids]
    elif isinstance(oids, dict):
        oid_map = dict((oids[k], k) for k in oids)
        oids = oids.values()
    else:
        raise ValueError("oids must be either string or dict")
    logger.debug("[%s] SNMP GET %s", address, oids)
    # Send GET PDU
    pdu = get_pdu(community=community, oids=oids, version=version)
    if udp_socket:
        sock = udp_socket
        prev_timeout = sock.get_timeout()
    else:
        sock = UDPSocket(ioloop=ioloop, tos=tos)
    sock.settimeout(timeout)
    # Wait for result
    try:
        yield sock.sendto(pdu, (address, port))
        data, addr = yield sock.recvfrom(4096)
    except socket.timeout:
        raise SNMPError(code=TIMED_OUT, oid=oids[0])
    except socket.gaierror as e:
        logger.debug("[%s] Cannot resolve address: %s", address, e)
        raise SNMPError(code=UNREACHABLE, oid=oids[0])
    except socket.error as e:
        logger.debug("[%s] Socket error: %s", address, e)
        raise SNMPError(code=UNREACHABLE, oid=oids[0])
    finally:
        if udp_socket:
            sock.settimeout(prev_timeout)
        else:
            sock.close()
    try:
        if raw_varbinds:
            resp = parse_get_response_raw(data)
        else:
            resp = parse_get_response(data)
    except ValueError:
        # Broken response
        raise SNMPError(code=BER_ERROR, oid=oids[0])
    if resp.error_status == NO_ERROR:
        # Success
        if oid_map:
            result = {}
            for k, v in resp.varbinds:
                if k in oid_map:
                    result[oid_map[k]] = v
                else:
                    logger.error("[%s] Invalid oid %s returned in reply",
                                 address, k)
        else:
            result = resp.varbinds[0][1]
        logger.debug("[%s] GET result: %r", address, result)
        raise Return(result)
    elif resp.error_status == NO_SUCH_NAME and len(oids) > 1:
        # One or more invalid oids
        b_idx = resp.error_index - 1
        logger.debug("[%s] Invalid oid %s detected, trying to exclude",
                     address, resp.varbinds[b_idx][0])
        result = {}
        oid_parts = []
        if b_idx:
            # Oids before b_idx are probable correct
            oid_parts += [[vb[0] for vb in resp.varbinds[:b_idx]]]
        if b_idx < len(resp.varbinds) - 1:
            # Some oids after b_idx may be correct
            oid_parts += [[vb[0] for vb in resp.varbinds[b_idx + 1:]]]
        for new_oids in oid_parts:
            try:
                new_result = yield snmp_get(address=address,
                                            oids=dict(
                                                (k, k) for k in new_oids),
                                            port=port,
                                            community=community,
                                            version=version,
                                            timeout=timeout,
                                            tos=tos,
                                            ioloop=ioloop,
                                            udp_socket=sock)
            except SNMPError as e:
                if e.code == NO_SUCH_NAME and len(new_oids) == 1:
                    # Ignore NO_SUCH_VALUE for last oid in list
                    new_result = {}
                else:
                    raise
            for k in new_result:
                if k in oid_map:
                    result[oid_map[k]] = new_result[k]
                else:
                    logger.info("[%s] Invalid oid %s returned in reply",
                                address, k)
        if result:
            logger.debug("[%s] GET result: %r", address, result)
            raise Return(result)
        else:
            # All oids excluded as broken
            logger.debug("[%s] All oids are broken", address)
            raise SNMPError(code=NO_SUCH_NAME, oid=oids[0])
    else:
        oid = None
        if resp.error_index and resp.varbinds:
            if resp.error_index & 0x8000:
                # Some broken SNMP servers (i.e. Huawei) returns
                # negative error index. Try to negotiate silently
                oid = resp.varbinds[65536 - resp.error_index][0]
            else:
                oid = resp.varbinds[resp.error_index - 1][0]
        logger.debug("[%s] SNMP error: %s %s", address, oid, resp.error_status)
        raise SNMPError(code=resp.error_status, oid=oid)
Exemplo n.º 13
0
Arquivo: snmp.py Projeto: skripkar/noc
def snmp_getnext(address,
                 oid,
                 port=161,
                 community="public",
                 version=SNMP_v2c,
                 timeout=10,
                 bulk=False,
                 filter=None,
                 max_repetitions=BULK_MAX_REPETITIONS,
                 only_first=False,
                 tos=None,
                 ioloop=None,
                 udp_socket=None,
                 max_retries=0,
                 raw_varbinds=False):
    """
    Perform SNMP GETNEXT/BULK request and returns Future to be used
    inside @tornado.gen.coroutine
    """
    def true(x, y):
        return True

    def close_socket():
        if udp_socket:
            sock.settimeout(prev_timeout)
        else:
            sock.close()

    logger.debug("[%s] SNMP GETNEXT %s", address, oid)
    if not filter:
        filter = true
    poid = oid + "."
    result = []
    if udp_socket:
        sock = udp_socket
        prev_timeout = sock.get_timeout()
    else:
        sock = UDPSocket(ioloop=ioloop, tos=tos)
    sock.settimeout(timeout)
    last_oid = None
    while True:
        # Get PDU
        if bulk:
            pdu = getbulk_pdu(community,
                              oid,
                              max_repetitions=max_repetitions
                              or BULK_MAX_REPETITIONS,
                              version=version)
        else:
            pdu = getnext_pdu(community, oid, version=version)
        # Send request and wait for response
        try:
            yield sock.sendto(pdu, (address, port))
            data, addr = yield sock.recvfrom(4096)
        except socket.timeout:
            if not max_retries:
                close_socket()
                raise SNMPError(code=TIMED_OUT, oid=oid)
            max_retries -= 1
            continue
        except socket.gaierror as e:
            logger.debug("[%s] Cannot resolve address: %s", address, e)
            close_socket()
            raise SNMPError(code=UNREACHABLE, oid=oid)
        except socket.error as e:
            logger.debug("[%s] Socket error: %s", address, e)
            close_socket()
            raise SNMPError(code=UNREACHABLE, oid=oid)
        # Parse response
        try:
            if raw_varbinds:
                resp = parse_get_response_raw(data)
            else:
                resp = parse_get_response(data)
        except ValueError:
            raise SNMPError(code=BER_ERROR, oid=oid)
        if resp.error_status == NO_SUCH_NAME:
            # NULL result
            break
        elif resp.error_status != NO_ERROR:
            # Error
            close_socket()
            raise SNMPError(code=resp.error_status, oid=oid)
        else:
            # Success value
            for oid, v in resp.varbinds:
                if oid.startswith(poid) and not (only_first and
                                                 result) and oid != last_oid:
                    # Next value
                    if filter(oid, v):
                        result += [(oid, v)]
                    last_oid = oid
                else:
                    logger.debug("[%s] GETNEXT result: %s", address, result)
                    close_socket()
                    raise Return(result)
    close_socket()
Exemplo n.º 14
0
Arquivo: snmp.py Projeto: skripkar/noc
def snmp_count(address,
               oid,
               port=161,
               community="public",
               version=SNMP_v2c,
               timeout=10,
               bulk=False,
               filter=None,
               max_repetitions=BULK_MAX_REPETITIONS,
               tos=None,
               ioloop=None,
               udp_socket=None):
    """
    Perform SNMP get request and returns Future to be used
    inside @tornado.gen.coroutine
    """
    def true(x, y):
        return true

    logger.debug("[%s] SNMP COUNT %s", address, oid)
    if not filter:
        filter = true
    poid = oid + "."
    result = 0
    if udp_socket:
        sock = udp_socket
        prev_timeout = sock.get_timeout()
    else:
        sock = UDPSocket(ioloop=ioloop, tos=tos)
    sock.settimeout(timeout)
    while True:
        # Get PDU
        if bulk:
            pdu = getbulk_pdu(community,
                              oid,
                              max_repetitions=max_repetitions,
                              version=version)
        else:
            pdu = getnext_pdu(community, oid, version=version)
        # Send request and wait for response
        try:
            yield sock.sendto(pdu, (address, port))
            data, addr = yield sock.recvfrom(4096)
        except socket.timeout:
            raise SNMPError(code=TIMED_OUT, oid=oid)
        except socket.gaierror as e:
            logger.debug("[%s] Cannot resolve address: %s", address, e)
            raise SNMPError(code=UNREACHABLE, oid=oid)
        except socket.error as e:
            logger.debug("[%s] Socket error: %s", address, e)
            raise SNMPError(code=UNREACHABLE, oid=oid)
        finally:
            if udp_socket:
                sock.settimeout(prev_timeout)
            else:
                sock.close()
        # Parse response
        try:
            resp = parse_get_response(data)
        except ValueError:
            raise SNMPError(code=BER_ERROR, oid=oid)
        if resp.error_status == NO_SUCH_NAME:
            # NULL result
            break
        elif resp.error_status != NO_ERROR:
            # Error
            raise SNMPError(code=resp.error_status, oid=oid)
        else:
            # Success value
            for oid, v in resp.varbinds:
                if oid.startswith(poid):
                    # Next value
                    if filter(oid, v):
                        result += 1
                else:
                    logger.debug("[%s] COUNT result: %s", address, result)
                    sock.close()
                    raise Return(result)