Commit 6870ef9b authored by Andrey Vertiprahov's avatar Andrey Vertiprahov
Browse files

Merge branch 'noc-fix-script-leak' into 'microservices'

Fix script's memory leaking

See merge request !1183
parents 643d7b3e b75a678f
Pipeline #8143 passed with stages
in 1 minute and 23 seconds
......@@ -19,7 +19,7 @@ from noc.core.snmp.get import (get_pdu, getnext_pdu, getbulk_pdu,
parse_get_response, parse_get_response_raw)
from noc.core.snmp.set import set_pdu
from noc.core.snmp.error import (NO_ERROR, NO_SUCH_NAME,
SNMPError, TIMED_OUT, UNREACHABLE)
SNMPError, TIMED_OUT, UNREACHABLE, BER_ERROR)
from noc.core.ioloop.udp import UDPSocket
_ERRNO_WOULDBLOCK = (errno.EWOULDBLOCK, errno.EAGAIN)
......@@ -74,10 +74,14 @@ def snmp_get(address, oids, port=161,
sock.settimeout(prev_timeout)
else:
sock.close()
if raw_varbinds:
resp = parse_get_response_raw(data)
else:
resp = parse_get_response(data)
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:
......@@ -205,7 +209,10 @@ def snmp_count(address, oid, port=161,
else:
sock.close()
# Parse response
resp = parse_get_response(data)
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
......@@ -294,10 +301,13 @@ def snmp_getnext(address, oid, port=161,
close_socket()
raise SNMPError(code=UNREACHABLE, oid=oid)
# Parse response
if raw_varbinds:
resp = parse_get_response_raw(data)
else:
resp = parse_get_response(data)
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
......@@ -359,7 +369,10 @@ def snmp_set(address, varbinds, port=161,
sock.settimeout(None)
else:
sock.close()
resp = parse_get_response(data)
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:
......
......@@ -257,7 +257,7 @@ class BaseScript(six.with_metaclass(BaseScriptMetaclass, object)):
finally:
if not self.parent:
# Close SNMP socket when necessary
self.snmp.close()
self.close_snmp()
# Close CLI socket when necessary
self.close_cli_stream()
# Close MML socket when necessary
......@@ -855,6 +855,13 @@ class BaseScript(six.with_metaclass(BaseScriptMetaclass, object)):
self.cli_stream.close()
self.cli_stream = None
def close_snmp(self):
if self.parent:
return
if self.snmp:
self.snmp.close()
self.snmp = None
def mml(self, cmd, **kwargs):
"""
Execute MML command and return result. Initiate MML session when necessary
......
......@@ -2,10 +2,12 @@
# ----------------------------------------------------------------------
# SNMP methods implementation
# ----------------------------------------------------------------------
# Copyright (C) 2007-2015 The NOC Project
# Copyright (C) 2007-2018 The NOC Project
# See LICENSE for details
# ----------------------------------------------------------------------
# Python modules
import weakref
# Third-party modules
import tornado.ioloop
import tornado.gen
......@@ -33,7 +35,7 @@ class SNMP(object):
SNMPError = SNMPError
def __init__(self, script):
self.script = script
self._script = weakref.ref(script)
self.ioloop = None
self.result = None
self.logger = PrefixLoggerAdapter(script.logger, self.name)
......@@ -41,6 +43,10 @@ class SNMP(object):
self.timeouts = 0
self.socket = None
@property
def script(self):
return self._script()
def set_timeout_limits(self, n):
"""
Set sequental timeouts l
......@@ -120,7 +126,8 @@ class SNMP(object):
version = self._get_snmp_version(version)
self.get_ioloop().run_sync(run)
return self.result
r, self.result = self.result, None
return r
def set(self, *args):
"""
......@@ -152,7 +159,8 @@ class SNMP(object):
else:
raise ValueError("Invalid varbinds")
self.get_ioloop().run_sync(run)
return self.result
r, self.result = self.result, None
return r
def count(self, oid, filter=None, version=None):
"""
......@@ -182,7 +190,8 @@ class SNMP(object):
version = self._get_snmp_version(version)
self.get_ioloop().run_sync(run)
return self.result
r, self.result = self.result, None
return r
def getnext(self, oid, community_suffix=None,
filter=None, cached=False,
......@@ -216,7 +225,8 @@ class SNMP(object):
version = self._get_snmp_version(version)
self.get_ioloop().run_sync(run)
return self.result
r, self.result = self.result, None
return r
def get_table(self, oid, community_suffix=None, cached=False):
"""
......
......@@ -2,7 +2,7 @@
# ----------------------------------------------------------------------
# ASN.1 BER utitities
# ----------------------------------------------------------------------
# Copyright (C) 2007-2017 The NOC Project
# Copyright (C) 2007-2018 The NOC Project
# See LICENSE for details
# ----------------------------------------------------------------------
......@@ -10,11 +10,7 @@
import math
import struct
# NOC modules
from noc.speedup.ber import parse_tlv_header, parse_p_oid, encode_oid, encode_int
class DecodeError(Exception):
pass
from noc.speedup.ber import parse_tlv_header, parse_p_oid, encode_int
def did(tag_class, is_constructed, tag_id):
......@@ -51,7 +47,7 @@ class BERDecoder(object):
pt = "implicit " + pt
if tag_class:
pt += " application %d" % tag_class
raise DecodeError(
raise ValueError(
"Cannot find BER decoder for %s class %d (0x%X): %s" % (
pt, tag, tag, value.encode('hex'))
)
......@@ -137,11 +133,11 @@ class BERDecoder(object):
elif f & 0x3f == 0x03: # ISO 6093 NR3 form
return float(msg[1:]) # 0123e456
except ValueError:
raise DecodeError("Invalid REAL representation: %s" % msg[1:])
raise ValueError("Invalid REAL representation: %s" % msg[1:])
elif f & 0x40: # infinitive, 8.5.8
return float("-inf" if f & 0x01 else "inf")
else:
raise DecodeError("Unknown REAL encoding: %s" % f)
raise ValueError("Unknown REAL encoding: %s" % f)
def parse_p_bitstring(self, msg):
unused = ord(msg[0])
......@@ -427,7 +423,20 @@ class BEREncoder(object):
:param data:
:return:
"""
return encode_oid(data)
d = [int(x) for x in data.split(".")]
r = [chr(d[0] * 40 + d[1])]
for v in d[2:]:
if v < 0x7f:
r += [chr(v)]
else:
rr = []
while v:
rr += [(v & 0x7f) | 0x80]
v >>= 7
rr.reverse()
rr[-1] &= 0x7f
r += [chr(x) for x in rr]
return self.encode_tlv(6, True, "".join(r))
def decode(msg):
......
......@@ -59,6 +59,7 @@ INCONSISTENT_NAME = 18
# Virtual code
TIMED_OUT = -1
UNREACHABLE = -2
BER_ERROR = -3
class SNMPError(Exception):
......
# -*- coding: utf-8 -*-
# ---------------------------------------------------------------------
# Syslog server
# SNMP Trap Server
# ---------------------------------------------------------------------
# Copyright (C) 2007-2015 The NOC Project
# Copyright (C) 2007-2018 The NOC Project
# See LICENSE for details
# ---------------------------------------------------------------------
......@@ -13,7 +13,6 @@ import time
from noc.core.ioloop.udpserver import UDPServer
from noc.lib.escape import fm_escape
from noc.core.snmp.trap import decode_trap
from noc.core.snmp.ber import DecodeError
from noc.config import config
......@@ -32,7 +31,7 @@ class TrapServer(UDPServer):
return # Invalid event source
try:
community, varbinds = decode_trap(data)
except DecodeError as e:
except ValueError as e:
self.service.perf_metrics["error", ("type", "decode_failed")] += 1
logger.error("Failed to decode trap: %s", data.encode("hex"))
logger.error("Decoder error: %s", e)
......
......@@ -147,11 +147,11 @@ def encode_oid(bytes msg):
cdef int v = 0
cdef int nv = 0
cdef int sn = 0
cdef char x
cdef char *ptr = msg
cdef unsigned char *ptr = msg
cdef unsigned char x
cdef char[1024] out
cdef char* o_ptr = out + 2
cdef l_msg = len(msg)
cdef int l_msg = len(msg)
out[0] = 0x6 # OID primitive
# out[1] should be length
......@@ -175,7 +175,7 @@ def encode_oid(bytes msg):
o_ptr = _write_int(o_ptr, v)
# Write length
out[1] = o_ptr - out - 2
return bytes(out[:o_ptr - out])
return out[:o_ptr - out]
cdef inline int _write_raw_int(char* ptr, int value):
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment