diff options
Diffstat (limited to 'meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice')
9 files changed, 462 insertions, 698 deletions
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0001-Add-unmerged-changes-for-http-retry-support.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0001-Add-unmerged-changes-for-http-retry-support.patch new file mode 100644 index 000000000..52135e255 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0001-Add-unmerged-changes-for-http-retry-support.patch @@ -0,0 +1,121 @@ +From 6ff897d2b5513f15445f18aae16d8439ed94f377 Mon Sep 17 00:00:00 2001 +From: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com> +Date: Mon, 11 Oct 2021 18:41:27 +0530 +Subject: [PATCH] Add unmerged changes for http retry support + +The http retry support added upstream as a single patch was slpit into +3 patches, but only 2 of them was merged. +This commit pulls in the differentail changes required to complete the +entire http retry support. and also allow for other subsequent patches +to be appplied easily. + +Change-Id: Id8ccd991b7ffc505196b1a92b23e1cd51e00bc89 +Signed-off-by: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com> +--- + http/http_client.hpp | 44 +++++++++++-------- + .../include/event_service_manager.hpp | 2 +- + 2 files changed, 27 insertions(+), 19 deletions(-) + +diff --git a/http/http_client.hpp b/http/http_client.hpp +index ab20eb0..aad1cce 100644 +--- a/http/http_client.hpp ++++ b/http/http_client.hpp +@@ -68,7 +68,6 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> + std::optional< + boost::beast::http::response_parser<boost::beast::http::string_body>> + parser; +- std::vector<std::pair<std::string, std::string>> headers; + boost::circular_buffer_space_optimized<std::string> requestDataQueue{}; + + ConnState state; +@@ -137,18 +136,6 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> + + BMCWEB_LOG_DEBUG << __FUNCTION__ << "(): " << host << ":" << port; + +- req.version(static_cast<int>(11)); // HTTP 1.1 +- req.target(uri); +- req.method(boost::beast::http::verb::post); +- +- // Set headers +- for (const auto& [key, value] : headers) +- { +- req.set(key, value); +- } +- req.set(boost::beast::http::field::host, host); +- req.keep_alive(true); +- + req.body() = data; + req.prepare_payload(); + +@@ -204,6 +191,17 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> + BMCWEB_LOG_DEBUG << "recvMessage() data: " + << self->parser->get(); + ++ // Check if the response and header are received ++ if (!self->parser->is_done()) ++ { ++ // The parser failed to receive the response ++ BMCWEB_LOG_ERROR ++ << "recvMessage() parser failed to receive response"; ++ self->state = ConnState::recvFailed; ++ self->handleConnState(); ++ return; ++ } ++ + unsigned int respCode = self->parser->get().result_int(); + BMCWEB_LOG_DEBUG << "recvMessage() Header Response Code: " + << respCode; +@@ -398,11 +396,17 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> + const std::string& destIP, const std::string& destPort, + const std::string& destUri) : + conn(ioc), +- timer(ioc), subId(id), host(destIP), port(destPort), uri(destUri), +- retryCount(0), maxRetryAttempts(5), retryIntervalSecs(0), ++ timer(ioc), req(boost::beast::http::verb::post, destUri, 11), ++ state(ConnState::initialized), subId(id), host(destIP), port(destPort), ++ uri(destUri), retryCount(0), maxRetryAttempts(5), retryIntervalSecs(0), + retryPolicyAction("TerminateAfterRetries"), runningTimer(false) + { +- state = ConnState::initialized; ++ // Set the request header ++ req.set(boost::beast::http::field::host, host); ++ req.set(boost::beast::http::field::content_type, "application/json"); ++ req.keep_alive(true); ++ ++ requestDataQueue.set_capacity(maxRequestQueueSize); + } + + void sendData(const std::string& data) +@@ -425,10 +429,14 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> + return; + } + +- void setHeaders( ++ void addHeaders( + const std::vector<std::pair<std::string, std::string>>& httpHeaders) + { +- headers = httpHeaders; ++ // Set custom headers ++ for (const auto& [key, value] : httpHeaders) ++ { ++ req.set(key, value); ++ } + } + + void setRetryConfig(const uint32_t retryAttempts, +diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp +index 8042803..0a63b8c 100644 +--- a/redfish-core/include/event_service_manager.hpp ++++ b/redfish-core/include/event_service_manager.hpp +@@ -412,7 +412,7 @@ class Subscription : public persistent_data::UserSubscription + reqHeaders.emplace_back(std::pair(key, val)); + } + } +- conn->setHeaders(reqHeaders); ++ conn->addHeaders(reqHeaders); + conn->sendData(msg); + this->eventSeqNum++; + } +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0001-EventService-Fix-retry-handling-for-http-client.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0001-EventService-Fix-retry-handling-for-http-client.patch deleted file mode 100644 index 7a6818008..000000000 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0001-EventService-Fix-retry-handling-for-http-client.patch +++ /dev/null @@ -1,546 +0,0 @@ -From f74393a9bca899e353be3d0e2dc5c224539fe432 Mon Sep 17 00:00:00 2001 -From: Sunitha Harish <sunithaharish04@gmail.com> -Date: Fri, 19 Feb 2021 13:38:31 +0530 -Subject: [PATCH] EventService : Fix retry handling for http-client - -When the event send/receive is failed, the bmcweb does not handle -the failure to tear-down the complete connection and start a fresh - -The keep-alive header from the event listener is read to update -the connection states, so that the connection will be kept alive -or closed as per the subscriber's specifications - -Updated the connection state machine to handle retry logic properly. -Avoided multiple simultaneous async calls which crashes the bmcweb. So -added connBusy flag which protects simultaneous async calls. - -Used boost http response parser as parser for producing the response -message. Set the parser skip option to handle the empty response message -from listening server. - -Tested by: - - Subscribe for the events at BMC using DMTF event listener - - Generate an event and see the same is received at the listener's console - - Update the listner to change the keep-alive to true/false and - observe the http-client connection states at bmcweb - - Changed listener client to return non success HTTP status code - and observed retry logic gets trigrred in http-client. - - Gave wrong fqdn and observed async resolve failure and retry logc. - - Stopped listener after connect and verified timeouts on http-client - side. - -Change-Id: Ibb45691f139916ba2954da37beda9d4f91c7cef3 -Signed-off-by: Sunitha Harish <sunithaharish04@gmail.com> -Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> ---- - http/http_client.hpp | 288 ++++++++++-------- - .../include/event_service_manager.hpp | 2 +- - 2 files changed, 162 insertions(+), 128 deletions(-) - -diff --git a/http/http_client.hpp b/http/http_client.hpp -index 992ac2b..feabbba 100644 ---- a/http/http_client.hpp -+++ b/http/http_client.hpp -@@ -34,22 +34,28 @@ namespace crow - { - - static constexpr uint8_t maxRequestQueueSize = 50; -+static constexpr unsigned int httpReadBodyLimit = 8192; - - enum class ConnState - { - initialized, - resolveInProgress, - resolveFailed, -+ resolved, - connectInProgress, - connectFailed, - connected, - sendInProgress, - sendFailed, -+ recvInProgress, - recvFailed, - idle, -- suspended, -+ closeInProgress, - closed, -- terminated -+ suspended, -+ terminated, -+ abortConnection, -+ retry - }; - - class HttpClient : public std::enable_shared_from_this<HttpClient> -@@ -58,11 +64,13 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> - crow::async_resolve::Resolver resolver; - boost::beast::tcp_stream conn; - boost::asio::steady_timer timer; -- boost::beast::flat_buffer buffer; -+ boost::beast::flat_static_buffer<httpReadBodyLimit> buffer; - boost::beast::http::request<boost::beast::http::string_body> req; -- boost::beast::http::response<boost::beast::http::string_body> res; -- std::vector<std::pair<std::string, std::string>> headers; -- std::queue<std::string> requestDataQueue; -+ std::optional< -+ boost::beast::http::response_parser<boost::beast::http::string_body>> -+ parser; -+ boost::circular_buffer_space_optimized<std::string> requestDataQueue{}; -+ std::vector<boost::asio::ip::tcp::endpoint> endPoints; - ConnState state; - std::string subId; - std::string host; -@@ -76,12 +84,7 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> - - void doResolve() - { -- if (state == ConnState::resolveInProgress) -- { -- return; -- } - state = ConnState::resolveInProgress; -- - BMCWEB_LOG_DEBUG << "Trying to resolve: " << host << ":" << port; - - auto respHandler = -@@ -89,78 +92,56 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> - const boost::beast::error_code ec, - const std::vector<boost::asio::ip::tcp::endpoint>& - endpointList) { -- if (ec) -+ if (ec || (endpointList.size() == 0)) - { - BMCWEB_LOG_ERROR << "Resolve failed: " << ec.message(); - self->state = ConnState::resolveFailed; -- self->checkQueue(); -+ self->handleConnState(); - return; - } - BMCWEB_LOG_DEBUG << "Resolved"; -- self->doConnect(endpointList); -+ self->endPoints.assign(endpointList.begin(), -+ endpointList.end()); -+ self->state = ConnState::resolved; -+ self->handleConnState(); - }; - resolver.asyncResolve(host, port, std::move(respHandler)); - } - -- void doConnect( -- const std::vector<boost::asio::ip::tcp::endpoint>& endpointList) -+ void doConnect() - { -- if (state == ConnState::connectInProgress) -- { -- return; -- } - state = ConnState::connectInProgress; - - BMCWEB_LOG_DEBUG << "Trying to connect to: " << host << ":" << port; - - conn.expires_after(std::chrono::seconds(30)); - conn.async_connect( -- endpointList, [self(shared_from_this())]( -- const boost::beast::error_code ec, -- const boost::asio::ip::tcp::endpoint& endpoint) { -+ endPoints, [self(shared_from_this())]( -+ const boost::beast::error_code ec, -+ const boost::asio::ip::tcp::endpoint& endpoint) { - if (ec) - { - BMCWEB_LOG_ERROR << "Connect " << endpoint - << " failed: " << ec.message(); - self->state = ConnState::connectFailed; -- self->checkQueue(); -+ self->handleConnState(); - return; - } -- self->state = ConnState::connected; - BMCWEB_LOG_DEBUG << "Connected to: " << endpoint; -- -- self->checkQueue(); -+ self->state = ConnState::connected; -+ self->handleConnState(); - }); - } - - void sendMessage(const std::string& data) - { -- if (state == ConnState::sendInProgress) -- { -- return; -- } - state = ConnState::sendInProgress; - - BMCWEB_LOG_DEBUG << __FUNCTION__ << "(): " << host << ":" << port; - -- req.version(static_cast<int>(11)); // HTTP 1.1 -- req.target(uri); -- req.method(boost::beast::http::verb::post); -- -- // Set headers -- for (const auto& [key, value] : headers) -- { -- req.set(key, value); -- } -- req.set(boost::beast::http::field::host, host); -- req.keep_alive(true); -- - req.body() = data; - req.prepare_payload(); - -- // Set a timeout on the operation -- conn.expires_after(std::chrono::seconds(30)); -- - // Send the HTTP request to the remote host - boost::beast::http::async_write( - conn, req, -@@ -171,7 +152,7 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> - BMCWEB_LOG_ERROR << "sendMessage() failed: " - << ec.message(); - self->state = ConnState::sendFailed; -- self->checkQueue(); -+ self->handleConnState(); - return; - } - BMCWEB_LOG_DEBUG << "sendMessage() bytes transferred: " -@@ -184,9 +165,17 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> - - void recvMessage() - { -+ state = ConnState::recvInProgress; -+ -+ parser.emplace(std::piecewise_construct, std::make_tuple()); -+ parser->body_limit(httpReadBodyLimit); -+ -+ // Check only for the response header -+ parser->skip(true); -+ - // Receive the HTTP response - boost::beast::http::async_read( -- conn, buffer, res, -+ conn, buffer, *parser, - [self(shared_from_this())](const boost::beast::error_code& ec, - const std::size_t& bytesTransferred) { - if (ec) -@@ -194,30 +183,47 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> - BMCWEB_LOG_ERROR << "recvMessage() failed: " - << ec.message(); - self->state = ConnState::recvFailed; -- self->checkQueue(); -+ self->handleConnState(); - return; - } - BMCWEB_LOG_DEBUG << "recvMessage() bytes transferred: " - << bytesTransferred; -- boost::ignore_unused(bytesTransferred); -- -- // Discard received data. We are not interested. -- BMCWEB_LOG_DEBUG << "recvMessage() data: " << self->res; -+ BMCWEB_LOG_DEBUG << "recvMessage() data: " -+ << self->parser->get(); - - // Send is successful, Lets remove data from queue - // check for next request data in queue. -- self->requestDataQueue.pop(); -+ if (!self->requestDataQueue.empty()) -+ { -+ self->requestDataQueue.pop_front(); -+ } - self->state = ConnState::idle; -- self->checkQueue(); -+ -+ // Keep the connection alive if server supports it -+ // Else close the connection -+ BMCWEB_LOG_DEBUG << "recvMessage() keepalive : " -+ << self->parser->keep_alive(); -+ if (!self->parser->keep_alive()) -+ { -+ // Abort the connection since server is not keep-alive -+ // enabled -+ self->state = ConnState::abortConnection; -+ } -+ -+ // Returns ownership of the parsed message -+ self->parser->release(); -+ -+ self->handleConnState(); - }); - } - - void doClose() - { -+ state = ConnState::closeInProgress; - boost::beast::error_code ec; - conn.socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec); -+ conn.close(); - -- state = ConnState::closed; - // not_connected happens sometimes so don't bother reporting it. - if (ec && ec != boost::beast::errc::not_connected) - { -@@ -225,112 +231,139 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> - return; - } - BMCWEB_LOG_DEBUG << "Connection closed gracefully"; -- } -- -- void checkQueue(const bool newRecord = false) -- { -- if (requestDataQueue.empty()) -+ if ((state != ConnState::suspended) && (state != ConnState::terminated)) - { -- // TODO: Having issue in keeping connection alive. So lets close if -- // nothing to be transferred. -- doClose(); -- -- BMCWEB_LOG_DEBUG << "requestDataQueue is empty\n"; -- return; -+ state = ConnState::closed; -+ handleConnState(); - } -+ } - -+ void waitAndRetry() -+ { - if (retryCount >= maxRetryAttempts) - { -- BMCWEB_LOG_ERROR << "Maximum number of retries is reached."; -+ BMCWEB_LOG_ERROR << "Maximum number of retries reached."; - - // Clear queue. - while (!requestDataQueue.empty()) - { -- requestDataQueue.pop(); -+ requestDataQueue.pop_front(); - } - -- BMCWEB_LOG_DEBUG << "Retry policy is set to " << retryPolicyAction; -+ BMCWEB_LOG_DEBUG << "Retry policy: " << retryPolicyAction; - if (retryPolicyAction == "TerminateAfterRetries") - { - // TODO: delete subscription - state = ConnState::terminated; -- return; - } - if (retryPolicyAction == "SuspendRetries") - { - state = ConnState::suspended; -- return; - } -- // keep retrying, reset count and continue. -+ // Reset the retrycount to zero so that client can try connecting -+ // again if needed - retryCount = 0; -+ handleConnState(); -+ return; - } - -- if ((state == ConnState::connectFailed) || -- (state == ConnState::sendFailed) || -- (state == ConnState::recvFailed)) -+ if (runningTimer) - { -- if (newRecord) -- { -- // We are already running async wait and retry. -- // Since record is added to queue, it gets the -- // turn in FIFO. -- return; -- } -- -- if (runningTimer) -- { -- BMCWEB_LOG_DEBUG << "Retry timer is already running."; -- return; -- } -- runningTimer = true; -- -- retryCount++; -- -- BMCWEB_LOG_DEBUG << "Attempt retry after " << retryIntervalSecs -- << " seconds. RetryCount = " << retryCount; -- timer.expires_after(std::chrono::seconds(retryIntervalSecs)); -- timer.async_wait( -- [self = shared_from_this()](const boost::system::error_code&) { -- self->runningTimer = false; -- self->connStateCheck(); -- }); -+ BMCWEB_LOG_DEBUG << "Retry timer is already running."; - return; - } -- // reset retry count. -- retryCount = 0; -- connStateCheck(); -+ runningTimer = true; -+ -+ retryCount++; -+ -+ BMCWEB_LOG_DEBUG << "Attempt retry after " << retryIntervalSecs -+ << " seconds. RetryCount = " << retryCount; -+ timer.expires_after(std::chrono::seconds(retryIntervalSecs)); -+ timer.async_wait( -+ [self = shared_from_this()](const boost::system::error_code ec) { -+ if (ec) -+ { -+ BMCWEB_LOG_ERROR << "async_wait failed: " << ec.message(); -+ // Ignore the error and continue the retry loop to attempt -+ // sending the event as per the retry policy -+ } -+ self->runningTimer = false; - -+ // Lets close connection and start from resolve. -+ self->doClose(); -+ }); - return; - } - -- void connStateCheck() -+ void handleConnState() - { - switch (state) - { - case ConnState::resolveInProgress: - case ConnState::connectInProgress: - case ConnState::sendInProgress: -- case ConnState::suspended: -- case ConnState::terminated: -- // do nothing -+ case ConnState::recvInProgress: -+ case ConnState::closeInProgress: -+ { -+ BMCWEB_LOG_DEBUG << "Async operation is already in progress"; - break; -+ } - case ConnState::initialized: - case ConnState::closed: -+ { -+ if (requestDataQueue.empty()) -+ { -+ BMCWEB_LOG_DEBUG << "requestDataQueue is empty"; -+ return; -+ } -+ doResolve(); -+ break; -+ } -+ case ConnState::resolved: -+ { -+ doConnect(); -+ break; -+ } -+ case ConnState::suspended: -+ case ConnState::terminated: -+ { -+ doClose(); -+ break; -+ } -+ case ConnState::resolveFailed: - case ConnState::connectFailed: - case ConnState::sendFailed: - case ConnState::recvFailed: -- case ConnState::resolveFailed: -+ case ConnState::retry: - { -- doResolve(); -+ // In case of failures during connect and handshake -+ // the retry policy will be applied -+ waitAndRetry(); - break; - } - case ConnState::connected: - case ConnState::idle: - { -+ // State idle means, previous attempt is successful -+ // State connected means, client connection is established -+ // successfully -+ if (requestDataQueue.empty()) -+ { -+ BMCWEB_LOG_DEBUG << "requestDataQueue is empty"; -+ return; -+ } - std::string data = requestDataQueue.front(); - sendMessage(data); - break; - } -+ case ConnState::abortConnection: -+ { -+ // Server did not want to keep alive the session -+ doClose(); -+ break; -+ } -+ default: -+ break; - } - } - -@@ -339,37 +372,38 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> - const std::string& destIP, const std::string& destPort, - const std::string& destUri) : - conn(ioc), -- timer(ioc), subId(id), host(destIP), port(destPort), uri(destUri), -- retryCount(0), maxRetryAttempts(5), retryIntervalSecs(0), -+ timer(ioc), req(boost::beast::http::verb::post, destUri, 11), -+ state(ConnState::initialized), subId(id), host(destIP), port(destPort), -+ uri(destUri), retryCount(0), maxRetryAttempts(5), retryIntervalSecs(0), - retryPolicyAction("TerminateAfterRetries"), runningTimer(false) - { -- state = ConnState::initialized; -+ // Set the request header -+ req.set(boost::beast::http::field::host, host); -+ req.set(boost::beast::http::field::content_type, "application/json"); -+ req.keep_alive(true); -+ -+ requestDataQueue.set_capacity(maxRequestQueueSize); - } - - void sendData(const std::string& data) - { -- if (state == ConnState::suspended) -+ if ((state == ConnState::suspended) || (state == ConnState::terminated)) - { - return; - } -- -- if (requestDataQueue.size() <= maxRequestQueueSize) -- { -- requestDataQueue.push(data); -- checkQueue(true); -- } -- else -- { -- BMCWEB_LOG_ERROR << "Request queue is full. So ignoring data."; -- } -- -+ requestDataQueue.push_back(data); -+ handleConnState(); - return; - } - -- void setHeaders( -+ void addHeaders( - const std::vector<std::pair<std::string, std::string>>& httpHeaders) - { -- headers = httpHeaders; -+ // Set custom headers -+ for (const auto& [key, value] : httpHeaders) -+ { -+ req.set(key, value); -+ } - } - - void setRetryConfig(const uint32_t retryAttempts, -diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp -index 11190ef..a8f7517 100644 ---- a/redfish-core/include/event_service_manager.hpp -+++ b/redfish-core/include/event_service_manager.hpp -@@ -422,7 +422,7 @@ class Subscription - reqHeaders.emplace_back(std::pair(key, val)); - } - } -- conn->setHeaders(reqHeaders); -+ conn->addHeaders(reqHeaders); - conn->sendData(msg); - this->eventSeqNum++; - } --- -2.25.1 diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0002-EventService-https-client-support.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0002-EventService-https-client-support.patch index eef0ff065..aeeafc421 100644 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0002-EventService-https-client-support.patch +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0002-EventService-https-client-support.patch @@ -1,28 +1,27 @@ -From 4df4a36d6d2cc11c51cc9d53cd441178cc97e39b Mon Sep 17 00:00:00 2001 +From 3f2ad28e6e124249cde3df50c9e18c283fbcbf3e Mon Sep 17 00:00:00 2001 From: AppaRao Puli <apparao.puli@linux.intel.com> Date: Mon, 22 Feb 2021 17:07:47 +0000 Subject: [PATCH] EventService: https client support -Add https client support for push style -eventing. Using this BMC can push the event -logs/telemetry data to event listener over -secure http channel. +Add https client support for push style eventing. Using this BMC can +push the event logs/telemetry data to event listener over secure http +channel. Tested: - - Created subscription with https destination - url. Using SubmitTestEvent action set the - event and can see event on event listener. + - Created subscription with https destination url. Using + SubmitTestEvent action set the event and can see event on event + listener. - Validator passed. Change-Id: I44c3918b39baa2eb5fddda9d635f99aa280a422a Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> --- - http/http_client.hpp | 257 ++++++++++++------ + http/http_client.hpp | 307 ++++++++++++------ .../include/event_service_manager.hpp | 2 +- - 2 files changed, 176 insertions(+), 83 deletions(-) + 2 files changed, 202 insertions(+), 107 deletions(-) diff --git a/http/http_client.hpp b/http/http_client.hpp -index feabbba..aaf1b2d 100644 +index aad1cce..5e7ff47 100644 --- a/http/http_client.hpp +++ b/http/http_client.hpp @@ -20,6 +20,7 @@ @@ -33,8 +32,8 @@ index feabbba..aaf1b2d 100644 #include <boost/beast/version.hpp> #include <include/async_resolve.hpp> -@@ -44,6 +45,8 @@ enum class ConnState - resolved, +@@ -43,6 +44,8 @@ enum class ConnState + resolveFailed, connectInProgress, connectFailed, + handshakeInProgress, @@ -42,7 +41,7 @@ index feabbba..aaf1b2d 100644 connected, sendInProgress, sendFailed, -@@ -62,7 +65,9 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> +@@ -61,7 +64,9 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> { private: crow::async_resolve::Resolver resolver; @@ -52,8 +51,8 @@ index feabbba..aaf1b2d 100644 boost::asio::steady_timer timer; boost::beast::flat_static_buffer<httpReadBodyLimit> buffer; boost::beast::http::request<boost::beast::http::string_body> req; -@@ -111,23 +116,52 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> - void doConnect() +@@ -108,23 +113,52 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> + const std::vector<boost::asio::ip::tcp::endpoint>& endpointList) { state = ConnState::connectInProgress; + sslConn.emplace(conn, ctx); @@ -83,10 +82,10 @@ index feabbba..aaf1b2d 100644 + }; conn.expires_after(std::chrono::seconds(30)); - conn.async_connect( -- endPoints, [self(shared_from_this())]( -- const boost::beast::error_code ec, -- const boost::asio::ip::tcp::endpoint& endpoint) { -+ conn.async_connect(endPoints, std::move(respHandler)); +- endpointList, [self(shared_from_this())]( +- const boost::beast::error_code ec, +- const boost::asio::ip::tcp::endpoint& endpoint) { ++ conn.async_connect(endpointList, std::move(respHandler)); + } + + void performHandshake() @@ -113,7 +112,7 @@ index feabbba..aaf1b2d 100644 self->state = ConnState::connected; self->handleConnState(); }); -@@ -135,106 +169,159 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> +@@ -132,132 +166,187 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> void sendMessage(const std::string& data) { @@ -125,6 +124,19 @@ index feabbba..aaf1b2d 100644 req.body() = data; req.prepare_payload(); +- // Set a timeout on the operation +- conn.expires_after(std::chrono::seconds(30)); ++ auto respHandler = [self(shared_from_this())]( ++ const boost::beast::error_code ec, ++ const std::size_t& bytesTransferred) { ++ if (ec) ++ { ++ BMCWEB_LOG_ERROR << "sendMessage() failed: " << ec.message(); ++ self->state = ConnState::sendFailed; ++ self->handleConnState(); ++ return; ++ } + - // Send the HTTP request to the remote host - boost::beast::http::async_write( - conn, req, @@ -141,26 +153,15 @@ index feabbba..aaf1b2d 100644 - BMCWEB_LOG_DEBUG << "sendMessage() bytes transferred: " - << bytesTransferred; - boost::ignore_unused(bytesTransferred); -+ auto respHandler = [self(shared_from_this())]( -+ const boost::beast::error_code ec, -+ const std::size_t& bytesTransferred) { -+ if (ec) -+ { -+ BMCWEB_LOG_ERROR << "sendMessage() failed: " << ec.message(); -+ self->state = ConnState::sendFailed; -+ self->handleConnState(); -+ return; -+ } - -- self->recvMessage(); -- }); -- } + BMCWEB_LOG_DEBUG << "sendMessage() bytes transferred: " + << bytesTransferred; + boost::ignore_unused(bytesTransferred); + self->recvMessage(); + }; +- self->recvMessage(); +- }); ++ // Set a timeout on the operation + conn.expires_after(std::chrono::seconds(30)); + if (sslConn) + { @@ -171,7 +172,8 @@ index feabbba..aaf1b2d 100644 + { + boost::beast::http::async_write(conn, req, std::move(respHandler)); + } -+ } + } +- void recvMessage() { state = ConnState::recvInProgress; @@ -191,6 +193,33 @@ index feabbba..aaf1b2d 100644 + BMCWEB_LOG_DEBUG << "recvMessage() bytes transferred: " + << bytesTransferred; + boost::ignore_unused(bytesTransferred); ++ ++ // Check if the response and header are received ++ if (!self->parser->is_done()) ++ { ++ // The parser failed to receive the response ++ BMCWEB_LOG_ERROR ++ << "recvMessage() parser failed to receive response"; ++ self->state = ConnState::recvFailed; ++ self->handleConnState(); ++ return; ++ } ++ ++ unsigned int respCode = self->parser->get().result_int(); ++ BMCWEB_LOG_DEBUG << "recvMessage() Header Response Code: " ++ << respCode; ++ ++ // 2XX response is considered to be successful ++ if ((respCode < 200) || (respCode >= 300)) ++ { ++ // The listener failed to receive the Sent-Event ++ BMCWEB_LOG_ERROR << "recvMessage() Listener Failed to " ++ "receive Sent-Event"; ++ self->state = ConnState::recvFailed; ++ self->handleConnState(); ++ return; ++ } ++ + // Send is successful, Lets remove data from queue + // check for next request data in queue. + if (!self->requestDataQueue.empty()) @@ -271,34 +300,56 @@ index feabbba..aaf1b2d 100644 - BMCWEB_LOG_DEBUG << "recvMessage() data: " - << self->parser->get(); - -- // Send is successful, Lets remove data from queue -- // check for next request data in queue. -- if (!self->requestDataQueue.empty()) +- // Check if the response and header are received +- if (!self->parser->is_done()) + else { -- self->requestDataQueue.pop_front(); +- // The parser failed to receive the response +- BMCWEB_LOG_ERROR +- << "recvMessage() parser failed to receive response"; +- self->state = ConnState::recvFailed; +- self->handleConnState(); +- return; + BMCWEB_LOG_DEBUG << "Connection closed gracefully..."; } -- self->state = ConnState::idle; + self->conn.close(); +- unsigned int respCode = self->parser->get().result_int(); +- BMCWEB_LOG_DEBUG << "recvMessage() Header Response Code: " +- << respCode; +- +- // 2XX response is considered to be successful +- if ((respCode < 200) || (respCode >= 300)) ++ if ((self->state != ConnState::suspended) && ++ (self->state != ConnState::terminated)) + { +- // The listener failed to receive the Sent-Event +- BMCWEB_LOG_ERROR << "recvMessage() Listener Failed to " +- "receive Sent-Event"; +- self->state = ConnState::recvFailed; ++ self->state = ConnState::closed; + self->handleConnState(); +- return; + } +- +- // Send is successful, Lets remove data from queue +- // check for next request data in queue. +- if (!self->requestDataQueue.empty()) +- { +- self->requestDataQueue.pop_front(); +- } +- self->state = ConnState::idle; +- - // Keep the connection alive if server supports it - // Else close the connection - BMCWEB_LOG_DEBUG << "recvMessage() keepalive : " - << self->parser->keep_alive(); - if (!self->parser->keep_alive()) -+ if ((self->state != ConnState::suspended) && -+ (self->state != ConnState::terminated)) - { +- { - // Abort the connection since server is not keep-alive - // enabled - self->state = ConnState::abortConnection; -+ self->state = ConnState::closed; -+ self->handleConnState(); - } -- -- // Returns ownership of the parsed message -- self->parser->release(); +- } - - self->handleConnState(); }); @@ -345,7 +396,7 @@ index feabbba..aaf1b2d 100644 } } -@@ -301,6 +388,7 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> +@@ -330,6 +419,7 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> { case ConnState::resolveInProgress: case ConnState::connectInProgress: @@ -353,7 +404,7 @@ index feabbba..aaf1b2d 100644 case ConnState::sendInProgress: case ConnState::recvInProgress: case ConnState::closeInProgress: -@@ -332,6 +420,7 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> +@@ -356,6 +446,7 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> } case ConnState::resolveFailed: case ConnState::connectFailed: @@ -361,7 +412,7 @@ index feabbba..aaf1b2d 100644 case ConnState::sendFailed: case ConnState::recvFailed: case ConnState::retry: -@@ -370,7 +459,8 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> +@@ -394,7 +485,8 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> public: explicit HttpClient(boost::asio::io_context& ioc, const std::string& id, const std::string& destIP, const std::string& destPort, @@ -371,7 +422,7 @@ index feabbba..aaf1b2d 100644 conn(ioc), timer(ioc), req(boost::beast::http::verb::post, destUri, 11), state(ConnState::initialized), subId(id), host(destIP), port(destPort), -@@ -383,8 +473,11 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> +@@ -407,8 +499,11 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> req.keep_alive(true); requestDataQueue.set_capacity(maxRequestQueueSize); @@ -385,10 +436,10 @@ index feabbba..aaf1b2d 100644 { if ((state == ConnState::suspended) || (state == ConnState::terminated)) diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp -index a8f7517..d4a5bc5 100644 +index 08d0b98..f1ce0c0 100644 --- a/redfish-core/include/event_service_manager.hpp +++ b/redfish-core/include/event_service_manager.hpp -@@ -397,7 +397,7 @@ class Subscription +@@ -385,7 +385,7 @@ class Subscription : public persistent_data::UserSubscription { conn = std::make_shared<crow::HttpClient>( crow::connections::systemBus->get_io_context(), id, host, port, @@ -398,4 +449,5 @@ index a8f7517..d4a5bc5 100644 Subscription(const std::shared_ptr<boost::beast::tcp_stream>& adaptor) : -- -2.25.1 +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0004-Add-Server-Sent-Events-support.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0004-Add-Server-Sent-Events-support.patch index da281467e..ea521a7e4 100644 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0004-Add-Server-Sent-Events-support.patch +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0004-Add-Server-Sent-Events-support.patch @@ -1,4 +1,4 @@ -From 54bdd897bd416fef4c043224b398b1b6d47fd271 Mon Sep 17 00:00:00 2001 +From d7a2660f200c38e74bfcbfe55b8da1b8bed08833 Mon Sep 17 00:00:00 2001 From: AppaRao Puli <apparao.puli@linux.intel.com> Date: Fri, 12 Mar 2021 18:53:25 +0000 Subject: [PATCH] Add Server-Sent-Events support @@ -21,47 +21,37 @@ Tested: Change-Id: I36956565cbba30c2007852c9471f477f6d1736e9 Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> +Signed-off-by: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com> --- - http/http_connection.hpp | 14 +- + http/http_connection.hpp | 10 +- http/http_response.hpp | 7 +- http/routing.hpp | 71 ++++++++++ http/server_sent_event.hpp | 279 +++++++++++++++++++++++++++++++++++++ - 4 files changed, 365 insertions(+), 6 deletions(-) + 4 files changed, 362 insertions(+), 5 deletions(-) create mode 100644 http/server_sent_event.hpp diff --git a/http/http_connection.hpp b/http/http_connection.hpp -index a1a7045..90535c5 100644 +index 8e53afa..a1bbfce 100644 --- a/http/http_connection.hpp +++ b/http/http_connection.hpp -@@ -331,7 +331,7 @@ class Connection : - BMCWEB_LOG_INFO << "Request: " - << " " << this << " HTTP/" << req->version() / 10 << "." - << req->version() % 10 << ' ' << req->methodString() -- << " " << req->target() << " " << req->ipAddress; -+ << " " << req->url << " " << req->ipAddress; +@@ -378,11 +378,13 @@ class Connection : + [self] { self->completeRequest(); }); + }); - needToCallAfterHandlers = false; - -@@ -350,11 +350,15 @@ class Connection : - boost::asio::post(self->adaptor.get_executor(), - [self] { self->completeRequest(); }); - }); -- if (req->isUpgrade() && -- boost::iequals( -- req->getHeaderValue(boost::beast::http::field::upgrade), -- "websocket")) -+ -+ if ((req->isUpgrade() && -+ boost::iequals(req->getHeaderValue( -+ boost::beast::http::field::upgrade), -+ "websocket")) || -+ (req->url == "/sse")) - { -+ BMCWEB_LOG_DEBUG << "Request: " << this -+ << " is getting upgraded"; - handler->handleUpgrade(*req, res, std::move(adaptor)); - // delete lambda with self shared_ptr - // to enable connection destruction +- if (thisReq.isUpgrade() && +- boost::iequals( +- thisReq.getHeaderValue(boost::beast::http::field::upgrade), +- "websocket")) ++ if ((thisReq.isUpgrade() && ++ boost::iequals( ++ thisReq.getHeaderValue(boost::beast::http::field::upgrade), ++ "websocket")) || ++ (req->url == "/sse")) + { ++ BMCWEB_LOG_DEBUG << "Request: " << this << " is getting upgraded"; + handler->handleUpgrade(thisReq, res, std::move(adaptor)); + // delete lambda with self shared_ptr + // to enable connection destruction diff --git a/http/http_response.hpp b/http/http_response.hpp index a983d4a..07b0265 100644 --- a/http/http_response.hpp @@ -93,7 +83,7 @@ index a983d4a..07b0265 100644 // In case of a JSON object, set the Content-Type header void jsonMode() diff --git a/http/routing.hpp b/http/routing.hpp -index d2a10b2..25e4ce8 100644 +index 5d9c8e3..bfff107 100644 --- a/http/routing.hpp +++ b/http/routing.hpp @@ -6,6 +6,7 @@ diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0005-Add-SSE-style-subscription-support-to-eventservice.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0005-Add-SSE-style-subscription-support-to-eventservice.patch index 42a1ebbf0..ee69081ef 100644 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0005-Add-SSE-style-subscription-support-to-eventservice.patch +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0005-Add-SSE-style-subscription-support-to-eventservice.patch @@ -1,4 +1,4 @@ -From 36c1391749e19e4a25ca6e57d369457f48e6bb11 Mon Sep 17 00:00:00 2001 +From 799e47842e179f7c752712004f0e96d3219eee11 Mon Sep 17 00:00:00 2001 From: AppaRao Puli <apparao.puli@linux.intel.com> Date: Tue, 16 Mar 2021 15:37:24 +0000 Subject: [PATCH] Add SSE style subscription support to eventservice @@ -18,33 +18,33 @@ Tested: response. - Ran RedfishValidation and its passed. -Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> -Signed-off-by: Nitin Wankhade <nitinx.arunrao.wankhade@intel.com> Change-Id: I7f4b7a34974080739c4ba968ed570489af0474de +Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com> +Signed-off-by: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com> --- http/http_connection.hpp | 2 +- include/eventservice_sse.hpp | 75 +++++ - .../include/event_service_manager.hpp | 111 +++++-- + .../include/event_service_manager.hpp | 109 +++++-- redfish-core/include/server_sent_events.hpp | 290 ------------------ redfish-core/lib/event_service.hpp | 8 +- src/webserver_main.cpp | 2 + - 6 files changed, 165 insertions(+), 323 deletions(-) + 6 files changed, 164 insertions(+), 322 deletions(-) create mode 100644 include/eventservice_sse.hpp delete mode 100644 redfish-core/include/server_sent_events.hpp diff --git a/http/http_connection.hpp b/http/http_connection.hpp -index 90535c5..37c0a0b 100644 +index a1bbfce..2d08501 100644 --- a/http/http_connection.hpp +++ b/http/http_connection.hpp -@@ -355,7 +355,7 @@ class Connection : - boost::iequals(req->getHeaderValue( - boost::beast::http::field::upgrade), - "websocket")) || -- (req->url == "/sse")) -+ (req->url == "/redfish/v1/EventService/Subscriptions/SSE")) - { - BMCWEB_LOG_DEBUG << "Request: " << this - << " is getting upgraded"; +@@ -382,7 +382,7 @@ class Connection : + boost::iequals( + thisReq.getHeaderValue(boost::beast::http::field::upgrade), + "websocket")) || +- (req->url == "/sse")) ++ (req->url == "/redfish/v1/EventService/Subscriptions/SSE")) + { + BMCWEB_LOG_DEBUG << "Request: " << this << " is getting upgraded"; + handler->handleUpgrade(thisReq, res, std::move(adaptor)); diff --git a/include/eventservice_sse.hpp b/include/eventservice_sse.hpp new file mode 100644 index 0000000..14daf00 @@ -127,7 +127,7 @@ index 0000000..14daf00 +} // namespace eventservice_sse +} // namespace redfish diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp -index ca46aa7..9397271 100644 +index 3f398d7..dd833ce 100644 --- a/redfish-core/include/event_service_manager.hpp +++ b/redfish-core/include/event_service_manager.hpp @@ -22,15 +22,17 @@ @@ -217,23 +217,23 @@ index ca46aa7..9397271 100644 ~Subscription() = default; -@@ -412,13 +412,14 @@ class Subscription : public persistent_data::UserSubscription - } - conn->addHeaders(reqHeaders); - conn->sendData(msg); -- this->eventSeqNum++; - } +@@ -417,7 +417,7 @@ class Subscription : public persistent_data::UserSubscription if (sseConn != nullptr) { - sseConn->sendData(eventSeqNum, msg); + sseConn->sendEvent(std::to_string(eventSeqNum), msg); } -+ + } + +@@ -508,6 +508,7 @@ class Subscription : public persistent_data::UserSubscription + + this->sendEvent( + msg.dump(2, ' ', true, nlohmann::json::error_handler_t::replace)); + this->eventSeqNum++; } + #endif - void sendTestEventLog() @@ -578,14 +579,39 @@ class Subscription : public persistent_data::UserSubscription return eventSeqNum; } @@ -622,7 +622,7 @@ index 7613d7b..0000000 - -} // namespace crow diff --git a/redfish-core/lib/event_service.hpp b/redfish-core/lib/event_service.hpp -index 67ad014..f8a2dac 100644 +index 8609862..249e594 100644 --- a/redfish-core/lib/event_service.hpp +++ b/redfish-core/lib/event_service.hpp @@ -37,8 +37,6 @@ static constexpr const std::array<const char*, 1> supportedResourceTypes = { diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0006-Add-EventService-SSE-filter-support.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0006-Add-EventService-SSE-filter-support.patch index 9043bd0b9..3914cc81a 100644 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0006-Add-EventService-SSE-filter-support.patch +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0006-Add-EventService-SSE-filter-support.patch @@ -1,4 +1,4 @@ -From 22c6b6cfb468f8de9ff3ea051dffdba05778645e Mon Sep 17 00:00:00 2001 +From 769f0e20d0a7e786d7091ffb7ee57d35204dfa28 Mon Sep 17 00:00:00 2001 From: AppaRao Puli <apparao.puli@linux.intel.com> Date: Wed, 17 Mar 2021 01:16:50 +0000 Subject: [PATCH] Add EventService SSE filter support @@ -41,7 +41,7 @@ Change-Id: I55c6f53bb5e57aa1f2d1601f1a16525a33b13bd2 5 files changed, 181 insertions(+), 9 deletions(-) diff --git a/include/eventservice_sse.hpp b/include/eventservice_sse.hpp -index 14daf00..2f22f98 100644 +index 14daf00..fed7fec 100644 --- a/include/eventservice_sse.hpp +++ b/include/eventservice_sse.hpp @@ -23,16 +23,153 @@ static bool createSubscription(std::shared_ptr<crow::SseConnection>& conn, @@ -203,7 +203,7 @@ index 14daf00..2f22f98 100644 std::string id = redfish::EventServiceManager::getInstance().addSubscription(subValue, diff --git a/redfish-core/include/error_messages.hpp b/redfish-core/include/error_messages.hpp -index 10567d1..f29e326 100644 +index 3d11cc4..90084e3 100644 --- a/redfish-core/include/error_messages.hpp +++ b/redfish-core/include/error_messages.hpp @@ -971,6 +971,15 @@ nlohmann::json mutualExclusiveProperties(const std::string& arg1, @@ -223,10 +223,10 @@ index 10567d1..f29e326 100644 } // namespace redfish diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp -index 5886d81..c3e7f61 100644 +index dd833ce..861f4cb 100644 --- a/redfish-core/include/event_service_manager.hpp +++ b/redfish-core/include/event_service_manager.hpp -@@ -56,6 +56,11 @@ static constexpr const char* eventServiceFile = +@@ -55,6 +55,11 @@ static constexpr const char* eventServiceFile = static constexpr const uint8_t maxNoOfSubscriptions = 20; static constexpr const uint8_t maxNoOfSSESubscriptions = 10; @@ -239,10 +239,10 @@ index 5886d81..c3e7f61 100644 static std::optional<boost::asio::posix::stream_descriptor> inotifyConn; static constexpr const char* redfishEventLogDir = "/var/log"; diff --git a/redfish-core/lib/event_service.hpp b/redfish-core/lib/event_service.hpp -index 2e7c3f3..9def549 100644 +index 249e594..6f01707 100644 --- a/redfish-core/lib/event_service.hpp +++ b/redfish-core/lib/event_service.hpp -@@ -25,11 +25,6 @@ +@@ -21,11 +21,6 @@ namespace redfish { @@ -255,10 +255,10 @@ index 2e7c3f3..9def549 100644 "TerminateAfterRetries", "SuspendRetries", "RetryForever"}; diff --git a/redfish-core/src/error_messages.cpp b/redfish-core/src/error_messages.cpp -index 48edaf1..bebb6d8 100644 +index 9c28e8f..2394398 100644 --- a/redfish-core/src/error_messages.cpp +++ b/redfish-core/src/error_messages.cpp -@@ -2174,6 +2174,32 @@ void mutualExclusiveProperties(crow::Response& res, const std::string& arg1, +@@ -2173,6 +2173,32 @@ void mutualExclusiveProperties(crow::Response& res, const std::string& arg1, addMessageToErrorJson(res.jsonValue, mutualExclusiveProperties(arg1, arg2)); } diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0010-Remove-Terminated-Event-Subscriptions.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0010-Remove-Terminated-Event-Subscriptions.patch index 7fcc235d2..9af5a066b 100644 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0010-Remove-Terminated-Event-Subscriptions.patch +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0010-Remove-Terminated-Event-Subscriptions.patch @@ -1,6 +1,6 @@ -From adaa5cb4c494148430b90edb248260eb2e66bca7 Mon Sep 17 00:00:00 2001 -From: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com> -Date: Wed, 8 Sep 2021 15:42:52 +0530 +From f665ba085bb2310f008b7534f827fb401ad973c2 Mon Sep 17 00:00:00 2001 +From: Krzysztof Grobelny <krzysztof.grobelny@intel.com> +Date: Tue, 12 Oct 2021 08:19:51 +0000 Subject: [PATCH] Delete/Remove Terminated Event Subscription(s) Added functionality to delete/remove event subscription(s) which are @@ -23,14 +23,14 @@ Change-Id: If447acb2db74fb29a5d1cfe6194b77cda82bc8a1 Signed-off-by: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com> --- http/http_client.hpp | 43 +++++++++++++++---- - .../include/event_service_manager.hpp | 37 ++++++++++++++++ - 2 files changed, 71 insertions(+), 9 deletions(-) + .../include/event_service_manager.hpp | 36 ++++++++++++++++ + 2 files changed, 70 insertions(+), 9 deletions(-) diff --git a/http/http_client.hpp b/http/http_client.hpp -index aaf1b2d..4f62c40 100644 +index 5e7ff47..54ae2c3 100644 --- a/http/http_client.hpp +++ b/http/http_client.hpp -@@ -56,6 +56,8 @@ enum class ConnState +@@ -55,6 +55,8 @@ enum class ConnState closeInProgress, closed, suspended, @@ -39,7 +39,7 @@ index aaf1b2d..4f62c40 100644 terminated, abortConnection, retry -@@ -263,7 +265,14 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> +@@ -288,7 +290,14 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> } void doClose() { @@ -55,7 +55,7 @@ index aaf1b2d..4f62c40 100644 // Set the timeout on the tcp stream socket for the async operation conn.expires_after(std::chrono::seconds(30)); -@@ -293,8 +302,11 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> +@@ -318,8 +327,11 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> } self->conn.close(); @@ -69,7 +69,7 @@ index aaf1b2d..4f62c40 100644 { self->state = ConnState::closed; self->handleConnState(); -@@ -316,8 +328,11 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> +@@ -341,8 +353,11 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> } conn.close(); @@ -83,7 +83,7 @@ index aaf1b2d..4f62c40 100644 { state = ConnState::closed; handleConnState(); -@@ -340,8 +355,7 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> +@@ -365,8 +380,7 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> BMCWEB_LOG_DEBUG << "Retry policy: " << retryPolicyAction; if (retryPolicyAction == "TerminateAfterRetries") { @@ -93,7 +93,7 @@ index aaf1b2d..4f62c40 100644 } if (retryPolicyAction == "SuspendRetries") { -@@ -392,6 +406,7 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> +@@ -423,6 +437,7 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> case ConnState::sendInProgress: case ConnState::recvInProgress: case ConnState::closeInProgress: @@ -101,7 +101,7 @@ index aaf1b2d..4f62c40 100644 { BMCWEB_LOG_DEBUG << "Async operation is already in progress"; break; -@@ -413,7 +428,7 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> +@@ -439,7 +454,7 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> break; } case ConnState::suspended: @@ -110,7 +110,7 @@ index aaf1b2d..4f62c40 100644 { doClose(); break; -@@ -480,7 +495,8 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> +@@ -506,7 +521,8 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> } void sendData(const std::string& data) { @@ -120,7 +120,7 @@ index aaf1b2d..4f62c40 100644 { return; } -@@ -489,6 +505,15 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> +@@ -524,6 +540,15 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> return; } @@ -137,7 +137,7 @@ index aaf1b2d..4f62c40 100644 const std::vector<std::pair<std::string, std::string>>& httpHeaders) { diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp -index 8d7067b..79618f6 100644 +index 6f60a31..363adb0 100644 --- a/redfish-core/include/event_service_manager.hpp +++ b/redfish-core/include/event_service_manager.hpp @@ -591,6 +591,14 @@ class Subscription : public persistent_data::UserSubscription @@ -254,5 +254,5 @@ index 8d7067b..79618f6 100644 { std::shared_ptr<Subscription> entry = it.second; -- -2.17.1 +2.25.1 diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0011-Fix-bmcweb-crash-while-deleting-terminated-subscriptions.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0011-Fix-bmcweb-crash-while-deleting-terminated-subscriptions.patch new file mode 100644 index 000000000..585f7bf09 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/0011-Fix-bmcweb-crash-while-deleting-terminated-subscriptions.patch @@ -0,0 +1,141 @@ +From 5b87bb61b58e92a8c5af37a7959347747409a65c Mon Sep 17 00:00:00 2001 +From: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com> +Date: Thu, 14 Oct 2021 02:56:11 +0530 +Subject: [PATCH] Fix bmcweb crash while deleting terminated subscriptions + +This commit fixes bmcweb crash while deleting the terminated +subscriptions. In the earlier implementation, detection of subscription +to be deleted and the deletion(erase) was happening in the same loop. +Due to this, if the Subscription to be deleted is the last one in the +list, the loop will enter into infinite loop. The fix is to keep the +detection and deletion loop separate. +Also, this commit adds code to : + - Delete from persistent storage + - Add journal entry for deleted entry + - update number of subcribers and update persistent storage. + +Apart from this, this commit also moves the retry timer check to the top +to avoid multiple calls to close when the retry count is 3 and timer is +running. + +Tested: + - Checked journal logs to confirm each retry is actually spanned to be + 30 secs + - Verified Journal entry for deleted subscription after retires. + - Verified Event service functionality by making three subscriptions: + retry for ever, terminate after retires and suspend after retries. + +Change-Id: I425a6c749923ce86c457a36394deb0fbbee232db +Signed-off-by: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com> +--- + http/http_client.hpp | 11 ++-- + .../include/event_service_manager.hpp | 59 ++++++++++++++++--- + 2 files changed, 58 insertions(+), 12 deletions(-) + +diff --git a/http/http_client.hpp b/http/http_client.hpp +index 54ae2c3..162cb09 100644 +--- a/http/http_client.hpp ++++ b/http/http_client.hpp +@@ -367,6 +367,12 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> + + void waitAndRetry() + { ++ if (runningTimer) ++ { ++ BMCWEB_LOG_DEBUG << "Retry timer is already running."; ++ return; ++ } ++ + if (retryCount >= maxRetryAttempts) + { + BMCWEB_LOG_ERROR << "Maximum number of retries reached."; +@@ -393,11 +399,6 @@ class HttpClient : public std::enable_shared_from_this<HttpClient> + return; + } + +- if (runningTimer) +- { +- BMCWEB_LOG_DEBUG << "Retry timer is already running."; +- return; +- } + runningTimer = true; + + retryCount++; +diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp +index 363adb0..7af7a4d 100644 +--- a/redfish-core/include/event_service_manager.hpp ++++ b/redfish-core/include/event_service_manager.hpp +@@ -857,18 +857,63 @@ class EventServiceManager + + void deleteTerminatedSubcriptions() + { +- boost::container::flat_map<std::string, +- std::shared_ptr<Subscription>>::iterator it = +- subscriptionsMap.begin(); +- while (it != subscriptionsMap.end()) ++ BMCWEB_LOG_ERROR << "Map size Before Delete : " ++ << subscriptionsMap.size(); ++ ++ std::vector<std::string> deleteIds; ++ ++ // Determine Subscription ID's to be deleted. ++ for (const auto& it : subscriptionsMap) + { +- std::shared_ptr<Subscription> entry = it->second; ++ std::shared_ptr<Subscription> entry = it.second; + if (entry->isTerminated()) + { +- subscriptionsMap.erase(it); ++ deleteIds.emplace_back(it.first); ++ } ++ } ++ ++ // Delete the Terminated Subcriptions ++ for (std::string& id : deleteIds) ++ { ++ auto map1 = subscriptionsMap.find(id); ++ if (map1 != subscriptionsMap.end()) ++ { ++ subscriptionsMap.erase(map1); ++ auto map2 = persistent_data::EventServiceStore::getInstance() ++ .subscriptionsConfigMap.find(id); ++ if (map2 != persistent_data::EventServiceStore::getInstance() ++ .subscriptionsConfigMap.end()) ++ { ++ persistent_data::EventServiceStore::getInstance() ++ .subscriptionsConfigMap.erase(map2); ++ } ++ else ++ { ++ BMCWEB_LOG_ERROR << "Couldn't find ID: " << id ++ << " in subscriptionsConfigMap"; ++ } ++ ++ /* Log event for subscription delete. */ ++ sd_journal_send("MESSAGE=Event subscription removed.(Id = %s)", ++ id.c_str(), "PRIORITY=%i", LOG_INFO, ++ "REDFISH_MESSAGE_ID=%s", ++ "OpenBMC.0.1.EventSubscriptionRemoved", ++ "REDFISH_MESSAGE_ARGS=%s", id.c_str(), NULL); ++ } ++ else ++ { ++ BMCWEB_LOG_ERROR << "Couldn't find ID: " << id ++ << " in subscriptionsMap"; + } +- it++; + } ++ if (deleteIds.size()) ++ { ++ updateNoOfSubscribersCount(); ++ persistSubscriptionData(); ++ } ++ ++ BMCWEB_LOG_ERROR << "Map size After Delete : " ++ << subscriptionsMap.size(); + } + + void updateNoOfSubscribersCount() +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/README b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/README index cd2e1c2bc..c09967456 100644 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/README +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/eventservice/README @@ -3,26 +3,32 @@ the upstream patches. These will be remove as soon as thee gets merged upstream. Upstream revision information: - - EventService : Fix retry handling for http-client - https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/40731/21 + - EventService : Add unmerged changes for http retry support (Downstream patch) + file://eventservice/0001-Add-unmerged-changes-for-http-retry-support.patch - EventService: https client support - https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/31735/40 + https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/31735/40 (Rebased on latest bmcweb) - Add Server-Sent-Events support - https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/41258/7 + https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/41258/9 - Add SSE style subscription support to eventservice - https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/41319/8 + https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/41319/10 - Add EventService SSE filter support - https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/41349/5 + https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/41349/7 (Modified boost::urls::query_params_view to boost::urls::url_view::params_type) - - EventService Log events for subscription actions - file://telemetry/0007-EventService-Log-events-for-subscription-actions.patch + - EventService Log events for subscription actions (Downstream patch) + file://eventservice/0007-EventService-Log-events-for-subscription-actions.patch - - Add checks on Event-Subscription input parameters - file://telemetry/0008-Add-checks-on-Event-Subscription-input-parameters.patch + - Add checks on Event-Subscription input parameters (Downstream patch) + file://eventservice//0008-Add-checks-on-Event-Subscription-input-parameters.patch - Restructure Redifsh EventLog Transmit code flow - file://telemetry/0009-Restructure-Redifsh-EventLog-Transmit-code-flow.patch + https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/44449/3 + + - Remove Terminated Event Subscriptions (Downstream patch) + file://eventservice/0010-Remove-Terminated-Event-Subscriptions.patch + + - Fix bmcweb crash while deleting terminated subscriptions (Downstream patch) + file://eventservice/0011-Fix-bmcweb-crash-while-deleting-terminated-subscriptions.patch |