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