1e21126ecSEd Tanous #pragma once
2e21126ecSEd Tanous 
3e21126ecSEd Tanous #include "app.hpp"
4e21126ecSEd Tanous #include "generated/enums/log_entry.hpp"
5e21126ecSEd Tanous #include "query.hpp"
6e21126ecSEd Tanous #include "registries/openbmc_message_registry.hpp"
7e21126ecSEd Tanous #include "registries/privilege_registry.hpp"
8e21126ecSEd Tanous #include "utils/time_utils.hpp"
9e21126ecSEd Tanous 
10e21126ecSEd Tanous #include <cstdint>
11e21126ecSEd Tanous #include <memory>
12e21126ecSEd Tanous #include <string_view>
13e21126ecSEd Tanous #include <utility>
14e21126ecSEd Tanous #include <vector>
15e21126ecSEd Tanous 
16e21126ecSEd Tanous namespace redfish
17e21126ecSEd Tanous {
18e21126ecSEd Tanous 
fillHostLoggerEntryJson(std::string_view logEntryID,std::string_view msg,nlohmann::json::object_t & logEntryJson)19e21126ecSEd Tanous inline void fillHostLoggerEntryJson(std::string_view logEntryID,
20e21126ecSEd Tanous                                     std::string_view msg,
21e21126ecSEd Tanous                                     nlohmann::json::object_t& logEntryJson)
22e21126ecSEd Tanous {
23e21126ecSEd Tanous     // Fill in the log entry with the gathered data.
24e21126ecSEd Tanous     logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
25e21126ecSEd Tanous     logEntryJson["@odata.id"] = boost::urls::format(
26e21126ecSEd Tanous         "/redfish/v1/Systems/{}/LogServices/HostLogger/Entries/{}",
27e21126ecSEd Tanous         BMCWEB_REDFISH_SYSTEM_URI_NAME, logEntryID);
28e21126ecSEd Tanous     logEntryJson["Name"] = "Host Logger Entry";
29e21126ecSEd Tanous     logEntryJson["Id"] = logEntryID;
30e21126ecSEd Tanous     logEntryJson["Message"] = msg;
31e21126ecSEd Tanous     logEntryJson["EntryType"] = log_entry::LogEntryType::Oem;
32e21126ecSEd Tanous     logEntryJson["Severity"] = log_entry::EventSeverity::OK;
33e21126ecSEd Tanous     logEntryJson["OemRecordFormat"] = "Host Logger Entry";
34e21126ecSEd Tanous }
35e21126ecSEd Tanous 
handleSystemsLogServicesHostloggerGet(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName)367945eeedSEd Tanous inline void handleSystemsLogServicesHostloggerGet(
377945eeedSEd Tanous     App& app, const crow::Request& req,
38e21126ecSEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
397945eeedSEd Tanous     const std::string& systemName)
407945eeedSEd Tanous {
41e21126ecSEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
42e21126ecSEd Tanous     {
43e21126ecSEd Tanous         return;
44e21126ecSEd Tanous     }
45e21126ecSEd Tanous     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
46e21126ecSEd Tanous     {
47e21126ecSEd Tanous         // Option currently returns no systems.  TBD
48e21126ecSEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
49e21126ecSEd Tanous                                    systemName);
50e21126ecSEd Tanous         return;
51e21126ecSEd Tanous     }
52e21126ecSEd Tanous     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
53e21126ecSEd Tanous     {
54e21126ecSEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
55e21126ecSEd Tanous                                    systemName);
56e21126ecSEd Tanous         return;
57e21126ecSEd Tanous     }
58e21126ecSEd Tanous     asyncResp->res.jsonValue["@odata.id"] =
59e21126ecSEd Tanous         std::format("/redfish/v1/Systems/{}/LogServices/HostLogger",
60e21126ecSEd Tanous                     BMCWEB_REDFISH_SYSTEM_URI_NAME);
617945eeedSEd Tanous     asyncResp->res.jsonValue["@odata.type"] = "#LogService.v1_2_0.LogService";
62e21126ecSEd Tanous     asyncResp->res.jsonValue["Name"] = "Host Logger Service";
63e21126ecSEd Tanous     asyncResp->res.jsonValue["Description"] = "Host Logger Service";
64e21126ecSEd Tanous     asyncResp->res.jsonValue["Id"] = "HostLogger";
657945eeedSEd Tanous     asyncResp->res.jsonValue["Entries"]["@odata.id"] =
667945eeedSEd Tanous         std::format("/redfish/v1/Systems/{}/LogServices/HostLogger/Entries",
67e21126ecSEd Tanous                     BMCWEB_REDFISH_SYSTEM_URI_NAME);
68e21126ecSEd Tanous }
69e21126ecSEd Tanous 
handleSystemsLogServicesHostloggerEntriesGet(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName)707945eeedSEd Tanous inline void handleSystemsLogServicesHostloggerEntriesGet(
717945eeedSEd Tanous     App& app, const crow::Request& req,
72e21126ecSEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
737945eeedSEd Tanous     const std::string& systemName)
747945eeedSEd Tanous {
75e21126ecSEd Tanous     query_param::QueryCapabilities capabilities = {
76e21126ecSEd Tanous         .canDelegateTop = true,
77e21126ecSEd Tanous         .canDelegateSkip = true,
78e21126ecSEd Tanous     };
79e21126ecSEd Tanous     query_param::Query delegatedQuery;
807945eeedSEd Tanous     if (!redfish::setUpRedfishRouteWithDelegation(app, req, asyncResp,
817945eeedSEd Tanous                                                   delegatedQuery, capabilities))
82e21126ecSEd Tanous     {
83e21126ecSEd Tanous         return;
84e21126ecSEd Tanous     }
85e21126ecSEd Tanous     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
86e21126ecSEd Tanous     {
87e21126ecSEd Tanous         // Option currently returns no systems.  TBD
88e21126ecSEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
89e21126ecSEd Tanous                                    systemName);
90e21126ecSEd Tanous         return;
91e21126ecSEd Tanous     }
92e21126ecSEd Tanous     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
93e21126ecSEd Tanous     {
94e21126ecSEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
95e21126ecSEd Tanous                                    systemName);
96e21126ecSEd Tanous         return;
97e21126ecSEd Tanous     }
987945eeedSEd Tanous     asyncResp->res.jsonValue["@odata.id"] =
997945eeedSEd Tanous         std::format("/redfish/v1/Systems/{}/LogServices/HostLogger/Entries",
100e21126ecSEd Tanous                     BMCWEB_REDFISH_SYSTEM_URI_NAME);
101e21126ecSEd Tanous     asyncResp->res.jsonValue["@odata.type"] =
102e21126ecSEd Tanous         "#LogEntryCollection.LogEntryCollection";
103e21126ecSEd Tanous     asyncResp->res.jsonValue["Name"] = "HostLogger Entries";
104e21126ecSEd Tanous     asyncResp->res.jsonValue["Description"] =
105e21126ecSEd Tanous         "Collection of HostLogger Entries";
106e21126ecSEd Tanous     nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
107e21126ecSEd Tanous     logEntryArray = nlohmann::json::array();
108e21126ecSEd Tanous     asyncResp->res.jsonValue["Members@odata.count"] = 0;
109e21126ecSEd Tanous 
110e21126ecSEd Tanous     std::vector<std::filesystem::path> hostLoggerFiles;
111e21126ecSEd Tanous     if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles))
112e21126ecSEd Tanous     {
113e21126ecSEd Tanous         BMCWEB_LOG_DEBUG("Failed to get host log file path");
114e21126ecSEd Tanous         return;
115e21126ecSEd Tanous     }
116e21126ecSEd Tanous     // If we weren't provided top and skip limits, use the defaults.
117e21126ecSEd Tanous     size_t skip = delegatedQuery.skip.value_or(0);
1187945eeedSEd Tanous     size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
119e21126ecSEd Tanous     size_t logCount = 0;
120e21126ecSEd Tanous     // This vector only store the entries we want to expose that
121e21126ecSEd Tanous     // control by skip and top.
122e21126ecSEd Tanous     std::vector<std::string> logEntries;
1237945eeedSEd Tanous     if (!getHostLoggerEntries(hostLoggerFiles, skip, top, logEntries, logCount))
124e21126ecSEd Tanous     {
125e21126ecSEd Tanous         messages::internalError(asyncResp->res);
126e21126ecSEd Tanous         return;
127e21126ecSEd Tanous     }
128e21126ecSEd Tanous     // If vector is empty, that means skip value larger than total
129e21126ecSEd Tanous     // log count
130e21126ecSEd Tanous     if (logEntries.empty())
131e21126ecSEd Tanous     {
132e21126ecSEd Tanous         asyncResp->res.jsonValue["Members@odata.count"] = logCount;
133e21126ecSEd Tanous         return;
134e21126ecSEd Tanous     }
135e21126ecSEd Tanous     if (!logEntries.empty())
136e21126ecSEd Tanous     {
137e21126ecSEd Tanous         for (size_t i = 0; i < logEntries.size(); i++)
138e21126ecSEd Tanous         {
139e21126ecSEd Tanous             nlohmann::json::object_t hostLogEntry;
1407945eeedSEd Tanous             fillHostLoggerEntryJson(std::to_string(skip + i), logEntries[i],
1417945eeedSEd Tanous                                     hostLogEntry);
142e21126ecSEd Tanous             logEntryArray.emplace_back(std::move(hostLogEntry));
143e21126ecSEd Tanous         }
144e21126ecSEd Tanous 
145e21126ecSEd Tanous         asyncResp->res.jsonValue["Members@odata.count"] = logCount;
146e21126ecSEd Tanous         if (skip + top < logCount)
147e21126ecSEd Tanous         {
148e21126ecSEd Tanous             asyncResp->res.jsonValue["Members@odata.nextLink"] =
149e21126ecSEd Tanous                 std::format(
150e21126ecSEd Tanous                     "/redfish/v1/Systems/{}/LogServices/HostLogger/Entries?$skip=",
151e21126ecSEd Tanous                     BMCWEB_REDFISH_SYSTEM_URI_NAME) +
152e21126ecSEd Tanous                 std::to_string(skip + top);
153e21126ecSEd Tanous         }
154e21126ecSEd Tanous     }
155e21126ecSEd Tanous }
156e21126ecSEd Tanous 
handleSystemsLogServicesHostloggerEntriesEntryGet(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName,const std::string & param)1577945eeedSEd Tanous inline void handleSystemsLogServicesHostloggerEntriesEntryGet(
1587945eeedSEd Tanous     App& app, const crow::Request& req,
159e21126ecSEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1607945eeedSEd Tanous     const std::string& systemName, const std::string& param)
1617945eeedSEd Tanous {
162e21126ecSEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
163e21126ecSEd Tanous     {
164e21126ecSEd Tanous         return;
165e21126ecSEd Tanous     }
166e21126ecSEd Tanous     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
167e21126ecSEd Tanous     {
168e21126ecSEd Tanous         // Option currently returns no systems.  TBD
169e21126ecSEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
170e21126ecSEd Tanous                                    systemName);
171e21126ecSEd Tanous         return;
172e21126ecSEd Tanous     }
173e21126ecSEd Tanous     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
174e21126ecSEd Tanous     {
175e21126ecSEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
176e21126ecSEd Tanous                                    systemName);
177e21126ecSEd Tanous         return;
178e21126ecSEd Tanous     }
179e21126ecSEd Tanous     std::string_view targetID = param;
180e21126ecSEd Tanous 
181e21126ecSEd Tanous     uint64_t idInt = 0;
182e21126ecSEd Tanous 
1837945eeedSEd Tanous     auto [ptr, ec] = std::from_chars(targetID.begin(), targetID.end(), idInt);
184e21126ecSEd Tanous     if (ec != std::errc{} || ptr != targetID.end())
185e21126ecSEd Tanous     {
1867945eeedSEd Tanous         messages::resourceNotFound(asyncResp->res, "LogEntry", param);
187e21126ecSEd Tanous         return;
188e21126ecSEd Tanous     }
189e21126ecSEd Tanous 
190e21126ecSEd Tanous     std::vector<std::filesystem::path> hostLoggerFiles;
191e21126ecSEd Tanous     if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles))
192e21126ecSEd Tanous     {
193e21126ecSEd Tanous         BMCWEB_LOG_DEBUG("Failed to get host log file path");
194e21126ecSEd Tanous         return;
195e21126ecSEd Tanous     }
196e21126ecSEd Tanous 
197e21126ecSEd Tanous     size_t logCount = 0;
198e21126ecSEd Tanous     size_t top = 1;
199e21126ecSEd Tanous     std::vector<std::string> logEntries;
200e21126ecSEd Tanous     // We can get specific entry by skip and top. For example, if we
201e21126ecSEd Tanous     // want to get nth entry, we can set skip = n-1 and top = 1 to
202e21126ecSEd Tanous     // get that entry
2037945eeedSEd Tanous     if (!getHostLoggerEntries(hostLoggerFiles, idInt, top, logEntries,
2047945eeedSEd Tanous                               logCount))
205e21126ecSEd Tanous     {
206e21126ecSEd Tanous         messages::internalError(asyncResp->res);
207e21126ecSEd Tanous         return;
208e21126ecSEd Tanous     }
209e21126ecSEd Tanous 
210e21126ecSEd Tanous     if (!logEntries.empty())
211e21126ecSEd Tanous     {
212e21126ecSEd Tanous         nlohmann::json::object_t hostLogEntry;
2137945eeedSEd Tanous         fillHostLoggerEntryJson(targetID, logEntries[0], hostLogEntry);
214e21126ecSEd Tanous         asyncResp->res.jsonValue.update(hostLogEntry);
215e21126ecSEd Tanous         return;
216e21126ecSEd Tanous     }
217e21126ecSEd Tanous 
218e21126ecSEd Tanous     // Requested ID was not found
219e21126ecSEd Tanous     messages::resourceNotFound(asyncResp->res, "LogEntry", param);
220e21126ecSEd Tanous }
221e21126ecSEd Tanous 
requestRoutesSystemsLogServiceHostlogger(App & app)222e21126ecSEd Tanous inline void requestRoutesSystemsLogServiceHostlogger(App& app)
223e21126ecSEd Tanous {
2247945eeedSEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/")
2257945eeedSEd Tanous         .privileges(redfish::privileges::getLogService)
2267945eeedSEd Tanous         .methods(boost::beast::http::verb::get)(std::bind_front(
2277945eeedSEd Tanous             handleSystemsLogServicesHostloggerGet, std::ref(app)));
2287945eeedSEd Tanous     BMCWEB_ROUTE(app,
2297945eeedSEd Tanous                  "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/")
230*3d45ef66SGunnar Mills         .privileges(redfish::privileges::getLogEntryCollection)
2317945eeedSEd Tanous         .methods(boost::beast::http::verb::get)(std::bind_front(
2327945eeedSEd Tanous             handleSystemsLogServicesHostloggerEntriesGet, std::ref(app)));
2337945eeedSEd Tanous 
2347945eeedSEd Tanous     BMCWEB_ROUTE(
2357945eeedSEd Tanous         app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/<str>/")
2367945eeedSEd Tanous         .privileges(redfish::privileges::getLogEntry)
2377945eeedSEd Tanous         .methods(boost::beast::http::verb::get)(std::bind_front(
2387945eeedSEd Tanous             handleSystemsLogServicesHostloggerEntriesEntryGet, std::ref(app)));
239e21126ecSEd Tanous }
240e21126ecSEd Tanous 
241e21126ecSEd Tanous } // namespace redfish
242