diff options
Diffstat (limited to 'redfish-core/include/event_service_manager.hpp')
-rw-r--r-- | redfish-core/include/event_service_manager.hpp | 641 |
1 files changed, 403 insertions, 238 deletions
diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp index 4c2d0eebbd..8fd0157f9d 100644 --- a/redfish-core/include/event_service_manager.hpp +++ b/redfish-core/include/event_service_manager.hpp @@ -1,22 +1,25 @@ /* -// Copyright (c) 2020 Intel Corporation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +Copyright (c) 2020 Intel Corporation + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. */ #pragma once #include "dbus_utility.hpp" #include "error_messages.hpp" #include "event_service_store.hpp" +#include "filter_expr_executor.hpp" +#include "generated/enums/event.hpp" +#include "generated/enums/log_entry.hpp" #include "http_client.hpp" #include "metric_report.hpp" #include "ossl_random.hpp" @@ -31,6 +34,7 @@ #include <sys/inotify.h> #include <boost/asio/io_context.hpp> +#include <boost/circular_buffer.hpp> #include <boost/container/flat_map.hpp> #include <boost/url/format.hpp> #include <boost/url/url_view_base.hpp> @@ -39,17 +43,16 @@ #include <algorithm> #include <cstdlib> #include <ctime> +#include <format> #include <fstream> #include <memory> #include <ranges> #include <span> +#include <string> namespace redfish { -using ReadingsObjType = - std::vector<std::tuple<std::string, std::string, double, int32_t>>; - static constexpr const char* eventFormatType = "Event"; static constexpr const char* metricReportFormatType = "MetricReport"; @@ -72,11 +75,13 @@ static int inotifyFd = -1; static int dirWatchDesc = -1; // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) static int fileWatchDesc = -1; - -// <ID, timestamp, RedfishLogId, registryPrefix, MessageId, MessageArgs> -using EventLogObjectsType = - std::tuple<std::string, std::string, std::string, std::string, std::string, - std::vector<std::string>>; +struct EventLogObjectsType +{ + std::string id; + std::string timestamp; + std::string messageId; + std::vector<std::string> messageArgs; +}; namespace registries { @@ -86,8 +91,8 @@ static const Message* { std::span<const MessageEntry>::iterator messageIt = std::ranges::find_if( registry, [&messageKey](const MessageEntry& messageEntry) { - return messageKey == messageEntry.first; - }); + return messageKey == messageEntry.first; + }); if (messageIt != registry.end()) { return &messageIt->second; @@ -159,6 +164,8 @@ inline int getEventLogParams(const std::string& logEntry, size_t space = logEntry.find_first_of(' '); if (space == std::string::npos) { + BMCWEB_LOG_ERROR("EventLog Params: could not find first space: {}", + logEntry); return -EINVAL; } timestamp = logEntry.substr(0, space); @@ -166,6 +173,8 @@ inline int getEventLogParams(const std::string& logEntry, size_t entryStart = logEntry.find_first_not_of(' ', space); if (entryStart == std::string::npos) { + BMCWEB_LOG_ERROR("EventLog Params: could not find log contents: {}", + logEntry); return -EINVAL; } std::string_view entry(logEntry); @@ -176,6 +185,8 @@ inline int getEventLogParams(const std::string& logEntry, // We need at least a MessageId to be valid if (logEntryFields.empty()) { + BMCWEB_LOG_ERROR("EventLog Params: could not find entry fields: {}", + logEntry); return -EINVAL; } messageID = logEntryFields[0]; @@ -212,12 +223,10 @@ inline void getRegistryAndMessageKey(const std::string& messageID, } } -inline int formatEventLogEntry(const std::string& logEntryID, - const std::string& messageID, - const std::span<std::string_view> messageArgs, - std::string timestamp, - const std::string& customText, - nlohmann::json& logEntryJson) +inline int formatEventLogEntry( + const std::string& logEntryID, const std::string& messageID, + const std::span<std::string_view> messageArgs, std::string timestamp, + const std::string& customText, nlohmann::json::object_t& logEntryJson) { // Get the Message from the MessageRegistry const registries::Message* message = registries::formatMessage(messageID); @@ -227,8 +236,8 @@ inline int formatEventLogEntry(const std::string& logEntryID, return -1; } - std::string msg = redfish::registries::fillMessageArgs(messageArgs, - message->message); + std::string msg = + redfish::registries::fillMessageArgs(messageArgs, message->message); if (msg.empty()) { return -1; @@ -246,7 +255,7 @@ inline int formatEventLogEntry(const std::string& logEntryID, // Fill in the log entry with the gathered data logEntryJson["EventId"] = logEntryID; - logEntryJson["EventType"] = "Event"; + logEntryJson["Severity"] = message->messageSeverity; logEntryJson["Message"] = std::move(msg); logEntryJson["MessageId"] = messageID; @@ -282,7 +291,7 @@ class Subscription : public persistent_data::UserSubscription ~Subscription() = default; - bool sendEvent(std::string&& msg) + bool sendEventToSubscriber(std::string&& msg) { persistent_data::EventServiceConfig eventServiceConfig = persistent_data::EventServiceStore::getInstance() @@ -292,33 +301,158 @@ class Subscription : public persistent_data::UserSubscription return false; } - // A connection pool will be created if one does not already exist if (client) { - client->sendData(std::move(msg), destinationUrl, httpHeaders, - boost::beast::http::verb::post); + client->sendData( + std::move(msg), destinationUrl, + static_cast<ensuressl::VerifyCertificate>(verifyCertificate), + httpHeaders, boost::beast::http::verb::post); return true; } if (sseConn != nullptr) { eventSeqNum++; - sseConn->sendEvent(std::to_string(eventSeqNum), msg); + sseConn->sendSseEvent(std::to_string(eventSeqNum), msg); } return true; } + bool eventMatchesFilter(const nlohmann::json::object_t& eventMessage, + std::string_view resType) + { + // If resourceTypes list is empty, assume all + if (!resourceTypes.empty()) + { + // Search the resourceTypes list for the subscription. + auto resourceTypeIndex = std::ranges::find_if( + resourceTypes, [resType](const std::string& rtEntry) { + return rtEntry == resType; + }); + if (resourceTypeIndex == resourceTypes.end()) + { + BMCWEB_LOG_DEBUG("Not subscribed to this resource"); + return false; + } + BMCWEB_LOG_DEBUG("ResourceType {} found in the subscribed list", + resType); + } + + // If registryPrefixes list is empty, don't filter events + // send everything. + if (!registryPrefixes.empty()) + { + auto eventJson = eventMessage.find("MessageId"); + if (eventJson == eventMessage.end()) + { + return false; + } + + const std::string* messageId = + eventJson->second.get_ptr<const std::string*>(); + if (messageId == nullptr) + { + BMCWEB_LOG_ERROR("MessageId wasn't a string???"); + return false; + } + + std::string registry; + std::string messageKey; + event_log::getRegistryAndMessageKey(*messageId, registry, + messageKey); + + auto obj = std::ranges::find(registryPrefixes, registry); + if (obj == registryPrefixes.end()) + { + return false; + } + } + + if (!originResources.empty()) + { + auto eventJson = eventMessage.find("OriginOfCondition"); + if (eventJson == eventMessage.end()) + { + return false; + } + + const std::string* originOfCondition = + eventJson->second.get_ptr<const std::string*>(); + if (originOfCondition == nullptr) + { + BMCWEB_LOG_ERROR("OriginOfCondition wasn't a string???"); + return false; + } + + auto obj = std::ranges::find(originResources, *originOfCondition); + + if (obj == originResources.end()) + { + return false; + } + } + + // If registryMsgIds list is empty, assume all + if (!registryMsgIds.empty()) + { + auto eventJson = eventMessage.find("MessageId"); + if (eventJson == eventMessage.end()) + { + BMCWEB_LOG_DEBUG("'MessageId' not present"); + return false; + } + + const std::string* messageId = + eventJson->second.get_ptr<const std::string*>(); + if (messageId == nullptr) + { + BMCWEB_LOG_ERROR("EventType wasn't a string???"); + return false; + } + + std::string registry; + std::string messageKey; + event_log::getRegistryAndMessageKey(*messageId, registry, + messageKey); + + BMCWEB_LOG_DEBUG("extracted registry {}", registry); + BMCWEB_LOG_DEBUG("extracted message key {}", messageKey); + + auto obj = std::ranges::find( + registryMsgIds, std::format("{}.{}", registry, messageKey)); + if (obj == registryMsgIds.end()) + { + BMCWEB_LOG_DEBUG("did not find registry {} in registryMsgIds", + registry); + BMCWEB_LOG_DEBUG("registryMsgIds has {} entries", + registryMsgIds.size()); + return false; + } + } + + if (filter) + { + if (!memberMatches(eventMessage, *filter)) + { + BMCWEB_LOG_DEBUG("Filter didn't match"); + return false; + } + } + + return true; + } + bool sendTestEventLog() { - nlohmann::json logEntryArray; - logEntryArray.push_back({}); - nlohmann::json& logEntryJson = logEntryArray.back(); + nlohmann::json::array_t logEntryArray; + nlohmann::json& logEntryJson = logEntryArray.emplace_back(); logEntryJson["EventId"] = "TestID"; - logEntryJson["EventType"] = "Event"; - logEntryJson["Severity"] = "OK"; + logEntryJson["Severity"] = log_entry::EventSeverity::OK; logEntryJson["Message"] = "Generated test event"; logEntryJson["MessageId"] = "OpenBMC.0.2.TestEventLog"; + // MemberId is 0 : since we are sending one event record. + logEntryJson["MemberId"] = 0; logEntryJson["MessageArgs"] = nlohmann::json::array(); logEntryJson["EventTimestamp"] = redfish::time_utils::getDateTimeOffsetNow().first; @@ -330,58 +464,37 @@ class Subscription : public persistent_data::UserSubscription msg["Name"] = "Event Log"; msg["Events"] = logEntryArray; - std::string strMsg = msg.dump(2, ' ', true, - nlohmann::json::error_handler_t::replace); - return sendEvent(std::move(strMsg)); + std::string strMsg = + msg.dump(2, ' ', true, nlohmann::json::error_handler_t::replace); + return sendEventToSubscriber(std::move(strMsg)); } void filterAndSendEventLogs( const std::vector<EventLogObjectsType>& eventRecords) { - nlohmann::json logEntryArray; + nlohmann::json::array_t logEntryArray; for (const EventLogObjectsType& logEntry : eventRecords) { - const std::string& idStr = std::get<0>(logEntry); - const std::string& timestamp = std::get<1>(logEntry); - const std::string& messageID = std::get<2>(logEntry); - const std::string& registryName = std::get<3>(logEntry); - const std::string& messageKey = std::get<4>(logEntry); - const std::vector<std::string>& messageArgs = std::get<5>(logEntry); - - // If registryPrefixes list is empty, don't filter events - // send everything. - if (!registryPrefixes.empty()) - { - auto obj = std::ranges::find(registryPrefixes, registryName); - if (obj == registryPrefixes.end()) - { - continue; - } - } + std::vector<std::string_view> messageArgsView( + logEntry.messageArgs.begin(), logEntry.messageArgs.end()); - // If registryMsgIds list is empty, don't filter events - // send everything. - if (!registryMsgIds.empty()) + nlohmann::json::object_t bmcLogEntry; + if (event_log::formatEventLogEntry( + logEntry.id, logEntry.messageId, messageArgsView, + logEntry.timestamp, customText, bmcLogEntry) != 0) { - auto obj = std::ranges::find(registryMsgIds, messageKey); - if (obj == registryMsgIds.end()) - { - continue; - } + BMCWEB_LOG_DEBUG("Read eventLog entry failed"); + continue; } - std::vector<std::string_view> messageArgsView(messageArgs.begin(), - messageArgs.end()); - - logEntryArray.push_back({}); - nlohmann::json& bmcLogEntry = logEntryArray.back(); - if (event_log::formatEventLogEntry(idStr, messageID, - messageArgsView, timestamp, - customText, bmcLogEntry) != 0) + if (!eventMatchesFilter(bmcLogEntry, "")) { - BMCWEB_LOG_DEBUG("Read eventLog entry failed"); + BMCWEB_LOG_DEBUG("Event {} did not match the filter", + nlohmann::json(bmcLogEntry).dump()); continue; } + + logEntryArray.emplace_back(std::move(bmcLogEntry)); } if (logEntryArray.empty()) @@ -394,10 +507,10 @@ class Subscription : public persistent_data::UserSubscription msg["@odata.type"] = "#Event.v1_4_0.Event"; msg["Id"] = std::to_string(eventSeqNum); msg["Name"] = "Event Log"; - msg["Events"] = logEntryArray; - std::string strMsg = msg.dump(2, ' ', true, - nlohmann::json::error_handler_t::replace); - sendEvent(std::move(strMsg)); + msg["Events"] = std::move(logEntryArray); + std::string strMsg = + msg.dump(2, ' ', true, nlohmann::json::error_handler_t::replace); + sendEventToSubscriber(std::move(strMsg)); eventSeqNum++; } @@ -434,9 +547,9 @@ class Subscription : public persistent_data::UserSubscription msg["Context"] = customText; } - std::string strMsg = msg.dump(2, ' ', true, - nlohmann::json::error_handler_t::replace); - sendEvent(std::move(strMsg)); + std::string strMsg = + msg.dump(2, ' ', true, nlohmann::json::error_handler_t::replace); + sendEventToSubscriber(std::move(strMsg)); } void updateRetryConfig(uint32_t retryAttempts, @@ -472,16 +585,6 @@ class Subscription : public persistent_data::UserSubscription return &thisConn == sseConn; } - private: - std::string subId; - uint64_t eventSeqNum = 1; - boost::urls::url host; - std::shared_ptr<crow::ConnectionPolicy> policy; - crow::sse_socket::Connection* sseConn = nullptr; - std::optional<crow::HttpClient> client; - std::string path; - std::string uriProto; - // Check used to indicate what response codes are valid as part of our retry // policy. 2XX is considered acceptable static boost::system::error_code retryRespHandler(unsigned int respCode) @@ -498,6 +601,18 @@ class Subscription : public persistent_data::UserSubscription return boost::system::errc::make_error_code( boost::system::errc::success); } + + private: + std::string subId; + uint64_t eventSeqNum = 1; + boost::urls::url host; + std::shared_ptr<crow::ConnectionPolicy> policy; + crow::sse_socket::Connection* sseConn = nullptr; + + std::optional<crow::HttpClient> client; + + public: + std::optional<filter_ast::LogicalAnd> filter; }; class EventServiceManager @@ -516,6 +631,15 @@ class EventServiceManager uint64_t eventId{1}; + struct Event + { + std::string id; + nlohmann::json message; + }; + + constexpr static size_t maxMessages = 200; + boost::circular_buffer<Event> messages{maxMessages}; + boost::asio::io_context& ioc; public: @@ -571,6 +695,7 @@ class EventServiceManager subValue->id = newSub->id; subValue->destinationUrl = newSub->destinationUrl; subValue->protocol = newSub->protocol; + subValue->verifyCertificate = newSub->verifyCertificate; subValue->retryPolicy = newSub->retryPolicy; subValue->customText = newSub->customText; subValue->eventFormatType = newSub->eventFormatType; @@ -580,6 +705,7 @@ class EventServiceManager subValue->resourceTypes = newSub->resourceTypes; subValue->httpHeaders = newSub->httpHeaders; subValue->metricReportDefinitions = newSub->metricReportDefinitions; + subValue->originResources = newSub->originResources; if (subValue->id.empty()) { @@ -796,8 +922,8 @@ class EventServiceManager return subValue; } - std::string addSubscription(const std::shared_ptr<Subscription>& subValue, - const bool updateFile = true) + std::string + addSubscriptionInternal(const std::shared_ptr<Subscription>& subValue) { std::uniform_int_distribution<uint32_t> dist(0); bmcweb::OpenSSLGenerator gen; @@ -841,16 +967,13 @@ class EventServiceManager newSub->resourceTypes = subValue->resourceTypes; newSub->httpHeaders = subValue->httpHeaders; newSub->metricReportDefinitions = subValue->metricReportDefinitions; + newSub->originResources = subValue->originResources; + persistent_data::EventServiceStore::getInstance() .subscriptionsConfigMap.emplace(newSub->id, newSub); updateNoOfSubscribersCount(); - if (updateFile) - { - updateSubscriptionData(); - } - if constexpr (!BMCWEB_REDFISH_DBUS_LOG) { if (redfishLogFilePosition != 0) @@ -863,6 +986,55 @@ class EventServiceManager // Set Subscription ID for back trace subValue->setSubscriptionId(id); + + return id; + } + + std::string + addSSESubscription(const std::shared_ptr<Subscription>& subValue, + std::string_view lastEventId) + { + std::string id = addSubscriptionInternal(subValue); + + if (!lastEventId.empty()) + { + BMCWEB_LOG_INFO("Attempting to find message for last id {}", + lastEventId); + boost::circular_buffer<Event>::iterator lastEvent = + std::find_if(messages.begin(), messages.end(), + [&lastEventId](const Event& event) { + return event.id == lastEventId; + }); + // Can't find a matching ID + if (lastEvent == messages.end()) + { + nlohmann::json msg = messages::eventBufferExceeded(); + // If the buffer overloaded, send all messages. + subValue->sendEventToSubscriber(msg); + lastEvent = messages.begin(); + } + else + { + // Skip the last event the user already has + lastEvent++; + } + + for (boost::circular_buffer<Event>::const_iterator event = + lastEvent; + lastEvent != messages.end(); lastEvent++) + { + subValue->sendEventToSubscriber(event->message); + } + } + return id; + } + + std::string + addPushSubscription(const std::shared_ptr<Subscription>& subValue) + { + std::string id = addSubscriptionInternal(subValue); + + updateSubscriptionData(); return id; } @@ -916,8 +1088,8 @@ class EventServiceManager subscriptionsMap, [](const std::pair<std::string, std::shared_ptr<Subscription>>& entry) { - return (entry.second->subscriptionType == subscriptionTypeSSE); - }); + return (entry.second->subscriptionType == subscriptionTypeSSE); + }); return static_cast<size_t>(size); } @@ -944,68 +1116,43 @@ class EventServiceManager return true; } - void sendEvent(nlohmann::json eventMessage, const std::string& origin, - const std::string& resType) + void sendEvent(nlohmann::json::object_t eventMessage, + std::string_view origin, std::string_view resourceType) { - if (!serviceEnabled || (noOfEventLogSubscribers == 0U)) - { - BMCWEB_LOG_DEBUG("EventService disabled or no Subscriptions."); - return; - } - nlohmann::json eventRecord = nlohmann::json::array(); - eventMessage["EventId"] = eventId; - // MemberId is 0 : since we are sending one event record. - eventMessage["MemberId"] = 0; + eventMessage["EventTimestamp"] = redfish::time_utils::getDateTimeOffsetNow().first; eventMessage["OriginOfCondition"] = origin; - eventRecord.emplace_back(std::move(eventMessage)); + // MemberId is 0 : since we are sending one event record. + eventMessage["MemberId"] = 0; - for (const auto& it : subscriptionsMap) + messages.push_back(Event(std::to_string(eventId), eventMessage)); + + for (auto& it : subscriptionsMap) { - std::shared_ptr<Subscription> entry = it.second; - bool isSubscribed = false; - // Search the resourceTypes list for the subscription. - // If resourceTypes list is empty, don't filter events - // send everything. - if (!entry->resourceTypes.empty()) + std::shared_ptr<Subscription>& entry = it.second; + if (!entry->eventMatchesFilter(eventMessage, resourceType)) { - for (const auto& resource : entry->resourceTypes) - { - if (resType == resource) - { - BMCWEB_LOG_INFO( - "ResourceType {} found in the subscribed list", - resource); - isSubscribed = true; - break; - } - } - } - else // resourceTypes list is empty. - { - isSubscribed = true; + BMCWEB_LOG_DEBUG("Filter didn't match"); + continue; } - if (isSubscribed) - { - nlohmann::json msgJson; - msgJson["@odata.type"] = "#Event.v1_4_0.Event"; - msgJson["Name"] = "Event Log"; - msgJson["Id"] = eventId; - msgJson["Events"] = eventRecord; + nlohmann::json::array_t eventRecord; + eventRecord.emplace_back(eventMessage); - std::string strMsg = msgJson.dump( - 2, ' ', true, nlohmann::json::error_handler_t::replace); - entry->sendEvent(std::move(strMsg)); - eventId++; // increment the eventId - } - else - { - BMCWEB_LOG_INFO("Not subscribed to this resource"); - } + nlohmann::json msgJson; + + msgJson["@odata.type"] = "#Event.v1_4_0.Event"; + msgJson["Name"] = "Event Log"; + msgJson["Id"] = eventId; + msgJson["Events"] = std::move(eventRecord); + + std::string strMsg = msgJson.dump( + 2, ' ', true, nlohmann::json::error_handler_t::replace); + entry->sendEventToSubscriber(std::move(strMsg)); + eventId++; // increment the eventId } } @@ -1046,17 +1193,24 @@ class EventServiceManager std::string logEntry; + BMCWEB_LOG_DEBUG("Redfish log file: seek to {}", + static_cast<int>(redfishLogFilePosition)); + // Get the read pointer to the next log to be read. logStream.seekg(redfishLogFilePosition); while (std::getline(logStream, logEntry)) { + BMCWEB_LOG_DEBUG("Redfish log file: found new event log entry"); // Update Pointer position redfishLogFilePosition = logStream.tellg(); std::string idStr; if (!event_log::getUniqueEntryID(logEntry, idStr)) { + BMCWEB_LOG_DEBUG( + "Redfish log file: could not get unique entry id for {}", + logEntry); continue; } @@ -1065,6 +1219,8 @@ class EventServiceManager // If Service is not enabled, no need to compute // the remaining items below. // But, Loop must continue to keep track of Timestamp + BMCWEB_LOG_DEBUG( + "Redfish log file: no subscribers / event service not enabled"); continue; } @@ -1074,21 +1230,12 @@ class EventServiceManager if (event_log::getEventLogParams(logEntry, timestamp, messageID, messageArgs) != 0) { - BMCWEB_LOG_DEBUG("Read eventLog entry params failed"); + BMCWEB_LOG_DEBUG("Read eventLog entry params failed for {}", + logEntry); continue; } - std::string registryName; - std::string messageKey; - event_log::getRegistryAndMessageKey(messageID, registryName, - messageKey); - if (registryName.empty() || messageKey.empty()) - { - continue; - } - - eventRecords.emplace_back(idStr, timestamp, messageID, registryName, - messageKey, messageArgs); + eventRecords.emplace_back(idStr, timestamp, messageID, messageArgs); } if (!serviceEnabled || noOfEventLogSubscribers == 0) @@ -1118,98 +1265,110 @@ class EventServiceManager { if (!inotifyConn) { + BMCWEB_LOG_ERROR("inotify Connection is not present"); return; } static std::array<char, 1024> readBuffer; - inotifyConn->async_read_some(boost::asio::buffer(readBuffer), - [&](const boost::system::error_code& ec, - const std::size_t& bytesTransferred) { - if (ec) - { - BMCWEB_LOG_ERROR("Callback Error: {}", ec.message()); - return; - } - std::size_t index = 0; - while ((index + iEventSize) <= bytesTransferred) - { - struct inotify_event event - {}; - std::memcpy(&event, &readBuffer[index], iEventSize); - if (event.wd == dirWatchDesc) + inotifyConn->async_read_some( + boost::asio::buffer(readBuffer), + [&](const boost::system::error_code& ec, + const std::size_t& bytesTransferred) { + if (ec == boost::asio::error::operation_aborted) { - if ((event.len == 0) || - (index + iEventSize + event.len > bytesTransferred)) - { - index += (iEventSize + event.len); - continue; - } + BMCWEB_LOG_DEBUG("Inotify was canceled (shutdown?)"); + return; + } + if (ec) + { + BMCWEB_LOG_ERROR("Callback Error: {}", ec.message()); + return; + } - std::string fileName(&readBuffer[index + iEventSize]); - if (fileName != "redfish") - { - index += (iEventSize + event.len); - continue; - } + BMCWEB_LOG_DEBUG("reading {} via inotify", bytesTransferred); - BMCWEB_LOG_DEBUG( - "Redfish log file created/deleted. event.name: {}", - fileName); - if (event.mask == IN_CREATE) + std::size_t index = 0; + while ((index + iEventSize) <= bytesTransferred) + { + struct inotify_event event + {}; + std::memcpy(&event, &readBuffer[index], iEventSize); + if (event.wd == dirWatchDesc) { - if (fileWatchDesc != -1) + if ((event.len == 0) || + (index + iEventSize + event.len > bytesTransferred)) { - BMCWEB_LOG_DEBUG( - "Remove and Add inotify watcher on " - "redfish event log file"); - // Remove existing inotify watcher and add - // with new redfish event log file. - inotify_rm_watch(inotifyFd, fileWatchDesc); - fileWatchDesc = -1; + index += (iEventSize + event.len); + continue; } - fileWatchDesc = inotify_add_watch( - inotifyFd, redfishEventLogFile, IN_MODIFY); - if (fileWatchDesc == -1) + std::string fileName(&readBuffer[index + iEventSize]); + if (fileName != "redfish") { - BMCWEB_LOG_ERROR("inotify_add_watch failed for " - "redfish log file."); - return; + index += (iEventSize + event.len); + continue; } - EventServiceManager::getInstance() - .resetRedfishFilePosition(); - EventServiceManager::getInstance() - .readEventLogsFromFile(); - } - else if ((event.mask == IN_DELETE) || - (event.mask == IN_MOVED_TO)) - { - if (fileWatchDesc != -1) + BMCWEB_LOG_DEBUG( + "Redfish log file created/deleted. event.name: {}", + fileName); + if (event.mask == IN_CREATE) { - inotify_rm_watch(inotifyFd, fileWatchDesc); - fileWatchDesc = -1; + if (fileWatchDesc != -1) + { + BMCWEB_LOG_DEBUG( + "Remove and Add inotify watcher on " + "redfish event log file"); + // Remove existing inotify watcher and add + // with new redfish event log file. + inotify_rm_watch(inotifyFd, fileWatchDesc); + fileWatchDesc = -1; + } + + fileWatchDesc = inotify_add_watch( + inotifyFd, redfishEventLogFile, IN_MODIFY); + if (fileWatchDesc == -1) + { + BMCWEB_LOG_ERROR("inotify_add_watch failed for " + "redfish log file."); + return; + } + + EventServiceManager::getInstance() + .resetRedfishFilePosition(); + EventServiceManager::getInstance() + .readEventLogsFromFile(); + } + else if ((event.mask == IN_DELETE) || + (event.mask == IN_MOVED_TO)) + { + if (fileWatchDesc != -1) + { + inotify_rm_watch(inotifyFd, fileWatchDesc); + fileWatchDesc = -1; + } } } - } - else if (event.wd == fileWatchDesc) - { - if (event.mask == IN_MODIFY) + else if (event.wd == fileWatchDesc) { - EventServiceManager::getInstance() - .readEventLogsFromFile(); + if (event.mask == IN_MODIFY) + { + EventServiceManager::getInstance() + .readEventLogsFromFile(); + } } + index += (iEventSize + event.len); } - index += (iEventSize + event.len); - } - watchRedfishEventLogFile(); - }); + watchRedfishEventLogFile(); + }); } static int startEventLogMonitor(boost::asio::io_context& ioc) { + BMCWEB_LOG_DEBUG("starting Event Log Monitor"); + inotifyConn.emplace(ioc); inotifyFd = inotify_init1(IN_NONBLOCK); if (inotifyFd == -1) @@ -1230,8 +1389,8 @@ class EventServiceManager } // Watch redfish event log file for modifications. - fileWatchDesc = inotify_add_watch(inotifyFd, redfishEventLogFile, - IN_MODIFY); + fileWatchDesc = + inotify_add_watch(inotifyFd, redfishEventLogFile, IN_MODIFY); if (fileWatchDesc == -1) { BMCWEB_LOG_ERROR("inotify_add_watch failed for redfish log file."); @@ -1246,6 +1405,11 @@ class EventServiceManager return 0; } + static void stopEventLogMonitor() + { + inotifyConn.reset(); + } + static void getReadingsForReport(sdbusplus::message_t& msg) { if (msg.is_method_error()) @@ -1267,8 +1431,9 @@ class EventServiceManager std::vector<std::string> invalidProps; msg.read(interface, props, invalidProps); - auto found = std::ranges::find_if( - props, [](const auto& x) { return x.first == "Readings"; }); + auto found = std::ranges::find_if(props, [](const auto& x) { + return x.first == "Readings"; + }); if (found == props.end()) { BMCWEB_LOG_INFO("Failed to get Readings from Report properties"); |