From 339ca1c5d3c9f138a13ae82c181b001df43645eb Mon Sep 17 00:00:00 2001 From: Vijay VK Date: Tue, 27 Mar 2018 02:05:36 +0100 Subject: fix tox setup for snmptrap Change-Id: I39adcd37cab64937af182c4716cba0cfaba6c7a2 Signed-off-by: VENKATESH KUMAR Issue-ID: DCAEGEN2-271 Signed-off-by: VENKATESH KUMAR Signed-off-by: Ladue, David (dl3158) --- Dockerfile | 2 +- bin/mod/trapd_exit.py | 63 --- bin/mod/trapd_file_utils.py | 225 ---------- bin/mod/trapd_get_cbs_config.py | 118 ----- bin/mod/trapd_http_session.py | 58 --- bin/mod/trapd_logging.py | 199 --------- bin/mod/trapd_runtime_pid.py | 94 ---- bin/mod/trapd_settings.py | 169 -------- bin/snmptrapd.py | 804 ---------------------------------- bin/snmptrapd.sh | 54 --- coverage.xml | 695 +++++++++++++++++++++++++++++ pom.xml | 3 +- setup.py | 14 +- snmptrap/__init__.py | 21 + snmptrap/mod/__init__.py | 21 + snmptrap/mod/trapd_exit.py | 63 +++ snmptrap/mod/trapd_get_cbs_config.py | 118 +++++ snmptrap/mod/trapd_http_session.py | 58 +++ snmptrap/mod/trapd_io.py | 396 +++++++++++++++++ snmptrap/mod/trapd_logging.py | 199 +++++++++ snmptrap/mod/trapd_runtime_pid.py | 94 ++++ snmptrap/mod/trapd_settings.py | 169 ++++++++ snmptrap/snmptrapd.py | 817 +++++++++++++++++++++++++++++++++++ snmptrap/snmptrapd.sh | 54 +++ tests/__init__.py | 21 + tests/_test_trapd_get_cbs_config.py | 44 -- tests/conftest.py | 12 + tests/setup.py | 73 ---- tests/snmp.setup.py | 73 ++++ tests/test_snmptrapd.py | 100 +++-- tests/test_trapd_get_cbs_config.py | 61 +++ tests/test_trapd_settings.py | 73 ++++ tests/tox.ini | 15 - tox.ini | 15 + 34 files changed, 3043 insertions(+), 1952 deletions(-) delete mode 100644 bin/mod/trapd_exit.py delete mode 100644 bin/mod/trapd_file_utils.py delete mode 100644 bin/mod/trapd_get_cbs_config.py delete mode 100644 bin/mod/trapd_http_session.py delete mode 100644 bin/mod/trapd_logging.py delete mode 100644 bin/mod/trapd_runtime_pid.py delete mode 100644 bin/mod/trapd_settings.py delete mode 100644 bin/snmptrapd.py delete mode 100755 bin/snmptrapd.sh create mode 100644 coverage.xml create mode 100644 snmptrap/__init__.py create mode 100644 snmptrap/mod/__init__.py create mode 100644 snmptrap/mod/trapd_exit.py create mode 100644 snmptrap/mod/trapd_get_cbs_config.py create mode 100644 snmptrap/mod/trapd_http_session.py create mode 100644 snmptrap/mod/trapd_io.py create mode 100644 snmptrap/mod/trapd_logging.py create mode 100644 snmptrap/mod/trapd_runtime_pid.py create mode 100644 snmptrap/mod/trapd_settings.py create mode 100644 snmptrap/snmptrapd.py create mode 100644 snmptrap/snmptrapd.sh create mode 100644 tests/__init__.py delete mode 100644 tests/_test_trapd_get_cbs_config.py create mode 100644 tests/conftest.py delete mode 100644 tests/setup.py create mode 100644 tests/snmp.setup.py create mode 100644 tests/test_trapd_get_cbs_config.py create mode 100644 tests/test_trapd_settings.py delete mode 100644 tests/tox.ini create mode 100644 tox.ini diff --git a/Dockerfile b/Dockerfile index 9475936..d967b0c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,7 +12,7 @@ WORKDIR ${APPDIR} EXPOSE 162:162/udp # Copy the current directory contents into the container at ${APPDIR} -COPY ./bin/ ./bin/ +COPY ./snmptrap/ ./bin/ COPY ./etc/ ./etc/ COPY requirements.txt ./ RUN pip install -r requirements.txt diff --git a/bin/mod/trapd_exit.py b/bin/mod/trapd_exit.py deleted file mode 100644 index a7ffc8a..0000000 --- a/bin/mod/trapd_exit.py +++ /dev/null @@ -1,63 +0,0 @@ -# ============LICENSE_START======================================================= -# org.onap.dcae -# ================================================================================ -# Copyright (c) 2017-2018 AT&T Intellectual Property. All rights reserved. -# ================================================================================ -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ============LICENSE_END========================================================= -# -# ECOMP is a trademark and service mark of AT&T Intellectual Property. -# -""" -trapc_exit_snmptrapd is responsible for removing any existing runtime PID -file, and exiting with the provided (param 1) exit code -""" - -__docformat__ = 'restructuredtext' - -import sys -import os -import string -from trapd_runtime_pid import save_pid, rm_pid - -prog_name = os.path.basename(__file__) - - -# # # # # # # # # # # # # -# fx: cleanup_and_exit -# - remove pid file -# - exit with supplied return code -# # # # # # # # # # # # # -def cleanup_and_exit(_loc_exit_code, _pid_file_name): - """ - Remove existing PID file, and exit with provided exit code - :Parameters: - _loc_exit_code - value to return to calling shell upon exit - _pid_file_name - name of file that contains current process ID (for - removal) - :Exceptions: - none - :Keywords: - runtime PID exit - :Variables: - _num_params - number of parameters passed to module - """ - - _num_params = len(locals()) - - if _num_params == 2: - rc = rm_pid(_pid_file_name) - sys.exit(_loc_exit_code) diff --git a/bin/mod/trapd_file_utils.py b/bin/mod/trapd_file_utils.py deleted file mode 100644 index e62b528..0000000 --- a/bin/mod/trapd_file_utils.py +++ /dev/null @@ -1,225 +0,0 @@ -# ============LICENSE_START=======================================================) -# org.onap.dcae -# ================================================================================ -# Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. -# ================================================================================ -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ============LICENSE_END========================================================= -# -# ECOMP is a trademark and service mark of AT&T Intellectual Property. -# -""" -""" - -__docformat__ = 'restructuredtext' - -# basics -import datetime -import errno -import inspect -import json -import logging -import logging.handlers -import os -import sys -import string -import time -import traceback -import unicodedata - -# dcae_snmptrap -import trapd_settings as tds -from trapd_logging import ecomp_logger, stdout_logger -from trapd_exit import cleanup_and_exit - -prog_name = os.path.basename(__file__) - - -# # # # # # # # # # # # # # # # # # # -# fx: roll_all_logs -> roll all logs to timestamped backup -# # # # # # # # # # ## # # # # # # # - - -def roll_all_logs(): - """ - roll all active logs to timestamped version, open new one - based on frequency defined in files.roll_frequency - """ - - # first roll all the eelf files - # NOTE: this will go away when onap logging is standardized/available - try: - # open various ecomp logs - if any fails, exit - for fd in [tds.eelf_error_fd, tds.eelf_debug_fd, tds.eelf_audit_fd, - tds.eelf_metrics_fd, tds.arriving_traps_fd, tds.json_traps_fd]: - fd.close() - - roll_file(tds.eelf_error_file_name) - roll_file(tds.eelf_debug_file_name) - roll_file(tds.eelf_audit_file_name) - roll_file(tds.eelf_metrics_file_name) - - except Exception as e: - msg = "Error closing logs: " + str(e) - stdout_logger(msg) - cleanup_and_exit(1, tds.pid_file_name) - - reopened_successfully = open_eelf_logs() - if not reopened_successfully: - msg = "Error re-opening EELF logs during roll-over to timestamped versions - EXITING" - stdout_logger(msg) - cleanup_and_exit(1, tds.pid_file_name) - - # json log - roll_file(tds.json_traps_filename) - - try: - tds.json_traps_fd = open_file(tds.json_traps_filename) - except Exception as e: - msg = ("Error opening json_log %s : %s" % - (json_traps_filename, str(e))) - stdout_logger(msg) - cleanup_and_exit(1, tds.pid_file_name) - - # arriving trap log - roll_file(tds.arriving_traps_filename) - - try: - tds.arriving_traps_fd = open_file(tds.arriving_traps_filename) - except Exception as e: - msg = ("Error opening arriving traps %s : %s" % - (arriving_traps_filename, str(e))) - stdout_logger(msg) - cleanup_and_exit(1, tds.pid_file_name) - - -# # # # # # # # # # # # # # # # # # # -# fx: setup_ecomp_logs -> log in eelf format until standard -# is released for python via LOG-161 -# # # # # # # # # # ## # # # # # # # - - -def open_eelf_logs(): - """ - open various (multiple ???) logs - """ - - try: - # open various ecomp logs - if any fails, exit - - tds.eelf_error_file_name = ( - tds.c_config['files.eelf_base_dir'] + "/" + tds.c_config['files.eelf_error']) - tds.eelf_error_fd = open_file(tds.eelf_error_file_name) - - except Exception as e: - msg = "Error opening eelf error log : " + str(e) - stdout_logger(msg) - cleanup_and_exit(1, tds.pid_file_name) - - try: - tds.eelf_debug_file_name = ( - tds.c_config['files.eelf_base_dir'] + "/" + tds.c_config['files.eelf_debug']) - tds.eelf_debug_fd = open_file(tds.eelf_debug_file_name) - - except Exception as e: - msg = "Error opening eelf debug log : " + str(e) - stdout_logger(msg) - cleanup_and_exit(1, tds.pid_file_name) - - try: - tds.eelf_audit_file_name = ( - tds.c_config['files.eelf_base_dir'] + "/" + tds.c_config['files.eelf_audit']) - tds.eelf_audit_fd = open_file(tds.eelf_audit_file_name) - except Exception as e: - msg = "Error opening eelf audit log : " + str(e) - stdout_logger(msg) - cleanup_and_exit(1, tds.pid_file_name) - - try: - tds.eelf_metrics_file_name = ( - tds.c_config['files.eelf_base_dir'] + "/" + tds.c_config['files.eelf_metrics']) - tds.eelf_metrics_fd = open_file(tds.eelf_metrics_file_name) - except Exception as e: - msg = "Error opening eelf metric log : " + str(e) - stdout_logger(msg) - cleanup_and_exit(1, tds.pid_file_name) - - return True - -# # # # # # # # # # # # # # # # # # # -# fx: roll_log_file -> move provided filename to timestamped version -# # # # # # # # # # ## # # # # # # # - - -def roll_file(_loc_file_name): - """ - move active file to timestamped archive - """ - - _file_name_suffix = "%s" % (datetime.datetime.fromtimestamp(time.time()). - fromtimestamp(time.time()). - strftime('%Y-%m-%dT%H:%M:%S')) - - _loc_file_name_bak = _loc_file_name + '.' + _file_name_suffix - - # roll existing file if present - if os.path.isfile(_loc_file_name): - try: - os.rename(_loc_file_name, _loc_file_name_bak) - except Exception as e: - _msg = ("ERROR: Unable to rename %s to %s" - % (_loc_file_name, - _loc_file_name_bak)) - ecomp_logger(tds.LOG_TYPE_ERROR, tds.SEV_CRIT, - tds.CODE_GENERAL, _msg) - - -# # # # # # # # # # # # # -# fx: open_log_file -# # # # # # # # # # # # # - - -def open_file(_loc_file_name): - """ - open _loc_file_name, return file handle - """ - - try: - # open append mode just in case so nothing is lost, but should be - # non-existent file - _loc_fd = open(_loc_file_name, 'a') - return _loc_fd - except Exception as e: - msg = "Error opening " + _loc_file_name + " append mode - " + str(e) - stdout_logger(msg) - cleanup_and_exit(1, tds.pid_file_name) - - -# # # # # # # # # # # # # -# fx: close_file -# # # # # # # # # # # # # - """ - close _loc_file_name, return True with success, False otherwise - """ - - -def close_file(_loc_fd, _loc_filename): - - try: - _loc_fd.close() - return True - except Exception as e: - msg = "Error closing %s : %s - results indeterminate" % ( - _loc_filename, str(e)) - ecomp_logger(tds.LOG_TYPE_ERROR, tds.SEV_FATAL, tds.CODE_GENERAL, msg) - return False diff --git a/bin/mod/trapd_get_cbs_config.py b/bin/mod/trapd_get_cbs_config.py deleted file mode 100644 index e0f5ca8..0000000 --- a/bin/mod/trapd_get_cbs_config.py +++ /dev/null @@ -1,118 +0,0 @@ -# ============LICENSE_START======================================================= -# org.onap.dcae -# ================================================================================ -# Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. -# ================================================================================ -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ============LICENSE_END========================================================= -# -# ECOMP is a trademark and service mark of AT&T Intellectual Property. -# -""" -Look for CBS broker and return application config; if not present, look for -env variable that specifies JSON equiv of CBS config (typically used for -testing purposes) -""" - -__docformat__ = 'restructuredtext' - -import json -import os -import sys -import string -import time -import traceback -import collections - -import trapd_settings as tds -from onap_dcae_cbs_docker_client.client import get_config -from trapd_exit import cleanup_and_exit -from trapd_logging import stdout_logger - -prog_name = os.path.basename(__file__) - - -# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # -# function: trapd_get_config_sim -# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # - - -def get_cbs_config(): - """ - Get config values from CBS or JSON file (fallback) - :Parameters: - none - :Exceptions: - """ - - tds.c_config = {} - - # See if we are in a config binding service (CBS) /controller environment - try: - tds.c_config = get_config() - if tds.c_config == {}: - msg = "Unable to fetch CBS config or it is erroneously empty - trying override/simulator config" - stdout_logger(msg) - - # if no CBS present, default to JSON config specified via CBS_SIM_JSON env var - except Exception as e: - msg = "ONAP controller not present, trying json config override via CBS_SIM_JSON env variable" - stdout_logger(msg) - - try: - _cbs_sim_json_file = os.getenv("CBS_SIM_JSON", "None") - except Exception as e: - msg = "CBS_SIM_JSON not defined - FATAL ERROR, exiting" - stdout_logger(msg) - cleanup_and_exit(1, pid_file_name) - - if _cbs_sim_json_file == "None": - msg = "CBS_SIM_JSON not defined - FATAL ERROR, exiting" - stdout_logger(msg) - cleanup_and_exit(1, pid_file_name) - else: - msg = ("ONAP controller override specified via CBS_SIM_JSON: %s" % - _cbs_sim_json_file) - stdout_logger(msg) - try: - tds.c_config = json.load(open(_cbs_sim_json_file)) - except Exception as e: - msg = "Unable to load CBS_SIM_JSON " + _cbs_sim_json_file + \ - " (invalid json?) - FATAL ERROR, exiting" - stdout_logger(msg) - cleanup_and_exit(1, tds.pid_file_name) - - # recalc timeout, set default if not present - try: - tds.timeout_seconds = tds.c_config['publisher.http_timeout_milliseconds'] / 1000.0 - except Exception as e: - tds.timeout_seconds = 1.5 - - # recalc seconds_between_retries, set default if not present - try: - tds.seconds_between_retries = tds.c_config['publisher.http_milliseconds_between_retries'] / 1000.0 - except Exception as e: - tds.seconds_between_retries = .750 - - # recalc min_severity_to_log, set default if not present - try: - tds.minimum_severity_to_log = tds.c_config['files.minimum_severity_to_log'] - except Exception as e: - tds.minimum_severity_to_log = 3 - - try: - tds.publisher_retries = tds.c_config['publisher.http_retries'] - except Exception as e: - tds.publisher_retries = 3 - - return True diff --git a/bin/mod/trapd_http_session.py b/bin/mod/trapd_http_session.py deleted file mode 100644 index b34c19d..0000000 --- a/bin/mod/trapd_http_session.py +++ /dev/null @@ -1,58 +0,0 @@ -# ============LICENSE_START======================================================= -# org.onap.dcae -# ================================================================================ -# Copyright (c) 2017-2018 AT&T Intellectual Property. All rights reserved. -# ================================================================================ -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ============LICENSE_END========================================================= -# -# ECOMP is a trademark and service mark of AT&T Intellectual Property. -# -""" -trapd_http_session establishes an http session for future use in publishing -messages to the dmaap cluster. -""" - -__docformat__ = 'restructuredtext' - -import os -import requests -import traceback - -prog_name = os.path.basename(__file__) - - -# # # # # # # # # # # # # -# fx: init_session_obj -# # # # # # # # # # # # # -def init_session_obj(): - """ - Initializes and returns a http request session object for later use - :Parameters: - none - :Exceptions: - session object creation - this function will throw an exception if unable to create - a new session object - :Keywords: - http request session - :Variables: - none - """ - - try: - _loc_session = requests.Session() - except Exception as e: - return None - - return _loc_session diff --git a/bin/mod/trapd_logging.py b/bin/mod/trapd_logging.py deleted file mode 100644 index ae5a1a0..0000000 --- a/bin/mod/trapd_logging.py +++ /dev/null @@ -1,199 +0,0 @@ -# ============LICENSE_START=======================================================) -# org.onap.dcae -# ================================================================================ -# Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. -# ================================================================================ -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ============LICENSE_END========================================================= -# -# ECOMP is a trademark and service mark of AT&T Intellectual Property. -# -""" -""" - -__docformat__ = 'restructuredtext' - -# basics -import datetime -import errno -import inspect -import json -import logging -import logging.handlers -import os -import sys -import string -import time -import traceback -import unicodedata - -import trapd_settings as tds - -prog_name = os.path.basename(__file__) - - -# # # # # # # # # # # # # # # # # # # -# fx: ecomp_logger -> log in eelf format until standard -# is released for python via LOG-161 -# # # # # # # # # # ## # # # # # # # - -def ecomp_logger(_log_type, _sev, _error_code, _msg): - """ - Log to ecomp-style logfiles. Logs include: - - Note: this will be updated when https://jira.onap.org/browse/LOG-161 - is closed/available; until then, we resort to a generic format with - valuable info in "extra=" field (?) - - :Parameters: - _msg - - :Exceptions: - none - :Keywords: - eelf logging - :Log Styles: - - :error.log: - - if CommonLogger.verbose: print("using CommonLogger.ErrorFile") - self._logger.log(50, '%s|%s|%s|%s|%s|%s|%s|%s|%s|%s' \ - % (requestID, threadID, serviceName, partnerName, targetEntity, targetServiceName, - errorCategory, errorCode, errorDescription, detailMessage)) - - error.log example: - - 2018-02-20T07:21:34,007+00:00||MainThread|snmp_log_monitor||||FATAL|900||Tue Feb 20 07:21:11 UTC 2018 CRITICAL: [a0cae74e-160e-11e8-8f9f-0242ac110002] ALL publish attempts failed to DMAPP server: dcae-mrtr-zltcrdm5bdce1.1dff83.rdm5b.tci.att.com, topic: DCAE-COLLECTOR-UCSNMP, 339 trap(s) not published in epoch_serno range: 15191112530000 - 15191112620010 - - :debug.log: - - if CommonLogger.verbose: print("using CommonLogger.DebugFile") - self._logger.log(50, '%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s' \ - % (requestID, threadID, serverName, serviceName, instanceUUID, upperLogLevel, - severity, serverIPAddress, server, IPAddress, className, timer, detailMessage)) - - debug.log example: - - none available - - :audit.log: - - if CommonLogger.verbose: print("using CommonLogger.AuditFile") - endAuditTime, endAuditMsec = self._getTime() - if self._begTime is not None: - d = {'begtime': self._begTime, 'begmsecs': self._begMsec, 'endtime': endAuditTime, - 'endmsecs': endAuditMsec} - else: - d = {'begtime': endAuditTime, 'begmsecs': endAuditMsec, 'endtime': endAuditTime, - 'endmsecs': endAuditMsec} - - self._logger.log(50, '%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s' \ - % (requestID, serviceInstanceID, threadID, serverName, serviceName, partnerName, - statusCode, responseCode, responseDescription, instanceUUID, upperLogLevel, - severity, serverIPAddress, timer, server, IPAddress, className, unused, - processKey, customField1, customField2, customField3, customField4, - detailMessage), extra=d) - - - :metrics.log: - - self._logger.log(50,'%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s' \ - % (requestID, serviceInstanceID, threadID, serverName, serviceName, partnerName, - targetEntity, targetServiceName, statusCode, responseCode, responseDescription, - instanceUUID, upperLogLevel, severity, serverIPAddress, timer, server, - IPAddress, - className, unused, processKey, targetVirtualEntity, customField1, customField2, - customField3, customField4, detailMessage), extra=d) - - metrics.log example: - - none available - - - """ - - unused = "" - - # ct = time.time() - # lt = time.localtime(ct) - # t_hman = time.strftime(DateFmt, lt) - # t_ms = (ct - int(ct)) * 1000 - # above were various attempts at setting time string found in other - # libs; instead, let's keep it real: - t_out = datetime.datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%S,%f")[:-3] - calling_fx = inspect.stack()[1][3] - - # FIXME: this entire module is a hack to override concept of prog logging - # written across multiple files (???), making diagnostics IMPOSSIBLE! - # Hoping to leverage ONAP logging libraries & standards when available - - # catch invalid log type - if _log_type < 1 or _log_type > 5: - msg = ("INVALID log type: %s " % _log_type) - _out_rec = ("%s|%s|%s|%s|%s|%s|%s|%s|%s|%s" - % ((t_out, calling_fx, "snmptrapd", unused, unused, unused, tds.SEV_TYPES[_sev], _error_code, unused, (msg + _msg)))) - tds.eelf_error_fd.write('%s\n' % str(_out_rec)) - return False - - if _sev >= tds.minimum_severity_to_log: - # log to appropriate eelf log (different files ??) - if _log_type == tds.LOG_TYPE_ERROR: - _out_rec = ('%s|%s|%s|%s|%s|%s|%s|%s|%s|%s' - % ((t_out, calling_fx, "snmptrapd", unused, unused, unused, tds.SEV_TYPES[_sev], _error_code, unused, _msg))) - tds.eelf_error_fd.write('%s\n' % str(_out_rec)) - elif _log_type == tds.LOG_TYPE_AUDIT: - # log message in AUDIT format - _out_rec = ('%s|%s|%s|%s|%s|%s|%s|%s|%s|%s' - % ((t_out, calling_fx, "snmptrapd", unused, unused, unused, tds.SEV_TYPES[_sev], _error_code, unused, _msg))) - tds.eelf_audit_fd.write('%s\n' % str(_out_rec)) - elif _log_type == tds.LOG_TYPE_METRICS: - # log message in METRICS format - _out_rec = ('%s|%s|%s|%s|%s|%s|%s|%s|%s|%s' - % ((t_out, calling_fx, "snmptrapd", unused, unused, unused, tds.SEV_TYPES[_sev], _error_code, unused, _msg))) - tds.eelf_metrics_fd.write('%s\n' % str(_out_rec)) - - # DEBUG *AND* others - there *MUST BE* a single time-sequenced log for diagnostics! - # FIXME: too much I/O !!! - # always write to debug; we need ONE logfile that has time-sequence full view !!! - # if (_log_type == tds.LOG_TYPE_DEBUG and _sev >= tds.current_min_sev_log_level) or (_log_type != tds.LOG_TYPE_DEBUG): - - # log message in DEBUG format - _out_rec = ("%s|%s|%s|%s|%s|%s|%s|%s|%s|%s" - % ((t_out, calling_fx, "snmptrapd", unused, unused, unused, tds.SEV_TYPES[_sev], _error_code, unused, _msg))) - tds.eelf_debug_fd.write('%s\n' % str(_out_rec)) - - return True - -# # # # # # # # # # # # # -# fx: stdout_logger -# # # # # # # # # # # # # - - -def stdout_logger(_msg): - """ - Log info/errors to stdout. This is done: - - for critical runtime issues - - :Parameters: - _msg - message to print - :Exceptions: - none - :Keywords: - log stdout - :Variables: - """ - - t_out = datetime.datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%S,%f")[:-3] - # calling_fx = inspect.stack()[1][3] - - print('%s %s' % (t_out, _msg)) diff --git a/bin/mod/trapd_runtime_pid.py b/bin/mod/trapd_runtime_pid.py deleted file mode 100644 index c6ef76e..0000000 --- a/bin/mod/trapd_runtime_pid.py +++ /dev/null @@ -1,94 +0,0 @@ -# ============LICENSE_START======================================================= -# org.onap.dcae -# ================================================================================ -# Copyright (c) 2017-2018 AT&T Intellectual Property. All rights reserved. -# ================================================================================ -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ============LICENSE_END========================================================= -# -# ECOMP is a trademark and service mark of AT&T Intellectual Property. -# -""" -trapd_runtime_pid maintains a 'PID file' (file that contains the -PID of currently running trap receiver) -""" - -__docformat__ = 'restructuredtext' - -import logging -import os -import string -import time -import traceback - -prog_name = os.path.basename(__file__) - - -# # # # # # # # # # # # # -# fx: save_pid - save PID of running process -# # # # # # # # # # # # # -def save_pid(_pid_file_name): - """ - Save the current process ID in a file for external - access. - :Parameters: - none - :Exceptions: - file open - this function will catch exception of unable to - open/create _pid_file_name - :Keywords: - pid /var/run - """ - - try: - pid_fd = open(_pid_file_name, 'w') - pid_fd.write('%d' % os.getpid()) - pid_fd.close() - except IOError: - print("IOError saving PID file %s :" % _pid_file_name) - return False - # except: - # print("Error saving PID file %s :" % _pid_file_name) - # return False - else: - # print("Runtime PID file: %s" % _pid_file_name) - return True - - -# # # # # # # # # # # # # -# fx: rm_pid - remove PID of running process -# # # # # # # # # # # # # -def rm_pid(_pid_file_name): - """ - Remove the current process ID file before exiting. - :Parameters: - none - :Exceptions: - file open - this function will catch exception of unable to find or remove - _pid_file_name - :Keywords: - pid /var/run - """ - - try: - if os.path.isfile(_pid_file_name): - os.remove(_pid_file_name) - return True - else: - return False - - except IOError: - print("Error removing Runtime PID file: %s" % _pid_file_name) - return False diff --git a/bin/mod/trapd_settings.py b/bin/mod/trapd_settings.py deleted file mode 100644 index be87e26..0000000 --- a/bin/mod/trapd_settings.py +++ /dev/null @@ -1,169 +0,0 @@ -# ============LICENSE_START=======================================================) -# org.onap.dcae -# ================================================================================ -# Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. -# ================================================================================ -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ============LICENSE_END========================================================= -# -# ECOMP is a trademark and service mark of AT&T Intellectual Property. -# -""" -""" - -__docformat__ = 'restructuredtext' - - -def init(): - - # - # consul config or simulated via json file - global c_config - c_config = None - # - - # - # - # dns_cache_ip_to_name - # key [ip address] -> fqdn - # dns_cache_ip_expires - # key [ip address] -> epoch time this entry expires and must - # be reloaded - global dns_cache_ip_to_name - dns_cache_ip_to_name = {} - global dns_cache_ip_expires - dns_cache_ip_expires = {} - # - - # - global eelf_error_file_name - eelf_error_file_name = "" - global eelf_error_fd - eelf_error_fd = None - - global eelf_debug_file_name - eelf_debug_file_name = "" - global eelf_debug_fd - eelf_debug_fd = None - - global eelf_audit_file_name - eelf_audit_file_name = "" - global eelf_audit_fd - eelf_audit_fd = None - - global eelf_metrics_file_name - eelf_metrics_file_name = "" - global eelf_metrics_fd - eelf_metrics_fd = None - - global last_minute - last_minute = 0 - global last_hour - last_hour = 0 - global last_day - last_day = 0 - # - - # - - # - global traps_in_minute - traps_in_minute = 0 - global last_epoch_second - last_epoch_second = 0 - global traps_since_last_publish - traps_since_last_publish = 0 - global last_pub_time - last_pub_time = 0 - global milliseconds_since_last_publish - milliseconds_since_last_publish = 0 - global timeout_seconds - timeout_seconds = 1.5 - global seconds_between_retries - seconds_between_retries = 2 - global publisher_retries - publisher_retries = 2 - # - - # - global http_requ_session - http_requ_session = None - # - - # - global json_traps_filename - json_log_filename = "" - global json_traps_fd - json_fd = None - # - - # - global arriving_traps_filename - arriving_traps_filename = "" - global arriving_traps_fd - arriving_traps_fd = None - # - - # - global pid_file_name - pid_file_name = "" - - # - global LOG_TYPES - global LOG_TYPE_NONE - global LOG_TYPE_ERROR - global LOG_TYPE_DEBUG - global LOG_TYPE_AUDIT - global LOG_TYPE_METRICS - LOG_TYPES = ["none", "ERROR", "DEBUG", "AUDIT", "METRICS"] - LOG_TYPE_NONE = 0 - LOG_TYPE_ERROR = 1 - LOG_TYPE_DEBUG = 2 - LOG_TYPE_AUDIT = 3 - LOG_TYPE_METRICS = 4 - - global SEV_TYPES - global SEV_NONE - global SEV_DETAILED - global SEV_INFO - global SEV_WARN - global SEV_CRIT - global SEV_FATAL - SEV_TYPES = ["none", "DETAILED", "INFO", "WARN", "CRITICAL", "FATAL"] - SEV_NONE = 0 - SEV_DETAILED = 1 - SEV_INFO = 2 - SEV_WARN = 3 - SEV_CRIT = 4 - SEV_FATAL = 5 - - global CODE_GENERAL - CODE_GENERAL = "100" - - global minimum_severity_to_log - minimum_severity_to_log = 3 - - # diff --git a/bin/snmptrapd.py b/bin/snmptrapd.py deleted file mode 100644 index 3765746..0000000 --- a/bin/snmptrapd.py +++ /dev/null @@ -1,804 +0,0 @@ -# ============LICENSE_START=======================================================) -# org.onap.dcae -# ================================================================================ -# Copyright (c) 2017-2018 AT&T Intellectual Property. All rights reserved. -# ================================================================================ -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ============LICENSE_END========================================================= -# -# ECOMP is a trademark and service mark of AT&T Intellectual Property. -# -""" -dcae_snmptrapd is responsible for SNMP trap receipt and publishing activities. -It's behavior is controlled by CBS (config binding service) using a -JSON construct obtained via a "get_config" call or (for testing/standalone -purposes) a file specified using the env variable "CBS_SIM_JSON". - -As traps arrive they are decomposed and transformed into a JSON message which -is published to a dmaap instance that has been defined by controller. - -:Parameters: - usage: snmptrapd.py [-v] -:Keywords: - onap dcae snmp trap publish dmaap -""" - -__docformat__ = 'restructuredtext' - -# basics -import argparse -import array -import asyncio -from collections import Counter -import datetime -import errno -import inspect -import json -import logging -import logging.handlers -import os -import pprint -import requests -import re -import sys -import signal -import string -import socket -import time -import traceback -import unicodedata -import uuid as uuid_mod - -# pysnmp -from pysnmp.entity import engine, config -from pysnmp.carrier.asyncio.dgram import udp, udp6 -# from pysnmp.carrier.asyncore.dgram import udp -from pysnmp.entity.rfc3413 import ntfrcv -from pysnmp.proto.api import v2c - -# dcae_snmptrap -import trapd_settings as tds -from trapd_runtime_pid import save_pid, rm_pid -from trapd_get_cbs_config import get_cbs_config -from trapd_exit import cleanup_and_exit -from trapd_http_session import init_session_obj - -from trapd_file_utils import roll_all_logs, open_eelf_logs, roll_file, open_file, close_file -from trapd_logging import ecomp_logger, stdout_logger - -prog_name = os.path.basename(__file__) -verbose = False - -# # # # # # # # # # # -# fx: usage_err -# # # # # # # # # # # - - -def usage_err(): - """ - Notify of incorrect (argument) usage - :Parameters: - none - :Exceptions: - none - :Keywords: - usage args - """ - - print('Incorrect usage invoked. Correct usage:') - print(' %s [-v]' % prog_name) - cleanup_and_exit(1, "undefined") - - -# # # # # # # # # # # # # # # # # # # -# fx: load_all_configs -# # # # # # # # # # ## # # # # # # # - - -def load_all_configs(_signum, _frame): - """ - Calls individual functions to read various config files required. This - function is called directly (e.g. at startup) and is also registered - with signal handling (e.g. kill -sigusr1 ) - - :Parameters: - signum and frame (only present when called via signal to running process) - :Exceptions: - none - :Keywords: - config files - :Variables: - yaml_conf_file - rs - """ - - if int(_signum) != 0: - msg = ("received signal %s at frame %s; re-reading configs" - % (_signum, _frame)) - ecomp_logger(tds.LOG_TYPE_DEBUG, tds.SEV_DETAILED, - tds.CODE_GENERAL, msg) - - # Initialize dmaap requests session object. Close existing session - # if applicable. - if tds.http_requ_session is not None: - tds.http_requ_session.close() - - tds.http_requ_session = init_session_obj() - if tds.http_requ_session is None: - msg = "Unable to create new http session - FATAL ERROR, exiting" - ecomp_logger(tds.LOG_TYPE_ERROR, tds.SEV_FATAL, tds.CODE_GENERAL, msg) - stdout_logger(msg) - cleanup_and_exit(1, tds.pid_file_name) - - # re-request config from config binding service - # (either broker, or json file override) - if not get_cbs_config(): - msg = "error (re)loading CBS config - FATAL ERROR, exiting" - stdout_logger(msg) - cleanup_and_exit(1, tds.pid_file_name) - - -# # # # # # # # # # # # # -# fx: log_all_arriving_traps -# # # # # # # # # # # # # - - -def log_all_arriving_traps(): - - # roll logs as needed/defined in files.roll_frequency - if tds.c_config['files.roll_frequency'] == "minute": - curr_minute = datetime.datetime.now().minute - if curr_minute != tds.last_minute: - roll_all_logs() - tds.last_minute = curr_minute - elif tds.c_config['files.roll_frequency'] == "hour": - curr_hour = datetime.datetime.now().hour - if curr_hour != tds.last_hour: - roll_all_logs() - tds.last_hour = curr_hour - else: - # otherwise, assume daily roll - curr_day = datetime.datetime.now().day - if curr_day != tds.last_day: - roll_all_logs() - tds.last_day = curr_day - - # now log latest arriving trap - try: - # going for: - # 1520971776 Tue Mar 13 16:09:36 2018; 1520971776 2018-03-13 16:09:36 DCAE-COLLECTOR-UCSNMP 15209717760049 .1.3.6.1.4.1.2636.4.1.6 gfpmt5pcs10.oss.att.com 135.91.10.139 12.123.1.240 12.123.1.240 2 varbinds: [0] .1.3.6.1.2.1.1.3.0 {10} 1212058366 140 days, 6:49:43.66 [1] .1.3.6.1.6.3.1.1.4.1.0 {6} .1.3.6.1.4.1.2636.4.1.6 [2] .1.3.6.1.4.1.2636.3.1.15.1.1.2.4.0.0 {2} 2 [3] .1.3.6.1.4.1.2636.3.1.15.1.2.2.4.0.0 {2} 4 [4] .1.3.6.1.4.1.2636.3.1.15.1.3.2.4.0.0 {2} 0 [5] .1.3.6.1.4.1.2636.3.1.15.1.4.2.4.0.0 {2} 0 [6] .1.3.6.1.4.1.2636.3.1.15.1.5.2.4.0.0 {4} PEM 3 [7] .1.3.6.1.4.1.2636.3.1.15.1.6.2.4.0.0 {2} 7 [8] .1.3.6.1.4.1.2636.3.1.15.1.7.2.4.0.0 {2} 4 [9] .1.3.6.1.6.3.18.1.3.0 {7} 12.123.1.240 - - tds.arriving_traps_fd.write('%s %s; %s %s %s %s %s %s %s %s %s %s %s\n' % - (tds.trap_dict["time received"], - time.strftime( - "%a %b %d %H:%M:%S %Y", time.localtime(time.time())), - time.strftime("%a %b %d %H:%M:%S %Y", time.localtime( - tds.trap_dict["time received"])), - tds.trap_dict["trap category"], - tds.trap_dict["epoch_serno"], - tds.trap_dict["notify OID"], - tds.trap_dict["agent name"], - tds.trap_dict["agent address"], - tds.trap_dict["cambria.partition"], - tds.trap_dict["protocol version"], - tds.trap_dict["sysUptime"], - tds.trap_dict["uuid"], - tds.all_vb_json_str)) - - except Exception as e: - msg = "Error writing to %s : %s - arriving trap %s NOT LOGGED" % ( - tds.arriving_traps_filename, str(e), tds.trap_dict["uuid"]) - ecomp_logger(tds.LOG_TYPE_ERROR, tds.SEV_CRIT, tds.CODE_GENERAL, msg) - - -# # # # # # # # # # # # # -# fx: log_published_messages -# # # # # # # # # # # # # - - -def log_published_messages(_post_data_enclosed): - - # FIXME: should keep data dictionary of Fd's open, and reference those vs. - # repeatedly opening append-mode - - msg = "adding trap UUID %s to json log" % tds.trap_dict["uuid"] - ecomp_logger(tds.LOG_TYPE_DEBUG, tds.SEV_INFO, tds.CODE_GENERAL, msg) - - try: - tds.json_traps_fd.write('%s\n' % _post_data_enclosed) - msg = "successfully logged json for %s to %s" % ( - tds.trap_dict["uuid"], tds.json_traps_filename) - ecomp_logger(tds.LOG_TYPE_DEBUG, tds.SEV_DETAILED, - tds.CODE_GENERAL, msg) - except Exception as e: - msg = "Error writing to %s : %s - trap %s NOT LOGGED" % ( - tds.json_traps_filename, str(e), tds.trap_dict["uuid"]) - ecomp_logger(tds.LOG_TYPE_ERROR, tds.SEV_CRIT, tds.CODE_GENERAL, msg) - - -# # # # # # # # # # # # # -# fx: post_dmaap -# # # # # # # # # # # # # - - -def post_dmaap(): - """ - Publish trap daata in json format to dmaap - :Parameters: - :Exceptions: - none - :Keywords: - http post dmaap json message - :Variables: - """ - - http_headers = {"Content-type": "application/json"} - - if tds.http_requ_session is None: - msg = "tds.http_requ_session is None - getting new (%s)" % tds.http_requ_session - ecomp_logger(tds.LOG_TYPE_DEBUG, tds.SEV_DETAILED, - tds.CODE_GENERAL, msg) - tds.http_requ_session = init_session_obj() - - # if only 1 trap, ship as-is - if tds.traps_since_last_publish == 1: - post_data_enclosed = tds.all_traps_str - else: - # otherwise, add brackets around package - post_data_enclosed = '[' + tds.all_traps_str + ']' - - msg = "post_data_enclosed: %s" % (post_data_enclosed) - ecomp_logger(tds.LOG_TYPE_DEBUG, tds.SEV_DETAILED, tds.CODE_GENERAL, msg) - - k = 0 - dmaap_pub_success = False - - while not dmaap_pub_success and k < (int(tds.c_config['publisher.http_retries'])): - try: - if tds.c_config['streams_publishes']['sec_fault_unsecure']['aaf_username'] == "" or tds.c_config['streams_publishes']['sec_fault_unsecure']['aaf_username'] is None: - msg = "%d trap(s) : %s - attempt %d (unsecure)" % ( - tds.traps_since_last_publish, tds.trap_uuids_in_buffer, k) - ecomp_logger(tds.LOG_TYPE_DEBUG, tds.SEV_DETAILED, - tds.CODE_GENERAL, msg) - http_resp = tds.http_requ_session.post(tds.c_config['streams_publishes']['sec_fault_unsecure']['dmaap_info']['topic_url'], post_data_enclosed, - headers=http_headers, - timeout=tds.timeout_seconds) - else: - msg = "%d trap(s) : %s - attempt %d (secure)" % ( - tds.traps_since_last_publish, tds.trap_uuids_in_buffer, k) - ecomp_logger(tds.LOG_TYPE_DEBUG, tds.SEV_DETAILED, - tds.CODE_GENERAL, msg) - http_resp = tds.http_requ_session.post(tds.c_config['streams_publishes']['sec_fault_unsecure']['dmaap_info']['topic_url'], post_data_enclosed, - auth=(tds.c_config['streams_publishes']['sec_fault_unsecure']['aaf_username'], - tds.c_config['streams_publishes']['sec_fault_unsecure']['aaf_password']), - headers=http_headers, - timeout=tds.timeout_seconds) - - if http_resp.status_code == requests.codes.ok: - # msg = "%d trap(s) : %s successfully published - response from %s: %d %s" % (traps_since_last_publish, trap_uuids_in_buffer, ((c_config['streams_publishes']['sec_fault_unsecure']['dmaap_info']['topic_url']).split('/')[2][:-5]) ,http_resp.status_code, http_resp.text) - msg = "%d trap(s) successfully published: %s" % ( - tds.traps_since_last_publish, tds.trap_uuids_in_buffer) - ecomp_logger(tds.LOG_TYPE_METRICS, tds.SEV_INFO, - tds.CODE_GENERAL, msg) - log_published_messages(post_data_enclosed) - tds.last_pub_time = time.time() - dmaap_pub_success = True - break - else: - msg = "Trap(s) %s publish attempt %d returned non-normal: %d %s" % ( - tds.trap_uuids_in_buffer, k, http_resp.status_code, http_resp.text) - ecomp_logger(tds.LOG_TYPE_ERROR, tds.SEV_WARN, - tds.CODE_GENERAL, msg) - - except OSError as e: - msg = "OS exception while attempting to post %s attempt %s: (%s) %s %s" % ( - tds.trap_uuids_in_buffer, k, e.errno, e.strerror, str(e)) - ecomp_logger(tds.LOG_TYPE_ERROR, tds.SEV_WARN, - tds.CODE_GENERAL, msg) - - except requests.exceptions.RequestException as e: - msg = "Requests exception while attempting to post %s attempt %d: (%d) %s" % ( - tds.trap_uuids_in_buffer, int(k), int(e.errno), str(e.strerror)) - ecomp_logger(tds.LOG_TYPE_ERROR, tds.SEV_WARN, - tds.CODE_GENERAL, msg) - - k += 1 - - if k < tds.c_config['publisher.http_retries']: - msg = "sleeping %.4f seconds and retrying" % ( - tds.seconds_between_retries) - ecomp_logger(tds.LOG_TYPE_DEBUG, tds.SEV_DETAILED, - tds.CODE_GENERAL, msg) - time.sleep(tds.seconds_between_retries) - else: - break - - if not dmaap_pub_success: - msg = "ALL publish attempts failed for traps %s to URL %s "\ - % (tds.trap_uuids_in_buffer, tds.c_config['streams_publishes']['sec_fault_unsecure']['dmaap_info']['topic_url']) - ecomp_logger(tds.LOG_TYPE_ERROR, tds.SEV_CRIT, tds.CODE_GENERAL, msg) - - # FIXME: This currently tries, then logs error and trashes buffer if all dmaap attempts fail. Better way? - tds.traps_since_last_publish = 0 - tds.trap_uuids_in_buffer = "" - tds.all_traps_str = "" - tds.first_trap = True - -# # # # # # # # # # # # # # # # # # # -# fx: request_observer for community string rewrite -# # # # # # # # # # # # # # # # # # # - - -def comm_string_rewrite_observer(snmpEngine, execpoint, variables, cbCtx): - - # match ALL community strings - if re.match('.*', str(variables['communityName'])): - # msg = "Rewriting communityName '%s' from %s into 'public'" % (variables['communityName'], ':'.join([str(x) for x in - # variables['transportInformation'][1]])) - # ecomp_logger(eelf_debug_fd, eelf_debug_fd, tds.LOG_TYPE_DEBUG, tds.SEV_INFO, tds.CODE_GENERAL, msg) - variables['communityName'] = variables['communityName'].clone('public') - -# # # # # # # # # # # # # # # # # # # -# fx: snmp_engine_observer_cb -# callback for when trap is received -# # # # # # # # # # # # # # # # # # # - - -def snmp_engine_observer_cb(snmp_engine, execpoint, variables, cbCtx): - """ - Decompose trap attributes and load in dictionary which is later used to - create json string for publishing to dmaap. - :Parameters: - snmp_engine - snmp engine created to listen for arriving traps - execpoint - point in code that snmp_engine_observer_cb was invoked - variables - trap attributes - cbCtx - callback context - :Exceptions: - none - :Keywords: - UEB non-AAF legacy http post - :Variables: - """ - - # init dictionary on new trap - tds.trap_dict = {} - - # assign uuid to trap - tds.trap_dict["uuid"] = str(uuid_mod.uuid1()) - - # ip and hostname - ip_addr_str = str(variables['transportAddress'][0]) - tds.trap_dict["agent address"] = ip_addr_str - - msg = 'snmp trap arrived from %s, assigned uuid: %s' % \ - (ip_addr_str, tds.trap_dict["uuid"]) - ecomp_logger(tds.LOG_TYPE_DEBUG, tds.SEV_DETAILED, tds.CODE_GENERAL, msg) - - try: - if int(tds.dns_cache_ip_expires[ip_addr_str] < int(time.time())): - raise Exception('cache expired for %s at %d - updating value' % - (ip_addr_str, (tds.dns_cache_ip_expires[ip_addr_str]))) - else: - tds.trap_dict["agent name"] = tds.dns_cache_ip_to_name[ip_addr_str] - except Exception as e: - msg = "dns cache expired or missing for %s - refreshing" % ip_addr_str - ecomp_logger(tds.LOG_TYPE_DEBUG, tds.SEV_DETAILED, - tds.CODE_GENERAL, msg) - try: - agent_fqdn, alias, addresslist = socket.gethostbyaddr(ip_addr_str) - except Exception as e: - agent_fqdn = ip_addr_str - - tds.trap_dict["agent name"] = agent_fqdn - - tds.dns_cache_ip_to_name[ip_addr_str] = agent_fqdn - tds.dns_cache_ip_expires[ip_addr_str] = ( - time.time() + tds.c_config['cache.dns_cache_ttl_seconds']) - msg = "cache for %s (%s) updated - set to expire at %d" % \ - (agent_fqdn, ip_addr_str, tds.dns_cache_ip_expires[ip_addr_str]) - ecomp_logger(tds.LOG_TYPE_DEBUG, tds.SEV_DETAILED, - tds.CODE_GENERAL, msg) - - tds.trap_dict["cambria.partition"] = str(tds.trap_dict["agent name"]) - # do not include cleartext community in pub - tds.trap_dict["community"] = "" - tds.trap_dict["community len"] = 0 - - # FIXME.CHECK_WITH_DOWNSTREAM_CONSUMERS: get rid of round for millisecond val - # epoch_second = int(round(time.time())) - epoch_msecond = time.time() - epoch_second = int(round(epoch_msecond)) - if epoch_second == tds.last_epoch_second: - tds.traps_in_epoch += 1 - else: - tds.traps_in_epoch = 0 - tds.last_epoch_second = epoch_second - traps_in_epoch_04d = format(tds.traps_in_epoch, '04d') - tds.trap_dict['epoch_serno'] = int( - (str(epoch_second) + str(traps_in_epoch_04d))) - - snmp_version = variables['securityModel'] - if snmp_version == 1: - tds.trap_dict["protocol version"] = "v1" - else: - if snmp_version == 2: - tds.trap_dict["protocol version"] = "v2c" - else: - if snmp_version == 3: - tds.trap_dict["protocol version"] = "v3" - else: - tds.trap_dict["protocol version"] = "unknown" - - if snmp_version == 3: - tds.trap_dict["protocol version"] = "v3" - tds.trap_dict["security level"] = str(variables['securityLevel']) - tds.trap_dict["context name"] = str( - variables['contextName'].prettyPrint()) - tds.trap_dict["security name"] = str(variables['securityName']) - tds.trap_dict["security engine"] = str( - variables['contextEngineId'].prettyPrint()) - tds.trap_dict['time received'] = epoch_msecond - tds.trap_dict['trap category'] = ( - tds.c_config['streams_publishes']['sec_fault_unsecure']['dmaap_info']['topic_url']).split('/')[-1] - - -# # # # # # # # # # # # # # # # # # # -# fx: request_observer for community string rewrite -# # # # # # # # # # # # # # # # # # # -def add_varbind_to_json(vb_idx, vb_oid, vb_type, vb_val): - """ - Called for each varbind, adds individual attributes of varbind instance to - vb_json_str. vb_json_str will be added to curr_trap_json_str prior to publish. - :Parameters: - vb_idx - index to specific varbind being processed - vb_oid - the varbind oid - vb_val - the value of the varbind - :Exceptions: - none - :Keywords: - varbind extract json - :Variables: - """ - - _individual_vb_dict = {} - - if tds.trap_dict["protocol version"] == "v2c": - # if v2c and first 2 varbinds, special handling required - e.g. put - # in trap_dict, not vb_json_str - if vb_idx == 0: - tds.trap_dict["sysUptime"] = str(vb_val.prettyPrint()) - return True - else: - if vb_idx == 1: - tds.trap_dict["notify OID"] = str(vb_val.prettyPrint()) - tds.trap_dict["notify OID len"] = ( - tds.trap_dict["notify OID"].count('.') + 1) - return True - if tds.first_varbind: - tds.all_vb_json_str = ', \"varbinds\": [' - tds.first_varbind = False - else: - # all_vb_json_str = ''.join([all_vb_json_str, ' ,']) - # all_vb_json_str = "%s ," % all_vb_json_str - tds.all_vb_json_str = tds.all_vb_json_str + " ," - - _individual_vb_dict.clear() - _individual_vb_dict['varbind_oid'] = vb_oid.prettyPrint() - _individual_vb_dict['varbind_type'] = vb_type - _individual_vb_dict['varbind_value'] = vb_val.prettyPrint() - - _individual_vb_json_str = json.dumps(_individual_vb_dict) - - # all_vb_json_str = "%s%s" % (all_vb_json_str, individual_vb_json_str) - # all_vb_json_str = ''.join([all_vb_json_str, individual_vb_json_str]) - tds.all_vb_json_str = tds.all_vb_json_str + _individual_vb_json_str - return True - - -# Callback function for receiving notifications -# noinspection PyUnusedLocal,PyUnusedLocal,PyUnusedLocal -def notif_receiver_cb(snmp_engine, stateReference, contextEngineId, contextName, - varBinds, cbCtx): - """ - Callback executed when trap arrives - :Parameters: - snmp_engine - snmp engine created to listen for arriving traps - stateReference - contextEngineId - contextName - varBinds - trap varbinds - why we are here - cbCtx - callback context - :Exceptions: - none - :Keywords: - callback trap arrival - :Variables: - """ - - msg = "processing varbinds for %s" % (tds.trap_dict["uuid"]) - ecomp_logger(tds.LOG_TYPE_DEBUG, tds.SEV_DETAILED, tds.CODE_GENERAL, msg) - - # FIXME update reset location when batching publishes - vb_idx = 0 - - # For reference: - # - # print('\nvarBinds ==> %s' % (varBinds)) - # - # varBinds ==> [(ObjectName('1.3.6.1.2.1.1.3.0'), TimeTicks(1243175676)), - # (ObjectName('1.3.6.1.6.3.1.1.4.1.0'), ObjectIdentifier('1.3.6.1.4.1.74.2.46.12.1.1')), - # (ObjectName('1.3.6.1.4.1.74.2.46.12.1.1.1'), OctetString(b'ucsnmp heartbeat - ignore')), - # (ObjectName('1.3.6.1.4.1.74.2.46.12.1.1.2'), OctetString(b'Fri Aug 11 17:46:01 EDT 2017'))] - # - - tds.all_vb_json_str = "" - vb_idx = 0 - tds.first_varbind = True - - # iterate over varbinds, add to json struct - for vb_oid, vb_val in varBinds: - add_varbind_to_json(vb_idx, vb_oid, vb_val.__class__.__name__, vb_val) - vb_idx += 1 - - # FIXME: DL back out first 2 varbinds for v2c notifs prior to publishing varbind count - # trap_dict["varbind count"] = vb_idx - curr_trap_json_str = json.dumps(tds.trap_dict) - # now have everything except varbinds in "curr_trap_json_str" - - # if varbinds present - which will almost always be the case - add all_vb_json_str to trap_json_message - if vb_idx != 0: - # close out vb array - # all_vb_json_str += "]" - # all_vb_json_str = ''.join([all_vb_json_str, ']']) - tds.all_vb_json_str = tds.all_vb_json_str + ']' - - # remove last close bracket from curr_trap_json_str - curr_trap_json_str = curr_trap_json_str[:-1] - - # add vb_json_str to payload - # curr_trap_json_str += all_vb_json_str - # curr_trap_json_str = ''.join([curr_trap_json_str, all_vb_json_str]) - curr_trap_json_str = curr_trap_json_str + tds.all_vb_json_str - - # add last close brace back in - # curr_trap_json_str += "}" - # curr_trap_json_str = ''.join([curr_trap_json_str, '}']) - curr_trap_json_str = curr_trap_json_str + '}' - - msg = "trap %s : %s" % (tds.trap_dict["uuid"], curr_trap_json_str) - ecomp_logger(tds.LOG_TYPE_DEBUG, tds.SEV_DETAILED, tds.CODE_GENERAL, msg) - - # now have a complete json message for this trap in "curr_trap_json_str" - tds.traps_since_last_publish += 1 - milliseconds_since_last_publish = (time.time() - tds.last_pub_time) * 1000 - - msg = "adding %s to buffer" % (tds.trap_dict["uuid"]) - ecomp_logger(tds.LOG_TYPE_DEBUG, tds.SEV_DETAILED, tds.CODE_GENERAL, msg) - if tds.first_trap: - tds.all_traps_str = curr_trap_json_str - tds.trap_uuids_in_buffer = tds.trap_dict["uuid"] - tds.first_trap = False - else: - tds.trap_uuids_in_buffer = tds.trap_uuids_in_buffer + \ - ', ' + tds.trap_dict["uuid"] - tds.all_traps_str = tds.all_traps_str + ', ' + curr_trap_json_str - - # always log arriving traps - log_all_arriving_traps() - - # publish to dmaap after last varbind is processed - if tds.traps_since_last_publish >= tds.c_config['publisher.max_traps_between_publishes']: - msg = "num traps since last publish (%d) exceeds threshold (%d) - publish traps" % ( - tds.traps_since_last_publish, tds.c_config['publisher.max_traps_between_publishes']) - ecomp_logger(tds.LOG_TYPE_DEBUG, tds.SEV_DETAILED, - tds.CODE_GENERAL, msg) - post_dmaap() - elif milliseconds_since_last_publish >= tds.c_config['publisher.max_milliseconds_between_publishes']: - msg = "num milliseconds since last publish (%.0f) exceeds threshold - publish traps" % milliseconds_since_last_publish - ecomp_logger(tds.LOG_TYPE_DEBUG, tds.SEV_DETAILED, - tds.CODE_GENERAL, msg) - post_dmaap() - - -# # # # # # # # # # # # # -# Main MAIN Main MAIN -# # # # # # # # # # # # # -# parse command line args -parser = argparse.ArgumentParser(description='Post SNMP traps ' - 'to message bus') -parser.add_argument('-v', action="store_true", dest="verbose", - help="verbose logging") -parser.add_argument('-?', action="store_true", dest="usage_requested", - help="show command line use") - -# parse args -args = parser.parse_args() - -# set vars from args -verbose = args.verbose -usage_requested = args.usage_requested - -# if usage, just display and exit -if usage_requested: - usage_err() - -# init vars -tds.init() - -# Set initial startup hour for rolling logfile -tds.last_hour = datetime.datetime.now().hour - -# get config binding service (CBS) values (either broker, or json file override) -load_all_configs(0, 0) -msg = "%s : %s version %s starting" % ( - prog_name, tds.c_config['snmptrap.title'], tds.c_config['snmptrap.version']) -stdout_logger(msg) - -# Avoid this unless needed for testing; it prints sensitive data to log -# -# msg = "Running config: " -# stdout_logger(msg) -# msg = json.dumps(c_config, sort_keys=False, indent=4) -# stdout_logger(msg) - -# open various ecomp logs -open_eelf_logs() - -# bump up logging level if overridden at command line -if verbose: - msg = "WARNING: '-v' argument present. All messages will be logged. This can slow things down, use only when needed." - tds.minimum_severity_to_log = 0 - stdout_logger(msg) - -# name and open arriving trap log -tds.arriving_traps_filename = tds.c_config['files.runtime_base_dir'] + "/" + \ - tds.c_config['files.log_dir'] + "/" + \ - (tds.c_config['files.arriving_traps_log']) -tds.arriving_traps_fd = open_file(tds.arriving_traps_filename) -msg = ("arriving traps logged to: %s" % tds.arriving_traps_filename) -stdout_logger(msg) -ecomp_logger(tds.LOG_TYPE_DEBUG, tds.SEV_INFO, tds.CODE_GENERAL, msg) - -# name and open json trap log -tds.json_traps_filename = tds.c_config['files.runtime_base_dir'] + "/" + tds.c_config['files.log_dir'] + "/" + "DMAAP_" + ( - tds.c_config['streams_publishes']['sec_fault_unsecure']['dmaap_info']['topic_url'].split('/')[-1]) + ".json" -tds.json_traps_fd = open_file(tds.json_traps_filename) -msg = ("published traps logged to: %s" % tds.json_traps_filename) -stdout_logger(msg) -ecomp_logger(tds.LOG_TYPE_DEBUG, tds.SEV_INFO, tds.CODE_GENERAL, msg) - -# setup signal handling for config reload -signal.signal(signal.SIGUSR1, load_all_configs) - -# save current PID for future/external reference -tds.pid_file_name = tds.c_config['files.runtime_base_dir'] + \ - '/' + tds.c_config['files.pid_dir'] + '/' + prog_name + ".pid" -msg = "Runtime PID file: %s" % tds.pid_file_name -ecomp_logger(tds.LOG_TYPE_DEBUG, tds.SEV_INFO, tds.CODE_GENERAL, msg) -rc = save_pid(tds.pid_file_name) - -# Get the event loop for this thread -loop = asyncio.get_event_loop() - -# Create SNMP engine with autogenernated engineID pre-bound -# to socket transport dispatcher -snmp_engine = engine.SnmpEngine() - -# # # # # # # # # # # # -# Transport setup -# # # # # # # # # # # # - -# UDP over IPv4 -# FIXME: add check for presense of ipv4_interface prior to attempting add OR just put entire thing in try/except clause -try: - ipv4_interface = tds.c_config['protocols.ipv4_interface'] - ipv4_port = tds.c_config['protocols.ipv4_port'] - - try: - config.addTransport( - snmp_engine, - udp.domainName + (1,), - udp.UdpTransport().openServerMode( - (ipv4_interface, ipv4_port)) - ) - except Exception as e: - msg = "Unable to bind to %s:%s - %s" % ( - ipv4_interface, ipv4_port, str(e)) - ecomp_logger(tds.LOG_TYPE_ERROR, tds.SEV_FATAL, tds.CODE_GENERAL, msg) - stdout_logger(msg) - cleanup_and_exit(1, tds.pid_file_name) - -except Exception as e: - msg = "IPv4 interface and/or port not specified in config - not listening for IPv4 traps" - stdout_logger(msg) - ecomp_logger(tds.LOG_TYPE_ERROR, tds.SEV_WARN, tds.CODE_GENERAL, msg) - - -# UDP over IPv4, second listening interface/port example if you don't want to listen on all -# config.addTransport( -# snmp_engine, -# udp.domainName + (2,), -# udp.UdpTransport().openServerMode(('127.0.0.1', 2162)) -# ) - - -# UDP over IPv6 -# FIXME: add check for presense of ipv6_interface prior to attempting add OR just put entire thing in try/except clause -try: - ipv6_interface = tds.c_config['protocols.ipv6_interface'] - ipv6_port = tds.c_config['protocols.ipv6_port'] - - try: - config.addTransport( - snmp_engine, - udp6.domainName, - udp6.Udp6Transport().openServerMode( - (ipv6_interface, ipv6_port)) - ) - except Exception as e: - msg = "Unable to bind to %s:%s - %s" % ( - ipv6_interface, ipv6_port, str(e)) - stdout_logger(msg) - ecomp_logger(tds.LOG_TYPE_ERROR, tds.SEV_FATAL, tds.CODE_GENERAL, msg) - cleanup_and_exit(1, tds.pid_file_name) - -except Exception as e: - msg = "IPv6 interface and/or port not specified in config - not listening for IPv6 traps" - stdout_logger(msg) - ecomp_logger(tds.LOG_TYPE_ERROR, tds.SEV_WARN, tds.CODE_GENERAL, msg) - - -# # # # # # # # # # # # -# SNMPv1/2c setup -# # # # # # # # # # # # - -# SecurityName <-> CommunityName mapping -# to restrict trap reception to only those with specific community -# strings -config.addV1System(snmp_engine, 'my-area', 'public') - -# register comm_string_rewrite_observer for message arrival -snmp_engine.observer.registerObserver( - comm_string_rewrite_observer, - 'rfc2576.processIncomingMsg:writable' -) - -# register snmp_engine_observer_cb for message arrival -snmp_engine.observer.registerObserver( - snmp_engine_observer_cb, - 'rfc3412.receiveMessage:request', - 'rfc3412.returnResponsePdu', -) - -# Register SNMP Application at the SNMP engine -ntfrcv.NotificationReceiver(snmp_engine, notif_receiver_cb) - -snmp_engine.transportDispatcher.jobStarted(1) # loop forever - -# Run I/O dispatcher which will receive traps -try: - snmp_engine.transportDispatcher.runDispatcher() -except Exception as e: - snmp_engine.observer.unregisterObserver() - snmp_engine.transportDispatcher.closeDispatcher() - cleanup_and_exit(1, tds.pid_file_name) diff --git a/bin/snmptrapd.sh b/bin/snmptrapd.sh deleted file mode 100755 index c4712f6..0000000 --- a/bin/snmptrapd.sh +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/env bash -# -# ============LICENSE_START======================================================= -# org.onap.dcae -# ================================================================================ -# Copyright (c) 2017-2018 AT&T Intellectual Property. All rights reserved. -# ================================================================================ -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ============LICENSE_END========================================================= -# -# ECOMP is a trademark and service mark of AT&T Intellectual Property. -# - - -# get to where we are supposed to be for startup -cd /opt/app/snmptrap/bin - -# include path to 3.6+ version of python that has required dependencies included -export PATH=/opt/app/python-3.6.1/bin:$PATH - -# expand search for python modules to include ./mod in runtime dir -export PYTHONPATH=./mod:./:$PYTHONPATH - -# set location of SSL certificates -export REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-bundle.crt - -# PYTHONUNBUFFERED: -# set PYTHONUNBUFFERED to a non-empty string to avoid output buffering; -# comment out for runtime environments/better performance! -# FIXME: This does *NOT* appear to work as desired, so -# we've added "-u" to command line below -# export PYTHONUNBUFFERED="True" - -# set location of config broker server overrride IF NEEDED -# -export CBS_SIM_JSON=../etc/snmptrapd.json - -# want tracing? Use this: -# python -m trace --trackcalls snmptrapd.py -v -# want verbose logging? Use this: -# python -u snmptrapd.py -v -# standard startup? Use this: -# python snmptrapd.py -python -u snmptrapd.py -v diff --git a/coverage.xml b/coverage.xml new file mode 100644 index 0000000..96da2c6 --- /dev/null +++ b/coverage.xml @@ -0,0 +1,695 @@ + + + + + + C:\Users\vv770d\git\onap\snmptrap\snmptrap + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pom.xml b/pom.xml index 17b54e7..5ce191a 100644 --- a/pom.xml +++ b/pom.xml @@ -34,7 +34,7 @@ ECOMP is a trademark and service mark of AT&T Intellectual Property. http://maven.apache.org UTF-8 - true + false . @@ -43,6 +43,7 @@ ECOMP is a trademark and service mark of AT&T Intellectual Property. py Python **/*.py + target/**,tests/**,setup.py,**/__init__.py