From 56b0f1877a02c43b51595a2d7e6f09e1fabd3d32 Mon Sep 17 00:00:00 2001 From: Zain Budhwani <99770260+zbud-msft@users.noreply.github.com> Date: Wed, 24 Aug 2022 09:10:04 -0700 Subject: [PATCH] Events: APIs to set/get global options (#672) * first cut * first cut lib code with unit test * save it just in case, as VM under risk * partial update, as vm at risk * intermediate saving * First run code complete * self review update * partial compile * In middle of compilation * compiled OK * common ut passes * events_service unit tests complete * test code in progress * evens publish covere by unit test * events 75% covered by UT * subscribe UT done * Drop internal readme * Update upon self review - mostly on comments * More on comments update * minor fix of copy/paste error * Comments update * more comments * minor updates; merged with master via shared * Per review comments * minor updates * minor: name change for a typedef * Added EXIT code * Minor name change; Enabled py build for events * Minor signature update to adapt to SWIG generated python * Made zmq send & receive thread safe * temp commit to enable merge * removed hacks; Added set log level API * Minor signature change * Added unit test for C wrap * Corrected per review comments; Addede log message for published events * minor updates;no logical code changes * corrected per review comments; Added accidentally removed test * Added back accidentally removed test code file * retire runtime id on deinit * restore accidental removal * Switched to shared_ptr per review comments * minor non logical code changes * fix syntax * few follow up changes for bare ptr to shared ptr conversion * send event as JSON string * syntax * syntax * syntax * syntax * syntax * compile fix * compile fix * compile fix * compile fix * compile fix * compile fix * compile fix * compile fix * changing wrap signature to use struct instead of JSON string * compile fix * compile fix * compile fix * compile fix * compile fix * compile fix * compile fix * compile fix * compile fix * compile fix * compile fix * compile fix * compile fix * compile fix * compile fix * compile fix * compile fix * compile fix * compile fix * compile fix * compile fix * compile fix * compile fix * Add libzmq5 as dependency for ubuntu-20.04 build (#7) Co-authored-by: Ubuntu * Modify azp (#8) * Add libzmq5 as dependency for ubuntu-20.04 build * Add libzmq3-dev dependency to build script Co-authored-by: Ubuntu * Modify azp (#9) * Add libzmq5 as dependency for ubuntu-20.04 build * Add libzmq3-dev dependency to build script * Add uuid-dev and libboost-serialization-dev dependencies Co-authored-by: Ubuntu * Modify azp (#10) * Add libzmq5 as dependency for ubuntu-20.04 build * Add libzmq3-dev dependency to build script * Add uuid-dev and libboost-serialization-dev dependencies * Add dependencies for bazel build Co-authored-by: Ubuntu * compile errors * compile errors * Compile error from Ubuntu * drop unused macro * compile fix * compile fix * remove pedantic * restored ABORT_IF_NOT * revert flag add * comments correction * Log every published event * Install dependencies for vstest (#15) * Install deps vstest (#16) * Install dependencies for vstest * Add comments * Install deps vstest (#17) * Install dependencies for vstest * Add comments * Correct lib spelling * Added LINGER timeout to service sockets * Added heartbeat * compile fix * compile fix * compile fix * set LINGER_TIMEOUT before connect/bind * Add global options * Add global options * Add global options * Add global options * Add global options * Add global options * Add global options * Add global options * Add global options * added define * Moved C API to C header file * minor upates * minor upates * Updated comments * comments update * comments update * Fix build issue * Modify comment * Modify comment * Modify comment * Modify comment * Modify comment * Modify comment * Modify comment Co-authored-by: Renuka Manavalan Co-authored-by: Renuka Manavalan <47282725+renukamanavalan@users.noreply.github.com> Co-authored-by: Ubuntu --- .azure-pipelines/build_and_install_module.sh | 2 +- common/events.cpp | 63 +++++++++++++++-- common/events.h | 6 +- common/events_common.h | 3 +- common/events_pi.h | 1 - common/events_service.cpp | 44 ++++++++++++ common/events_service.h | 33 +++++++++ common/events_wrap.h | 71 ++++++++++++++++++++ tests/events_service_ut.cpp | 21 +++++- tests/events_ut.cpp | 38 +++++++++++ 10 files changed, 270 insertions(+), 12 deletions(-) diff --git a/.azure-pipelines/build_and_install_module.sh b/.azure-pipelines/build_and_install_module.sh index fc94a825..2269e123 100755 --- a/.azure-pipelines/build_and_install_module.sh +++ b/.azure-pipelines/build_and_install_module.sh @@ -29,7 +29,7 @@ function build_and_install_kmodule() apt-get install -y build-essential linux-headers-${KERNEL_RELEASE} autoconf pkg-config fakeroot apt-get install -y flex bison libssl-dev libelf-dev apt-get install -y libnl-route-3-200 libnl-route-3-dev libnl-cli-3-200 libnl-cli-3-dev libnl-3-dev - # Install libs required by libswsscommon + # Install libs required by libswsscommon for build apt-get install -y libzmq3-dev libzmq5 libboost-serialization1.71.0 uuid-dev # Add the apt source mirrors and download the linux image source code diff --git a/common/events.cpp b/common/events.cpp index c2a955b0..47d5c072 100644 --- a/common/events.cpp +++ b/common/events.cpp @@ -8,7 +8,6 @@ */ lst_publishers_t EventPublisher::s_publishers; -int EventPublisher::LINGER_TIMEOUT = 100; // In milliseconds event_handle_t EventPublisher::get_publisher(const string event_source) @@ -73,15 +72,18 @@ get_uuid() int EventPublisher::init(const string event_source) { + int rc = -1; m_zmq_ctx = zmq_ctx_new(); - void *sock = zmq_socket (m_zmq_ctx, ZMQ_PUB); - int rc = zmq_connect (sock, get_config(XSUB_END_KEY).c_str()); - RET_ON_ERR(rc == 0, "Publisher fails to connect %s", get_config(XSUB_END_KEY).c_str()); + void *sock = zmq_socket (m_zmq_ctx, ZMQ_PUB); + RET_ON_ERR(sock != NULL, "Failed to ZMQ_PUB socket"); rc = zmq_setsockopt (sock, ZMQ_LINGER, &LINGER_TIMEOUT, sizeof (LINGER_TIMEOUT)); RET_ON_ERR(rc == 0, "Failed to ZMQ_LINGER to %d", LINGER_TIMEOUT); + rc = zmq_connect (sock, get_config(XSUB_END_KEY).c_str()); + RET_ON_ERR(rc == 0, "Publisher fails to connect %s", get_config(XSUB_END_KEY).c_str()); + /* * Event service could be down. So have a timeout. * @@ -191,7 +193,7 @@ EventPublisher::publish(const string tag, const event_params_t *params) } str_data = convert_to_json(m_event_source + ":" + tag, *params); - SWSS_LOG_INFO("EVENT_PUBLISHED: %s", str_data.c_str()); + SWSS_LOG_ERROR("EVENT_PUBLISHED: %s", str_data.c_str()); rc = send_evt(str_data); RET_ON_ERR(rc == 0, "failed to send event str[%d]= %s", (int)str_data.size(), @@ -681,8 +683,59 @@ event_receive_wrap(void *handle, event_receive_op_C_t *evt) } + void swssSetLogPriority(int pri) { swss::Logger::setMinPrio((swss::Logger::Priority) pri); } + +int +event_set_global_options(const char *options) +{ + int ret = -1, rc; + void *zmq_ctx; + event_service svc; + + zmq_ctx = zmq_ctx_new(); + RET_ON_ERR(zmq_ctx != NULL, "Failed to get zmq ctx"); + + rc = svc.init_client(zmq_ctx); + RET_ON_ERR (rc == 0, "Failed to init event service rc=%d", rc); + + rc = svc.global_options_set(options); + RET_ON_ERR (rc == 0, "Failed to set options in event service rc=%d", rc); + ret = 0; +out: + svc.close_service(); + zmq_ctx_term(zmq_ctx); + + return ret; +} + + +int +event_get_global_options(char *options, int options_size) +{ + int ret = -1, rc; + void *zmq_ctx; + event_service svc; + + zmq_ctx = zmq_ctx_new(); + RET_ON_ERR(zmq_ctx != NULL, "Failed to get zmq ctx"); + + rc = svc.init_client(zmq_ctx); + RET_ON_ERR (rc == 0, "Failed to init event service rc=%d", rc); + + rc = svc.global_options_get(options, options_size); + RET_ON_ERR (rc >= 0, "Failed to set options in event service rc=%d", rc); + + ret = rc; + +out: + svc.close_service(); + zmq_ctx_term(zmq_ctx); + + return ret; +} + diff --git a/common/events.h b/common/events.h index a4a32a0a..9fc3f389 100644 --- a/common/events.h +++ b/common/events.h @@ -6,7 +6,7 @@ #include /* - * Events library + * Events library APIs. * * APIs are for publishing & receiving events with source, tag and params along with timestamp. * Used by event publishers and those interested in receiving published events. @@ -31,7 +31,7 @@ typedef void* event_handle_t; * is complete. Hence recommend, do the init as soon as the process starts. * * Input: - * event_source + * event_source: * The YANG module name for the event source. All events published with the handle * returned by this call is tagged with this source, transparently. The receiver * could subscribe with this source as filter. @@ -47,7 +47,7 @@ event_handle_t events_init_publisher(const std::string event_source); * De-init/free the publisher * * Input: - * Handle returned from events_init_publisher + * Handle returned from events_init_publisher. * * Output: * Handle is nullified. diff --git a/common/events_common.h b/common/events_common.h index d83d1f62..ba760acd 100644 --- a/common/events_common.h +++ b/common/events_common.h @@ -51,6 +51,7 @@ using namespace chrono; SWSS_LOG_ERROR("last:errno=%d", _e); \ goto out; } +static const int LINGER_TIMEOUT = 100; /* Linger timeout in milliseconds */ /* helper API to print variable type */ /* @@ -210,7 +211,7 @@ typedef string runtime_id_t; #define EVENT_STR_CTRL_PREFIX_SZ ((int)sizeof(EVENT_STR_CTRL_PREFIX) - 1) /* The internal code that caches runtime-IDs could retire upon de-init */ -#define EVENT_STR_CTRL_DEINIT "CONTROL_DEINIT" +#define EVENT_STR_CTRL_DEINIT EVENT_STR_CTRL_PREFIX "DEINIT" typedef vector internal_events_lst_t; diff --git a/common/events_pi.h b/common/events_pi.h index 22ff6f67..72aab927 100644 --- a/common/events_pi.h +++ b/common/events_pi.h @@ -44,7 +44,6 @@ typedef map lst_publishers_t; class EventPublisher : public events_base { static lst_publishers_t s_publishers; - static int LINGER_TIMEOUT; public: virtual ~EventPublisher(); diff --git a/common/events_service.cpp b/common/events_service.cpp index b6ee8056..1f33cdad 100644 --- a/common/events_service.cpp +++ b/common/events_service.cpp @@ -35,6 +35,9 @@ event_service::init_client(void *zmq_ctx, int block_ms) void *sock = zmq_socket (zmq_ctx, ZMQ_REQ); RET_ON_ERR(sock != NULL, "Failed to get ZMQ_REQ socket rc=%d", rc); + rc = zmq_setsockopt (sock, ZMQ_LINGER, &LINGER_TIMEOUT, sizeof (LINGER_TIMEOUT)); + RET_ON_ERR(rc == 0, "Failed to ZMQ_LINGER to %d", LINGER_TIMEOUT); + rc = zmq_connect (sock, get_config(REQ_REP_END_KEY).c_str()); RET_ON_ERR(rc == 0, "Failed to connect to %s", get_config(REQ_REP_END_KEY).c_str()); @@ -60,6 +63,9 @@ event_service::init_server(void *zmq_ctx, int block_ms) void *sock = zmq_socket (zmq_ctx, ZMQ_REP); RET_ON_ERR(sock != NULL, "Failed to get ZMQ_REP socket rc=%d", rc); + rc = zmq_setsockopt (sock, ZMQ_LINGER, &LINGER_TIMEOUT, sizeof (LINGER_TIMEOUT)); + RET_ON_ERR(rc == 0, "Failed to ZMQ_LINGER to %d", LINGER_TIMEOUT); + rc = zmq_bind (sock, get_config(REQ_REP_END_KEY).c_str()); RET_ON_ERR(rc == 0, "Failed to bind to %s", get_config(REQ_REP_END_KEY).c_str()); @@ -155,6 +161,44 @@ event_service::cache_read(event_serialized_lst_t &lst) } +int +event_service::global_options_set(const char *val) +{ + int rc; + event_serialized_lst_t lst; + + lst.push_back(string(val)); + + RET_ON_ERR((rc = send_recv(EVENT_OPTIONS, &lst, NULL)) == 0, + "Failed to send global options request rc=%d", rc); +out: + return rc; +} + + +int +event_service::global_options_get(char *val, int sz) +{ + int ret = -1, rc; + string s; + event_serialized_lst_t lst; + + RET_ON_ERR((rc = send_recv(EVENT_OPTIONS, NULL, &lst)) == 0, + "Failed to receive global options request rc=%d", rc); + + if (!lst.empty()) { + s = *lst.begin(); + } + + strncpy(val, s.c_str(), sz); + + val[sz - 1] = 0; + ret = (int)s.size(); +out: + return ret; +} + + int event_service::channel_read(int &code, event_serialized_lst_t &data) { diff --git a/common/events_service.h b/common/events_service.h index f0931d0a..70023eed 100644 --- a/common/events_service.h +++ b/common/events_service.h @@ -40,6 +40,7 @@ typedef enum { EVENT_CACHE_STOP, /* Stop the cache */ EVENT_CACHE_READ, /* Read cached events */ EVENT_ECHO, /* Echoes the received data in request via response */ + EVENT_OPTIONS, /* global options Set/Get */ EVENT_EXIT /* Exit the eventd service -- Useful for unit test.*/ } event_req_type_t; @@ -217,6 +218,38 @@ class event_service { */ int echo_receive(string &s); + + /* + * Global options request set + * + * Input: + * val -- Put the interval for set + * + * Return: + * 0 - On Success + * -1 - On Failure + */ + int global_options_set(const char *val); + + + /* + * Global options request get. + * + * Input: + * val_sz -- Size of val buffer + * + * Output: + * val -- Get the current val + * + * Return: + * > 0 - Count of bytes to copied/to-be-copied. + * Result is truncated if given size <= this value. + * But copied string is *always* null termninated. + * + * -1 - On Failure + */ + int global_options_get(char *val, int val_sz); + /* * The read for req/resp from client/server. The APIs above use this * to read response and the server use this to read request. diff --git a/common/events_wrap.h b/common/events_wrap.h index 64502590..b9ac7ca6 100644 --- a/common/events_wrap.h +++ b/common/events_wrap.h @@ -116,6 +116,77 @@ int event_receive_wrap(void *handle, event_receive_op_C_t *evt); */ void swssSetLogPriority(int pri); + +/* + * Global configurable options can be set via this API. + * + * The options are provided as JSON object with key/values as JSON string. + * key =