From 7416337cd7d8256712c9e90a2739ca7e1fc97181 Mon Sep 17 00:00:00 2001 From: spenugondaa Date: Thu, 3 Jun 2021 01:15:18 +0000 Subject: [PATCH 01/19] Event and Alarm Framework Define libeventnotify for applications to use LOG_EVENT to raise events/alarms. Eventd to receive and store them in the DB. Signed-off-by: spenugondaa --- dockers/docker-database/critical_processes | 1 + .../docker-database/database_config.json.j2 | 11 + dockers/docker-eventd/Dockerfile.j2 | 59 ++ dockers/docker-eventd/critical_processes | 1 + dockers/docker-eventd/docker-init.sh | 10 + dockers/docker-eventd/start.sh | 9 + dockers/docker-eventd/supervisord.conf | 40 + .../docker-sonic-mgmt-framework/Dockerfile.j2 | 2 +- files/build_templates/eventd.service.j2 | 16 + files/build_templates/init_cfg.json.j2 | 1 + rules/docker-eventd.dep | 11 + rules/docker-eventd.mk | 31 + rules/docker-sonic-mgmt-framework.mk | 1 + rules/eventd.dep | 11 + rules/eventd.mk | 18 + rules/libeventnotify.dep | 11 + rules/libeventnotify.mk | 13 + sonic-slave-buster/Dockerfile.j2 | 2 + src/sonic-eventd/Makefile.am | 4 + src/sonic-eventd/autogen.sh | 6 + src/sonic-eventd/configure.ac | 50 ++ src/sonic-eventd/debian/changelog | 6 + src/sonic-eventd/debian/compat | 1 + src/sonic-eventd/debian/control | 19 + src/sonic-eventd/debian/eventd.dirs | 1 + src/sonic-eventd/debian/eventd.install | 2 + src/sonic-eventd/debian/rules | 35 + src/sonic-eventd/etc/eventd.json | 6 + src/sonic-eventd/include/eventconsume.h | 53 ++ src/sonic-eventd/include/eventutils.h | 60 ++ src/sonic-eventd/include/loghandler.h | 5 + src/sonic-eventd/lib/Makefile.am | 5 + src/sonic-eventd/lib/autogen.sh | 6 + src/sonic-eventd/lib/configure.ac | 50 ++ src/sonic-eventd/lib/debian/changelog | 5 + src/sonic-eventd/lib/debian/compat | 1 + src/sonic-eventd/lib/debian/control | 17 + .../lib/debian/libeventnotify-dev.dirs | 2 + .../lib/debian/libeventnotify-dev.install | 1 + .../lib/debian/libeventnotify-dev.links | 2 + .../lib/debian/libeventnotify.dirs | 1 + .../lib/debian/libeventnotify.install | 1 + src/sonic-eventd/lib/debian/rules | 31 + src/sonic-eventd/lib/include/eventnotify.h | 44 ++ src/sonic-eventd/lib/src/Makefile.am | 19 + src/sonic-eventd/lib/src/eventnotify.cpp | 96 +++ src/sonic-eventd/src/Makefile.am | 25 + src/sonic-eventd/src/eventconsume.cpp | 685 ++++++++++++++++++ src/sonic-eventd/src/eventd.cpp | 34 + src/sonic-eventd/src/eventutils.cpp | 112 +++ src/sonic-eventd/src/loghandler.cpp | 37 + src/sonic-eventd/tests/event_unittest.py | 253 +++++++ .../tests/eventnotify/__init__.py | 0 .../tests/eventnotify/eventnotify.py | 44 ++ src/sonic-eventd/var/evprofile/default.json | 17 + 55 files changed, 1983 insertions(+), 1 deletion(-) create mode 100644 dockers/docker-eventd/Dockerfile.j2 create mode 100644 dockers/docker-eventd/critical_processes create mode 100755 dockers/docker-eventd/docker-init.sh create mode 100644 dockers/docker-eventd/start.sh create mode 100644 dockers/docker-eventd/supervisord.conf create mode 100644 files/build_templates/eventd.service.j2 create mode 100644 rules/docker-eventd.dep create mode 100644 rules/docker-eventd.mk create mode 100644 rules/eventd.dep create mode 100644 rules/eventd.mk create mode 100644 rules/libeventnotify.dep create mode 100644 rules/libeventnotify.mk create mode 100644 src/sonic-eventd/Makefile.am create mode 100755 src/sonic-eventd/autogen.sh create mode 100644 src/sonic-eventd/configure.ac create mode 100644 src/sonic-eventd/debian/changelog create mode 100644 src/sonic-eventd/debian/compat create mode 100644 src/sonic-eventd/debian/control create mode 100644 src/sonic-eventd/debian/eventd.dirs create mode 100644 src/sonic-eventd/debian/eventd.install create mode 100755 src/sonic-eventd/debian/rules create mode 100644 src/sonic-eventd/etc/eventd.json create mode 100644 src/sonic-eventd/include/eventconsume.h create mode 100644 src/sonic-eventd/include/eventutils.h create mode 100644 src/sonic-eventd/include/loghandler.h create mode 100644 src/sonic-eventd/lib/Makefile.am create mode 100755 src/sonic-eventd/lib/autogen.sh create mode 100644 src/sonic-eventd/lib/configure.ac create mode 100644 src/sonic-eventd/lib/debian/changelog create mode 100644 src/sonic-eventd/lib/debian/compat create mode 100644 src/sonic-eventd/lib/debian/control create mode 100644 src/sonic-eventd/lib/debian/libeventnotify-dev.dirs create mode 100644 src/sonic-eventd/lib/debian/libeventnotify-dev.install create mode 100644 src/sonic-eventd/lib/debian/libeventnotify-dev.links create mode 100644 src/sonic-eventd/lib/debian/libeventnotify.dirs create mode 100644 src/sonic-eventd/lib/debian/libeventnotify.install create mode 100755 src/sonic-eventd/lib/debian/rules create mode 100644 src/sonic-eventd/lib/include/eventnotify.h create mode 100644 src/sonic-eventd/lib/src/Makefile.am create mode 100644 src/sonic-eventd/lib/src/eventnotify.cpp create mode 100644 src/sonic-eventd/src/Makefile.am create mode 100644 src/sonic-eventd/src/eventconsume.cpp create mode 100644 src/sonic-eventd/src/eventd.cpp create mode 100644 src/sonic-eventd/src/eventutils.cpp create mode 100755 src/sonic-eventd/src/loghandler.cpp create mode 100644 src/sonic-eventd/tests/event_unittest.py create mode 100644 src/sonic-eventd/tests/eventnotify/__init__.py create mode 100644 src/sonic-eventd/tests/eventnotify/eventnotify.py create mode 100644 src/sonic-eventd/var/evprofile/default.json diff --git a/dockers/docker-database/critical_processes b/dockers/docker-database/critical_processes index 53a45931dfc9..6c45721cdb63 100644 --- a/dockers/docker-database/critical_processes +++ b/dockers/docker-database/critical_processes @@ -1 +1,2 @@ program:redis +program:redis4 diff --git a/dockers/docker-database/database_config.json.j2 b/dockers/docker-database/database_config.json.j2 index 5ad730f10015..a17653c87b75 100644 --- a/dockers/docker-database/database_config.json.j2 +++ b/dockers/docker-database/database_config.json.j2 @@ -12,6 +12,12 @@ "unix_socket_path": "/var/run/redis-chassis/redis_chassis.sock", "persistence_for_warm_boot" : "yes" } + "redis4":{ + "hostname" : "{{HOST_IP}}", + "port" : 6381, + "unix_socket_path" : "/var/run/redis{{NAMESPACE_ID}}/redis4.sock", + "persistence_for_warm_boot" : "yes" + }, }, "DATABASES" : { "APPL_DB" : { @@ -88,6 +94,11 @@ "id" : 13, "separator": "|", "instance" : "redis_chassis" + }, + "EVENT_DB" : { + "id" : 14, + "separator": "|", + "instance" : "redis4" } }, "VERSION" : "1.0" diff --git a/dockers/docker-eventd/Dockerfile.j2 b/dockers/docker-eventd/Dockerfile.j2 new file mode 100644 index 000000000000..ea2db10d8141 --- /dev/null +++ b/dockers/docker-eventd/Dockerfile.j2 @@ -0,0 +1,59 @@ +FROM docker-config-engine-buster + +ARG docker_container_name +RUN [ -f /etc/rsyslog.conf ] && sed -ri "s/%syslogtag%/$docker_container_name#%syslogtag%/;" /etc/rsyslog.conf + +## Make apt-get non-interactive +ENV DEBIAN_FRONTEND=noninteractive + +# Update apt cache and +# pre-install fundamental packages +RUN apt-get update && \ + apt-get -y install \ + curl \ + less \ + perl \ + procps \ + python3 \ + python3-distutils \ + python3-pip \ + rsyslog \ + vim-tiny + +# Upgrade pip via PyPI and uninstall the Debian version +#RUN pip3 install --upgrade pip +RUN apt-get purge -y python3-pip + +# setuptools and wheel are necessary for installing some Python wheel packages +#RUN pip3 install --no-cache-dir setuptools==49.6.00 +#RUN pip3 install --no-cache-dir wheel==0.35.1 + +# For templating +#RUN pip3 install j2cli + +# Install supervisor +#RUN pip3 install supervisor==4.2.1 + +## Install redis-tools dependencies +## TODO: implicitly install dependencies +RUN pip3 install supervisord-dependent-startup==1.4.0 + +COPY \ +{% for deb in docker_eventd_debs.split(' ') -%} +debs/{{ deb }}{{' '}} +{%- endfor -%} +debs/ + +RUN dpkg -i \ +{% for deb in docker_eventd_debs.split(' ') -%} +debs/{{ deb }}{{' '}} +{%- endfor %} + +COPY ["docker-init.sh", "files/supervisor-proc-exit-listener", "/usr/bin/"] +COPY ["supervisord.conf", "/etc/supervisor/conf.d/"] +COPY ["critical_processes", "/etc/supervisor"] + +RUN apt-get clean -y; apt-get autoclean -y; apt-get autoremove -y +RUN rm -rf /debs + +ENTRYPOINT ["/usr/bin/docker-init.sh"] diff --git a/dockers/docker-eventd/critical_processes b/dockers/docker-eventd/critical_processes new file mode 100644 index 000000000000..8ff28edbc148 --- /dev/null +++ b/dockers/docker-eventd/critical_processes @@ -0,0 +1 @@ +program:eventd diff --git a/dockers/docker-eventd/docker-init.sh b/dockers/docker-eventd/docker-init.sh new file mode 100755 index 000000000000..470b3f526e20 --- /dev/null +++ b/dockers/docker-eventd/docker-init.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +sonic-db-cli EVENT_DB config set notify-keyspace-events AKE +sed -i '/username=/d' /etc/supervisor/supervisord.conf +sed -i '/password=/d' /etc/supervisor/supervisord.conf + +cp /var/evprofile/default.json /etc/evprofile/default.json + +exec /usr/bin/supervisord + diff --git a/dockers/docker-eventd/start.sh b/dockers/docker-eventd/start.sh new file mode 100644 index 000000000000..3b189572561f --- /dev/null +++ b/dockers/docker-eventd/start.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +rm -f /var/run/rsyslogd.pid + +supervisorctl start rsyslogd + +supervisorctl start eventd + + diff --git a/dockers/docker-eventd/supervisord.conf b/dockers/docker-eventd/supervisord.conf new file mode 100644 index 000000000000..48f05557965a --- /dev/null +++ b/dockers/docker-eventd/supervisord.conf @@ -0,0 +1,40 @@ +[supervisord] +logfile_maxbytes=1MB +logfile_backups=2 +nodaemon=true + +[eventlistener:dependent-startup] +command=python -m supervisord_dependent_startup +autostart=true +autorestart=unexpected +startretries=0 +exitcodes=0,3 +events=PROCESS_STATE +buffer_size=1024 + +[eventlistener:supervisor-proc-exit-listener] +command=/usr/bin/supervisor-proc-exit-listener --container-name eventd +events=PROCESS_STATE_EXITED,PROCESS_STATE_RUNNING +autostart=true +autorestart=unexpected +buffer_size=1024 + +[program:rsyslogd] +command=/usr/sbin/rsyslogd -n -iNONE +priority=1 +autostart=false +startsecs=1 +stdout_logfile=syslog +stderr_logfile=syslog +dependent_startup=true + +[program:eventd] +command=/usr/bin/eventd +priority=2 +autostart=false +autorestart=false +stdout_logfile=syslog +stderr_logfile=syslog +dependent_startup=true +dependent_startup_wait_for=rsyslogd:running + diff --git a/dockers/docker-sonic-mgmt-framework/Dockerfile.j2 b/dockers/docker-sonic-mgmt-framework/Dockerfile.j2 index 5ee8cae84466..d4637a3c18f2 100644 --- a/dockers/docker-sonic-mgmt-framework/Dockerfile.j2 +++ b/dockers/docker-sonic-mgmt-framework/Dockerfile.j2 @@ -7,7 +7,7 @@ RUN [ -f /etc/rsyslog.conf ] && sed -ri "s/%syslogtag%/$docker_container_name#%s ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update && \ - apt-get install -y g++ python3-dev libxml2 + apt-get install -y g++ python3-dev libxml2 libcjson1 libcurl3-gnutls # TODO: Remove these lines once we no longer need Python 2 RUN apt-get install -f -y python-dev python-pip diff --git a/files/build_templates/eventd.service.j2 b/files/build_templates/eventd.service.j2 new file mode 100644 index 000000000000..36635a515b3d --- /dev/null +++ b/files/build_templates/eventd.service.j2 @@ -0,0 +1,16 @@ +[Unit] +Description=Eventd container +Requires=database.service +After=database.service +Before=ntp-config.service +StartLimitIntervalSec=1200 +StartLimitBurst=20 + +[Service] +ExecStartPre=/usr/bin/{{docker_container_name}}.sh start +ExecStart=/usr/bin/{{docker_container_name}}.sh wait +ExecStop=/usr/bin/{{docker_container_name}}.sh stop +Restart=always + +[Install] +WantedBy=multi-user.target diff --git a/files/build_templates/init_cfg.json.j2 b/files/build_templates/init_cfg.json.j2 index b8ed7c1453e7..83a8df6086be 100644 --- a/files/build_templates/init_cfg.json.j2 +++ b/files/build_templates/init_cfg.json.j2 @@ -27,6 +27,7 @@ ("snmp", "enabled", true, "enabled"), ("swss", "enabled", false, "enabled"), ("syncd", "enabled", false, "enabled"), + ("eventd", "enabled", false, "enabled"), ("teamd", "enabled", false, "enabled")] %} {%- if sonic_asic_platform == "vs" %}{% do features.append(("gbsyncd", "enabled", false, "enabled")) %}{% endif %} {%- if include_iccpd == "y" %}{% do features.append(("iccpd", "disabled", false, "enabled")) %}{% endif %} diff --git a/rules/docker-eventd.dep b/rules/docker-eventd.dep new file mode 100644 index 000000000000..7047ba0350b0 --- /dev/null +++ b/rules/docker-eventd.dep @@ -0,0 +1,11 @@ +DPATH := $($(DOCKER_EVENTD)_PATH) +DEP_FILES := $(SONIC_COMMON_FILES_LIST) rules/docker-eventd.mk rules/docker-eventd.dep +DEP_FILES += $(SONIC_COMMON_BASE_FILES_LIST) +DEP_FILES += $(shell git ls-files $(DPATH)) + +$(DOCKER_EVENTD)_CACHE_MODE := GIT_CONTENT_SHA +$(DOCKER_EVENTD)_DEP_FLAGS := $(SONIC_COMMON_FLAGS_LIST) +$(DOCKER_EVENTD)_DEP_FILES := $(DEP_FILES) + +$(eval $(call add_dbg_docker,$(DOCKER_EVENTD),$(DOCKER_EVENTD_DBG))) + diff --git a/rules/docker-eventd.mk b/rules/docker-eventd.mk new file mode 100644 index 000000000000..3904441de72d --- /dev/null +++ b/rules/docker-eventd.mk @@ -0,0 +1,31 @@ +# Docker image for EVENTD + +DOCKER_EVENTD_STEM = docker-eventd +DOCKER_EVENTD = $(DOCKER_EVENTD_STEM).gz +DOCKER_EVENTD_DBG = $(DOCKER_EVENTD_STEM)-$(DBG_IMAGE_MARK).gz + +$(DOCKER_EVENTD)_PATH = $(DOCKERS_PATH)/$(DOCKER_EVENTD_STEM) + +$(DOCKER_EVENTD)_DEPENDS += $(EVENTD) $(LIBSWSSCOMMON) $(LIBEVENTNOTIFY) +$(DOCKER_EVENTD)_DBG_DEPENDS = $($(DOCKER_CONFIG_ENGINE_BUSTER)_DBG_DEPENDS) +$(DOCKER_EVENTD)_DBG_DEPENDS += $(EVENTD) $(LIBSWSSCOMMON) $(LIBEVENTNOTIFY) +$(DOCKER_EVENTD)_DBG_IMAGE_PACKAGES = $($(DOCKER_CONFIG_ENGINE_BUSTER)_DBG_IMAGE_PACKAGES) + +SONIC_DOCKER_IMAGES += $(DOCKER_EVENTD) +#SONIC_STRETCH_DOCKERS += $(DOCKER_EVENTD) +SONIC_INSTALL_DOCKER_IMAGES += $(DOCKER_EVENTD) + +SONIC_DOCKER_DBG_IMAGES += $(DOCKER_EVENTD_DBG) +#SONIC_STRETCH_DBG_DOCKERS += $(DOCKER_EVENTD_DBG) +SONIC_INSTALL_DOCKER_DBG_IMAGES += $(DOCKER_EVENTD_DBG) + +$(DOCKER_EVENTD)_LOAD_DOCKERS = $(DOCKER_CONFIG_ENGINE_BUSTER) + +$(DOCKER_EVENTD)_CONTAINER_NAME = eventd +$(DOCKER_EVENTD)_RUN_OPT += --net=host --privileged -t +$(DOCKER_EVENTD)_RUN_OPT += -v /etc/sonic/:/etc/sonic/:ro +$(DOCKER_EVENTD)_RUN_OPT += -v /etc/evprofile:/etc/evprofile:rw +$(DOCKER_EVENTD)_RUN_OPT += -v /host/warmboot:/var/warmboot + +$(DOCKER_EVENTD)_FILES += $(SUPERVISOR_PROC_EXIT_LISTENER_SCRIPT) + diff --git a/rules/docker-sonic-mgmt-framework.mk b/rules/docker-sonic-mgmt-framework.mk index ef1d55990816..08093d2d86a8 100644 --- a/rules/docker-sonic-mgmt-framework.mk +++ b/rules/docker-sonic-mgmt-framework.mk @@ -31,6 +31,7 @@ endif $(DOCKER_MGMT_FRAMEWORK)_CONTAINER_NAME = mgmt-framework $(DOCKER_MGMT_FRAMEWORK)_RUN_OPT += --privileged -t $(DOCKER_MGMT_FRAMEWORK)_RUN_OPT += -v /etc/sonic:/etc/sonic:ro +$(DOCKER_MGMT_FRAMEWORK)_RUN_OPT += -v /etc/evprofile:/etc/evprofile:ro $(DOCKER_MGMT_FRAMEWORK)_RUN_OPT += -v /etc:/host_etc:ro $(DOCKER_MGMT_FRAMEWORK)_RUN_OPT += -v /var/run/dbus:/var/run/dbus:rw $(DOCKER_MGMT_FRAMEWORK)_RUN_OPT += --mount type=bind,source="/var/platform/",target="/mnt/platform/" diff --git a/rules/eventd.dep b/rules/eventd.dep new file mode 100644 index 000000000000..df8d9de4f6c3 --- /dev/null +++ b/rules/eventd.dep @@ -0,0 +1,11 @@ +SPATH := $($(EVENTD)_SRC_PATH) +DEP_FILES := $(SONIC_COMMON_FILES_LIST) rules/eventd.mk rules/eventd.dep +DEP_FILES += $(SONIC_COMMON_BASE_FILES_LIST) +SMDEP_FILES := $(addprefix $(SPATH)/,$(shell cd $(SPATH) && git ls-files)) + +$(EVENTD)_CACHE_MODE := GIT_CONTENT_SHA +$(EVENTD)_DEP_FLAGS := $(SONIC_COMMON_FLAGS_LIST) +$(EVENTD)_DEP_FILES := $(DEP_FILES) +$(EVENTD)_SMDEP_FILES := $(SMDEP_FILES) +$(EVENTD)_SMDEP_PATHS := $(SPATH) + diff --git a/rules/eventd.mk b/rules/eventd.mk new file mode 100644 index 000000000000..52d3baed46c1 --- /dev/null +++ b/rules/eventd.mk @@ -0,0 +1,18 @@ +# EVENTD package +# +EVENTD_VERSION = 1.0.0 +export EVENTD_VERSION + +EVENTD = eventd_$(EVENTD_VERSION)_amd64.deb +$(EVENTD)_SRC_PATH = $(SRC_PATH)/sonic-eventd +$(EVENTD)_DEPENDS += $(LIBSWSSCOMMON_DEV) $(LIBEVENTNOTIFY_DEV) +$(EVENTD)_RDEPENDS += $(LIBSWSSCOMMON) $(LIBEVENTNOTIFY) +SONIC_DPKG_DEBS += $(EVENTD) + +EVENTD_DBG = eventd-dbg_1.0.0_amd64.deb +$(EVENTD_DBG)_DEPENDS += $(EVENTD) +$(EVENTD_DBG)_RDEPENDS += $(EVENTD) +$(eval $(call add_derived_package,$(EVENTD),$(EVENTD_DBG))) + +export EVENTD + diff --git a/rules/libeventnotify.dep b/rules/libeventnotify.dep new file mode 100644 index 000000000000..d16b711000c7 --- /dev/null +++ b/rules/libeventnotify.dep @@ -0,0 +1,11 @@ +SPATH := $($(LIBEVENTNOTIFY)_SRC_PATH) +DEP_FILES := $(SONIC_COMMON_FILES_LIST) rules/libeventnotify.mk rules/libeventnotify.dep +DEP_FILES += $(SONIC_COMMON_BASE_FILES_LIST) +SMDEP_FILES := $(addprefix $(SPATH)/,$(shell cd $(SPATH) && git ls-files)) + +$(LIBEVENTNOTIFY)_CACHE_MODE := GIT_CONTENT_SHA +$(LIBEVENTNOTIFY)_DEP_FLAGS := $(SONIC_COMMON_FLAGS_LIST) +$(LIBEVENTNOTIFY)_DEP_FILES := $(DEP_FILES) +$(LIBEVENTNOTIFY)_SMDEP_FILES := $(SMDEP_FILES) +$(LIBEVENTNOTIFY)_SMDEP_PATHS := $(SPATH) + diff --git a/rules/libeventnotify.mk b/rules/libeventnotify.mk new file mode 100644 index 000000000000..4377c5dd3168 --- /dev/null +++ b/rules/libeventnotify.mk @@ -0,0 +1,13 @@ +# SONiC event notfiy library + +LIBEVENTNOTIFY_VERSION = 1.0.0 +LIBEVENTNOTIFY = libeventnotify_$(LIBEVENTNOTIFY_VERSION)_amd64.deb +$(LIBEVENTNOTIFY)_DEPENDS += $(LIBSWSSCOMMON_DEV) +$(LIBEVENTNOTIFY)_RDEPENDS += $(LIBSWSSCOMMON) + +$(LIBEVENTNOTIFY)_SRC_PATH = $(SRC_PATH)/sonic-eventd/lib +SONIC_DPKG_DEBS += $(LIBEVENTNOTIFY) + +LIBEVENTNOTIFY_DEV = libeventnotify-dev_$(LIBEVENTNOTIFY_VERSION)_amd64.deb +$(eval $(call add_derived_package,$(LIBEVENTNOTIFY),$(LIBEVENTNOTIFY_DEV))) + diff --git a/sonic-slave-buster/Dockerfile.j2 b/sonic-slave-buster/Dockerfile.j2 index 316007c4041e..8a572d85fbf4 100644 --- a/sonic-slave-buster/Dockerfile.j2 +++ b/sonic-slave-buster/Dockerfile.j2 @@ -302,6 +302,8 @@ RUN apt-get update && apt-get install -y \ xsltproc \ python-lxml \ libexpat1-dev \ + libcjson-dev \ + libcurl3-gnutls \ # For WPA supplication qtbase5-dev \ aspell-en \ diff --git a/src/sonic-eventd/Makefile.am b/src/sonic-eventd/Makefile.am new file mode 100644 index 000000000000..3f06593df83a --- /dev/null +++ b/src/sonic-eventd/Makefile.am @@ -0,0 +1,4 @@ +ACLOCAL_AMFLAGS = -I m4 +#INCLUDES = -I $(top_srcdir) +SUBDIRS = src + diff --git a/src/sonic-eventd/autogen.sh b/src/sonic-eventd/autogen.sh new file mode 100755 index 000000000000..c8d0bbe4a251 --- /dev/null +++ b/src/sonic-eventd/autogen.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +libtoolize --force --copy && +autoreconf --force --install -I m4 +rm -Rf autom4te.cache + diff --git a/src/sonic-eventd/configure.ac b/src/sonic-eventd/configure.ac new file mode 100644 index 000000000000..b415ad674e52 --- /dev/null +++ b/src/sonic-eventd/configure.ac @@ -0,0 +1,50 @@ +AC_INIT([sonic-eventd],[1.0.0]) +AC_CONFIG_SRCDIR([]) +AC_CONFIG_AUX_DIR(config) +AM_CONFIG_HEADER(config.h) +AM_INIT_AUTOMAKE([foreign]) +AC_LANG_C +AC_LANG([C++]) +AC_PROG_CC +AC_PROG_CXX +AC_PROG_LIBTOOL +AC_HEADER_STDC + +AC_ARG_ENABLE(debug, +[ --enable-debug Compile with debugging flags], +[case "${enableval}" in + yes) debug=true ;; + no) debug=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-debug) ;; +esac],[debug=false]) +AM_CONDITIONAL(DEBUG, test x$debug = xtrue) + +AC_ARG_ENABLE(gtest, +[ --enable-gtest Compile with googletest flags], +[case "${enableval}" in + yes) gtest=true ;; + no) gtest=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-gtest) ;; +esac],[gtest=false]) +AM_CONDITIONAL(GTEST, test x$gtest = xtrue) + +CFLAGS_COMMON="-std=c++11 -Wall -fPIC -Wno-write-strings -I/usr/include/swss -I/usr/include" + +CFLAGS_COMMON+=" -Werror" + +AC_SUBST(CFLAGS_COMMON) + +dnl --------------- +dnl dlopen & dlinfo +dnl --------------- +AC_SEARCH_LIBS([dlopen], [dl dld], [], [ + AC_MSG_ERROR([unable to find the dlopen()]) +]) + +AC_CONFIG_FILES([ + src/Makefile + Makefile +]) + +AC_OUTPUT + diff --git a/src/sonic-eventd/debian/changelog b/src/sonic-eventd/debian/changelog new file mode 100644 index 000000000000..f279392cfd4a --- /dev/null +++ b/src/sonic-eventd/debian/changelog @@ -0,0 +1,6 @@ +sonic (1.0.0) stable; urgency=medium + + * Initial release. + + -- Eventd Thu, 9 Apr 2020 12:00:00 -0800 + diff --git a/src/sonic-eventd/debian/compat b/src/sonic-eventd/debian/compat new file mode 100644 index 000000000000..ec635144f600 --- /dev/null +++ b/src/sonic-eventd/debian/compat @@ -0,0 +1 @@ +9 diff --git a/src/sonic-eventd/debian/control b/src/sonic-eventd/debian/control new file mode 100644 index 000000000000..36c33aad9397 --- /dev/null +++ b/src/sonic-eventd/debian/control @@ -0,0 +1,19 @@ +Source: sonic +Maintainer: Dell +Section: net +Priority: optional +Build-Depends: dh-exec (>=0.3), debhelper (>= 9), autotools-dev +Standards-Version: 1.0.0 + +Package: eventd +Architecture: any +Depends: ${shlibs:Depends} +Description: This package contains Eventd for SONiC project. + +Package: eventd-dbg +Architecture: any +Section: debug +Priority: extra +Depends: stp (=${binary:Version}) +Description: debugging symbols for eventd + diff --git a/src/sonic-eventd/debian/eventd.dirs b/src/sonic-eventd/debian/eventd.dirs new file mode 100644 index 000000000000..0bf940b3a49b --- /dev/null +++ b/src/sonic-eventd/debian/eventd.dirs @@ -0,0 +1 @@ +/usr/lib diff --git a/src/sonic-eventd/debian/eventd.install b/src/sonic-eventd/debian/eventd.install new file mode 100644 index 000000000000..ca3bc3904510 --- /dev/null +++ b/src/sonic-eventd/debian/eventd.install @@ -0,0 +1,2 @@ +/etc/eventd.json +/var/evprofile/default.json diff --git a/src/sonic-eventd/debian/rules b/src/sonic-eventd/debian/rules new file mode 100755 index 000000000000..707d224ea242 --- /dev/null +++ b/src/sonic-eventd/debian/rules @@ -0,0 +1,35 @@ +#!/usr/bin/make -f +# See debhelper(7) (uncomment to enable) +# output every command that modifies files on the build system. +#export DH_VERBOSE = 1 + +# see EXAMPLES in dpkg-buildflags(1) and read /usr/share/dpkg/* +DPKG_EXPORT_BUILDFLAGS = 1 +include /usr/share/dpkg/default.mk + +# see FEATURE AREAS in dpkg-buildflags(1) +#export DEB_BUILD_MAINT_OPTIONS = hardening=+all + +# see ENVIRONMENT in dpkg-buildflags(1) +# package maintainers to append CFLAGS +#export DEB_CFLAGS_MAINT_APPEND = -Wall -pedantic +# package maintainers to append LDFLAGS +#export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed + + +# main packaging script based on dh7 syntax +%: + dh $@ --with autotools-dev + +# dh_make generated override targets +# This is example for Cmake (See https://bugs.debian.org/641051 ) +#override_dh_auto_configure: +# dh_auto_configure -- \ +# -DCMAKE_LIBRARY_PATH=$(DEB_HOST_MULTIARCH) + +override_dh_auto_install: + dh_auto_install --destdir=debian/eventd + +override_dh_strip: + dh_strip --dbg-package=eventd-dbg + diff --git a/src/sonic-eventd/etc/eventd.json b/src/sonic-eventd/etc/eventd.json new file mode 100644 index 000000000000..567add7c9e4c --- /dev/null +++ b/src/sonic-eventd/etc/eventd.json @@ -0,0 +1,6 @@ +{ + "__README__": "Specify size of event history table. Whichever limit is hit first, eventd wraps event history table around and deletes older records.", + "no-of-records": 40000, + "no-of-days": 30 +} + diff --git a/src/sonic-eventd/include/eventconsume.h b/src/sonic-eventd/include/eventconsume.h new file mode 100644 index 000000000000..1b7e9aba76d4 --- /dev/null +++ b/src/sonic-eventd/include/eventconsume.h @@ -0,0 +1,53 @@ +#ifndef __EVENTCONSUME_H__ +#define __EVENTCONSUME_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "dbconnector.h" +#include "subscriberstatetable.h" + +namespace evt { +using namespace swss; +using namespace std; + +class EventConsume +{ +public: + EventConsume(DBConnector* dbConn); + ~EventConsume(); + void run(); + void read_eventd_config(bool read_all=true); + uint64_t get_seq_id(); + +private: + Table m_eventTable; + Table m_alarmTable; + Table m_eventStatsTable; + Table m_alarmStatsTable; + SubscriberStateTable m_consumerTable; + SubscriberStateTable m_evprofileTable; + Table m_eventPubSubTable; + u_int32_t days, count; + + void handle_notification(std::deque kco); + void handle_custom_evprofile(std::deque); + void read_events(); + void updateAlarmStatistics(string ev_sev, string ev_act); + void updateEventStatistics(bool is_add, bool is_alarm, bool is_ack, bool is_clear); + void read_config_and_purge(); + void update_events(string seq_id, string ts, vector vec); + void purge_events(); + void modifyEventStats(string seq_id); + void initEventStats(); + void initAlarmStats(); +}; +} + +#endif /* __EVENTCONSUME_H__ */ + diff --git a/src/sonic-eventd/include/eventutils.h b/src/sonic-eventd/include/eventutils.h new file mode 100644 index 000000000000..bff76ce4da4e --- /dev/null +++ b/src/sonic-eventd/include/eventutils.h @@ -0,0 +1,60 @@ +#ifndef __EVENTUTILS_H__ +#define __EVENTUTILS_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace evtutils { +using namespace std; + +const string EVENT_SEVERITY_CRITICAL_STR = "CRITICAL"; +const string EVENT_SEVERITY_MAJOR_STR = "MAJOR"; +const string EVENT_SEVERITY_MINOR_STR = "MINOR"; +const string EVENT_SEVERITY_WARNING_STR = "WARNING"; +const string EVENT_SEVERITY_INFORMATIONAL_STR = "INFORMATIONAL"; + +const string EVENT_ENABLE_TRUE_STR = "true"; +const string EVENT_ENABLE_FALSE_STR = "false"; + +const string EVENT_ACTION_RAISE_STR = "RAISE"; +const string EVENT_ACTION_CLEAR_STR = "CLEAR"; +const string EVENT_ACTION_ACK_STR = "ACKNOWLEDGE"; +const string EVENT_ACTION_UNACK_STR = "UNACKNOWLEDGE"; + +constexpr char EVENTD_PROFILE_DIR[] = "/etc/evprofile/"; +constexpr char EVENTD_DEFAULT_MAP_FILE[] = "/etc/evprofile/default.json"; +constexpr char EVENTD_PROFILE_SYMLINK[] = "/etc/evprofile/.current"; + +constexpr size_t EHT_MAX_ELEMS = 40000; +constexpr size_t EHT_MAX_DAYS = 30; +constexpr char EVENTD_CONF_FILE[] = "/etc/eventd.json"; + +typedef struct EventInfo_t { + string severity; + string enable; + string static_event_msg; +} EventInfo; + +//unordered_map static_event_table; +typedef unordered_map EventMap; + +bool isValidSeverity(string severityStr); +bool isValidEnable(string enableStr); +bool parse_config(const char *filename, unsigned int& days, unsigned int& count); +bool parse(const char *filename, EventMap& tmp_event_table); +void merge(EventMap& static_event_table, EventMap &profile_map); +void create_symlink(); +string getTimeTicks(); + +} + +#endif diff --git a/src/sonic-eventd/include/loghandler.h b/src/sonic-eventd/include/loghandler.h new file mode 100644 index 000000000000..1e98a940152f --- /dev/null +++ b/src/sonic-eventd/include/loghandler.h @@ -0,0 +1,5 @@ +#include +extern "C" void openSyslog(); +extern "C" void writeToSyslog(std::string ev_id, int ev_sev, std::string ev_type, std::string ev_act, std::string ev_msg, std::string ev_static_msg); +extern "C" void closeSyslog(); + diff --git a/src/sonic-eventd/lib/Makefile.am b/src/sonic-eventd/lib/Makefile.am new file mode 100644 index 000000000000..5ac634e08fa7 --- /dev/null +++ b/src/sonic-eventd/lib/Makefile.am @@ -0,0 +1,5 @@ +ACLOCAL_AMFLAGS = -I m4 +#INCLUDES = -I $(top_srcdir) +SUBDIRS = src + + diff --git a/src/sonic-eventd/lib/autogen.sh b/src/sonic-eventd/lib/autogen.sh new file mode 100755 index 000000000000..c8d0bbe4a251 --- /dev/null +++ b/src/sonic-eventd/lib/autogen.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +libtoolize --force --copy && +autoreconf --force --install -I m4 +rm -Rf autom4te.cache + diff --git a/src/sonic-eventd/lib/configure.ac b/src/sonic-eventd/lib/configure.ac new file mode 100644 index 000000000000..624608c31085 --- /dev/null +++ b/src/sonic-eventd/lib/configure.ac @@ -0,0 +1,50 @@ +AC_INIT([libeventnotify],[1.0.0]) +AC_CONFIG_SRCDIR([]) +AC_CONFIG_AUX_DIR(config) +AM_CONFIG_HEADER(config.h) +AM_INIT_AUTOMAKE([foreign]) +AC_LANG_C +AC_LANG([C++]) +AC_PROG_CC +AC_PROG_CXX +AC_PROG_LIBTOOL +AC_HEADER_STDC + +AC_ARG_ENABLE(debug, +[ --enable-debug Compile with debugging flags], +[case "${enableval}" in + yes) debug=true ;; + no) debug=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-debug) ;; +esac],[debug=false]) +AM_CONDITIONAL(DEBUG, test x$debug = xtrue) + +AC_ARG_ENABLE(gtest, +[ --enable-gtest Compile with googletest flags], +[case "${enableval}" in + yes) gtest=true ;; + no) gtest=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-gtest) ;; +esac],[gtest=false]) +AM_CONDITIONAL(GTEST, test x$gtest = xtrue) + +CFLAGS_COMMON="-std=c++11 -Wall -fPIC -Wno-write-strings -I/usr/include/swss -I/usr/include" + +CFLAGS_COMMON+=" -Werror" + +AC_SUBST(CFLAGS_COMMON) + +dnl --------------- +dnl dlopen & dlinfo +dnl --------------- +AC_SEARCH_LIBS([dlopen], [dl dld], [], [ + AC_MSG_ERROR([unable to find the dlopen()]) +]) + +AC_CONFIG_FILES([ + src/Makefile + Makefile +]) + +AC_OUTPUT + diff --git a/src/sonic-eventd/lib/debian/changelog b/src/sonic-eventd/lib/debian/changelog new file mode 100644 index 000000000000..ebdbdea909d3 --- /dev/null +++ b/src/sonic-eventd/lib/debian/changelog @@ -0,0 +1,5 @@ +sonic (1.0.0) stable; urgency=medium + + * Initial release. + + -- Eventd Thu, 9 Apr 2020 12:00:00 -0800 diff --git a/src/sonic-eventd/lib/debian/compat b/src/sonic-eventd/lib/debian/compat new file mode 100644 index 000000000000..ec635144f600 --- /dev/null +++ b/src/sonic-eventd/lib/debian/compat @@ -0,0 +1 @@ +9 diff --git a/src/sonic-eventd/lib/debian/control b/src/sonic-eventd/lib/debian/control new file mode 100644 index 000000000000..fd52acf007c6 --- /dev/null +++ b/src/sonic-eventd/lib/debian/control @@ -0,0 +1,17 @@ +Source: sonic +Maintainer: Dell +Section: net +Priority: optional +Build-Depends: dh-exec (>=0.3), debhelper (>= 9), autotools-dev +Standards-Version: 1.0.0 + +Package: libeventnotify +Architecture: any +Section: libs +Description: This package contains Event notify API. + +Package: libeventnotify-dev +Architecture: any +Depends: libeventnotify (= ${binary:Version}) +Section: libdevel +Description: This package contains development files for Event Notify diff --git a/src/sonic-eventd/lib/debian/libeventnotify-dev.dirs b/src/sonic-eventd/lib/debian/libeventnotify-dev.dirs new file mode 100644 index 000000000000..44188162ec7a --- /dev/null +++ b/src/sonic-eventd/lib/debian/libeventnotify-dev.dirs @@ -0,0 +1,2 @@ +usr/lib +usr/include diff --git a/src/sonic-eventd/lib/debian/libeventnotify-dev.install b/src/sonic-eventd/lib/debian/libeventnotify-dev.install new file mode 100644 index 000000000000..bf6d08a7cbba --- /dev/null +++ b/src/sonic-eventd/lib/debian/libeventnotify-dev.install @@ -0,0 +1 @@ +include/*.h usr/include diff --git a/src/sonic-eventd/lib/debian/libeventnotify-dev.links b/src/sonic-eventd/lib/debian/libeventnotify-dev.links new file mode 100644 index 000000000000..df5d23d95e98 --- /dev/null +++ b/src/sonic-eventd/lib/debian/libeventnotify-dev.links @@ -0,0 +1,2 @@ +#! /usr/bin/dh-exec +/usr/lib/x86_64-linux-gnu/libeventnotify.so.0 /usr/lib/x86_64-linux-gnu/libeventnotify.so diff --git a/src/sonic-eventd/lib/debian/libeventnotify.dirs b/src/sonic-eventd/lib/debian/libeventnotify.dirs new file mode 100644 index 000000000000..0bf940b3a49b --- /dev/null +++ b/src/sonic-eventd/lib/debian/libeventnotify.dirs @@ -0,0 +1 @@ +/usr/lib diff --git a/src/sonic-eventd/lib/debian/libeventnotify.install b/src/sonic-eventd/lib/debian/libeventnotify.install new file mode 100644 index 000000000000..b4e9de2503fb --- /dev/null +++ b/src/sonic-eventd/lib/debian/libeventnotify.install @@ -0,0 +1 @@ +usr/lib/*/libeventnotify*.so.* diff --git a/src/sonic-eventd/lib/debian/rules b/src/sonic-eventd/lib/debian/rules new file mode 100755 index 000000000000..638c6a4dec07 --- /dev/null +++ b/src/sonic-eventd/lib/debian/rules @@ -0,0 +1,31 @@ +#!/usr/bin/make -f +# See debhelper(7) (uncomment to enable) +# output every command that modifies files on the build system. +#export DH_VERBOSE = 1 + +# see EXAMPLES in dpkg-buildflags(1) and read /usr/share/dpkg/* +DPKG_EXPORT_BUILDFLAGS = 1 +include /usr/share/dpkg/default.mk + +# see FEATURE AREAS in dpkg-buildflags(1) +#export DEB_BUILD_MAINT_OPTIONS = hardening=+all + +# see ENVIRONMENT in dpkg-buildflags(1) +# package maintainers to append CFLAGS +#export DEB_CFLAGS_MAINT_APPEND = -Wall -pedantic +# package maintainers to append LDFLAGS +#export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed + + +# main packaging script based on dh7 syntax +%: + dh $@ --with autotools-dev + +# dh_make generated override targets +# This is example for Cmake (See https://bugs.debian.org/641051 ) +#override_dh_auto_configure: +# dh_auto_configure -- \ +# -DCMAKE_LIBRARY_PATH=$(DEB_HOST_MULTIARCH) + +override_dh_auto_install: + dh_auto_install diff --git a/src/sonic-eventd/lib/include/eventnotify.h b/src/sonic-eventd/lib/include/eventnotify.h new file mode 100644 index 000000000000..ad76d956b313 --- /dev/null +++ b/src/sonic-eventd/lib/include/eventnotify.h @@ -0,0 +1,44 @@ +#ifndef SWSS_COMMON_EVENTNOTIFY_H +#define SWSS_COMMON_EVENTNOTIFY_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "dbconnector.h" +#include "table.h" +using namespace swss; +namespace alertmgr { + +class EventNotify +{ +public: + static EventNotify *getInstance(); + void _send_event(const char *ev_name_p, const char *source_p, int action, const char *fmt, ...); +private: + EventNotify() = default; + ~EventNotify(); + EventNotify(DBConnector* stateDbConnector); + EventNotify(const EventNotify&); + static EventNotify *m_pInstance; + static DBConnector *p_state_db; + Table m_statePubsubTable; +}; + +#define NOTIFY 0 +#define CLEAR_ALARM 1 +#define RAISE_ALARM 2 +#define ACK_ALARM 3 +#define UNACK_ALARM 4 + +#define LOG_EVENT(name, source, action, MSG, ...) alertmgr::EventNotify::getInstance()->_send_event(#name, source, action, MSG, ##__VA_ARGS__) +} + +#endif /* SWSS_COMMON_EVENTNOTIFY_H */ diff --git a/src/sonic-eventd/lib/src/Makefile.am b/src/sonic-eventd/lib/src/Makefile.am new file mode 100644 index 000000000000..a99263427cd4 --- /dev/null +++ b/src/sonic-eventd/lib/src/Makefile.am @@ -0,0 +1,19 @@ + +INCLUDES = -I ../include + +lib_LTLIBRARIES = libeventnotify.la + +if DEBUG +DBGFLAGS = -ggdb -DDEBUG +else +#DBGFLAGS = -g -DNDEBUG +DBGFLAGS = -ggdb -DDEBUG +endif + + +libeventnotify_la_SOURCES = eventnotify.cpp + +#CXXFLAGS += -ffunction-sections -fdata-sections +#eventd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(COV_CFLAGS) $(ASAN_CFLAGS) $(CXXFLAGS) +libeventnotify_la_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(COV_CFLAGS) $(ASAN_CFLAGS) +libeventnotify_la_LIBADD = -lhiredis -lswsscommon $(COV_LDFLAGS) $(ASAN_LDFLAGS) diff --git a/src/sonic-eventd/lib/src/eventnotify.cpp b/src/sonic-eventd/lib/src/eventnotify.cpp new file mode 100644 index 000000000000..bfa0af570718 --- /dev/null +++ b/src/sonic-eventd/lib/src/eventnotify.cpp @@ -0,0 +1,96 @@ +#include "eventnotify.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "schema.h" +#include "select.h" +#include "dbconnector.h" +#include "redisclient.h" +#include "timestamp.h" + +using namespace swss; +using namespace std; +using namespace std::chrono; + +namespace alertmgr { + +string getActionStr(int action); +string getTimestamp(); +EventNotify *EventNotify::m_pInstance = NULL; +uint64_t seq_id = 1; + +EventNotify::EventNotify(DBConnector* stateDbConnector): + m_statePubsubTable(stateDbConnector, EVENT_PUBSUB_TABLE_NAME) { + SWSS_LOG_ENTER(); +} + +EventNotify::~EventNotify() { +} + +EventNotify *EventNotify::getInstance() +{ + if (!m_pInstance) { + DBConnector db("EVENT_DB", 0); + m_pInstance = new EventNotify(&db); + } + + return m_pInstance; +} + +// timeticks are relative to the Unix Epoch +string getTimestamp() { + const auto p1 = system_clock::now(); + return to_string(duration_cast(p1.time_since_epoch()).count()); +} + +string getActionStr(int action) { + switch (action) { + case CLEAR_ALARM: + return string("CLEAR"); + case RAISE_ALARM: + return string("RAISE"); + case ACK_ALARM: + return string("ACKNOWLEDGE"); + case UNACK_ALARM: + return string("UNACKNOWLEDGE"); + default: + return string(); + } +} + +void EventNotify::_send_event(const char *ev_name_p, const char *source_p, int action, const char *fmt, ...) +{ + va_list args; + char buff[1024]; + memset(buff, 0, sizeof(buff)); + + SWSS_LOG_ENTER(); + + va_start(args, fmt); + vsnprintf(buff, sizeof(buff), fmt, args); + va_end (args); + + string tblkey = string(ev_name_p) + to_string(seq_id++); + vector fvs; + fvs.emplace_back("type-id", string(ev_name_p)); + fvs.emplace_back("text", buff); + fvs.emplace_back("action", getActionStr(action)); + if (source_p && (strlen(source_p) > 0)) { + fvs.emplace_back("resource", string(source_p)); + } + fvs.emplace_back("time-created", getTimestamp()); + + m_statePubsubTable.set(tblkey, fvs); +} + +}; diff --git a/src/sonic-eventd/src/Makefile.am b/src/sonic-eventd/src/Makefile.am new file mode 100644 index 000000000000..8826afcb1612 --- /dev/null +++ b/src/sonic-eventd/src/Makefile.am @@ -0,0 +1,25 @@ +INCLUDES = -I ../include + +bin_PROGRAMS = eventd + +lib_LTLIBRARIES = libloghandler.la + +if DEBUG +DBGFLAGS = -ggdb -DDEBUG +else +#DBGFLAGS = -g -DNDEBUG +DBGFLAGS = -ggdb -DDEBUG +endif + +LIB_LOG_HANDLER=libloghandler.la + +libloghandler_la_SOURCES = loghandler.cpp +libloghandler_la_LDFLAGS = -version-info 0:0:0 + +eventd_SOURCES = eventd.cpp eventutils.cpp eventconsume.cpp + +#CXXFLAGS += -ffunction-sections -fdata-sections +#eventd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(COV_CFLAGS) $(ASAN_CFLAGS) $(CXXFLAGS) +eventd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(COV_CFLAGS) $(ASAN_CFLAGS) +eventd_LDADD = -lnl-3 -lhiredis -lswsscommon -leventnotify $(LIB_LOG_HANDLER) $(COV_LDFLAGS) $(ASAN_LDFLAGS) + diff --git a/src/sonic-eventd/src/eventconsume.cpp b/src/sonic-eventd/src/eventconsume.cpp new file mode 100644 index 000000000000..a280d1c80dae --- /dev/null +++ b/src/sonic-eventd/src/eventconsume.cpp @@ -0,0 +1,685 @@ +#include "eventconsume.h" +#include "eventnotify.h" +#include "dbconnector.h" +#include "subscriberstatetable.h" +#include "select.h" +#include "loghandler.h" +#include "eventutils.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace evt { + +using namespace swss; +using namespace std; +using namespace evtutils; +using namespace std::chrono; + +constexpr size_t LOG_SZ = 500; +constexpr char LOG_TYPE_EVENT[] = "event"; +constexpr char LOG_TYPE_ALARM[] = "alarm"; + +// map to store sequence-id for alarms +unordered_map cal_lookup_map; + +// Map to hold "default" map of events +EventMap default_static_event_table; + +// temporary map to hold merge of default map of events and any event profile +EventMap static_event_table; + +volatile bool g_run = true; +uint64_t seq_id = 0; +uint64_t PURGE_DAYS = pow(2.592, 15); + +//typedef pair pi; +typedef pair pi; +priority_queue, greater > event_history_list; + +map SYSLOG_SEVERITY = { + {EVENT_SEVERITY_CRITICAL_STR, LOG_ALERT}, + {EVENT_SEVERITY_MAJOR_STR, LOG_CRIT}, + {EVENT_SEVERITY_MINOR_STR, LOG_ERR}, + {EVENT_SEVERITY_WARNING_STR, LOG_WARNING}, + {EVENT_SEVERITY_INFORMATIONAL_STR, LOG_NOTICE} +}; + +map SYSLOG_SEVERITY_STR = { + {LOG_ALERT , EVENT_SEVERITY_CRITICAL_STR}, + {LOG_CRIT , EVENT_SEVERITY_MAJOR_STR}, + {LOG_ERR , EVENT_SEVERITY_MINOR_STR}, + {LOG_WARNING , EVENT_SEVERITY_WARNING_STR}, + {LOG_NOTICE , EVENT_SEVERITY_INFORMATIONAL_STR} +}; + +static string flood_ev_id; +static string flood_ev_action; +static string flood_ev_resource; + +EventConsume::EventConsume(DBConnector* dbConn) : + m_eventTable(dbConn, EVENT_HISTORY_TABLE_NAME), + m_alarmTable(dbConn, EVENT_CURRENT_ALARM_TABLE_NAME), + m_eventStatsTable(dbConn, EVENT_STATS_TABLE_NAME), + m_alarmStatsTable(dbConn, EVENT_ALARM_STATS_TABLE_NAME), + m_consumerTable(dbConn, EVENT_PUBSUB_TABLE_NAME), + m_evprofileTable(dbConn, EVENT_EVPROFILE_TABLE_NAME), + m_eventPubSubTable(dbConn, EVENT_PUBSUB_TABLE_NAME) { + SWSS_LOG_ENTER(); + + // open syslog connection + openSyslog(); + + // intialize statistics + initEventStats(); + initAlarmStats(); + + // populate local queue of event histor table + read_events(); + + // read and apply eventd configuration files + // read eventd.json and apply it on history table. + // read default and custom profiles, build static_event_table + read_eventd_config(); + + // if symlink pointing to default/custom profile, doesnt exist, create one + create_symlink(); + + SWSS_LOG_NOTICE("DONE WITH EventConsume constructor"); +} + +EventConsume::~EventConsume() { +} + +uint64_t EventConsume::get_seq_id() { + return seq_id; +} + +void EventConsume::run() +{ + SWSS_LOG_ENTER(); + + swss::Select s; + KeyOpFieldsValuesTuple kco; + + // selectable for various tables + s.addSelectable(&m_consumerTable); + s.addSelectable(&m_evprofileTable); + + while (g_run) { + swss::Selectable *sel; + + std::deque kco; + + int result = s.select(&sel); + + if (result == Select::OBJECT) { + if (sel == &m_evprofileTable) { + m_evprofileTable.pops(kco); + handle_custom_evprofile(kco); + } else { + m_consumerTable.pops(kco); + handle_notification(kco); + } + } + } +} + +void EventConsume::read_eventd_config(bool read_all) { + // read manifest file for config options + if (read_all) { + read_config_and_purge(); + } + + // read from default map + static_event_table.clear(); + if (!parse(EVENTD_DEFAULT_MAP_FILE, static_event_table)) { + SWSS_LOG_ERROR("Can not initialize event map"); + exit(0); + } + + // Maintain the native default profile in default_static_event_table. + if (default_static_event_table.empty()) { + default_static_event_table = static_event_table; + } + + // read from any potential event profile + EventMap profile_map; + profile_map.clear(); + if (parse(EVENTD_PROFILE_SYMLINK, profile_map)) { + // merge both default map and profile map + merge(static_event_table, profile_map); + } + + SWSS_LOG_NOTICE("Event map is built as follows:"); + for (auto& x: static_event_table) { + SWSS_LOG_NOTICE(" %s (%s %s %s)", x.first.c_str(), x.second.severity.c_str(), x.second.enable.c_str(), x.second.static_event_msg.c_str()); + } +} + +void EventConsume::handle_notification(std::deque kco) +{ + SWSS_LOG_ENTER(); + + for (auto entry: kco) { + string ev_id, ev_msg, ev_src, ev_act, ev_timestamp, ev_type("EVENT"), ev_static_msg(""), ev_reckey; + string ev_sev = string(EVENT_SEVERITY_INFORMATIONAL_STR); + bool is_raise = false; + bool is_clear = false; + bool is_ack = false; + vector vec; + + ev_reckey = kfvKey(entry); + std::string op = kfvOp(entry); + if (op != "SET") { + continue; + } + + const vector& data = kfvFieldsValues(entry); + for (auto idx : data) { + if (fvField(idx) == "type-id") { + ev_id = fvValue(idx); + vec.push_back(idx); + SWSS_LOG_DEBUG("type-id: <%s> ", ev_id.c_str()); + } else if (fvField(idx) == "text") { + ev_msg = fvValue(idx); + vec.push_back(idx); + SWSS_LOG_DEBUG("text: <%s> ", ev_msg.c_str()); + } else if (fvField(idx) == "resource") { + ev_src = fvValue(idx); + vec.push_back(idx); + SWSS_LOG_DEBUG("resource: <%s> ", ev_src.c_str()); + } else if (fvField(idx) == "action") { + ev_act = fvValue(idx); + // for events, action is empty + if (!ev_act.empty()) { + vec.push_back(idx); + } + } else if (fvField(idx) == "time-created") { + ev_timestamp = fvValue(idx); + vec.push_back(idx); + SWSS_LOG_DEBUG("time-created: <%s> ", ev_timestamp.c_str()); + } + } + + m_eventPubSubTable.del(ev_reckey); + +//TODO: uncomment this out once unt test is done +#if 0 + // flood protection. If a rogue application sends same event repeatedly, sqaush that repeated instances of that event + if (!flood_ev_resource.compare(ev_src) && + !flood_ev_action.compare(ev_act) && + !flood_ev_id.compare(ev_id)) { + SWSS_LOG_INFO("Ignoring the event %s from %s action %s as it is repeated", ev_id.c_str(), ev_src.c_str(), ev_act.c_str()); + continue; + } +#endif + flood_ev_resource = ev_src; + flood_ev_action = ev_act; + flood_ev_id = ev_id; + + // get static info + auto it = static_event_table.find(ev_id); + if (it != static_event_table.end()) { + EventInfo tmp = (EventInfo) (it->second); + // discard the event as event_static_map shows enable is false for this event + if (tmp.enable == EVENT_ENABLE_FALSE_STR) { + SWSS_LOG_NOTICE("Discarding event <%s> as it is set to disabled", ev_id.c_str()); + continue; + } + + // get severity in the map and store it in the db + ev_sev = tmp.severity; + ev_static_msg = tmp.static_event_msg; + SWSS_LOG_DEBUG("static info: <%s> <%s> ", tmp.severity.c_str(), tmp.static_event_msg.c_str()); + + FieldValueTuple seqfv1("severity", tmp.severity); + vec.push_back(seqfv1); + } else { + if ((ev_act.compare(EVENT_ACTION_ACK_STR) && ev_act.compare(EVENT_ACTION_UNACK_STR))) { + SWSS_LOG_ERROR("static info NOT FOUND for <%s> ", ev_id.c_str()); + continue; + } + } + + // increment save seq-id for the newly received event + seq_id++; + FieldValueTuple seqfv("id", to_string(seq_id)); + vec.push_back(seqfv); + + if (ev_act.length() > 0) { + SWSS_LOG_DEBUG("ev_act %s", ev_act.c_str()); + ev_type = "ALARM"; + string almkey = ev_id; + if (!ev_src.empty()) { + almkey += "|" + ev_src; + } + + if (ev_act.compare(EVENT_ACTION_RAISE_STR) == 0) { + is_raise = true; + // TODO: update system LED + cal_lookup_map.insert(make_pair(almkey, seq_id)); + + FieldValueTuple seqfv1("acknowledged", "false"); + vec.push_back(seqfv1); + m_alarmTable.set(to_string(seq_id), vec); + + // update alarm counters + updateAlarmStatistics(ev_sev, ev_act); + } else if (ev_act.compare(EVENT_ACTION_CLEAR_STR) == 0) { + is_clear = true; + SWSS_LOG_NOTICE(" Received clear alarm for %s", almkey.c_str()); + + // find and remove the raised alarm + uint64_t lookup_seq_id = 0; + bool ack_flag = false; + auto it = cal_lookup_map.find(almkey); + if (it != cal_lookup_map.end()) { + lookup_seq_id = (uint64_t) (it->second); + cal_lookup_map.erase(almkey); + + // get status of is_aknowledged flag so that we dont decrement counters twice + vector alm_rec; + m_alarmTable.get(to_string(lookup_seq_id), alm_rec); + for (auto fvr: alm_rec) { + if (!fvr.first.compare("acknowledged")) { + ack_flag = (fvr.second.compare("true") == 0) ? true : false; + break; + } + } + + // delete the record from alarm table + m_alarmTable.del(to_string(lookup_seq_id)); + } else { + // possible - when event profile removes alarms for which enable is false and application cleared them later. + // ignore by logging a debug message.. + SWSS_LOG_INFO("Received alarm-clear for non-existing alarm %s", almkey.c_str()); + continue; + } + // update alarm counters ONLY if it has not been ack'd before + if (!ack_flag) { + updateAlarmStatistics(ev_sev, ev_act); + } + } else { + // ack/unack events comes with seq-id of raised alarm as resource field. + // fetch details of "raised" alarm record + vector raise_vec; + m_alarmTable.get(ev_src, raise_vec); + string raise_act; + string raise_ack_flag; + string raise_ts; + for (auto fv: raise_vec) { + if (!fv.first.compare("type-id")) { + ev_id = fv.second; + vec.push_back(fv); + } + if (!fv.first.compare("severity")) { + ev_sev = fv.second; + vec.push_back(fv); + } + if (!fv.first.compare("action")) { + raise_act = fv.second; + } + if (!fv.first.compare("acknowledged")) { + raise_ack_flag = fv.second; + } + if (!fv.first.compare("time-created")) { + raise_ts = fv.second; + } + } + + // vector to hold those parameters that change on the raised record + vector ack_vec; + + if (ev_act.compare(EVENT_ACTION_ACK_STR) == 0) { + if (raise_ack_flag.compare("true") == 0) { + SWSS_LOG_ERROR(" %s/%s is already acknowledged", ev_id.c_str(), ev_src.c_str()); + continue; + } + if (raise_act.compare(EVENT_ACTION_RAISE_STR) == 0) { + is_ack = true; + SWSS_LOG_NOTICE(" received ACKnowledge event - %s/%s", ev_id.c_str(), ev_src.c_str()); + + FieldValueTuple seqfv1("acknowledged", "true"); + ack_vec.push_back(seqfv1); + + FieldValueTuple seqfv2("acknowledge-time", ev_timestamp); + ack_vec.push_back(seqfv2); + + // update alarm stats + updateAlarmStatistics(ev_sev, ev_act); + + // update alarm/event tables for the "raise" record with ack flag and ack timestamp + m_alarmTable.set(ev_src, ack_vec); + m_eventTable.set(ev_src, ack_vec); + } else { + SWSS_LOG_ERROR(" %s/%s is not in raised state", ev_id.c_str(), ev_src.c_str()); + continue; + } + } else if (ev_act.compare(EVENT_ACTION_UNACK_STR) == 0) { + if (raise_ack_flag.compare("true") == 0) { + is_ack = false; + SWSS_LOG_NOTICE(" received un-ACKnowledge event - %s/%s", ev_id.c_str(), ev_src.c_str()); + + FieldValueTuple seqfv1("acknowledged", "false"); + ack_vec.push_back(seqfv1); + + FieldValueTuple seqfv2("acknowledge-time", ev_timestamp); + ack_vec.push_back(seqfv2); + + // update alarm stats as it is un-ack, is in effect, a raise action for stats + updateAlarmStatistics(ev_sev, ev_act); + // update alarm/event tables for the "raise" record with ack flag and ack timestamp + m_alarmTable.set(ev_src, ack_vec); + m_eventTable.set(ev_src, ack_vec); + } else { + SWSS_LOG_ERROR(" %s/%s is already un-acknowledged", ev_id.c_str(), ev_src.c_str()); + continue; + } + } + } + } + // verify the size of history table; delete older entry; add new entry + update_events(to_string(seq_id), ev_timestamp, vec); + + updateEventStatistics(true, is_raise, is_ack, is_clear); + + // raise a syslog message + writeToSyslog(ev_id, (int) (SYSLOG_SEVERITY.find(ev_sev)->second), ev_type, ev_act, ev_msg, ev_static_msg); + } + + return; +} + +void EventConsume::read_events() { + vector tuples; + m_eventTable.getContent(tuples); + + SWSS_LOG_ENTER(); + for (auto tuple: tuples) { + for (auto fv: kfvFieldsValues(tuple)) { + if (fvField(fv) == "time-created") { + char* end; + uint64_t seq = strtoull(kfvKey(tuple).c_str(), &end,10); + if (seq > seq_id) { + seq_id = seq; + } + uint64_t val = strtoull(fvValue(fv).c_str(), &end,10); + event_history_list.push(make_pair( seq, val )); + } + } + } + SWSS_LOG_NOTICE("eventd sequence-id intialized to %lu", seq_id); +} + +void EventConsume::updateAlarmStatistics(string ev_sev, string ev_act) { + vector vec; + vector temp; + + // severity counter names are of lower case + transform(ev_sev.begin(), ev_sev.end(), ev_sev.begin(), ::tolower); + + if (m_alarmStatsTable.get("state", vec)) { + for (auto fv: vec) { + if (!fv.first.compare("alarms")) { + if ((ev_act.compare(EVENT_ACTION_RAISE_STR) == 0) || (ev_act.compare(EVENT_ACTION_UNACK_STR) == 0)) { + fv.second = to_string(stoi(fv.second.c_str())+1); + } else { + fv.second = to_string(stoi(fv.second.c_str())-1); + } + temp.push_back(fv); + } else if (!fv.first.compare(ev_sev)) { + if ((ev_act.compare(EVENT_ACTION_RAISE_STR) == 0) || (ev_act.compare(EVENT_ACTION_UNACK_STR) == 0)) { + fv.second = to_string(stoi(fv.second.c_str())+1); + } else { + fv.second = to_string(stoi(fv.second.c_str())-1); + } + temp.push_back(fv); + } else if (!fv.first.compare("acknowledged")) { + if (ev_act.compare(EVENT_ACTION_ACK_STR) == 0) { + fv.second = to_string(stoi(fv.second.c_str())+1); + } else if (ev_act.compare(EVENT_ACTION_UNACK_STR) == 0) { + fv.second = to_string(stoi(fv.second.c_str())-1); + } + temp.push_back(fv); + } + } + m_alarmStatsTable.set("state", temp); + } else { + SWSS_LOG_ERROR("Can not update Alarm Statistics table"); + } +} + +void EventConsume::updateEventStatistics(bool is_add, bool is_raise, bool is_ack, bool is_clear) { + vector vec; + vector temp; + + if (m_eventStatsTable.get("state", vec)) { + for (auto fv: vec) { + if (!fv.first.compare("events")) { + if (is_add) { + fv.second = to_string(stoi(fv.second.c_str())+1); + } else { + fv.second = to_string(stoi(fv.second.c_str())-1); + } + temp.push_back(fv); + } else if (!fv.first.compare("raised")) { + if (is_raise) { + if (is_add) { + fv.second = to_string(stoi(fv.second.c_str())+1); + } else { + fv.second = to_string(stoi(fv.second.c_str())-1); + } + temp.push_back(fv); + } + } else if (!fv.first.compare("cleared")) { + if (is_clear) { + if (is_add) { + fv.second = to_string(stoi(fv.second.c_str())+1); + } else { + fv.second = to_string(stoi(fv.second.c_str())-1); + } + temp.push_back(fv); + } + } else if (!fv.first.compare("acked")) { + if (is_ack) { + if (is_add) { + fv.second = to_string(stoi(fv.second.c_str())+1); + } else { + fv.second = to_string(stoi(fv.second.c_str())-1); + } + temp.push_back(fv); + } + } + } + m_eventStatsTable.set("state", temp); + } else { + SWSS_LOG_ERROR("Can not update Event Statistics table"); + } +} + +void EventConsume::modifyEventStats(string seq_id) { + vector rec; + m_eventTable.get(seq_id, rec); + bool is_raise = false; + bool is_clear = false; + bool is_ack = false; + for (auto fvr: rec) { + if (!fvr.first.compare("action")) { + if (!fvr.second.compare(EVENT_ACTION_RAISE_STR)) { + is_raise = true; + } else if (!fvr.second.compare(EVENT_ACTION_CLEAR_STR)) { + is_clear = true; + } + } + if (!fvr.first.compare("acknowledged")) { + if (!fvr.second.compare("true")) { + is_ack = true; + } + } + } + updateEventStatistics(false, is_raise, is_ack, is_clear); +} + +void EventConsume::purge_events() { + SWSS_LOG_ENTER(); + uint32_t size = event_history_list.size(); + + while (size > count) { + pair oldest_entry = event_history_list.top(); + m_eventTable.del(to_string(oldest_entry.first)); + modifyEventStats(to_string(oldest_entry.first)); + event_history_list.pop(); + --size; + } + + const auto p1 = system_clock::now(); + uint64_t tnow = duration_cast(p1.time_since_epoch()).count(); + + while (!event_history_list.empty()) { + pair oldest_entry = event_history_list.top(); + if ((tnow - oldest_entry.second) > PURGE_DAYS) { + m_eventTable.del(to_string(oldest_entry.first)); + modifyEventStats(to_string(oldest_entry.first)); + event_history_list.pop(); + } else { + return; + } + } + return; +} + +void EventConsume::read_config_and_purge() { + days = 0; + count = 0; + // read from the manifest file + parse_config(EVENTD_CONF_FILE, days, count); + SWSS_LOG_NOTICE("no-of-days %d no-of-records %d", days, count); + + // update the nanosecond limit + PURGE_DAYS = days * pow(8.64, 13); + + // purge events based on # of days + purge_events(); +} + +void EventConsume::update_events(string seq_id, string ts, vector vec) { + // purge events based on # of days + purge_events(); + + // now add the event to the event table + m_eventTable.set(seq_id, vec); + + // store it into the event history list + char* end; + uint64_t seq = strtoull(seq_id.c_str(), &end, 10); + uint64_t val = strtoull(ts.c_str(), &end, 10); + event_history_list.push(make_pair( seq, val )); +} + +void EventConsume::handle_custom_evprofile(std::deque entries) { + string filename; + for (auto entry: entries) { + std::string op = kfvOp(entry); + if (op != "SET") return; + const vector& data = kfvFieldsValues(entry); + for (auto idx : data) { + if (fvField(idx) == "name") { + filename = fvValue(idx); + break; + } + } + } + + if (filename.empty()) { + SWSS_LOG_ERROR("Received Event Profile name is empty."); + return; + } + string custom_profile = EVENTD_PROFILE_DIR + filename; + + SWSS_LOG_NOTICE("Received profile is %s", custom_profile.c_str()); + + // the profile is already validated by rest-server. create symlink + if (unlink(EVENTD_PROFILE_SYMLINK) != 0) { + // it is possible.. if there is no symlink exists and user trying for the first time + SWSS_LOG_DEBUG("Unlink of custom profile failed"); + } + if (symlink(custom_profile.c_str(), EVENTD_PROFILE_SYMLINK) != 0) { + SWSS_LOG_ERROR("Error applying custom profile"); + } else { + SWSS_LOG_NOTICE("Applying custom profile"); + read_eventd_config(false); + // generate an event informing new profile is in effect + LOG_EVENT(CUSTOM_EVPROFILE_CHANGE, custom_profile.c_str(), NOTIFY, "Custom Event Profile %s is applied.", filename.c_str()); + + // walk through event table and remove those alarms for which enable flag is set to false + for (auto it : cal_lookup_map) { + //key in the cal_lookup_map is tokenized with | with event-id and source + char *evid = strtok((char *) (it.first.c_str()), "|"); + // find the record in the static_event_table that merged the custom profile + auto itr = static_event_table.find(string(evid)); + if (itr != static_event_table.end()) { + EventInfo tmp = (EventInfo) (itr->second); + // if enable flag is false, remove the record from alarm table + if (tmp.enable == EVENT_ENABLE_FALSE_STR) { + SWSS_LOG_NOTICE("enable for evid %s is false.. clearing alarm", evid); + uint64_t lookup_seq_id = (long unsigned int) (it.second); + cal_lookup_map.erase(it.first); + m_alarmTable.del(to_string(lookup_seq_id)); + // TODO: need to update alarm stats + updateAlarmStatistics(tmp.severity, EVENT_ACTION_CLEAR_STR); + } + } + } + } +} + +void EventConsume::initEventStats() { + vector temp; + FieldValueTuple fv; + fv = FieldValueTuple("events", "0"); + temp.push_back(fv); + fv = FieldValueTuple("raised", "0"); + temp.push_back(fv); + fv = FieldValueTuple("cleared", "0"); + temp.push_back(fv); + fv = FieldValueTuple("acked", "0"); + temp.push_back(fv); + m_eventStatsTable.set("state", temp); +} + +void EventConsume::initAlarmStats() { + vector temp; + FieldValueTuple fv; + map::iterator it; + for (it = SYSLOG_SEVERITY_STR.begin(); it != SYSLOG_SEVERITY_STR.end(); it++) { + // there wont be any informational alarms + if (it->second.compare(EVENT_SEVERITY_INFORMATIONAL_STR) != 0) { + string str = it->second; + // severity counter names are of lower case + transform(str.begin(), str.end(),str.begin(), ::tolower); + fv = FieldValueTuple(str, "0"); + temp.push_back(fv); + } + } + fv = FieldValueTuple("alarms", "0"); + temp.push_back(fv); + fv = FieldValueTuple("acknowledged", "0"); + temp.push_back(fv); + m_alarmStatsTable.set("state", temp); +} + +}; + + diff --git a/src/sonic-eventd/src/eventd.cpp b/src/sonic-eventd/src/eventd.cpp new file mode 100644 index 000000000000..618d78ada897 --- /dev/null +++ b/src/sonic-eventd/src/eventd.cpp @@ -0,0 +1,34 @@ +#include "eventconsume.h" +#include + +static evt::EventConsume *evtd_instance = NULL; + +void signalHandler(const int signal) { + SWSS_LOG_NOTICE("in signalHandler"); + + if (signal == SIGINT) { + evtd_instance->read_eventd_config(); + } +} + +int main() +{ + swss::Logger::getInstance().setMinPrio(swss::Logger::SWSS_DEBUG); + + swss::DBConnector eventDb("EVENT_DB", 0); + + // register signal SIGINT and signal handler + signal(SIGINT, signalHandler); + + evt::EventConsume evtd(&eventDb); + evtd_instance = &evtd; + + evtd.run(); + + return 0; +} + + + + + diff --git a/src/sonic-eventd/src/eventutils.cpp b/src/sonic-eventd/src/eventutils.cpp new file mode 100644 index 000000000000..3d900aa48a59 --- /dev/null +++ b/src/sonic-eventd/src/eventutils.cpp @@ -0,0 +1,112 @@ +#include "eventutils.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "json.h" +#include "json.hpp" + +namespace evtutils { +using namespace std; +using namespace swss; +using namespace std::chrono; +using json = nlohmann::json; + +bool isValidSeverity(string severityStr) { + transform(severityStr.begin(), severityStr.end(), severityStr.begin(), ::toupper); + if (severityStr == EVENT_SEVERITY_MAJOR_STR) return true; + if (severityStr == EVENT_SEVERITY_CRITICAL_STR) return true; + if (severityStr == EVENT_SEVERITY_MINOR_STR) return true; + if (severityStr == EVENT_SEVERITY_WARNING_STR) return true; + if (severityStr == EVENT_SEVERITY_INFORMATIONAL_STR) return true; + return false; +} + +bool isValidEnable(string enableStr) { + if (enableStr == EVENT_ENABLE_TRUE_STR) return true; + if (enableStr == EVENT_ENABLE_FALSE_STR) return true; + return false; +} + +bool parse_config(const char *filename, unsigned int& days, unsigned int& count) { + days = EHT_MAX_DAYS; + count = EHT_MAX_ELEMS; + std::ifstream ifs(filename); + json j = json::parse(ifs); + for (json::iterator it = j.begin(); it != j.end(); ++it) { + if(it.key() == "no-of-days") { + days = it.value(); + } + if(it.key() == "no-of-records") { + count = it.value(); + } + } + return true; +} + +bool parse(const char *filename, EventMap& tmp_event_table) { + ifstream fs(filename); + if (!fs.is_open()) { + return false; + } + + fstream file(filename, fstream::in); + json j; + file >> j; + + if (j["events"].size() == 0) { + SWSS_LOG_ERROR("No entries in 'events' field in %s", filename); + return false; + } + + for (size_t i = 0; i < j["events"].size(); i++) { + auto elem = j["events"][i]; + struct EventInfo_t ev_info; + string ev_name = elem["name"]; + ev_info.severity = elem["severity"]; + ev_info.enable = elem["enable"]; + ev_info.static_event_msg = elem["message"]; + tmp_event_table.emplace(ev_name, ev_info); + } + + return true; +} + +void merge(EventMap& static_event_table, EventMap &profile_map) { + for (auto it = profile_map.begin(); it != profile_map.end(); it++) { + if (static_event_table.find(it->first) != static_event_table.end()) { + //TODO: try copying individual parametrs + static_event_table[it->first] = it->second; + } else { + static_event_table.emplace(it->first, it->second); + } + } +} + +void create_symlink() { + struct stat info; + if (lstat(EVENTD_PROFILE_SYMLINK, &info) != 0) { + if (symlink(EVENTD_DEFAULT_MAP_FILE, EVENTD_PROFILE_SYMLINK) != 0) { + SWSS_LOG_ERROR("Error creating symlink to default profile"); + } else { + SWSS_LOG_NOTICE("Created symlink to default profile"); + } + } +} + +// timeticks are relative to the Unix Epoch +string getTimeTicks() { + const auto p1 = system_clock::now(); + return to_string(duration_cast(p1.time_since_epoch()).count()); +} + +} + diff --git a/src/sonic-eventd/src/loghandler.cpp b/src/sonic-eventd/src/loghandler.cpp new file mode 100755 index 000000000000..163e752902b0 --- /dev/null +++ b/src/sonic-eventd/src/loghandler.cpp @@ -0,0 +1,37 @@ +#include +#include + +extern "C" void openSyslog() { + openlog (NULL, LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL4); +} + +extern "C" void writeToSyslog(std::string ev_id, int ev_sev, std::string ev_type, std::string ev_act, std::string ev_msg, std::string ev_static_msg) { + int SYSLOG_FACILITY = LOG_LOCAL4; + if (ev_act.empty()) { + const char LOG_FORMAT[] = "[%s], %%%s : %s - %s"; + // event Type + // Event Name + // Static Desc + // Dynamic Desc + + // raise a syslog message + syslog(LOG_MAKEPRI(ev_sev, SYSLOG_FACILITY), LOG_FORMAT, + ev_type.c_str(), + ev_id.c_str(), ev_static_msg.c_str(), ev_msg.c_str()); + } else { + const char LOG_FORMAT[] = "[%s] (%s), %%%s : %s - %s"; + // event Type + // event action + // Event Name + // Static Desc + // Dynamic Desc + // raise a syslog message + syslog(LOG_MAKEPRI(ev_sev, SYSLOG_FACILITY), LOG_FORMAT, + ev_type.c_str(), ev_act.c_str(), + ev_id.c_str(), ev_static_msg.c_str(), ev_msg.c_str()); + } +} + +extern "C" void closeSyslog() { + closelog (); +} diff --git a/src/sonic-eventd/tests/event_unittest.py b/src/sonic-eventd/tests/event_unittest.py new file mode 100644 index 000000000000..7e167e96a41c --- /dev/null +++ b/src/sonic-eventd/tests/event_unittest.py @@ -0,0 +1,253 @@ +from eventnotify import eventnotify +from swsscommon import swsscommon +import time +import enum +import time +import os +import json + +class EventUnitTest: + def unittest_init(self): + self.event_db = swsscommon.DBConnector("EVENT_DB", 0, True) + self.eventTbl = swsscommon.Table(self.event_db, "EVENT") + self.alarmTbl = swsscommon.Table(self.event_db, "ALARM") + self.eventStateTbl = swsscommon.Table(self.event_db, "EVENT_STATS") + self.alarmStateTbl = swsscommon.Table(self.event_db, "ALARM_STATS") + self.evProfileTbl = swsscommon.Table(self.event_db, "EVPROFILE") + self.notify = eventnotify.EventNotify() + + def test_event(self): + print("\nTEST: raise event") + eventCount = 0 + newEventCount = 0 + fvs = 0 + (status, fvs) = self.eventStateTbl.get("state") + for fv in fvs: + if fv[0] == "events": + eventCount = int(fv[1]) + + self.notify.logevent("CUSTOM_EVPROFILE_CHANGE", "x.json", eventnotify.EvAction.NOTIFY, "Raised for unit testing") + time.sleep(0.2) + (status, fvs) = self.eventStateTbl.get("state") + for fv in fvs: + if fv[0] == "events": + newEventCount = int(fv[1]) + if (eventCount+1) == newEventCount: + print("test_event success") + else: + print("ERROR: test_event failed" + " " + str(eventCount) + " " + str(newEventCount)) + + def raise_alarm(self): + print("\nTEST: raise alarm") + raisedCount = 0 + newRaisedCount = 0 + fvs = 0 + (status, fvs) = self.eventStateTbl.get("state") + for fv in fvs: + if fv[0] == "raised": + raisedCount = int(fv[1]) + + (status, fvs) = self.alarmStateTbl.get("state") + for fv in fvs: + if fv[0] == "alarms": + alarmCount = int(fv[1]) + if fv[0] == "warning": + warningCount = int(fv[1]) + + self.notify.logevent("DUMMY_ALARM", "test_raise_alarm", eventnotify.EvAction.RAISE_ALARM, "Raised for unit testing") + time.sleep(0.2) + + (status, fvs) = self.eventStateTbl.get("state") + for fv in fvs: + if fv[0] == "raised": + newRaisedCount = int(fv[1]) + + (status, fvs) = self.alarmStateTbl.get("state") + for fv in fvs: + if fv[0] == "alarms": + newAlarmCount = int(fv[1]) + if fv[0] == "warning": + newWarningCount = int(fv[1]) + + if (raisedCount+1) == newRaisedCount: + if (alarmCount + 1) == newAlarmCount: + if (warningCount + 1) == newWarningCount: + print("test_raise_alarm success") + else: + print("ERROR: test_raise_alarm severity count failed" + " " + str(warningCount) + " " + str(newWarningCount)) + else: + print("ERROR: test_raise_alarm alarm count failed" + " " + str(alarmCount) + " " + str(newAlarmCount)) + else: + print("ERROR: test_raise_alarm event count failed" + " " + str(raisedCount) + " " + str(newRaisedCount)) + + self.notify.logevent("DUMMY_ALARM", "test_raise_alarm", eventnotify.EvAction.CLEAR_ALARM, "Clearing for unit testing") + time.sleep(0.2) + + def clear_alarm(self): + print("\nTEST: raise and clear alarm") + self.notify.logevent("DUMMY_ALARM", "test_clear_alarm", eventnotify.EvAction.RAISE_ALARM, "Raised for unit testing") + time.sleep(0.2) + clearCount = 0 + newClearCount = 0 + fvs = 0 + (status, fvs) = self.eventStateTbl.get("state") + for fv in fvs: + if fv[0] == "cleared": + clearCount = int(fv[1]) + + (status, fvs) = self.alarmStateTbl.get("state") + for fv in fvs: + if fv[0] == "alarms": + alarmCount = int(fv[1]) + if fv[0] == "warning": + warningCount = int(fv[1]) + + self.notify.logevent("DUMMY_ALARM", "test_clear_alarm", eventnotify.EvAction.CLEAR_ALARM, "Clearing for unit testing") + time.sleep(0.2) + + (status, fvs) = self.eventStateTbl.get("state") + for fv in fvs: + if fv[0] == "cleared": + newClearCount = int(fv[1]) + + (status, fvs) = self.alarmStateTbl.get("state") + for fv in fvs: + if fv[0] == "alarms": + newAlarmCount = int(fv[1]) + if fv[0] == "warning": + newWarningCount = int(fv[1]) + + if (clearCount+1) == newClearCount: + if (alarmCount-1) == newAlarmCount: + if (warningCount-1) == newWarningCount: + print("test_clear_alarm success") + else: + print("ERROR: test_clear_alarm severity count failed" + " " + str(warningCount) + " " + str(newWarningCount)) + else: + print("ERROR: test_clear_alarm alarm count failed" + " " + str(alarmCount) + " " + str(newAlarmCount)) + else: + print("ERROR: test_clear_alarm failed" + " " + str(clearCount) + " " + str(newClearCount)) + + def ack_alarm(self): + print("\nTEST: ack alarm") + (status, fvs) = self.eventStateTbl.get("state") + ackCount = 0 + newAckCount = 0 + + for fv in fvs: + if fv[0] == "acked": + ackCount = int(fv[1]) + + (status, fvs) = self.alarmStateTbl.get("state") + for fv in fvs: + if fv[0] == "acknowledged": + alarmAckCount = int(fv[1]) + + self.notify.logevent("DUMMY_ALARM", "test_ack_alarm", eventnotify.EvAction.RAISE_ALARM, "RAISing for unit testing") + time.sleep(0.2) + + alm_keys = self.alarmTbl.getKeys() + print(alm_keys) + for key in alm_keys: + (status, fvs) = self.alarmTbl.get(key) + for fv in fvs: + if fv[1] == "test_ack_alarm": + raise_id = key + + print("raise_id is " + raise_id) + self.notify.logevent("", raise_id, eventnotify.EvAction.ACK_ALARM, "ACKNOWLEDGing for unit testing") + time.sleep(0.2) + + (status, fvs) = self.eventStateTbl.get("state") + for fv in fvs: + if fv[0] == "acked": + newAckCount = int(fv[1]) + + (status, fvs) = self.alarmStateTbl.get("state") + ackTime = "" + for fv in fvs: + if fv[0] == "acknowledged": + newAlarmAckCount = int(fv[1]) + if fv[0] == "acknowledge-time": + ackTime = fv[1] + + if (ackCount+1) == newAckCount: + if (alarmAckCount+1) == newAlarmAckCount: + if not ackTime: + print("test_ack_alarm success") + else: + print("ERROR: test_ack_alarm acknowedge-time not populated") + else: + print("ERROR: test_ack_alarm alarm-stats ack count failed" + " " + str(alarmAckCount) + " " + str(newAlarmAckCount)) + else: + print("ERROR: test_ack_alarm event-stats ack count failed" + " " + str(ackCount) + " " + str(newAckCount)) + + self.notify.logevent("DUMMY_ALARM", "test_ack_alarm", eventnotify.EvAction.CLEAR_ALARM, "CLEARing for unit testing") + + def unack_alarm(self): + print("\nTEST: unack alarm") + + self.notify.logevent("DUMMY_ALARM", "test_unack_alarm", eventnotify.EvAction.RAISE_ALARM, "RAISing for unit testing") + time.sleep(0.2) + + alm_keys = self.alarmTbl.getKeys() + print(alm_keys) + for key in alm_keys: + (status, fvs) = self.alarmTbl.get(key) + for fv in fvs: + if fv[1] == "test_unack_alarm": + raise_id = key + + print("raise_id is " + raise_id) + self.notify.logevent("", raise_id, eventnotify.EvAction.ACK_ALARM, "ACKNOWLEDGing for unit testing") + time.sleep(0.2) + + (status, fvs) = self.alarmStateTbl.get("state") + for fv in fvs: + if fv[0] == "acknowledged": + alarmAckCount = int(fv[1]) + + self.notify.logevent("", raise_id, eventnotify.EvAction.UNACK_ALARM, "UNACKNOWLEDGing for unit testing") + time.sleep(0.2) + + (status, fvs) = self.alarmStateTbl.get("state") + ackTime = "" + for fv in fvs: + if fv[0] == "acknowledged": + newAlarmAckCount = int(fv[1]) + if fv[0] == "acknowledge-time": + ackTime = fv[1] + + if (alarmAckCount-1) == newAlarmAckCount: + if not ackTime: + print("test_unack_alarm success") + else: + print("ERROR: test_unack_alarm acknowedge-time not populated") + else: + print("ERROR: test_unack_alarm alarm-stats ack count failed" + " " + str(alarmAckCount) + " " + str(newAlarmAckCount)) + + self.notify.logevent("DUMMY_ALARM", "test_unack_alarm", eventnotify.EvAction.CLEAR_ALARM, "CLEARing for unit testing") + + def evprofile_change_alarm_severity(self): + data = {} + data['events'] = [] + data['events'].append({ + 'name': 'DUMMY_ALARM', + 'severity': 'CRITICAL', + 'enable': 'true' + }) + + with open('unittest.json', 'w') as outfile: + json.dump(data, outfile) + + def evprofile_disable_event(self): + pass + +ut = EventUnitTest() +ut.unittest_init() +ut.test_event() +ut.raise_alarm() +ut.clear_alarm() +ut.ack_alarm() +ut.unack_alarm() + diff --git a/src/sonic-eventd/tests/eventnotify/__init__.py b/src/sonic-eventd/tests/eventnotify/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/src/sonic-eventd/tests/eventnotify/eventnotify.py b/src/sonic-eventd/tests/eventnotify/eventnotify.py new file mode 100644 index 000000000000..5e94265dbe45 --- /dev/null +++ b/src/sonic-eventd/tests/eventnotify/eventnotify.py @@ -0,0 +1,44 @@ +from swsscommon import swsscommon +import time +import enum +import time +import os + +class EvAction(enum.Enum): + NOTIFY = 0 + CLEAR_ALARM = 1 + RAISE_ALARM = 2 + ACK_ALARM = 3 + UNACK_ALARM = 4 + +class EventNotify: + def __init__(self): + """Create a new Event Notify class.""" + self.event_db = swsscommon.DBConnector("EVENT_DB", 0, True) + self.evntPubTbl = swsscommon.Table(self.event_db, "EVENTPUBSUB") + self.evProfileTbl = swsscommon.Table(self.event_db, "EVPROFILE") + self.evntStateTbl = swsscommon.Table(self.event_db, "EVENT_STATS") + self.almStateTbl = swsscommon.Table(self.event_db, "ALARM_STATS") + self.sequence_id = 0 + + def getTicks(self): + return int(time.time() * (10**7)) + 621355968000000000 + + def getActionStr(self, action): + if action == EvAction.CLEAR_ALARM: + return "CLEAR" + elif action == EvAction.RAISE_ALARM: + return "RAISE" + elif action == EvAction.ACK_ALARM: + return "ACKNOWLEDGE" + elif action == EvAction.UNACK_ALARM: + return "UNACKNOWLEDGE" + else: + return "" + + def logevent(self, name, source, action, message): + self.sequence_id = self.sequence_id + 1 + key = name + str(self.sequence_id) + actionStr = self.getActionStr(action) + fvs = swsscommon.FieldValuePairs([("time-created", str(self.getTicks())), ("type-id", name), ("text", message), ("action", actionStr), ("resource", source)]) + self.evntPubTbl.set(key, fvs) diff --git a/src/sonic-eventd/var/evprofile/default.json b/src/sonic-eventd/var/evprofile/default.json new file mode 100644 index 000000000000..40150a29583c --- /dev/null +++ b/src/sonic-eventd/var/evprofile/default.json @@ -0,0 +1,17 @@ +{ + "__README__" : "This is default map of events that eventd uses. Developer can modify this file and send SIGINT to eventd to make it read and use the updated file. Alternatively developer can test the new event by adding it to a custom event profile and use 'event profile ' command to apply that profile without having to send SIGINT to eventd. Developer need to commit default.json file with the new event after testing it out. Supported severities are: CRITICAL, MAJOR, MINOR, WARNING and INFORMATIONAL. Supported enable flag values are: true and false.", + "events":[ + { + "name" : "CUSTOM_EVPROFILE_CHANGE", + "severity" : "INFORMATIONAL", + "enable" : "true", + "message" : "Event Profile is applied." + }, + { + "name" : "DUMMY_ALARM", + "severity" : "WARNING", + "enable" : "true", + "message" : "Simulating an alarm." + } + ] +} From 7964d26709e2b1da4141ef8593dc9b250e2b7fc7 Mon Sep 17 00:00:00 2001 From: spenugondaa Date: Thu, 3 Jun 2021 02:13:09 +0000 Subject: [PATCH 02/19] Restore persisted redis data on cold boot Signed-off-by: spenugondaa --- files/build_templates/docker_image_ctl.j2 | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/files/build_templates/docker_image_ctl.j2 b/files/build_templates/docker_image_ctl.j2 index 7b4f91f3d5d0..7a9385f35d09 100644 --- a/files/build_templates/docker_image_ctl.j2 +++ b/files/build_templates/docker_image_ctl.j2 @@ -88,9 +88,16 @@ function preStartAction() # Load redis content from /host/warmboot/dump.rdb docker cp $WARM_DIR/dump.rdb database$DEV:/var/lib/redis/dump.rdb else - # Create an emtpy file and overwrite any RDB if already there - echo -n > /tmp/dump.rdb - docker cp /tmp/dump.rdb database$DEV:/var/lib/redis/ + COLD_DIR=/host/coldboot + # In case of cold reboot, load redis content from /host/coldboot/dump.rdb + if [[ -f $COLD_DIR/dump.rdb ]]; then + #Load redis content from /host/coldboot/dump.rdb + docker cp $COLD_DIR/dump.rdb database:/var/lib/redisrdb/dump.rdb + else + # Create an emtpy file and overwrite any RDB if already there + echo -n > /tmp/dump.rdb + docker cp /tmp/dump.rdb database:/var/lib/redisrdb/ + fi fi fi {%- elif docker_container_name == "snmp" %} From 766a30a6cd8272bbaeac01d36001ce1b167b9882 Mon Sep 17 00:00:00 2001 From: spenugondaa Date: Thu, 3 Jun 2021 22:56:20 +0000 Subject: [PATCH 03/19] use python3; fix event stats intialization; use right path for supervisord; Signed-off-by: spenugondaa --- .../docker-database/database_config.json.j2 | 4 +-- dockers/docker-eventd/docker-init.sh | 2 +- dockers/docker-eventd/supervisord.conf | 2 +- src/sonic-eventd/include/eventconsume.h | 2 +- src/sonic-eventd/src/eventconsume.cpp | 26 ++++++++++++++----- 5 files changed, 25 insertions(+), 11 deletions(-) diff --git a/dockers/docker-database/database_config.json.j2 b/dockers/docker-database/database_config.json.j2 index a17653c87b75..aa8308ebff29 100644 --- a/dockers/docker-database/database_config.json.j2 +++ b/dockers/docker-database/database_config.json.j2 @@ -11,13 +11,13 @@ "port": 6380, "unix_socket_path": "/var/run/redis-chassis/redis_chassis.sock", "persistence_for_warm_boot" : "yes" - } + }, "redis4":{ "hostname" : "{{HOST_IP}}", "port" : 6381, "unix_socket_path" : "/var/run/redis{{NAMESPACE_ID}}/redis4.sock", "persistence_for_warm_boot" : "yes" - }, + } }, "DATABASES" : { "APPL_DB" : { diff --git a/dockers/docker-eventd/docker-init.sh b/dockers/docker-eventd/docker-init.sh index 470b3f526e20..eb562c9669af 100755 --- a/dockers/docker-eventd/docker-init.sh +++ b/dockers/docker-eventd/docker-init.sh @@ -6,5 +6,5 @@ sed -i '/password=/d' /etc/supervisor/supervisord.conf cp /var/evprofile/default.json /etc/evprofile/default.json -exec /usr/bin/supervisord +exec /usr/local/bin/supervisord diff --git a/dockers/docker-eventd/supervisord.conf b/dockers/docker-eventd/supervisord.conf index 48f05557965a..c4460b4f6a4b 100644 --- a/dockers/docker-eventd/supervisord.conf +++ b/dockers/docker-eventd/supervisord.conf @@ -4,7 +4,7 @@ logfile_backups=2 nodaemon=true [eventlistener:dependent-startup] -command=python -m supervisord_dependent_startup +command=python3 -m supervisord_dependent_startup autostart=true autorestart=unexpected startretries=0 diff --git a/src/sonic-eventd/include/eventconsume.h b/src/sonic-eventd/include/eventconsume.h index 1b7e9aba76d4..eacb4684fd3f 100644 --- a/src/sonic-eventd/include/eventconsume.h +++ b/src/sonic-eventd/include/eventconsume.h @@ -44,7 +44,7 @@ class EventConsume void update_events(string seq_id, string ts, vector vec); void purge_events(); void modifyEventStats(string seq_id); - void initEventStats(); + void initEventStats(int, int, int, int); void initAlarmStats(); }; } diff --git a/src/sonic-eventd/src/eventconsume.cpp b/src/sonic-eventd/src/eventconsume.cpp index a280d1c80dae..5e42553b5c6f 100644 --- a/src/sonic-eventd/src/eventconsume.cpp +++ b/src/sonic-eventd/src/eventconsume.cpp @@ -82,7 +82,6 @@ EventConsume::EventConsume(DBConnector* dbConn) : openSyslog(); // intialize statistics - initEventStats(); initAlarmStats(); // populate local queue of event histor table @@ -405,9 +404,14 @@ void EventConsume::handle_notification(std::deque kco) void EventConsume::read_events() { vector tuples; m_eventTable.getContent(tuples); + int total = 0; + int raised = 0; + int acked = 0; + int cleared = 0; SWSS_LOG_ENTER(); for (auto tuple: tuples) { + total++; for (auto fv: kfvFieldsValues(tuple)) { if (fvField(fv) == "time-created") { char* end; @@ -418,8 +422,18 @@ void EventConsume::read_events() { uint64_t val = strtoull(fvValue(fv).c_str(), &end,10); event_history_list.push(make_pair( seq, val )); } + if (fvField(fv) == "action") { + if (!fvValue(fv).compare(EVENT_ACTION_RAISE_STR)) { + raised++; + } else if (!fvValue(fv).compare(EVENT_ACTION_CLEAR_STR)) { + cleared++; + } else if (!fvValue(fv).compare(EVENT_ACTION_ACK_STR)) { + acked++; + } + } } } + initEventStats(total, raised, cleared, acked); SWSS_LOG_NOTICE("eventd sequence-id intialized to %lu", seq_id); } @@ -645,16 +659,16 @@ void EventConsume::handle_custom_evprofile(std::deque en } } -void EventConsume::initEventStats() { +void EventConsume::initEventStats(int total, int raised, int cleared, int acked) { vector temp; FieldValueTuple fv; - fv = FieldValueTuple("events", "0"); + fv = FieldValueTuple("events", to_string(total)); temp.push_back(fv); - fv = FieldValueTuple("raised", "0"); + fv = FieldValueTuple("raised", to_string(raised)); temp.push_back(fv); - fv = FieldValueTuple("cleared", "0"); + fv = FieldValueTuple("cleared", to_string(cleared)); temp.push_back(fv); - fv = FieldValueTuple("acked", "0"); + fv = FieldValueTuple("acked", to_string(acked)); temp.push_back(fv); m_eventStatsTable.set("state", temp); } From 081b20d48b85490e6166b24fafa9af0cd4c2254a Mon Sep 17 00:00:00 2001 From: spenugondaa Date: Fri, 4 Jun 2021 17:52:45 +0000 Subject: [PATCH 04/19] updated syslog message format --- src/sonic-eventd/src/loghandler.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sonic-eventd/src/loghandler.cpp b/src/sonic-eventd/src/loghandler.cpp index 163e752902b0..d560ccc2e0e3 100755 --- a/src/sonic-eventd/src/loghandler.cpp +++ b/src/sonic-eventd/src/loghandler.cpp @@ -8,7 +8,7 @@ extern "C" void openSyslog() { extern "C" void writeToSyslog(std::string ev_id, int ev_sev, std::string ev_type, std::string ev_act, std::string ev_msg, std::string ev_static_msg) { int SYSLOG_FACILITY = LOG_LOCAL4; if (ev_act.empty()) { - const char LOG_FORMAT[] = "[%s], %%%s : %s - %s"; + const char LOG_FORMAT[] = "[%s], %%%s: %s %s"; // event Type // Event Name // Static Desc @@ -19,7 +19,7 @@ extern "C" void writeToSyslog(std::string ev_id, int ev_sev, std::string ev_type ev_type.c_str(), ev_id.c_str(), ev_static_msg.c_str(), ev_msg.c_str()); } else { - const char LOG_FORMAT[] = "[%s] (%s), %%%s : %s - %s"; + const char LOG_FORMAT[] = "[%s] (%s), %%%s: %s %s"; // event Type // event action // Event Name From 773fd200c27b518c94395e2dc0f9d0ef7310a797 Mon Sep 17 00:00:00 2001 From: spenugondaa Date: Sat, 5 Jun 2021 03:23:41 +0000 Subject: [PATCH 05/19] updated purge events code Signed-off-by: spenugondaa --- src/sonic-eventd/src/eventconsume.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sonic-eventd/src/eventconsume.cpp b/src/sonic-eventd/src/eventconsume.cpp index 5e42553b5c6f..bf56883fd7cb 100644 --- a/src/sonic-eventd/src/eventconsume.cpp +++ b/src/sonic-eventd/src/eventconsume.cpp @@ -557,7 +557,7 @@ void EventConsume::purge_events() { event_history_list.pop(); --size; } - +#if 0 const auto p1 = system_clock::now(); uint64_t tnow = duration_cast(p1.time_since_epoch()).count(); @@ -571,6 +571,7 @@ void EventConsume::purge_events() { return; } } +#endif return; } From 85288687f72b56ce80dc4b13e640459687c1a5a5 Mon Sep 17 00:00:00 2001 From: spenugondaa Date: Sat, 5 Jun 2021 20:33:00 +0000 Subject: [PATCH 06/19] Use time_ns() from python library Signed-off-by: spenugondaa --- src/sonic-eventd/src/eventconsume.cpp | 17 ++++++++++------- .../tests/eventnotify/eventnotify.py | 2 +- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/sonic-eventd/src/eventconsume.cpp b/src/sonic-eventd/src/eventconsume.cpp index bf56883fd7cb..539a693df84b 100644 --- a/src/sonic-eventd/src/eventconsume.cpp +++ b/src/sonic-eventd/src/eventconsume.cpp @@ -42,7 +42,7 @@ EventMap static_event_table; volatile bool g_run = true; uint64_t seq_id = 0; -uint64_t PURGE_DAYS = pow(2.592, 15); +uint64_t PURGE_SECONDS = 86400; //typedef pair pi; typedef pair pi; @@ -550,20 +550,24 @@ void EventConsume::purge_events() { SWSS_LOG_ENTER(); uint32_t size = event_history_list.size(); - while (size > count) { + while (size >= count) { pair oldest_entry = event_history_list.top(); + SWSS_LOG_NOTICE("Rollover based on count(%d/%d). Deleting %lu", size, count, oldest_entry.first); m_eventTable.del(to_string(oldest_entry.first)); modifyEventStats(to_string(oldest_entry.first)); event_history_list.pop(); --size; } -#if 0 + const auto p1 = system_clock::now(); - uint64_t tnow = duration_cast(p1.time_since_epoch()).count(); + unsigned tnow_seconds = duration_cast(p1.time_since_epoch()).count(); while (!event_history_list.empty()) { pair oldest_entry = event_history_list.top(); - if ((tnow - oldest_entry.second) > PURGE_DAYS) { + unsigned old_seconds = oldest_entry.second / 1000000000ULL; + + if ((tnow_seconds - old_seconds) > PURGE_SECONDS) { + SWSS_LOG_NOTICE("Rollover based on time (%lu days). Deleting %lu.. now %u old %u", (PURGE_SECONDS/days), oldest_entry.first, tnow_seconds, old_seconds); m_eventTable.del(to_string(oldest_entry.first)); modifyEventStats(to_string(oldest_entry.first)); event_history_list.pop(); @@ -571,7 +575,6 @@ void EventConsume::purge_events() { return; } } -#endif return; } @@ -583,7 +586,7 @@ void EventConsume::read_config_and_purge() { SWSS_LOG_NOTICE("no-of-days %d no-of-records %d", days, count); // update the nanosecond limit - PURGE_DAYS = days * pow(8.64, 13); + PURGE_SECONDS *= days; // purge events based on # of days purge_events(); diff --git a/src/sonic-eventd/tests/eventnotify/eventnotify.py b/src/sonic-eventd/tests/eventnotify/eventnotify.py index 5e94265dbe45..5327da942010 100644 --- a/src/sonic-eventd/tests/eventnotify/eventnotify.py +++ b/src/sonic-eventd/tests/eventnotify/eventnotify.py @@ -22,7 +22,7 @@ def __init__(self): self.sequence_id = 0 def getTicks(self): - return int(time.time() * (10**7)) + 621355968000000000 + return (time.time_ns()) def getActionStr(self, action): if action == EvAction.CLEAR_ALARM: From af8b22ac6467977fef4af491ef16691de9e549e7 Mon Sep 17 00:00:00 2001 From: spenugondaa Date: Sat, 5 Jun 2021 22:00:44 +0000 Subject: [PATCH 07/19] changed eventd.json limits to max-days and max-records --- src/sonic-eventd/etc/eventd.json | 4 ++-- src/sonic-eventd/src/eventconsume.cpp | 2 +- src/sonic-eventd/src/eventutils.cpp | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sonic-eventd/etc/eventd.json b/src/sonic-eventd/etc/eventd.json index 567add7c9e4c..d1fc54479037 100644 --- a/src/sonic-eventd/etc/eventd.json +++ b/src/sonic-eventd/etc/eventd.json @@ -1,6 +1,6 @@ { "__README__": "Specify size of event history table. Whichever limit is hit first, eventd wraps event history table around and deletes older records.", - "no-of-records": 40000, - "no-of-days": 30 + "max-records": 40000, + "max-days": 30 } diff --git a/src/sonic-eventd/src/eventconsume.cpp b/src/sonic-eventd/src/eventconsume.cpp index 539a693df84b..e2d7198f1418 100644 --- a/src/sonic-eventd/src/eventconsume.cpp +++ b/src/sonic-eventd/src/eventconsume.cpp @@ -583,7 +583,7 @@ void EventConsume::read_config_and_purge() { count = 0; // read from the manifest file parse_config(EVENTD_CONF_FILE, days, count); - SWSS_LOG_NOTICE("no-of-days %d no-of-records %d", days, count); + SWSS_LOG_NOTICE("max-days %d max-records %d", days, count); // update the nanosecond limit PURGE_SECONDS *= days; diff --git a/src/sonic-eventd/src/eventutils.cpp b/src/sonic-eventd/src/eventutils.cpp index 3d900aa48a59..0ab74e39278e 100644 --- a/src/sonic-eventd/src/eventutils.cpp +++ b/src/sonic-eventd/src/eventutils.cpp @@ -42,10 +42,10 @@ bool parse_config(const char *filename, unsigned int& days, unsigned int& count) std::ifstream ifs(filename); json j = json::parse(ifs); for (json::iterator it = j.begin(); it != j.end(); ++it) { - if(it.key() == "no-of-days") { + if(it.key() == "max-days") { days = it.value(); } - if(it.key() == "no-of-records") { + if(it.key() == "max-records") { count = it.value(); } } From 136aa908c7884530085c241aa757d03a7add29e1 Mon Sep 17 00:00:00 2001 From: spenugondaa Date: Sun, 6 Jun 2021 21:54:17 +0000 Subject: [PATCH 08/19] update ack counter on clear action Signed-off-by: spenugondaa --- src/sonic-eventd/include/eventconsume.h | 2 +- src/sonic-eventd/src/eventconsume.cpp | 16 ++++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/sonic-eventd/include/eventconsume.h b/src/sonic-eventd/include/eventconsume.h index eacb4684fd3f..5241a417ca07 100644 --- a/src/sonic-eventd/include/eventconsume.h +++ b/src/sonic-eventd/include/eventconsume.h @@ -39,7 +39,7 @@ class EventConsume void handle_custom_evprofile(std::deque); void read_events(); void updateAlarmStatistics(string ev_sev, string ev_act); - void updateEventStatistics(bool is_add, bool is_alarm, bool is_ack, bool is_clear); + void updateEventStatistics(bool is_add, bool is_alarm, bool is_ack, bool is_clear, bool is_unack); void read_config_and_purge(); void update_events(string seq_id, string ts, vector vec); void purge_events(); diff --git a/src/sonic-eventd/src/eventconsume.cpp b/src/sonic-eventd/src/eventconsume.cpp index e2d7198f1418..0f6662690762 100644 --- a/src/sonic-eventd/src/eventconsume.cpp +++ b/src/sonic-eventd/src/eventconsume.cpp @@ -177,6 +177,7 @@ void EventConsume::handle_notification(std::deque kco) bool is_raise = false; bool is_clear = false; bool is_ack = false; + bool is_unack = false; vector vec; ev_reckey = kfvKey(entry); @@ -368,7 +369,7 @@ void EventConsume::handle_notification(std::deque kco) } } else if (ev_act.compare(EVENT_ACTION_UNACK_STR) == 0) { if (raise_ack_flag.compare("true") == 0) { - is_ack = false; + is_unack = true; SWSS_LOG_NOTICE(" received un-ACKnowledge event - %s/%s", ev_id.c_str(), ev_src.c_str()); FieldValueTuple seqfv1("acknowledged", "false"); @@ -392,7 +393,7 @@ void EventConsume::handle_notification(std::deque kco) // verify the size of history table; delete older entry; add new entry update_events(to_string(seq_id), ev_timestamp, vec); - updateEventStatistics(true, is_raise, is_ack, is_clear); + updateEventStatistics(true, is_raise, is_ack, is_clear, is_unack); // raise a syslog message writeToSyslog(ev_id, (int) (SYSLOG_SEVERITY.find(ev_sev)->second), ev_type, ev_act, ev_msg, ev_static_msg); @@ -463,7 +464,7 @@ void EventConsume::updateAlarmStatistics(string ev_sev, string ev_act) { } else if (!fv.first.compare("acknowledged")) { if (ev_act.compare(EVENT_ACTION_ACK_STR) == 0) { fv.second = to_string(stoi(fv.second.c_str())+1); - } else if (ev_act.compare(EVENT_ACTION_UNACK_STR) == 0) { + } else if ((ev_act.compare(EVENT_ACTION_UNACK_STR) == 0) || (ev_act.compare(EVENT_ACTION_CLEAR_STR) == 0)){ fv.second = to_string(stoi(fv.second.c_str())-1); } temp.push_back(fv); @@ -475,7 +476,7 @@ void EventConsume::updateAlarmStatistics(string ev_sev, string ev_act) { } } -void EventConsume::updateEventStatistics(bool is_add, bool is_raise, bool is_ack, bool is_clear) { +void EventConsume::updateEventStatistics(bool is_add, bool is_raise, bool is_ack, bool is_clear, bool is_unack) { vector vec; vector temp; @@ -513,8 +514,10 @@ void EventConsume::updateEventStatistics(bool is_add, bool is_raise, bool is_ack } else { fv.second = to_string(stoi(fv.second.c_str())-1); } - temp.push_back(fv); + } else if (is_unack) { + fv.second = to_string(stoi(fv.second.c_str())-1); } + temp.push_back(fv); } } m_eventStatsTable.set("state", temp); @@ -529,6 +532,7 @@ void EventConsume::modifyEventStats(string seq_id) { bool is_raise = false; bool is_clear = false; bool is_ack = false; + bool is_unack = false; for (auto fvr: rec) { if (!fvr.first.compare("action")) { if (!fvr.second.compare(EVENT_ACTION_RAISE_STR)) { @@ -543,7 +547,7 @@ void EventConsume::modifyEventStats(string seq_id) { } } } - updateEventStatistics(false, is_raise, is_ack, is_clear); + updateEventStatistics(false, is_raise, is_ack, is_clear, is_unack); } void EventConsume::purge_events() { From 4f9000f5814b1ef8eb07ca566224776968d3f0ab Mon Sep 17 00:00:00 2001 From: spenugondaa Date: Sun, 6 Jun 2021 23:56:35 +0000 Subject: [PATCH 09/19] update acknowledged counter on alarm clear Signed-off-by: spenugondaa --- src/sonic-eventd/include/eventconsume.h | 1 + src/sonic-eventd/src/eventconsume.cpp | 26 ++++++++++++++++++++++--- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/sonic-eventd/include/eventconsume.h b/src/sonic-eventd/include/eventconsume.h index 5241a417ca07..fbc967b45ec2 100644 --- a/src/sonic-eventd/include/eventconsume.h +++ b/src/sonic-eventd/include/eventconsume.h @@ -46,6 +46,7 @@ class EventConsume void modifyEventStats(string seq_id); void initEventStats(int, int, int, int); void initAlarmStats(); + void clearAckAlarmStatistic(); }; } diff --git a/src/sonic-eventd/src/eventconsume.cpp b/src/sonic-eventd/src/eventconsume.cpp index 0f6662690762..8cc93d2ca098 100644 --- a/src/sonic-eventd/src/eventconsume.cpp +++ b/src/sonic-eventd/src/eventconsume.cpp @@ -307,10 +307,13 @@ void EventConsume::handle_notification(std::deque kco) SWSS_LOG_INFO("Received alarm-clear for non-existing alarm %s", almkey.c_str()); continue; } - // update alarm counters ONLY if it has not been ack'd before + // update alarm counters ONLY if it has not been ack'd before. This is because when alarm is ack'd, alarms/severity counter is reduced already. if (!ack_flag) { updateAlarmStatistics(ev_sev, ev_act); - } + } else { + // if it has been ack'd before, ack counter would have been incremented for this alrm. Now is the time reduce it. + clearAckAlarmStatistic(); + } } else { // ack/unack events comes with seq-id of raised alarm as resource field. // fetch details of "raised" alarm record @@ -464,7 +467,7 @@ void EventConsume::updateAlarmStatistics(string ev_sev, string ev_act) { } else if (!fv.first.compare("acknowledged")) { if (ev_act.compare(EVENT_ACTION_ACK_STR) == 0) { fv.second = to_string(stoi(fv.second.c_str())+1); - } else if ((ev_act.compare(EVENT_ACTION_UNACK_STR) == 0) || (ev_act.compare(EVENT_ACTION_CLEAR_STR) == 0)){ + } else if (ev_act.compare(EVENT_ACTION_UNACK_STR) == 0) { fv.second = to_string(stoi(fv.second.c_str())-1); } temp.push_back(fv); @@ -702,6 +705,23 @@ void EventConsume::initAlarmStats() { m_alarmStatsTable.set("state", temp); } + +void EventConsume::clearAckAlarmStatistic() { + vector vec; + vector temp; + + if (m_alarmStatsTable.get("state", vec)) { + for (auto fv: vec) { + if (!fv.first.compare("acknowledged")) { + fv.second = to_string(stoi(fv.second.c_str())-1); + temp.push_back(fv); + m_alarmStatsTable.set("state", temp); + return; + } + } + } +} + }; From d51e64f9ee47a8ce281f6ea7beaf59ee626b2c9c Mon Sep 17 00:00:00 2001 From: spenugondaa Date: Mon, 7 Jun 2021 00:03:01 +0000 Subject: [PATCH 10/19] update acknowledged event stats counter on clear Signed-off-by: spenugondaa --- src/sonic-eventd/src/eventconsume.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sonic-eventd/src/eventconsume.cpp b/src/sonic-eventd/src/eventconsume.cpp index 8cc93d2ca098..3edd28e135ac 100644 --- a/src/sonic-eventd/src/eventconsume.cpp +++ b/src/sonic-eventd/src/eventconsume.cpp @@ -313,6 +313,7 @@ void EventConsume::handle_notification(std::deque kco) } else { // if it has been ack'd before, ack counter would have been incremented for this alrm. Now is the time reduce it. clearAckAlarmStatistic(); + is_unack = true; } } else { // ack/unack events comes with seq-id of raised alarm as resource field. From cf2506f269c604f5dc5802a8b851be263e579f69 Mon Sep 17 00:00:00 2001 From: spenugondaa Date: Mon, 7 Jun 2021 04:16:52 +0000 Subject: [PATCH 11/19] event acknowledged counter update --- src/sonic-eventd/include/eventconsume.h | 2 +- src/sonic-eventd/src/eventconsume.cpp | 16 +++++----------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/sonic-eventd/include/eventconsume.h b/src/sonic-eventd/include/eventconsume.h index fbc967b45ec2..28a5cd2cb5af 100644 --- a/src/sonic-eventd/include/eventconsume.h +++ b/src/sonic-eventd/include/eventconsume.h @@ -39,7 +39,7 @@ class EventConsume void handle_custom_evprofile(std::deque); void read_events(); void updateAlarmStatistics(string ev_sev, string ev_act); - void updateEventStatistics(bool is_add, bool is_alarm, bool is_ack, bool is_clear, bool is_unack); + void updateEventStatistics(bool is_add, bool is_alarm, bool is_ack, bool is_clear); void read_config_and_purge(); void update_events(string seq_id, string ts, vector vec); void purge_events(); diff --git a/src/sonic-eventd/src/eventconsume.cpp b/src/sonic-eventd/src/eventconsume.cpp index 3edd28e135ac..af8982486fee 100644 --- a/src/sonic-eventd/src/eventconsume.cpp +++ b/src/sonic-eventd/src/eventconsume.cpp @@ -177,7 +177,6 @@ void EventConsume::handle_notification(std::deque kco) bool is_raise = false; bool is_clear = false; bool is_ack = false; - bool is_unack = false; vector vec; ev_reckey = kfvKey(entry); @@ -313,7 +312,6 @@ void EventConsume::handle_notification(std::deque kco) } else { // if it has been ack'd before, ack counter would have been incremented for this alrm. Now is the time reduce it. clearAckAlarmStatistic(); - is_unack = true; } } else { // ack/unack events comes with seq-id of raised alarm as resource field. @@ -373,7 +371,6 @@ void EventConsume::handle_notification(std::deque kco) } } else if (ev_act.compare(EVENT_ACTION_UNACK_STR) == 0) { if (raise_ack_flag.compare("true") == 0) { - is_unack = true; SWSS_LOG_NOTICE(" received un-ACKnowledge event - %s/%s", ev_id.c_str(), ev_src.c_str()); FieldValueTuple seqfv1("acknowledged", "false"); @@ -397,7 +394,7 @@ void EventConsume::handle_notification(std::deque kco) // verify the size of history table; delete older entry; add new entry update_events(to_string(seq_id), ev_timestamp, vec); - updateEventStatistics(true, is_raise, is_ack, is_clear, is_unack); + updateEventStatistics(true, is_raise, is_ack, is_clear); // raise a syslog message writeToSyslog(ev_id, (int) (SYSLOG_SEVERITY.find(ev_sev)->second), ev_type, ev_act, ev_msg, ev_static_msg); @@ -480,7 +477,7 @@ void EventConsume::updateAlarmStatistics(string ev_sev, string ev_act) { } } -void EventConsume::updateEventStatistics(bool is_add, bool is_raise, bool is_ack, bool is_clear, bool is_unack) { +void EventConsume::updateEventStatistics(bool is_add, bool is_raise, bool is_ack, bool is_clear) { vector vec; vector temp; @@ -518,10 +515,8 @@ void EventConsume::updateEventStatistics(bool is_add, bool is_raise, bool is_ack } else { fv.second = to_string(stoi(fv.second.c_str())-1); } - } else if (is_unack) { - fv.second = to_string(stoi(fv.second.c_str())-1); - } - temp.push_back(fv); + temp.push_back(fv); + } } } m_eventStatsTable.set("state", temp); @@ -536,7 +531,6 @@ void EventConsume::modifyEventStats(string seq_id) { bool is_raise = false; bool is_clear = false; bool is_ack = false; - bool is_unack = false; for (auto fvr: rec) { if (!fvr.first.compare("action")) { if (!fvr.second.compare(EVENT_ACTION_RAISE_STR)) { @@ -551,7 +545,7 @@ void EventConsume::modifyEventStats(string seq_id) { } } } - updateEventStatistics(false, is_raise, is_ack, is_clear, is_unack); + updateEventStatistics(false, is_raise, is_ack, is_clear); } void EventConsume::purge_events() { From 98682d9fb329e5c35cf39e58886372dc58c16de1 Mon Sep 17 00:00:00 2001 From: spenugondaa Date: Mon, 7 Jun 2021 22:46:32 +0000 Subject: [PATCH 12/19] protect against a bad application flooding Signed-off-by: spenugondaa --- src/sonic-eventd/src/eventconsume.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/sonic-eventd/src/eventconsume.cpp b/src/sonic-eventd/src/eventconsume.cpp index af8982486fee..230f65bf1da6 100644 --- a/src/sonic-eventd/src/eventconsume.cpp +++ b/src/sonic-eventd/src/eventconsume.cpp @@ -214,8 +214,6 @@ void EventConsume::handle_notification(std::deque kco) m_eventPubSubTable.del(ev_reckey); -//TODO: uncomment this out once unt test is done -#if 0 // flood protection. If a rogue application sends same event repeatedly, sqaush that repeated instances of that event if (!flood_ev_resource.compare(ev_src) && !flood_ev_action.compare(ev_act) && @@ -223,7 +221,7 @@ void EventConsume::handle_notification(std::deque kco) SWSS_LOG_INFO("Ignoring the event %s from %s action %s as it is repeated", ev_id.c_str(), ev_src.c_str(), ev_act.c_str()); continue; } -#endif + flood_ev_resource = ev_src; flood_ev_action = ev_act; flood_ev_id = ev_id; From 82e13126eb99a021735b26105c5fd3f5822673b8 Mon Sep 17 00:00:00 2001 From: spenugondaa Date: Mon, 7 Jun 2021 23:24:44 +0000 Subject: [PATCH 13/19] remove unused start.sh; cleanup eventconsumer Signed-off-by: spenugondaa --- dockers/docker-eventd/start.sh | 9 --------- src/sonic-eventd/src/eventconsume.cpp | 4 ++-- 2 files changed, 2 insertions(+), 11 deletions(-) delete mode 100644 dockers/docker-eventd/start.sh diff --git a/dockers/docker-eventd/start.sh b/dockers/docker-eventd/start.sh deleted file mode 100644 index 3b189572561f..000000000000 --- a/dockers/docker-eventd/start.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash - -rm -f /var/run/rsyslogd.pid - -supervisorctl start rsyslogd - -supervisorctl start eventd - - diff --git a/src/sonic-eventd/src/eventconsume.cpp b/src/sonic-eventd/src/eventconsume.cpp index 230f65bf1da6..655f359f4861 100644 --- a/src/sonic-eventd/src/eventconsume.cpp +++ b/src/sonic-eventd/src/eventconsume.cpp @@ -265,7 +265,7 @@ void EventConsume::handle_notification(std::deque kco) if (ev_act.compare(EVENT_ACTION_RAISE_STR) == 0) { is_raise = true; - // TODO: update system LED + // add entry to the lookup map cal_lookup_map.insert(make_pair(almkey, seq_id)); FieldValueTuple seqfv1("acknowledged", "false"); @@ -655,7 +655,7 @@ void EventConsume::handle_custom_evprofile(std::deque en uint64_t lookup_seq_id = (long unsigned int) (it.second); cal_lookup_map.erase(it.first); m_alarmTable.del(to_string(lookup_seq_id)); - // TODO: need to update alarm stats + // update alarm stats updateAlarmStatistics(tmp.severity, EVENT_ACTION_CLEAR_STR); } } From 385bc0b60d990e4020751ce53a41167384e67c6b Mon Sep 17 00:00:00 2001 From: spenugondaa Date: Tue, 8 Jun 2021 01:21:56 +0000 Subject: [PATCH 14/19] Revert "Restore persisted redis data on cold boot" This reverts commit 7964d26709e2b1da4141ef8593dc9b250e2b7fc7. --- files/build_templates/docker_image_ctl.j2 | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/files/build_templates/docker_image_ctl.j2 b/files/build_templates/docker_image_ctl.j2 index 7a9385f35d09..7b4f91f3d5d0 100644 --- a/files/build_templates/docker_image_ctl.j2 +++ b/files/build_templates/docker_image_ctl.j2 @@ -88,16 +88,9 @@ function preStartAction() # Load redis content from /host/warmboot/dump.rdb docker cp $WARM_DIR/dump.rdb database$DEV:/var/lib/redis/dump.rdb else - COLD_DIR=/host/coldboot - # In case of cold reboot, load redis content from /host/coldboot/dump.rdb - if [[ -f $COLD_DIR/dump.rdb ]]; then - #Load redis content from /host/coldboot/dump.rdb - docker cp $COLD_DIR/dump.rdb database:/var/lib/redisrdb/dump.rdb - else - # Create an emtpy file and overwrite any RDB if already there - echo -n > /tmp/dump.rdb - docker cp /tmp/dump.rdb database:/var/lib/redisrdb/ - fi + # Create an emtpy file and overwrite any RDB if already there + echo -n > /tmp/dump.rdb + docker cp /tmp/dump.rdb database$DEV:/var/lib/redis/ fi fi {%- elif docker_container_name == "snmp" %} From 1296e953e08a437ef1b2bbbe712fef727348c4bd Mon Sep 17 00:00:00 2001 From: spenugondaa Date: Wed, 9 Jun 2021 19:45:31 +0000 Subject: [PATCH 15/19] docker eventd infra cleanup Signed-off-by: spenugondaa --- dockers/docker-eventd/Dockerfile.j2 | 32 ---------------------------- dockers/docker-eventd/docker-init.sh | 2 -- 2 files changed, 34 deletions(-) diff --git a/dockers/docker-eventd/Dockerfile.j2 b/dockers/docker-eventd/Dockerfile.j2 index ea2db10d8141..7005f9f9367e 100644 --- a/dockers/docker-eventd/Dockerfile.j2 +++ b/dockers/docker-eventd/Dockerfile.j2 @@ -6,38 +6,6 @@ RUN [ -f /etc/rsyslog.conf ] && sed -ri "s/%syslogtag%/$docker_container_name#%s ## Make apt-get non-interactive ENV DEBIAN_FRONTEND=noninteractive -# Update apt cache and -# pre-install fundamental packages -RUN apt-get update && \ - apt-get -y install \ - curl \ - less \ - perl \ - procps \ - python3 \ - python3-distutils \ - python3-pip \ - rsyslog \ - vim-tiny - -# Upgrade pip via PyPI and uninstall the Debian version -#RUN pip3 install --upgrade pip -RUN apt-get purge -y python3-pip - -# setuptools and wheel are necessary for installing some Python wheel packages -#RUN pip3 install --no-cache-dir setuptools==49.6.00 -#RUN pip3 install --no-cache-dir wheel==0.35.1 - -# For templating -#RUN pip3 install j2cli - -# Install supervisor -#RUN pip3 install supervisor==4.2.1 - -## Install redis-tools dependencies -## TODO: implicitly install dependencies -RUN pip3 install supervisord-dependent-startup==1.4.0 - COPY \ {% for deb in docker_eventd_debs.split(' ') -%} debs/{{ deb }}{{' '}} diff --git a/dockers/docker-eventd/docker-init.sh b/dockers/docker-eventd/docker-init.sh index eb562c9669af..4bdb55360c0f 100755 --- a/dockers/docker-eventd/docker-init.sh +++ b/dockers/docker-eventd/docker-init.sh @@ -1,8 +1,6 @@ #!/usr/bin/env bash sonic-db-cli EVENT_DB config set notify-keyspace-events AKE -sed -i '/username=/d' /etc/supervisor/supervisord.conf -sed -i '/password=/d' /etc/supervisor/supervisord.conf cp /var/evprofile/default.json /etc/evprofile/default.json From 135275ba0ff39f04e62a7080793a095ab7aae5d3 Mon Sep 17 00:00:00 2001 From: spenugondaa Date: Mon, 21 Jun 2021 20:10:59 +0000 Subject: [PATCH 16/19] change instance name for event-db. Support cold boot to provide peristency. Signed-off-by: spenugondaa --- dockers/docker-database/critical_processes | 2 +- dockers/docker-database/database_config.json.j2 | 6 +++--- files/build_templates/docker_image_ctl.j2 | 9 +++++++-- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/dockers/docker-database/critical_processes b/dockers/docker-database/critical_processes index 6c45721cdb63..5fdfd100672d 100644 --- a/dockers/docker-database/critical_processes +++ b/dockers/docker-database/critical_processes @@ -1,2 +1,2 @@ program:redis -program:redis4 +program:redis1 diff --git a/dockers/docker-database/database_config.json.j2 b/dockers/docker-database/database_config.json.j2 index aa8308ebff29..b15dcf26ce0d 100644 --- a/dockers/docker-database/database_config.json.j2 +++ b/dockers/docker-database/database_config.json.j2 @@ -12,10 +12,10 @@ "unix_socket_path": "/var/run/redis-chassis/redis_chassis.sock", "persistence_for_warm_boot" : "yes" }, - "redis4":{ + "redis1":{ "hostname" : "{{HOST_IP}}", "port" : 6381, - "unix_socket_path" : "/var/run/redis{{NAMESPACE_ID}}/redis4.sock", + "unix_socket_path" : "/var/run/redis{{NAMESPACE_ID}}/redis1.sock", "persistence_for_warm_boot" : "yes" } }, @@ -98,7 +98,7 @@ "EVENT_DB" : { "id" : 14, "separator": "|", - "instance" : "redis4" + "instance" : "redis1" } }, "VERSION" : "1.0" diff --git a/files/build_templates/docker_image_ctl.j2 b/files/build_templates/docker_image_ctl.j2 index 7b4f91f3d5d0..214fa2e528a3 100644 --- a/files/build_templates/docker_image_ctl.j2 +++ b/files/build_templates/docker_image_ctl.j2 @@ -88,9 +88,14 @@ function preStartAction() # Load redis content from /host/warmboot/dump.rdb docker cp $WARM_DIR/dump.rdb database$DEV:/var/lib/redis/dump.rdb else + COLD_DIR=/host/coldboot # Create an emtpy file and overwrite any RDB if already there - echo -n > /tmp/dump.rdb - docker cp /tmp/dump.rdb database$DEV:/var/lib/redis/ + if [[ -s $COLD_DIR/dump.rdb ]]; then + docker cp $COLD_DIR/dump.rdb database$DEV:/var/lib/redis/dump.rdb + else + echo -n > /tmp/dump.rdb + docker cp /tmp/dump.rdb database$DEV:/var/lib/redis/ + fi fi fi {%- elif docker_container_name == "snmp" %} From 09f7b1a1004553c1b17319c1e1b3647739311d9c Mon Sep 17 00:00:00 2001 From: spenugondaa Date: Tue, 22 Jun 2021 03:57:01 +0000 Subject: [PATCH 17/19] on bootup, if the read event profile is same as already configured, ignore it. throttle-timeout support to specify time duration to keep throttling the event from an applicaiton. Signed-off-by: spenugondaa --- src/sonic-eventd/etc/eventd.json | 5 +++-- src/sonic-eventd/include/eventconsume.h | 2 +- src/sonic-eventd/include/eventutils.h | 2 +- src/sonic-eventd/src/eventconsume.cpp | 29 ++++++++++++++++++++----- 4 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/sonic-eventd/etc/eventd.json b/src/sonic-eventd/etc/eventd.json index d1fc54479037..7161e899a7b7 100644 --- a/src/sonic-eventd/etc/eventd.json +++ b/src/sonic-eventd/etc/eventd.json @@ -1,6 +1,7 @@ { - "__README__": "Specify size of event history table. Whichever limit is hit first, eventd wraps event history table around and deletes older records.", + "__README__": "Specify size of event history table. Whichever limit is hit first, eventd wraps event history table around and deletes older records. 'throttle_timeout' is used to specify how long eventd shoud sqaush same event from an application that gone bad.", "max-records": 40000, - "max-days": 30 + "max-days": 30, + "throttle-timeout": 3600 } diff --git a/src/sonic-eventd/include/eventconsume.h b/src/sonic-eventd/include/eventconsume.h index 28a5cd2cb5af..49e41fd5c4e9 100644 --- a/src/sonic-eventd/include/eventconsume.h +++ b/src/sonic-eventd/include/eventconsume.h @@ -33,7 +33,7 @@ class EventConsume SubscriberStateTable m_consumerTable; SubscriberStateTable m_evprofileTable; Table m_eventPubSubTable; - u_int32_t days, count; + u_int32_t days, count, ttimeout; void handle_notification(std::deque kco); void handle_custom_evprofile(std::deque); diff --git a/src/sonic-eventd/include/eventutils.h b/src/sonic-eventd/include/eventutils.h index bff76ce4da4e..d5b4f5e54be1 100644 --- a/src/sonic-eventd/include/eventutils.h +++ b/src/sonic-eventd/include/eventutils.h @@ -49,7 +49,7 @@ typedef unordered_map EventMap; bool isValidSeverity(string severityStr); bool isValidEnable(string enableStr); -bool parse_config(const char *filename, unsigned int& days, unsigned int& count); +bool parse_config(const char *filename, unsigned int& days, unsigned int& count, unsigned int &throttle_timeout); bool parse(const char *filename, EventMap& tmp_event_table); void merge(EventMap& static_event_table, EventMap &profile_map); void create_symlink(); diff --git a/src/sonic-eventd/src/eventconsume.cpp b/src/sonic-eventd/src/eventconsume.cpp index 655f359f4861..03ee71c612e5 100644 --- a/src/sonic-eventd/src/eventconsume.cpp +++ b/src/sonic-eventd/src/eventconsume.cpp @@ -67,6 +67,7 @@ map SYSLOG_SEVERITY_STR = { static string flood_ev_id; static string flood_ev_action; static string flood_ev_resource; +static system_clock::time_point f_old_ts; EventConsume::EventConsume(DBConnector* dbConn) : m_eventTable(dbConn, EVENT_HISTORY_TABLE_NAME), @@ -77,6 +78,7 @@ EventConsume::EventConsume(DBConnector* dbConn) : m_evprofileTable(dbConn, EVENT_EVPROFILE_TABLE_NAME), m_eventPubSubTable(dbConn, EVENT_PUBSUB_TABLE_NAME) { SWSS_LOG_ENTER(); + f_old_ts = system_clock::now(); // open syslog connection openSyslog(); @@ -212,10 +214,13 @@ void EventConsume::handle_notification(std::deque kco) } } - m_eventPubSubTable.del(ev_reckey); + m_eventPubSubTable.del(ev_reckey); - // flood protection. If a rogue application sends same event repeatedly, sqaush that repeated instances of that event - if (!flood_ev_resource.compare(ev_src) && + // flood protection. If a rogue application sends same event repeatedly, throttle repeated instances of that event + system_clock::time_point f_current_ts = system_clock::now(); + auto int_s = std::chrono::duration_cast(f_current_ts - f_old_ts); + if ((int_s.count() < ttimeout) && + !flood_ev_resource.compare(ev_src) && !flood_ev_action.compare(ev_act) && !flood_ev_id.compare(ev_id)) { SWSS_LOG_INFO("Ignoring the event %s from %s action %s as it is repeated", ev_id.c_str(), ev_src.c_str(), ev_act.c_str()); @@ -225,6 +230,7 @@ void EventConsume::handle_notification(std::deque kco) flood_ev_resource = ev_src; flood_ev_action = ev_act; flood_ev_id = ev_id; + f_old_ts = system_clock::now(); // get static info auto it = static_event_table.find(ev_id); @@ -581,9 +587,10 @@ void EventConsume::purge_events() { void EventConsume::read_config_and_purge() { days = 0; count = 0; + ttimeout = 0; // read from the manifest file - parse_config(EVENTD_CONF_FILE, days, count); - SWSS_LOG_NOTICE("max-days %d max-records %d", days, count); + parse_config(EVENTD_CONF_FILE, days, count, ttimeout); + SWSS_LOG_NOTICE("max-days %d max-records %d throttle-timeout %d", days, count, ttimeout); // update the nanosecond limit PURGE_SECONDS *= days; @@ -628,6 +635,18 @@ void EventConsume::handle_custom_evprofile(std::deque en SWSS_LOG_NOTICE("Received profile is %s", custom_profile.c_str()); + // make sure that event profile is not already configured + char buf[1024]; + std::size_t len; + if ((len = readlink(EVENTD_PROFILE_SYMLINK, buf, sizeof(buf)-1)) > 0) { + buf[len] = '\0'; + + if (string(buf).compare(custom_profile) == 0) { + SWSS_LOG_DEBUG("Event Profile name is already configured."); + return; + } + } + // the profile is already validated by rest-server. create symlink if (unlink(EVENTD_PROFILE_SYMLINK) != 0) { // it is possible.. if there is no symlink exists and user trying for the first time From 96f887d98ddae1b8b71f0e13dcc97b6d4fddfb8b Mon Sep 17 00:00:00 2001 From: spenugondaa Date: Tue, 22 Jun 2021 18:32:05 +0000 Subject: [PATCH 18/19] check message as well while throttling. Signed-off-by: spenugondaa --- src/sonic-eventd/etc/eventd.json | 5 ++--- src/sonic-eventd/include/eventconsume.h | 2 +- src/sonic-eventd/include/eventutils.h | 2 +- src/sonic-eventd/src/eventconsume.cpp | 20 ++++++++------------ 4 files changed, 12 insertions(+), 17 deletions(-) diff --git a/src/sonic-eventd/etc/eventd.json b/src/sonic-eventd/etc/eventd.json index 7161e899a7b7..d1fc54479037 100644 --- a/src/sonic-eventd/etc/eventd.json +++ b/src/sonic-eventd/etc/eventd.json @@ -1,7 +1,6 @@ { - "__README__": "Specify size of event history table. Whichever limit is hit first, eventd wraps event history table around and deletes older records. 'throttle_timeout' is used to specify how long eventd shoud sqaush same event from an application that gone bad.", + "__README__": "Specify size of event history table. Whichever limit is hit first, eventd wraps event history table around and deletes older records.", "max-records": 40000, - "max-days": 30, - "throttle-timeout": 3600 + "max-days": 30 } diff --git a/src/sonic-eventd/include/eventconsume.h b/src/sonic-eventd/include/eventconsume.h index 49e41fd5c4e9..28a5cd2cb5af 100644 --- a/src/sonic-eventd/include/eventconsume.h +++ b/src/sonic-eventd/include/eventconsume.h @@ -33,7 +33,7 @@ class EventConsume SubscriberStateTable m_consumerTable; SubscriberStateTable m_evprofileTable; Table m_eventPubSubTable; - u_int32_t days, count, ttimeout; + u_int32_t days, count; void handle_notification(std::deque kco); void handle_custom_evprofile(std::deque); diff --git a/src/sonic-eventd/include/eventutils.h b/src/sonic-eventd/include/eventutils.h index d5b4f5e54be1..bff76ce4da4e 100644 --- a/src/sonic-eventd/include/eventutils.h +++ b/src/sonic-eventd/include/eventutils.h @@ -49,7 +49,7 @@ typedef unordered_map EventMap; bool isValidSeverity(string severityStr); bool isValidEnable(string enableStr); -bool parse_config(const char *filename, unsigned int& days, unsigned int& count, unsigned int &throttle_timeout); +bool parse_config(const char *filename, unsigned int& days, unsigned int& count); bool parse(const char *filename, EventMap& tmp_event_table); void merge(EventMap& static_event_table, EventMap &profile_map); void create_symlink(); diff --git a/src/sonic-eventd/src/eventconsume.cpp b/src/sonic-eventd/src/eventconsume.cpp index 03ee71c612e5..a87b7f014d5e 100644 --- a/src/sonic-eventd/src/eventconsume.cpp +++ b/src/sonic-eventd/src/eventconsume.cpp @@ -67,7 +67,7 @@ map SYSLOG_SEVERITY_STR = { static string flood_ev_id; static string flood_ev_action; static string flood_ev_resource; -static system_clock::time_point f_old_ts; +static string flood_ev_msg; EventConsume::EventConsume(DBConnector* dbConn) : m_eventTable(dbConn, EVENT_HISTORY_TABLE_NAME), @@ -78,7 +78,6 @@ EventConsume::EventConsume(DBConnector* dbConn) : m_evprofileTable(dbConn, EVENT_EVPROFILE_TABLE_NAME), m_eventPubSubTable(dbConn, EVENT_PUBSUB_TABLE_NAME) { SWSS_LOG_ENTER(); - f_old_ts = system_clock::now(); // open syslog connection openSyslog(); @@ -217,20 +216,18 @@ void EventConsume::handle_notification(std::deque kco) m_eventPubSubTable.del(ev_reckey); // flood protection. If a rogue application sends same event repeatedly, throttle repeated instances of that event - system_clock::time_point f_current_ts = system_clock::now(); - auto int_s = std::chrono::duration_cast(f_current_ts - f_old_ts); - if ((int_s.count() < ttimeout) && - !flood_ev_resource.compare(ev_src) && + if (!flood_ev_resource.compare(ev_src) && !flood_ev_action.compare(ev_act) && - !flood_ev_id.compare(ev_id)) { - SWSS_LOG_INFO("Ignoring the event %s from %s action %s as it is repeated", ev_id.c_str(), ev_src.c_str(), ev_act.c_str()); + !flood_ev_id.compare(ev_id) && + !(flood_ev_msg.compare(ev_msg))) { + SWSS_LOG_INFO("Ignoring the event %s from %s action %s msg %s as it is repeated", ev_id.c_str(), ev_src.c_str(), ev_act.c_str(), ev_msg.c_str()); continue; } flood_ev_resource = ev_src; flood_ev_action = ev_act; flood_ev_id = ev_id; - f_old_ts = system_clock::now(); + flood_ev_msg = ev_msg; // get static info auto it = static_event_table.find(ev_id); @@ -587,10 +584,9 @@ void EventConsume::purge_events() { void EventConsume::read_config_and_purge() { days = 0; count = 0; - ttimeout = 0; // read from the manifest file - parse_config(EVENTD_CONF_FILE, days, count, ttimeout); - SWSS_LOG_NOTICE("max-days %d max-records %d throttle-timeout %d", days, count, ttimeout); + parse_config(EVENTD_CONF_FILE, days, count); + SWSS_LOG_NOTICE("max-days %d max-records %d", days, count); // update the nanosecond limit PURGE_SECONDS *= days; From 6db5f12ad19c0ded6acfb6773931667c5d8c0e80 Mon Sep 17 00:00:00 2001 From: Srinadh Penugonda Date: Sun, 14 Nov 2021 20:03:11 +0000 Subject: [PATCH 19/19] Updated based on review comments; log levels, time stampswq Signed-off-by: Srinadh Penugonda --- src/sonic-eventd/debian/changelog | 2 +- src/sonic-eventd/include/eventconsume.h | 13 +- src/sonic-eventd/lib/debian/changelog | 2 +- src/sonic-eventd/lib/src/Makefile.am | 4 - src/sonic-eventd/src/eventconsume.cpp | 418 +++++++++++++----------- src/sonic-eventd/src/eventd.cpp | 5 - 6 files changed, 245 insertions(+), 199 deletions(-) diff --git a/src/sonic-eventd/debian/changelog b/src/sonic-eventd/debian/changelog index f279392cfd4a..bd71a2619f89 100644 --- a/src/sonic-eventd/debian/changelog +++ b/src/sonic-eventd/debian/changelog @@ -2,5 +2,5 @@ sonic (1.0.0) stable; urgency=medium * Initial release. - -- Eventd Thu, 9 Apr 2020 12:00:00 -0800 + -- Eventd Thu, 9 Apr 2021 12:00:00 -0800 diff --git a/src/sonic-eventd/include/eventconsume.h b/src/sonic-eventd/include/eventconsume.h index 28a5cd2cb5af..18654dba8299 100644 --- a/src/sonic-eventd/include/eventconsume.h +++ b/src/sonic-eventd/include/eventconsume.h @@ -19,7 +19,7 @@ using namespace std; class EventConsume { public: - EventConsume(DBConnector* dbConn); + EventConsume(DBConnector *dbConn); ~EventConsume(); void run(); void read_eventd_config(bool read_all=true); @@ -44,11 +44,16 @@ class EventConsume void update_events(string seq_id, string ts, vector vec); void purge_events(); void modifyEventStats(string seq_id); - void initEventStats(int, int, int, int); - void initAlarmStats(); void clearAckAlarmStatistic(); + void resetAlarmStats(int, int, int, int, int, int); + void fetchFieldValues(const vector& , vector &, string &, string &, string &, string &, string &); + bool isFloodedEvent(string, string, string, string); + bool staticInfoExists(string &, string &, string &, string &, vector &); + bool udpateLocalCacheAndAlarmTable(string, bool &); + void initStats(); + void updateAckInfo(bool, string, string, string, string); + void fetchRaiseInfo(vector &, string, string &, string &, string &, string &, string &); }; } #endif /* __EVENTCONSUME_H__ */ - diff --git a/src/sonic-eventd/lib/debian/changelog b/src/sonic-eventd/lib/debian/changelog index ebdbdea909d3..0f2ff23294dc 100644 --- a/src/sonic-eventd/lib/debian/changelog +++ b/src/sonic-eventd/lib/debian/changelog @@ -2,4 +2,4 @@ sonic (1.0.0) stable; urgency=medium * Initial release. - -- Eventd Thu, 9 Apr 2020 12:00:00 -0800 + -- Eventd Thu, 9 Apr 2021 12:00:00 -0800 diff --git a/src/sonic-eventd/lib/src/Makefile.am b/src/sonic-eventd/lib/src/Makefile.am index a99263427cd4..84dbe3114fe9 100644 --- a/src/sonic-eventd/lib/src/Makefile.am +++ b/src/sonic-eventd/lib/src/Makefile.am @@ -6,14 +6,10 @@ lib_LTLIBRARIES = libeventnotify.la if DEBUG DBGFLAGS = -ggdb -DDEBUG else -#DBGFLAGS = -g -DNDEBUG DBGFLAGS = -ggdb -DDEBUG endif - libeventnotify_la_SOURCES = eventnotify.cpp -#CXXFLAGS += -ffunction-sections -fdata-sections -#eventd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(COV_CFLAGS) $(ASAN_CFLAGS) $(CXXFLAGS) libeventnotify_la_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(COV_CFLAGS) $(ASAN_CFLAGS) libeventnotify_la_LIBADD = -lhiredis -lswsscommon $(COV_LDFLAGS) $(ASAN_LDFLAGS) diff --git a/src/sonic-eventd/src/eventconsume.cpp b/src/sonic-eventd/src/eventconsume.cpp index a87b7f014d5e..1bfb9c8d1a31 100644 --- a/src/sonic-eventd/src/eventconsume.cpp +++ b/src/sonic-eventd/src/eventconsume.cpp @@ -82,10 +82,10 @@ EventConsume::EventConsume(DBConnector* dbConn) : // open syslog connection openSyslog(); - // intialize statistics - initAlarmStats(); + // init stats + initStats(); - // populate local queue of event histor table + // populate local queue of event history table read_events(); // read and apply eventd configuration files @@ -128,9 +128,11 @@ void EventConsume::run() if (sel == &m_evprofileTable) { m_evprofileTable.pops(kco); handle_custom_evprofile(kco); - } else { + } else if (sel == &m_consumerTable) { m_consumerTable.pops(kco); handle_notification(kco); + } else { + SWSS_LOG_DEBUG("received invalid trigger by select"); } } } @@ -146,6 +148,7 @@ void EventConsume::read_eventd_config(bool read_all) { static_event_table.clear(); if (!parse(EVENTD_DEFAULT_MAP_FILE, static_event_table)) { SWSS_LOG_ERROR("Can not initialize event map"); + closeSyslog(); exit(0); } @@ -186,71 +189,21 @@ void EventConsume::handle_notification(std::deque kco) continue; } + // parse the record and fetch various event fields const vector& data = kfvFieldsValues(entry); - for (auto idx : data) { - if (fvField(idx) == "type-id") { - ev_id = fvValue(idx); - vec.push_back(idx); - SWSS_LOG_DEBUG("type-id: <%s> ", ev_id.c_str()); - } else if (fvField(idx) == "text") { - ev_msg = fvValue(idx); - vec.push_back(idx); - SWSS_LOG_DEBUG("text: <%s> ", ev_msg.c_str()); - } else if (fvField(idx) == "resource") { - ev_src = fvValue(idx); - vec.push_back(idx); - SWSS_LOG_DEBUG("resource: <%s> ", ev_src.c_str()); - } else if (fvField(idx) == "action") { - ev_act = fvValue(idx); - // for events, action is empty - if (!ev_act.empty()) { - vec.push_back(idx); - } - } else if (fvField(idx) == "time-created") { - ev_timestamp = fvValue(idx); - vec.push_back(idx); - SWSS_LOG_DEBUG("time-created: <%s> ", ev_timestamp.c_str()); - } - } + fetchFieldValues(data, vec, ev_id, ev_msg, ev_src, ev_act, ev_timestamp); - m_eventPubSubTable.del(ev_reckey); + // delete the pubsub entry + m_eventPubSubTable.del(ev_reckey); // flood protection. If a rogue application sends same event repeatedly, throttle repeated instances of that event - if (!flood_ev_resource.compare(ev_src) && - !flood_ev_action.compare(ev_act) && - !flood_ev_id.compare(ev_id) && - !(flood_ev_msg.compare(ev_msg))) { - SWSS_LOG_INFO("Ignoring the event %s from %s action %s msg %s as it is repeated", ev_id.c_str(), ev_src.c_str(), ev_act.c_str(), ev_msg.c_str()); - continue; + if (isFloodedEvent(ev_src, ev_act, ev_id, ev_msg)) { + continue; } - flood_ev_resource = ev_src; - flood_ev_action = ev_act; - flood_ev_id = ev_id; - flood_ev_msg = ev_msg; - // get static info - auto it = static_event_table.find(ev_id); - if (it != static_event_table.end()) { - EventInfo tmp = (EventInfo) (it->second); - // discard the event as event_static_map shows enable is false for this event - if (tmp.enable == EVENT_ENABLE_FALSE_STR) { - SWSS_LOG_NOTICE("Discarding event <%s> as it is set to disabled", ev_id.c_str()); - continue; - } - - // get severity in the map and store it in the db - ev_sev = tmp.severity; - ev_static_msg = tmp.static_event_msg; - SWSS_LOG_DEBUG("static info: <%s> <%s> ", tmp.severity.c_str(), tmp.static_event_msg.c_str()); - - FieldValueTuple seqfv1("severity", tmp.severity); - vec.push_back(seqfv1); - } else { - if ((ev_act.compare(EVENT_ACTION_ACK_STR) && ev_act.compare(EVENT_ACTION_UNACK_STR))) { - SWSS_LOG_ERROR("static info NOT FOUND for <%s> ", ev_id.c_str()); - continue; - } + if (!staticInfoExists(ev_id, ev_act, ev_sev, ev_static_msg, vec)) { + continue; } // increment save seq-id for the newly received event @@ -271,6 +224,7 @@ void EventConsume::handle_notification(std::deque kco) // add entry to the lookup map cal_lookup_map.insert(make_pair(almkey, seq_id)); + // add acknowledged field intializing it to false FieldValueTuple seqfv1("acknowledged", "false"); vec.push_back(seqfv1); m_alarmTable.set(to_string(seq_id), vec); @@ -279,114 +233,56 @@ void EventConsume::handle_notification(std::deque kco) updateAlarmStatistics(ev_sev, ev_act); } else if (ev_act.compare(EVENT_ACTION_CLEAR_STR) == 0) { is_clear = true; - SWSS_LOG_NOTICE(" Received clear alarm for %s", almkey.c_str()); + SWSS_LOG_DEBUG(" Received clear alarm for %s", almkey.c_str()); - // find and remove the raised alarm - uint64_t lookup_seq_id = 0; bool ack_flag = false; - auto it = cal_lookup_map.find(almkey); - if (it != cal_lookup_map.end()) { - lookup_seq_id = (uint64_t) (it->second); - cal_lookup_map.erase(almkey); - - // get status of is_aknowledged flag so that we dont decrement counters twice - vector alm_rec; - m_alarmTable.get(to_string(lookup_seq_id), alm_rec); - for (auto fvr: alm_rec) { - if (!fvr.first.compare("acknowledged")) { - ack_flag = (fvr.second.compare("true") == 0) ? true : false; - break; - } - } - - // delete the record from alarm table - m_alarmTable.del(to_string(lookup_seq_id)); - } else { - // possible - when event profile removes alarms for which enable is false and application cleared them later. - // ignore by logging a debug message.. - SWSS_LOG_INFO("Received alarm-clear for non-existing alarm %s", almkey.c_str()); + // remove entry from local cache, alarm table + if (! udpateLocalCacheAndAlarmTable(almkey, ack_flag)) { continue; } - // update alarm counters ONLY if it has not been ack'd before. This is because when alarm is ack'd, alarms/severity counter is reduced already. + + // update alarm counters ONLY if it has not been ack'd before. + // This is because when alarm is ack'd, alarms/severity counter is reduced already. if (!ack_flag) { updateAlarmStatistics(ev_sev, ev_act); } else { - // if it has been ack'd before, ack counter would have been incremented for this alrm. Now is the time reduce it. + // if it has been ack'd before, ack counter would have been incremented for this alrm. + // Now is the time reduce it. clearAckAlarmStatistic(); } } else { // ack/unack events comes with seq-id of raised alarm as resource field. // fetch details of "raised" alarm record - vector raise_vec; - m_alarmTable.get(ev_src, raise_vec); string raise_act; string raise_ack_flag; string raise_ts; - for (auto fv: raise_vec) { - if (!fv.first.compare("type-id")) { - ev_id = fv.second; - vec.push_back(fv); - } - if (!fv.first.compare("severity")) { - ev_sev = fv.second; - vec.push_back(fv); - } - if (!fv.first.compare("action")) { - raise_act = fv.second; - } - if (!fv.first.compare("acknowledged")) { - raise_ack_flag = fv.second; - } - if (!fv.first.compare("time-created")) { - raise_ts = fv.second; - } - } - // vector to hold those parameters that change on the raised record - vector ack_vec; + // fetch information from raised event record + fetchRaiseInfo(vec, ev_src, ev_id, ev_sev, raise_act, raise_ack_flag, raise_ts); if (ev_act.compare(EVENT_ACTION_ACK_STR) == 0) { if (raise_ack_flag.compare("true") == 0) { - SWSS_LOG_ERROR(" %s/%s is already acknowledged", ev_id.c_str(), ev_src.c_str()); + SWSS_LOG_NOTICE(" %s/%s is already acknowledged", ev_id.c_str(), ev_src.c_str()); continue; } if (raise_act.compare(EVENT_ACTION_RAISE_STR) == 0) { is_ack = true; - SWSS_LOG_NOTICE(" received ACKnowledge event - %s/%s", ev_id.c_str(), ev_src.c_str()); - - FieldValueTuple seqfv1("acknowledged", "true"); - ack_vec.push_back(seqfv1); - - FieldValueTuple seqfv2("acknowledge-time", ev_timestamp); - ack_vec.push_back(seqfv2); - - // update alarm stats - updateAlarmStatistics(ev_sev, ev_act); - - // update alarm/event tables for the "raise" record with ack flag and ack timestamp - m_alarmTable.set(ev_src, ack_vec); - m_eventTable.set(ev_src, ack_vec); + SWSS_LOG_DEBUG(" received ACKnowledge event - %s/%s", ev_id.c_str(), ev_src.c_str()); + + // update the record with ack flag and ack-time and stats + updateAckInfo(is_ack, ev_timestamp, ev_sev, ev_act, ev_src); } else { - SWSS_LOG_ERROR(" %s/%s is not in raised state", ev_id.c_str(), ev_src.c_str()); + SWSS_LOG_NOTICE(" %s/%s is not in raised state", ev_id.c_str(), ev_src.c_str()); continue; } } else if (ev_act.compare(EVENT_ACTION_UNACK_STR) == 0) { if (raise_ack_flag.compare("true") == 0) { - SWSS_LOG_NOTICE(" received un-ACKnowledge event - %s/%s", ev_id.c_str(), ev_src.c_str()); - - FieldValueTuple seqfv1("acknowledged", "false"); - ack_vec.push_back(seqfv1); - - FieldValueTuple seqfv2("acknowledge-time", ev_timestamp); - ack_vec.push_back(seqfv2); + SWSS_LOG_DEBUG(" received un-ACKnowledge event - %s/%s", ev_id.c_str(), ev_src.c_str()); - // update alarm stats as it is un-ack, is in effect, a raise action for stats - updateAlarmStatistics(ev_sev, ev_act); - // update alarm/event tables for the "raise" record with ack flag and ack timestamp - m_alarmTable.set(ev_src, ack_vec); - m_eventTable.set(ev_src, ack_vec); + // update the record with ack flag and ack-time and stats + updateAckInfo(is_ack, ev_timestamp, ev_sev, ev_act, ev_src); } else { - SWSS_LOG_ERROR(" %s/%s is already un-acknowledged", ev_id.c_str(), ev_src.c_str()); + SWSS_LOG_NOTICE(" %s/%s is already un-acknowledged", ev_id.c_str(), ev_src.c_str()); continue; } } @@ -407,14 +303,10 @@ void EventConsume::handle_notification(std::deque kco) void EventConsume::read_events() { vector tuples; m_eventTable.getContent(tuples); - int total = 0; - int raised = 0; - int acked = 0; - int cleared = 0; SWSS_LOG_ENTER(); + // find out last sequence-id; build local history list for (auto tuple: tuples) { - total++; for (auto fv: kfvFieldsValues(tuple)) { if (fvField(fv) == "time-created") { char* end; @@ -425,18 +317,8 @@ void EventConsume::read_events() { uint64_t val = strtoull(fvValue(fv).c_str(), &end,10); event_history_list.push(make_pair( seq, val )); } - if (fvField(fv) == "action") { - if (!fvValue(fv).compare(EVENT_ACTION_RAISE_STR)) { - raised++; - } else if (!fvValue(fv).compare(EVENT_ACTION_CLEAR_STR)) { - cleared++; - } else if (!fvValue(fv).compare(EVENT_ACTION_ACK_STR)) { - acked++; - } - } } } - initEventStats(total, raised, cleared, acked); SWSS_LOG_NOTICE("eventd sequence-id intialized to %lu", seq_id); } @@ -474,7 +356,7 @@ void EventConsume::updateAlarmStatistics(string ev_sev, string ev_act) { } m_alarmStatsTable.set("state", temp); } else { - SWSS_LOG_ERROR("Can not update Alarm Statistics table"); + SWSS_LOG_ERROR("Can not update alarm statistics (table does not exist)"); } } @@ -517,12 +399,13 @@ void EventConsume::updateEventStatistics(bool is_add, bool is_raise, bool is_ack fv.second = to_string(stoi(fv.second.c_str())-1); } temp.push_back(fv); - } + } } } + m_eventStatsTable.set("state", temp); } else { - SWSS_LOG_ERROR("Can not update Event Statistics table"); + SWSS_LOG_ERROR("Can not update event statistics (table does not exist)"); } } @@ -629,7 +512,7 @@ void EventConsume::handle_custom_evprofile(std::deque en } string custom_profile = EVENTD_PROFILE_DIR + filename; - SWSS_LOG_NOTICE("Received profile is %s", custom_profile.c_str()); + SWSS_LOG_DEBUG("Received profile is %s", custom_profile.c_str()); // make sure that event profile is not already configured char buf[1024]; @@ -651,7 +534,7 @@ void EventConsume::handle_custom_evprofile(std::deque en if (symlink(custom_profile.c_str(), EVENTD_PROFILE_SYMLINK) != 0) { SWSS_LOG_ERROR("Error applying custom profile"); } else { - SWSS_LOG_NOTICE("Applying custom profile"); + SWSS_LOG_DEBUG("Applying custom profile"); read_eventd_config(false); // generate an event informing new profile is in effect LOG_EVENT(CUSTOM_EVPROFILE_CHANGE, custom_profile.c_str(), NOTIFY, "Custom Event Profile %s is applied.", filename.c_str()); @@ -678,42 +561,33 @@ void EventConsume::handle_custom_evprofile(std::deque en } } -void EventConsume::initEventStats(int total, int raised, int cleared, int acked) { - vector temp; - FieldValueTuple fv; - fv = FieldValueTuple("events", to_string(total)); - temp.push_back(fv); - fv = FieldValueTuple("raised", to_string(raised)); - temp.push_back(fv); - fv = FieldValueTuple("cleared", to_string(cleared)); - temp.push_back(fv); - fv = FieldValueTuple("acked", to_string(acked)); - temp.push_back(fv); - m_eventStatsTable.set("state", temp); -} - -void EventConsume::initAlarmStats() { +void EventConsume::resetAlarmStats(int alarms, int critical, int major, int minor, int warning, int acknowledged) { vector temp; FieldValueTuple fv; map::iterator it; for (it = SYSLOG_SEVERITY_STR.begin(); it != SYSLOG_SEVERITY_STR.end(); it++) { // there wont be any informational alarms - if (it->second.compare(EVENT_SEVERITY_INFORMATIONAL_STR) != 0) { - string str = it->second; - // severity counter names are of lower case - transform(str.begin(), str.end(),str.begin(), ::tolower); - fv = FieldValueTuple(str, "0"); + if (it->second.compare(EVENT_SEVERITY_CRITICAL_STR) == 0) { + fv = FieldValueTuple("critical", to_string(critical)); + temp.push_back(fv); + } else if (it->second.compare(EVENT_SEVERITY_MAJOR_STR) == 0) { + fv = FieldValueTuple("major", to_string(major)); + temp.push_back(fv); + } else if (it->second.compare(EVENT_SEVERITY_MINOR_STR) == 0) { + fv = FieldValueTuple("minor", to_string(minor)); + temp.push_back(fv); + } else if (it->second.compare(EVENT_SEVERITY_WARNING_STR) == 0) { + fv = FieldValueTuple("warning", to_string(warning)); temp.push_back(fv); } } - fv = FieldValueTuple("alarms", "0"); + fv = FieldValueTuple("alarms", to_string(alarms)); temp.push_back(fv); - fv = FieldValueTuple("acknowledged", "0"); + fv = FieldValueTuple("acknowledged", to_string(acknowledged)); temp.push_back(fv); m_alarmStatsTable.set("state", temp); } - void EventConsume::clearAckAlarmStatistic() { vector vec; vector temp; @@ -730,6 +604,182 @@ void EventConsume::clearAckAlarmStatistic() { } } -}; +void EventConsume::fetchFieldValues(const vector& data, + vector &vec, + string &ev_id, + string &ev_msg, + string &ev_src, + string &ev_act, + string &ev_timestamp) { + for (auto idx : data) { + if (fvField(idx) == "type-id") { + ev_id = fvValue(idx); + vec.push_back(idx); + SWSS_LOG_DEBUG("type-id: <%s> ", ev_id.c_str()); + } else if (fvField(idx) == "text") { + ev_msg = fvValue(idx); + vec.push_back(idx); + SWSS_LOG_DEBUG("text: <%s> ", ev_msg.c_str()); + } else if (fvField(idx) == "resource") { + ev_src = fvValue(idx); + vec.push_back(idx); + SWSS_LOG_DEBUG("resource: <%s> ", ev_src.c_str()); + } else if (fvField(idx) == "action") { + ev_act = fvValue(idx); + // for events, action is empty + if (!ev_act.empty()) { + vec.push_back(idx); + } + } else if (fvField(idx) == "time-created") { + ev_timestamp = fvValue(idx); + vec.push_back(idx); + SWSS_LOG_DEBUG("time-created: <%s> ", ev_timestamp.c_str()); + } + } +} + +bool EventConsume::isFloodedEvent(string ev_src, string ev_act, string ev_id, string ev_msg) { + // flood protection. If a rogue application sends same event repeatedly, throttle repeated instances of that event + if (!flood_ev_resource.compare(ev_src) && + !flood_ev_action.compare(ev_act) && + !flood_ev_id.compare(ev_id) && + !(flood_ev_msg.compare(ev_msg))) { + SWSS_LOG_INFO("Ignoring the event %s from %s action %s msg %s as it is repeated", ev_id.c_str(), ev_src.c_str(), ev_act.c_str(), ev_msg.c_str()); + return true; + } + + flood_ev_resource = ev_src; + flood_ev_action = ev_act; + flood_ev_id = ev_id; + flood_ev_msg = ev_msg; + return false; +} + +bool EventConsume::staticInfoExists(string &ev_id, string &ev_act, string &ev_sev, string &ev_static_msg, vector &vec) { + auto it = static_event_table.find(ev_id); + if (it != static_event_table.end()) { + EventInfo tmp = (EventInfo) (it->second); + // discard the event as event_static_map shows enable is false for this event + if (tmp.enable == EVENT_ENABLE_FALSE_STR) { + SWSS_LOG_INFO("Discarding event <%s> as it is set to disabled", ev_id.c_str()); + return false;; + } + + // get severity in the map and store it in the db + ev_sev = tmp.severity; + ev_static_msg = tmp.static_event_msg; + SWSS_LOG_DEBUG("static info: <%s> <%s> ", tmp.severity.c_str(), tmp.static_event_msg.c_str()); + + FieldValueTuple seqfv1("severity", tmp.severity); + vec.push_back(seqfv1); + return true; + } else { + // dont process the incoming alarms if action is neither raise nor clear + // for ack/unack, no need for this check + if ((ev_act.compare(EVENT_ACTION_ACK_STR) && ev_act.compare(EVENT_ACTION_UNACK_STR))) { + SWSS_LOG_ERROR("static info NOT FOUND for <%s> ", ev_id.c_str()); + return false; + } + } + return true; +} + +bool EventConsume::udpateLocalCacheAndAlarmTable(string almkey, bool &ack_flag) { + // find and remove the raised alarm + uint64_t lookup_seq_id = 0; + auto it = cal_lookup_map.find(almkey); + if (it != cal_lookup_map.end()) { + lookup_seq_id = (uint64_t) (it->second); + cal_lookup_map.erase(almkey); + + // get status of is_aknowledged flag so that we dont decrement counters twice + vector alm_rec; + m_alarmTable.get(to_string(lookup_seq_id), alm_rec); + for (auto fvr: alm_rec) { + if (!fvr.first.compare("acknowledged")) { + ack_flag = (fvr.second.compare("true") == 0) ? true : false; + break; + } + } + + // delete the record from alarm table + m_alarmTable.del(to_string(lookup_seq_id)); + } else { + // possible - when event profile removes alarms for which enable is false and application cleared them later. + // ignore by logging a debug message.. + SWSS_LOG_INFO("Received alarm-clear for non-existing alarm %s", almkey.c_str()); + return false; + } + return true; +} + +void EventConsume::initStats() { + vector vec; + // possible after a cold-boot or very first time + if (! m_eventStatsTable.get("state", vec)) { + FieldValueTuple fv; + vector temp; + + SWSS_LOG_DEBUG("resetting Event Statistics table"); + fv = FieldValueTuple("events", to_string(0)); + temp.push_back(fv); + fv = FieldValueTuple("raised", to_string(0)); + temp.push_back(fv); + fv = FieldValueTuple("cleared", to_string(0)); + temp.push_back(fv); + fv = FieldValueTuple("acked", to_string(0)); + temp.push_back(fv); + m_eventStatsTable.set("state", temp); + } + if (! m_alarmStatsTable.get("state", vec)) { + SWSS_LOG_DEBUG("resetting Alarm Statistics table"); + resetAlarmStats(0, 0, 0, 0, 0, 0); + } +} + +void EventConsume::updateAckInfo(bool is_ack, string ev_timestamp, string ev_sev, string ev_act, string ev_src) { + vector ack_vec; + + FieldValueTuple seqfv1("acknowledged", (is_ack ? "true" : "false")); + ack_vec.push_back(seqfv1); + + FieldValueTuple seqfv2("acknowledge-time", ev_timestamp); + ack_vec.push_back(seqfv2); + + // update alarm stats + updateAlarmStatistics(ev_sev, ev_act); + // update alarm/event tables for the "raise" record with ack flag and ack timestamp + // for ack/unack, ev_src contains the "seq-id" + m_alarmTable.set(ev_src, ack_vec); + m_eventTable.set(ev_src, ack_vec); +} + + +void EventConsume::fetchRaiseInfo(vector &vec, string ev_src, string &ev_id, string &ev_sev, string &raise_act, + string &raise_ack_flag, string &raise_ts) { + vector raise_vec; + m_alarmTable.get(ev_src, raise_vec); + for (auto fv: raise_vec) { + if (!fv.first.compare("type-id")) { + ev_id = fv.second; + vec.push_back(fv); + } + if (!fv.first.compare("severity")) { + ev_sev = fv.second; + vec.push_back(fv); + } + if (!fv.first.compare("action")) { + raise_act = fv.second; + } + if (!fv.first.compare("acknowledged")) { + raise_ack_flag = fv.second; + } + if (!fv.first.compare("time-created")) { + raise_ts = fv.second; + } + } +} + +}; diff --git a/src/sonic-eventd/src/eventd.cpp b/src/sonic-eventd/src/eventd.cpp index 618d78ada897..0ff0373c8dd4 100644 --- a/src/sonic-eventd/src/eventd.cpp +++ b/src/sonic-eventd/src/eventd.cpp @@ -27,8 +27,3 @@ int main() return 0; } - - - - -