blob: 49911f31d4d4867aa32cfc3b6f6b5a3aa44ef469 [file] [log] [blame]
Ed Tanous1da66f72018-07-27 16:13:37 -07001/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16#pragma once
17
Spencer Kub7028eb2021-10-26 15:27:35 +080018#include "gzfile.hpp"
George Liu647b3cd2021-07-05 12:43:56 +080019#include "http_utility.hpp"
Spencer Kub7028eb2021-10-26 15:27:35 +080020#include "human_sort.hpp"
Jason M. Bills4851d452019-03-28 11:27:48 -070021#include "registries.hpp"
22#include "registries/base_message_registry.hpp"
23#include "registries/openbmc_message_registry.hpp"
James Feist46229572020-02-19 15:11:58 -080024#include "task.hpp"
Ed Tanous1da66f72018-07-27 16:13:37 -070025
Jason M. Billse1f26342018-07-18 12:12:00 -070026#include <systemd/sd-journal.h>
Adriana Kobylak400fd1f2021-01-29 09:01:30 -060027#include <unistd.h>
Jason M. Billse1f26342018-07-18 12:12:00 -070028
John Edward Broadbent7e860f12021-04-08 15:57:16 -070029#include <app.hpp>
Adriana Kobylak400fd1f2021-01-29 09:01:30 -060030#include <boost/algorithm/string/replace.hpp>
Jason M. Bills4851d452019-03-28 11:27:48 -070031#include <boost/algorithm/string/split.hpp>
Adriana Kobylak400fd1f2021-01-29 09:01:30 -060032#include <boost/beast/http.hpp>
Ed Tanous1da66f72018-07-27 16:13:37 -070033#include <boost/container/flat_map.hpp>
Jason M. Bills1ddcf012019-11-26 14:59:21 -080034#include <boost/system/linux_error.hpp>
Ed Tanous168e20c2021-12-13 14:39:53 -080035#include <dbus_utility.hpp>
Andrew Geisslercb92c032018-08-17 07:56:14 -070036#include <error_messages.hpp>
Ed Tanous45ca1b82022-03-25 13:07:27 -070037#include <query.hpp>
Ed Tanoused398212021-06-09 17:05:54 -070038#include <registries/privilege_registry.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050039
George Liu647b3cd2021-07-05 12:43:56 +080040#include <charconv>
James Feist4418c7f2019-04-15 11:09:15 -070041#include <filesystem>
Xiaochao Ma75710de2021-01-21 17:56:02 +080042#include <optional>
Ed Tanous26702d02021-11-03 15:02:33 -070043#include <span>
Jason M. Billscd225da2019-05-08 15:31:57 -070044#include <string_view>
Ed Tanousabf2add2019-01-22 16:40:12 -080045#include <variant>
Ed Tanous1da66f72018-07-27 16:13:37 -070046
47namespace redfish
48{
49
Gunnar Mills1214b7e2020-06-04 10:11:30 -050050constexpr char const* crashdumpObject = "com.intel.crashdump";
51constexpr char const* crashdumpPath = "/com/intel/crashdump";
Gunnar Mills1214b7e2020-06-04 10:11:30 -050052constexpr char const* crashdumpInterface = "com.intel.crashdump";
53constexpr char const* deleteAllInterface =
Jason M. Bills5b61b5e2019-10-16 10:59:02 -070054 "xyz.openbmc_project.Collection.DeleteAll";
Gunnar Mills1214b7e2020-06-04 10:11:30 -050055constexpr char const* crashdumpOnDemandInterface =
Jason M. Bills424c4172019-03-21 13:50:33 -070056 "com.intel.crashdump.OnDemand";
Kenny L. Ku6eda7682020-06-19 09:48:36 -070057constexpr char const* crashdumpTelemetryInterface =
58 "com.intel.crashdump.Telemetry";
Ed Tanous1da66f72018-07-27 16:13:37 -070059
Ed Tanousfffb8c12022-02-07 23:53:03 -080060namespace registries
Jason M. Bills4851d452019-03-28 11:27:48 -070061{
Ed Tanous26702d02021-11-03 15:02:33 -070062static const Message*
63 getMessageFromRegistry(const std::string& messageKey,
64 const std::span<const MessageEntry> registry)
Jason M. Bills4851d452019-03-28 11:27:48 -070065{
Ed Tanous26702d02021-11-03 15:02:33 -070066 std::span<const MessageEntry>::iterator messageIt = std::find_if(
67 registry.begin(), registry.end(),
68 [&messageKey](const MessageEntry& messageEntry) {
Ed Tanouse662eae2022-01-25 10:39:19 -080069 return std::strcmp(messageEntry.first, messageKey.c_str()) == 0;
Ed Tanous26702d02021-11-03 15:02:33 -070070 });
71 if (messageIt != registry.end())
Jason M. Bills4851d452019-03-28 11:27:48 -070072 {
73 return &messageIt->second;
74 }
75
76 return nullptr;
77}
78
Gunnar Mills1214b7e2020-06-04 10:11:30 -050079static const Message* getMessage(const std::string_view& messageID)
Jason M. Bills4851d452019-03-28 11:27:48 -070080{
81 // Redfish MessageIds are in the form
82 // RegistryName.MajorVersion.MinorVersion.MessageKey, so parse it to find
83 // the right Message
84 std::vector<std::string> fields;
85 fields.reserve(4);
86 boost::split(fields, messageID, boost::is_any_of("."));
Gunnar Mills1214b7e2020-06-04 10:11:30 -050087 std::string& registryName = fields[0];
88 std::string& messageKey = fields[3];
Jason M. Bills4851d452019-03-28 11:27:48 -070089
90 // Find the right registry and check it for the MessageKey
91 if (std::string(base::header.registryPrefix) == registryName)
92 {
93 return getMessageFromRegistry(
Ed Tanous26702d02021-11-03 15:02:33 -070094 messageKey, std::span<const MessageEntry>(base::registry));
Jason M. Bills4851d452019-03-28 11:27:48 -070095 }
96 if (std::string(openbmc::header.registryPrefix) == registryName)
97 {
98 return getMessageFromRegistry(
Ed Tanous26702d02021-11-03 15:02:33 -070099 messageKey, std::span<const MessageEntry>(openbmc::registry));
Jason M. Bills4851d452019-03-28 11:27:48 -0700100 }
101 return nullptr;
102}
Ed Tanousfffb8c12022-02-07 23:53:03 -0800103} // namespace registries
Jason M. Bills4851d452019-03-28 11:27:48 -0700104
James Feistf6150402019-01-08 10:36:20 -0800105namespace fs = std::filesystem;
Ed Tanous1da66f72018-07-27 16:13:37 -0700106
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500107inline std::string translateSeverityDbusToRedfish(const std::string& s)
Andrew Geisslercb92c032018-08-17 07:56:14 -0700108{
Ed Tanousd4d25792020-09-29 15:15:03 -0700109 if ((s == "xyz.openbmc_project.Logging.Entry.Level.Alert") ||
110 (s == "xyz.openbmc_project.Logging.Entry.Level.Critical") ||
111 (s == "xyz.openbmc_project.Logging.Entry.Level.Emergency") ||
112 (s == "xyz.openbmc_project.Logging.Entry.Level.Error"))
Andrew Geisslercb92c032018-08-17 07:56:14 -0700113 {
114 return "Critical";
115 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700116 if ((s == "xyz.openbmc_project.Logging.Entry.Level.Debug") ||
117 (s == "xyz.openbmc_project.Logging.Entry.Level.Informational") ||
118 (s == "xyz.openbmc_project.Logging.Entry.Level.Notice"))
Andrew Geisslercb92c032018-08-17 07:56:14 -0700119 {
120 return "OK";
121 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700122 if (s == "xyz.openbmc_project.Logging.Entry.Level.Warning")
Andrew Geisslercb92c032018-08-17 07:56:14 -0700123 {
124 return "Warning";
125 }
126 return "";
127}
128
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700129inline static int getJournalMetadata(sd_journal* journal,
130 const std::string_view& field,
131 std::string_view& contents)
Jason M. Bills16428a12018-11-02 12:42:29 -0700132{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500133 const char* data = nullptr;
Jason M. Bills16428a12018-11-02 12:42:29 -0700134 size_t length = 0;
135 int ret = 0;
136 // Get the metadata from the requested field of the journal entry
Ed Tanous46ff87b2022-01-07 09:25:51 -0800137 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
138 const void** dataVoid = reinterpret_cast<const void**>(&data);
139
140 ret = sd_journal_get_data(journal, field.data(), dataVoid, &length);
Jason M. Bills16428a12018-11-02 12:42:29 -0700141 if (ret < 0)
142 {
143 return ret;
144 }
Ed Tanous39e77502019-03-04 17:35:53 -0800145 contents = std::string_view(data, length);
Jason M. Bills16428a12018-11-02 12:42:29 -0700146 // Only use the content after the "=" character.
Ed Tanous81ce6092020-12-17 16:54:55 +0000147 contents.remove_prefix(std::min(contents.find('=') + 1, contents.size()));
Jason M. Bills16428a12018-11-02 12:42:29 -0700148 return ret;
149}
150
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700151inline static int getJournalMetadata(sd_journal* journal,
152 const std::string_view& field,
153 const int& base, long int& contents)
Jason M. Bills16428a12018-11-02 12:42:29 -0700154{
155 int ret = 0;
Ed Tanous39e77502019-03-04 17:35:53 -0800156 std::string_view metadata;
Jason M. Bills16428a12018-11-02 12:42:29 -0700157 // Get the metadata from the requested field of the journal entry
158 ret = getJournalMetadata(journal, field, metadata);
159 if (ret < 0)
160 {
161 return ret;
162 }
Ed Tanousb01bf292019-03-25 19:25:26 +0000163 contents = strtol(metadata.data(), nullptr, base);
Jason M. Bills16428a12018-11-02 12:42:29 -0700164 return ret;
165}
166
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700167inline static bool getEntryTimestamp(sd_journal* journal,
168 std::string& entryTimestamp)
ZhikuiRena3316fc2020-01-29 14:58:08 -0800169{
170 int ret = 0;
171 uint64_t timestamp = 0;
172 ret = sd_journal_get_realtime_usec(journal, &timestamp);
173 if (ret < 0)
174 {
175 BMCWEB_LOG_ERROR << "Failed to read entry timestamp: "
176 << strerror(-ret);
177 return false;
178 }
Nan Zhou1d8782e2021-11-29 22:23:18 -0800179 entryTimestamp = crow::utility::getDateTimeUint(timestamp / 1000 / 1000);
Asmitha Karunanithi9c620e22020-08-02 11:55:21 -0500180 return true;
ZhikuiRena3316fc2020-01-29 14:58:08 -0800181}
Ed Tanous50b8a432022-02-03 16:29:50 -0800182
Ed Tanous67df0732021-10-26 11:23:56 -0700183static bool getSkipParam(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
184 const crow::Request& req, uint64_t& skip)
185{
186 boost::urls::params_view::iterator it = req.urlView.params().find("$skip");
187 if (it != req.urlView.params().end())
188 {
189 std::from_chars_result r = std::from_chars(
190 (*it).value.data(), (*it).value.data() + (*it).value.size(), skip);
191 if (r.ec != std::errc())
192 {
193 messages::queryParameterValueTypeError(asyncResp->res, "", "$skip");
194 return false;
195 }
196 }
197 return true;
198}
199
200static constexpr const uint64_t maxEntriesPerPage = 1000;
201static bool getTopParam(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
202 const crow::Request& req, uint64_t& top)
203{
204 boost::urls::params_view::iterator it = req.urlView.params().find("$top");
205 if (it != req.urlView.params().end())
206 {
207 std::from_chars_result r = std::from_chars(
208 (*it).value.data(), (*it).value.data() + (*it).value.size(), top);
209 if (r.ec != std::errc())
210 {
211 messages::queryParameterValueTypeError(asyncResp->res, "", "$top");
212 return false;
213 }
214 if (top < 1U || top > maxEntriesPerPage)
215 {
216
217 messages::queryParameterOutOfRange(
218 asyncResp->res, std::to_string(top), "$top",
219 "1-" + std::to_string(maxEntriesPerPage));
220 return false;
221 }
222 }
223 return true;
224}
225
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700226inline static bool getUniqueEntryID(sd_journal* journal, std::string& entryID,
227 const bool firstEntry = true)
Jason M. Bills16428a12018-11-02 12:42:29 -0700228{
229 int ret = 0;
230 static uint64_t prevTs = 0;
231 static int index = 0;
Jason M. Billse85d6b12019-07-29 17:01:15 -0700232 if (firstEntry)
233 {
234 prevTs = 0;
235 }
236
Jason M. Bills16428a12018-11-02 12:42:29 -0700237 // Get the entry timestamp
238 uint64_t curTs = 0;
239 ret = sd_journal_get_realtime_usec(journal, &curTs);
240 if (ret < 0)
241 {
242 BMCWEB_LOG_ERROR << "Failed to read entry timestamp: "
243 << strerror(-ret);
244 return false;
245 }
246 // If the timestamp isn't unique, increment the index
247 if (curTs == prevTs)
248 {
249 index++;
250 }
251 else
252 {
253 // Otherwise, reset it
254 index = 0;
255 }
256 // Save the timestamp
257 prevTs = curTs;
258
259 entryID = std::to_string(curTs);
260 if (index > 0)
261 {
262 entryID += "_" + std::to_string(index);
263 }
264 return true;
265}
266
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500267static bool getUniqueEntryID(const std::string& logEntry, std::string& entryID,
Jason M. Billse85d6b12019-07-29 17:01:15 -0700268 const bool firstEntry = true)
Jason M. Bills95820182019-04-22 16:25:34 -0700269{
Ed Tanous271584a2019-07-09 16:24:22 -0700270 static time_t prevTs = 0;
Jason M. Bills95820182019-04-22 16:25:34 -0700271 static int index = 0;
Jason M. Billse85d6b12019-07-29 17:01:15 -0700272 if (firstEntry)
273 {
274 prevTs = 0;
275 }
276
Jason M. Bills95820182019-04-22 16:25:34 -0700277 // Get the entry timestamp
Ed Tanous271584a2019-07-09 16:24:22 -0700278 std::time_t curTs = 0;
Jason M. Bills95820182019-04-22 16:25:34 -0700279 std::tm timeStruct = {};
280 std::istringstream entryStream(logEntry);
281 if (entryStream >> std::get_time(&timeStruct, "%Y-%m-%dT%H:%M:%S"))
282 {
283 curTs = std::mktime(&timeStruct);
284 }
285 // If the timestamp isn't unique, increment the index
286 if (curTs == prevTs)
287 {
288 index++;
289 }
290 else
291 {
292 // Otherwise, reset it
293 index = 0;
294 }
295 // Save the timestamp
296 prevTs = curTs;
297
298 entryID = std::to_string(curTs);
299 if (index > 0)
300 {
301 entryID += "_" + std::to_string(index);
302 }
303 return true;
304}
305
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700306inline static bool
zhanghch058d1b46d2021-04-01 11:18:24 +0800307 getTimestampFromID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
308 const std::string& entryID, uint64_t& timestamp,
309 uint64_t& index)
Jason M. Bills16428a12018-11-02 12:42:29 -0700310{
311 if (entryID.empty())
312 {
313 return false;
314 }
315 // Convert the unique ID back to a timestamp to find the entry
Ed Tanous39e77502019-03-04 17:35:53 -0800316 std::string_view tsStr(entryID);
Jason M. Bills16428a12018-11-02 12:42:29 -0700317
Ed Tanous81ce6092020-12-17 16:54:55 +0000318 auto underscorePos = tsStr.find('_');
Ed Tanous71d5d8d2022-01-25 11:04:33 -0800319 if (underscorePos != std::string_view::npos)
Jason M. Bills16428a12018-11-02 12:42:29 -0700320 {
321 // Timestamp has an index
322 tsStr.remove_suffix(tsStr.size() - underscorePos);
Ed Tanous39e77502019-03-04 17:35:53 -0800323 std::string_view indexStr(entryID);
Jason M. Bills16428a12018-11-02 12:42:29 -0700324 indexStr.remove_prefix(underscorePos + 1);
Ed Tanousc0bd5e42021-09-13 17:00:19 -0700325 auto [ptr, ec] = std::from_chars(
326 indexStr.data(), indexStr.data() + indexStr.size(), index);
327 if (ec != std::errc())
Jason M. Bills16428a12018-11-02 12:42:29 -0700328 {
Ed Tanousace85d62021-10-26 12:45:59 -0700329 messages::resourceMissingAtURI(
330 asyncResp->res, crow::utility::urlFromPieces(entryID));
Jason M. Bills16428a12018-11-02 12:42:29 -0700331 return false;
332 }
333 }
334 // Timestamp has no index
Ed Tanousc0bd5e42021-09-13 17:00:19 -0700335 auto [ptr, ec] =
336 std::from_chars(tsStr.data(), tsStr.data() + tsStr.size(), timestamp);
337 if (ec != std::errc())
Jason M. Bills16428a12018-11-02 12:42:29 -0700338 {
Ed Tanousace85d62021-10-26 12:45:59 -0700339 messages::resourceMissingAtURI(asyncResp->res,
340 crow::utility::urlFromPieces(entryID));
Jason M. Bills16428a12018-11-02 12:42:29 -0700341 return false;
342 }
343 return true;
344}
345
Jason M. Bills95820182019-04-22 16:25:34 -0700346static bool
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500347 getRedfishLogFiles(std::vector<std::filesystem::path>& redfishLogFiles)
Jason M. Bills95820182019-04-22 16:25:34 -0700348{
349 static const std::filesystem::path redfishLogDir = "/var/log";
350 static const std::string redfishLogFilename = "redfish";
351
352 // Loop through the directory looking for redfish log files
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500353 for (const std::filesystem::directory_entry& dirEnt :
Jason M. Bills95820182019-04-22 16:25:34 -0700354 std::filesystem::directory_iterator(redfishLogDir))
355 {
356 // If we find a redfish log file, save the path
357 std::string filename = dirEnt.path().filename();
358 if (boost::starts_with(filename, redfishLogFilename))
359 {
360 redfishLogFiles.emplace_back(redfishLogDir / filename);
361 }
362 }
363 // As the log files rotate, they are appended with a ".#" that is higher for
364 // the older logs. Since we don't expect more than 10 log files, we
365 // can just sort the list to get them in order from newest to oldest
366 std::sort(redfishLogFiles.begin(), redfishLogFiles.end());
367
368 return !redfishLogFiles.empty();
369}
370
zhanghch058d1b46d2021-04-01 11:18:24 +0800371inline void
372 getDumpEntryCollection(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
373 const std::string& dumpType)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500374{
375 std::string dumpPath;
376 if (dumpType == "BMC")
377 {
378 dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/";
379 }
380 else if (dumpType == "System")
381 {
382 dumpPath = "/redfish/v1/Systems/system/LogServices/Dump/Entries/";
383 }
384 else
385 {
386 BMCWEB_LOG_ERROR << "Invalid dump type" << dumpType;
387 messages::internalError(asyncResp->res);
388 return;
389 }
390
391 crow::connections::systemBus->async_method_call(
Ed Tanous711ac7a2021-12-20 09:34:41 -0800392 [asyncResp, dumpPath,
393 dumpType](const boost::system::error_code ec,
394 dbus::utility::ManagedObjectType& resp) {
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500395 if (ec)
396 {
397 BMCWEB_LOG_ERROR << "DumpEntry resp_handler got error " << ec;
398 messages::internalError(asyncResp->res);
399 return;
400 }
401
402 nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"];
403 entriesArray = nlohmann::json::array();
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500404 std::string dumpEntryPath =
405 "/xyz/openbmc_project/dump/" +
406 std::string(boost::algorithm::to_lower_copy(dumpType)) +
407 "/entry/";
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500408
409 for (auto& object : resp)
410 {
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500411 if (object.first.str.find(dumpEntryPath) == std::string::npos)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500412 {
413 continue;
414 }
Nan Zhou1d8782e2021-11-29 22:23:18 -0800415 uint64_t timestamp = 0;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500416 uint64_t size = 0;
Asmitha Karunanithi35440d12021-09-07 11:17:57 -0500417 std::string dumpStatus;
418 nlohmann::json thisEntry;
Ed Tanous2dfd18e2020-12-18 00:41:31 +0000419
420 std::string entryID = object.first.filename();
421 if (entryID.empty())
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500422 {
423 continue;
424 }
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500425
426 for (auto& interfaceMap : object.second)
427 {
Asmitha Karunanithi35440d12021-09-07 11:17:57 -0500428 if (interfaceMap.first ==
429 "xyz.openbmc_project.Common.Progress")
430 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800431 for (const auto& propertyMap : interfaceMap.second)
Asmitha Karunanithi35440d12021-09-07 11:17:57 -0500432 {
433 if (propertyMap.first == "Status")
434 {
Ed Tanous55f79e62022-01-25 11:26:16 -0800435 const auto* status = std::get_if<std::string>(
Asmitha Karunanithi35440d12021-09-07 11:17:57 -0500436 &propertyMap.second);
437 if (status == nullptr)
438 {
439 messages::internalError(asyncResp->res);
440 break;
441 }
442 dumpStatus = *status;
443 }
444 }
445 }
446 else if (interfaceMap.first ==
447 "xyz.openbmc_project.Dump.Entry")
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500448 {
449
450 for (auto& propertyMap : interfaceMap.second)
451 {
452 if (propertyMap.first == "Size")
453 {
Ed Tanous55f79e62022-01-25 11:26:16 -0800454 const auto* sizePtr =
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500455 std::get_if<uint64_t>(&propertyMap.second);
456 if (sizePtr == nullptr)
457 {
458 messages::internalError(asyncResp->res);
459 break;
460 }
461 size = *sizePtr;
462 break;
463 }
464 }
465 }
466 else if (interfaceMap.first ==
467 "xyz.openbmc_project.Time.EpochTime")
468 {
469
Ed Tanous9eb808c2022-01-25 10:19:23 -0800470 for (const auto& propertyMap : interfaceMap.second)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500471 {
472 if (propertyMap.first == "Elapsed")
473 {
474 const uint64_t* usecsTimeStamp =
475 std::get_if<uint64_t>(&propertyMap.second);
476 if (usecsTimeStamp == nullptr)
477 {
478 messages::internalError(asyncResp->res);
479 break;
480 }
Nan Zhou1d8782e2021-11-29 22:23:18 -0800481 timestamp = (*usecsTimeStamp / 1000 / 1000);
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500482 break;
483 }
484 }
485 }
486 }
487
George Liu0fda0f12021-11-16 10:06:17 +0800488 if (dumpStatus !=
489 "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" &&
Asmitha Karunanithi35440d12021-09-07 11:17:57 -0500490 !dumpStatus.empty())
491 {
492 // Dump status is not Complete, no need to enumerate
493 continue;
494 }
495
George Liu647b3cd2021-07-05 12:43:56 +0800496 thisEntry["@odata.type"] = "#LogEntry.v1_8_0.LogEntry";
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500497 thisEntry["@odata.id"] = dumpPath + entryID;
498 thisEntry["Id"] = entryID;
499 thisEntry["EntryType"] = "Event";
Nan Zhou1d8782e2021-11-29 22:23:18 -0800500 thisEntry["Created"] =
501 crow::utility::getDateTimeUint(timestamp);
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500502 thisEntry["Name"] = dumpType + " Dump Entry";
503
Asmitha Karunanithid337bb72020-09-21 10:34:02 -0500504 thisEntry["AdditionalDataSizeBytes"] = size;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500505
506 if (dumpType == "BMC")
507 {
Asmitha Karunanithid337bb72020-09-21 10:34:02 -0500508 thisEntry["DiagnosticDataType"] = "Manager";
509 thisEntry["AdditionalDataURI"] =
Abhishek Patelde8d94a2021-05-13 22:57:36 -0500510 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/" +
511 entryID + "/attachment";
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500512 }
513 else if (dumpType == "System")
514 {
Asmitha Karunanithid337bb72020-09-21 10:34:02 -0500515 thisEntry["DiagnosticDataType"] = "OEM";
516 thisEntry["OEMDiagnosticDataType"] = "System";
517 thisEntry["AdditionalDataURI"] =
Abhishek Patelde8d94a2021-05-13 22:57:36 -0500518 "/redfish/v1/Systems/system/LogServices/Dump/Entries/" +
519 entryID + "/attachment";
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500520 }
Asmitha Karunanithi35440d12021-09-07 11:17:57 -0500521 entriesArray.push_back(std::move(thisEntry));
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500522 }
523 asyncResp->res.jsonValue["Members@odata.count"] =
524 entriesArray.size();
525 },
526 "xyz.openbmc_project.Dump.Manager", "/xyz/openbmc_project/dump",
527 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
528}
529
zhanghch058d1b46d2021-04-01 11:18:24 +0800530inline void
Ed Tanous45ca1b82022-03-25 13:07:27 -0700531 getDumpEntryById(crow::App& app, const crow::Request& req,
532 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
zhanghch058d1b46d2021-04-01 11:18:24 +0800533 const std::string& entryID, const std::string& dumpType)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500534{
Ed Tanous45ca1b82022-03-25 13:07:27 -0700535 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
536 {
537 return;
538 }
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500539 std::string dumpPath;
540 if (dumpType == "BMC")
541 {
542 dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/";
543 }
544 else if (dumpType == "System")
545 {
546 dumpPath = "/redfish/v1/Systems/system/LogServices/Dump/Entries/";
547 }
548 else
549 {
550 BMCWEB_LOG_ERROR << "Invalid dump type" << dumpType;
551 messages::internalError(asyncResp->res);
552 return;
553 }
554
555 crow::connections::systemBus->async_method_call(
Ed Tanous711ac7a2021-12-20 09:34:41 -0800556 [asyncResp, entryID, dumpPath,
557 dumpType](const boost::system::error_code ec,
558 dbus::utility::ManagedObjectType& resp) {
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500559 if (ec)
560 {
561 BMCWEB_LOG_ERROR << "DumpEntry resp_handler got error " << ec;
562 messages::internalError(asyncResp->res);
563 return;
564 }
565
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500566 bool foundDumpEntry = false;
567 std::string dumpEntryPath =
568 "/xyz/openbmc_project/dump/" +
569 std::string(boost::algorithm::to_lower_copy(dumpType)) +
570 "/entry/";
571
Ed Tanous9eb808c2022-01-25 10:19:23 -0800572 for (const auto& objectPath : resp)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500573 {
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500574 if (objectPath.first.str != dumpEntryPath + entryID)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500575 {
576 continue;
577 }
578
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500579 foundDumpEntry = true;
Nan Zhou1d8782e2021-11-29 22:23:18 -0800580 uint64_t timestamp = 0;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500581 uint64_t size = 0;
Asmitha Karunanithi35440d12021-09-07 11:17:57 -0500582 std::string dumpStatus;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500583
Ed Tanous9eb808c2022-01-25 10:19:23 -0800584 for (const auto& interfaceMap : objectPath.second)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500585 {
Asmitha Karunanithi35440d12021-09-07 11:17:57 -0500586 if (interfaceMap.first ==
587 "xyz.openbmc_project.Common.Progress")
588 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800589 for (const auto& propertyMap : interfaceMap.second)
Asmitha Karunanithi35440d12021-09-07 11:17:57 -0500590 {
591 if (propertyMap.first == "Status")
592 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800593 const std::string* status =
594 std::get_if<std::string>(
595 &propertyMap.second);
Asmitha Karunanithi35440d12021-09-07 11:17:57 -0500596 if (status == nullptr)
597 {
598 messages::internalError(asyncResp->res);
599 break;
600 }
601 dumpStatus = *status;
602 }
603 }
604 }
605 else if (interfaceMap.first ==
606 "xyz.openbmc_project.Dump.Entry")
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500607 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800608 for (const auto& propertyMap : interfaceMap.second)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500609 {
610 if (propertyMap.first == "Size")
611 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800612 const uint64_t* sizePtr =
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500613 std::get_if<uint64_t>(&propertyMap.second);
614 if (sizePtr == nullptr)
615 {
616 messages::internalError(asyncResp->res);
617 break;
618 }
619 size = *sizePtr;
620 break;
621 }
622 }
623 }
624 else if (interfaceMap.first ==
625 "xyz.openbmc_project.Time.EpochTime")
626 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800627 for (const auto& propertyMap : interfaceMap.second)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500628 {
629 if (propertyMap.first == "Elapsed")
630 {
631 const uint64_t* usecsTimeStamp =
632 std::get_if<uint64_t>(&propertyMap.second);
633 if (usecsTimeStamp == nullptr)
634 {
635 messages::internalError(asyncResp->res);
636 break;
637 }
Nan Zhou1d8782e2021-11-29 22:23:18 -0800638 timestamp = *usecsTimeStamp / 1000 / 1000;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500639 break;
640 }
641 }
642 }
643 }
644
George Liu0fda0f12021-11-16 10:06:17 +0800645 if (dumpStatus !=
646 "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" &&
Asmitha Karunanithi35440d12021-09-07 11:17:57 -0500647 !dumpStatus.empty())
648 {
649 // Dump status is not Complete
650 // return not found until status is changed to Completed
651 messages::resourceNotFound(asyncResp->res,
652 dumpType + " dump", entryID);
653 return;
654 }
655
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500656 asyncResp->res.jsonValue["@odata.type"] =
George Liu647b3cd2021-07-05 12:43:56 +0800657 "#LogEntry.v1_8_0.LogEntry";
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500658 asyncResp->res.jsonValue["@odata.id"] = dumpPath + entryID;
659 asyncResp->res.jsonValue["Id"] = entryID;
660 asyncResp->res.jsonValue["EntryType"] = "Event";
661 asyncResp->res.jsonValue["Created"] =
Nan Zhou1d8782e2021-11-29 22:23:18 -0800662 crow::utility::getDateTimeUint(timestamp);
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500663 asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entry";
664
Asmitha Karunanithid337bb72020-09-21 10:34:02 -0500665 asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500666
667 if (dumpType == "BMC")
668 {
Asmitha Karunanithid337bb72020-09-21 10:34:02 -0500669 asyncResp->res.jsonValue["DiagnosticDataType"] = "Manager";
670 asyncResp->res.jsonValue["AdditionalDataURI"] =
Abhishek Patelde8d94a2021-05-13 22:57:36 -0500671 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/" +
672 entryID + "/attachment";
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500673 }
674 else if (dumpType == "System")
675 {
Asmitha Karunanithid337bb72020-09-21 10:34:02 -0500676 asyncResp->res.jsonValue["DiagnosticDataType"] = "OEM";
677 asyncResp->res.jsonValue["OEMDiagnosticDataType"] =
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500678 "System";
Asmitha Karunanithid337bb72020-09-21 10:34:02 -0500679 asyncResp->res.jsonValue["AdditionalDataURI"] =
Abhishek Patelde8d94a2021-05-13 22:57:36 -0500680 "/redfish/v1/Systems/system/LogServices/Dump/Entries/" +
681 entryID + "/attachment";
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500682 }
683 }
Ed Tanouse05aec52022-01-25 10:28:56 -0800684 if (!foundDumpEntry)
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500685 {
686 BMCWEB_LOG_ERROR << "Can't find Dump Entry";
687 messages::internalError(asyncResp->res);
688 return;
689 }
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500690 },
691 "xyz.openbmc_project.Dump.Manager", "/xyz/openbmc_project/dump",
692 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
693}
694
zhanghch058d1b46d2021-04-01 11:18:24 +0800695inline void deleteDumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Stanley Chu98782562020-11-04 16:10:24 +0800696 const std::string& entryID,
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500697 const std::string& dumpType)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500698{
George Liu3de8d8b2021-03-22 17:49:39 +0800699 auto respHandler = [asyncResp,
700 entryID](const boost::system::error_code ec) {
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500701 BMCWEB_LOG_DEBUG << "Dump Entry doDelete callback: Done";
702 if (ec)
703 {
George Liu3de8d8b2021-03-22 17:49:39 +0800704 if (ec.value() == EBADR)
705 {
706 messages::resourceNotFound(asyncResp->res, "LogEntry", entryID);
707 return;
708 }
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500709 BMCWEB_LOG_ERROR << "Dump (DBus) doDelete respHandler got error "
710 << ec;
711 messages::internalError(asyncResp->res);
712 return;
713 }
714 };
715 crow::connections::systemBus->async_method_call(
716 respHandler, "xyz.openbmc_project.Dump.Manager",
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500717 "/xyz/openbmc_project/dump/" +
718 std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/" +
719 entryID,
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500720 "xyz.openbmc_project.Object.Delete", "Delete");
721}
722
zhanghch058d1b46d2021-04-01 11:18:24 +0800723inline void
Ed Tanous98be3e32021-09-16 15:05:36 -0700724 createDumpTaskCallback(task::Payload&& payload,
zhanghch058d1b46d2021-04-01 11:18:24 +0800725 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
726 const uint32_t& dumpId, const std::string& dumpPath,
727 const std::string& dumpType)
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500728{
729 std::shared_ptr<task::TaskData> task = task::TaskData::createTask(
Asmitha Karunanithi6145ed62020-09-17 23:40:03 -0500730 [dumpId, dumpPath, dumpType](
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500731 boost::system::error_code err, sdbusplus::message::message& m,
732 const std::shared_ptr<task::TaskData>& taskData) {
Ed Tanouscb13a392020-07-25 19:02:03 +0000733 if (err)
734 {
Asmitha Karunanithi6145ed62020-09-17 23:40:03 -0500735 BMCWEB_LOG_ERROR << "Error in creating a dump";
736 taskData->state = "Cancelled";
737 return task::completed;
Ed Tanouscb13a392020-07-25 19:02:03 +0000738 }
Ed Tanousb9d36b42022-02-26 21:42:46 -0800739
740 dbus::utility::DBusInteracesMap interfacesList;
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500741
742 sdbusplus::message::object_path objPath;
743
744 m.read(objPath, interfacesList);
745
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500746 if (objPath.str ==
747 "/xyz/openbmc_project/dump/" +
748 std::string(boost::algorithm::to_lower_copy(dumpType)) +
749 "/entry/" + std::to_string(dumpId))
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500750 {
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500751 nlohmann::json retMessage = messages::success();
752 taskData->messages.emplace_back(retMessage);
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500753
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500754 std::string headerLoc =
755 "Location: " + dumpPath + std::to_string(dumpId);
756 taskData->payload->httpHeaders.emplace_back(
757 std::move(headerLoc));
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500758
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500759 taskData->state = "Completed";
760 return task::completed;
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500761 }
Asmitha Karunanithi6145ed62020-09-17 23:40:03 -0500762 return task::completed;
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500763 },
Jason M. Bills4978b632022-02-22 14:17:43 -0800764 "type='signal',interface='org.freedesktop.DBus.ObjectManager',"
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500765 "member='InterfacesAdded', "
766 "path='/xyz/openbmc_project/dump'");
767
768 task->startTimer(std::chrono::minutes(3));
769 task->populateResp(asyncResp->res);
Ed Tanous98be3e32021-09-16 15:05:36 -0700770 task->payload.emplace(std::move(payload));
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500771}
772
zhanghch058d1b46d2021-04-01 11:18:24 +0800773inline void createDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
774 const crow::Request& req, const std::string& dumpType)
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500775{
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500776 std::string dumpPath;
777 if (dumpType == "BMC")
778 {
779 dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/";
780 }
781 else if (dumpType == "System")
782 {
783 dumpPath = "/redfish/v1/Systems/system/LogServices/Dump/Entries/";
784 }
785 else
786 {
787 BMCWEB_LOG_ERROR << "Invalid dump type: " << dumpType;
788 messages::internalError(asyncResp->res);
789 return;
790 }
791
792 std::optional<std::string> diagnosticDataType;
793 std::optional<std::string> oemDiagnosticDataType;
794
Willy Tu15ed6782021-12-14 11:03:16 -0800795 if (!redfish::json_util::readJsonAction(
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500796 req, asyncResp->res, "DiagnosticDataType", diagnosticDataType,
797 "OEMDiagnosticDataType", oemDiagnosticDataType))
798 {
799 return;
800 }
801
802 if (dumpType == "System")
803 {
804 if (!oemDiagnosticDataType || !diagnosticDataType)
805 {
Jason M. Bills4978b632022-02-22 14:17:43 -0800806 BMCWEB_LOG_ERROR
807 << "CreateDump action parameter 'DiagnosticDataType'/'OEMDiagnosticDataType' value not found!";
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500808 messages::actionParameterMissing(
809 asyncResp->res, "CollectDiagnosticData",
810 "DiagnosticDataType & OEMDiagnosticDataType");
811 return;
812 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700813 if ((*oemDiagnosticDataType != "System") ||
814 (*diagnosticDataType != "OEM"))
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500815 {
816 BMCWEB_LOG_ERROR << "Wrong parameter values passed";
Ed Tanousace85d62021-10-26 12:45:59 -0700817 messages::internalError(asyncResp->res);
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500818 return;
819 }
820 }
821 else if (dumpType == "BMC")
822 {
823 if (!diagnosticDataType)
824 {
George Liu0fda0f12021-11-16 10:06:17 +0800825 BMCWEB_LOG_ERROR
826 << "CreateDump action parameter 'DiagnosticDataType' not found!";
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500827 messages::actionParameterMissing(
828 asyncResp->res, "CollectDiagnosticData", "DiagnosticDataType");
829 return;
830 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700831 if (*diagnosticDataType != "Manager")
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500832 {
833 BMCWEB_LOG_ERROR
834 << "Wrong parameter value passed for 'DiagnosticDataType'";
Ed Tanousace85d62021-10-26 12:45:59 -0700835 messages::internalError(asyncResp->res);
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500836 return;
837 }
838 }
839
840 crow::connections::systemBus->async_method_call(
Ed Tanous98be3e32021-09-16 15:05:36 -0700841 [asyncResp, payload(task::Payload(req)), dumpPath,
842 dumpType](const boost::system::error_code ec,
843 const uint32_t& dumpId) mutable {
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500844 if (ec)
845 {
846 BMCWEB_LOG_ERROR << "CreateDump resp_handler got error " << ec;
847 messages::internalError(asyncResp->res);
848 return;
849 }
850 BMCWEB_LOG_DEBUG << "Dump Created. Id: " << dumpId;
851
Ed Tanous98be3e32021-09-16 15:05:36 -0700852 createDumpTaskCallback(std::move(payload), asyncResp, dumpId,
853 dumpPath, dumpType);
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500854 },
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500855 "xyz.openbmc_project.Dump.Manager",
856 "/xyz/openbmc_project/dump/" +
857 std::string(boost::algorithm::to_lower_copy(dumpType)),
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500858 "xyz.openbmc_project.Dump.Create", "CreateDump");
859}
860
zhanghch058d1b46d2021-04-01 11:18:24 +0800861inline void clearDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
862 const std::string& dumpType)
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500863{
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500864 std::string dumpTypeLowerCopy =
865 std::string(boost::algorithm::to_lower_copy(dumpType));
zhanghch058d1b46d2021-04-01 11:18:24 +0800866
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500867 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -0800868 [asyncResp, dumpType](
869 const boost::system::error_code ec,
870 const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) {
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500871 if (ec)
872 {
873 BMCWEB_LOG_ERROR << "resp_handler got error " << ec;
874 messages::internalError(asyncResp->res);
875 return;
876 }
877
878 for (const std::string& path : subTreePaths)
879 {
Ed Tanous2dfd18e2020-12-18 00:41:31 +0000880 sdbusplus::message::object_path objPath(path);
881 std::string logID = objPath.filename();
882 if (logID.empty())
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500883 {
Ed Tanous2dfd18e2020-12-18 00:41:31 +0000884 continue;
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500885 }
Ed Tanous2dfd18e2020-12-18 00:41:31 +0000886 deleteDumpEntry(asyncResp, logID, dumpType);
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500887 }
888 },
889 "xyz.openbmc_project.ObjectMapper",
890 "/xyz/openbmc_project/object_mapper",
891 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500892 "/xyz/openbmc_project/dump/" + dumpTypeLowerCopy, 0,
893 std::array<std::string, 1>{"xyz.openbmc_project.Dump.Entry." +
894 dumpType});
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500895}
896
Ed Tanousb9d36b42022-02-26 21:42:46 -0800897inline static void
898 parseCrashdumpParameters(const dbus::utility::DBusPropertiesMap& params,
899 std::string& filename, std::string& timestamp,
900 std::string& logfile)
Johnathan Mantey043a0532020-03-10 17:15:28 -0700901{
902 for (auto property : params)
903 {
904 if (property.first == "Timestamp")
905 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500906 const std::string* value =
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500907 std::get_if<std::string>(&property.second);
Johnathan Mantey043a0532020-03-10 17:15:28 -0700908 if (value != nullptr)
909 {
910 timestamp = *value;
911 }
912 }
913 else if (property.first == "Filename")
914 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500915 const std::string* value =
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500916 std::get_if<std::string>(&property.second);
Johnathan Mantey043a0532020-03-10 17:15:28 -0700917 if (value != nullptr)
918 {
919 filename = *value;
920 }
921 }
922 else if (property.first == "Log")
923 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500924 const std::string* value =
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500925 std::get_if<std::string>(&property.second);
Johnathan Mantey043a0532020-03-10 17:15:28 -0700926 if (value != nullptr)
927 {
928 logfile = *value;
929 }
930 }
931 }
932}
933
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500934constexpr char const* postCodeIface = "xyz.openbmc_project.State.Boot.PostCode";
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700935inline void requestRoutesSystemLogServiceCollection(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -0700936{
Jason M. Billsc4bf6372018-11-05 13:48:27 -0800937 /**
938 * Functions triggers appropriate requests on DBus
939 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700940 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/")
Ed Tanoused398212021-06-09 17:05:54 -0700941 .privileges(redfish::privileges::getLogServiceCollection)
Ed Tanous45ca1b82022-03-25 13:07:27 -0700942 .methods(boost::beast::http::verb::get)([&app](const crow::Request& req,
943 const std::shared_ptr<
944 bmcweb::AsyncResp>&
945 asyncResp) {
946 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700947 {
Ed Tanous45ca1b82022-03-25 13:07:27 -0700948 return;
949 }
950 // Collections don't include the static data added by SubRoute
951 // because it has a duplicate entry for members
952 asyncResp->res.jsonValue["@odata.type"] =
953 "#LogServiceCollection.LogServiceCollection";
954 asyncResp->res.jsonValue["@odata.id"] =
955 "/redfish/v1/Systems/system/LogServices";
956 asyncResp->res.jsonValue["Name"] = "System Log Services Collection";
957 asyncResp->res.jsonValue["Description"] =
958 "Collection of LogServices for this Computer System";
959 nlohmann::json& logServiceArray =
960 asyncResp->res.jsonValue["Members"];
961 logServiceArray = nlohmann::json::array();
962 logServiceArray.push_back(
963 {{"@odata.id",
964 "/redfish/v1/Systems/system/LogServices/EventLog"}});
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500965#ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG
Ed Tanous45ca1b82022-03-25 13:07:27 -0700966 logServiceArray.push_back(
967 {{"@odata.id", "/redfish/v1/Systems/system/LogServices/Dump"}});
raviteja-bc9bb6862020-02-03 11:53:32 -0600968#endif
969
Jason M. Billsd53dd412019-02-12 17:16:22 -0800970#ifdef BMCWEB_ENABLE_REDFISH_CPU_LOG
Ed Tanous45ca1b82022-03-25 13:07:27 -0700971 logServiceArray.push_back(
972 {{"@odata.id",
973 "/redfish/v1/Systems/system/LogServices/Crashdump"}});
Jason M. Billsd53dd412019-02-12 17:16:22 -0800974#endif
Spencer Kub7028eb2021-10-26 15:27:35 +0800975
976#ifdef BMCWEB_ENABLE_REDFISH_HOST_LOGGER
Ed Tanous45ca1b82022-03-25 13:07:27 -0700977 logServiceArray.push_back(
978 {{"@odata.id",
979 "/redfish/v1/Systems/system/LogServices/HostLogger"}});
Spencer Kub7028eb2021-10-26 15:27:35 +0800980#endif
Ed Tanous45ca1b82022-03-25 13:07:27 -0700981 asyncResp->res.jsonValue["Members@odata.count"] =
982 logServiceArray.size();
ZhikuiRena3316fc2020-01-29 14:58:08 -0800983
Ed Tanous45ca1b82022-03-25 13:07:27 -0700984 crow::connections::systemBus->async_method_call(
985 [asyncResp](const boost::system::error_code ec,
986 const dbus::utility::MapperGetSubTreePathsResponse&
987 subtreePath) {
988 if (ec)
989 {
990 BMCWEB_LOG_ERROR << ec;
991 return;
992 }
993
994 for (const auto& pathStr : subtreePath)
995 {
996 if (pathStr.find("PostCode") != std::string::npos)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700997 {
Ed Tanous45ca1b82022-03-25 13:07:27 -0700998 nlohmann::json& logServiceArrayLocal =
999 asyncResp->res.jsonValue["Members"];
1000 logServiceArrayLocal.push_back(
1001 {{"@odata.id",
1002 "/redfish/v1/Systems/system/LogServices/PostCodes"}});
1003 asyncResp->res.jsonValue["Members@odata.count"] =
1004 logServiceArrayLocal.size();
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001005 return;
1006 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07001007 }
1008 },
1009 "xyz.openbmc_project.ObjectMapper",
1010 "/xyz/openbmc_project/object_mapper",
1011 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/", 0,
1012 std::array<const char*, 1>{postCodeIface});
1013 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001014}
1015
1016inline void requestRoutesEventLogService(App& app)
1017{
1018 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/EventLog/")
Ed Tanoused398212021-06-09 17:05:54 -07001019 .privileges(redfish::privileges::getLogService)
Ed Tanous45ca1b82022-03-25 13:07:27 -07001020 .methods(boost::beast::http::verb::get)([&app](const crow::Request& req,
1021 const std::shared_ptr<
1022 bmcweb::AsyncResp>&
1023 asyncResp) {
1024 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
1025 {
1026 return;
1027 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001028 asyncResp->res.jsonValue["@odata.id"] =
1029 "/redfish/v1/Systems/system/LogServices/EventLog";
1030 asyncResp->res.jsonValue["@odata.type"] =
1031 "#LogService.v1_1_0.LogService";
1032 asyncResp->res.jsonValue["Name"] = "Event Log Service";
1033 asyncResp->res.jsonValue["Description"] =
1034 "System Event Log Service";
1035 asyncResp->res.jsonValue["Id"] = "EventLog";
1036 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
Tejas Patil7c8c4052021-06-04 17:43:14 +05301037
1038 std::pair<std::string, std::string> redfishDateTimeOffset =
1039 crow::utility::getDateTimeOffsetNow();
1040
1041 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
1042 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
1043 redfishDateTimeOffset.second;
1044
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001045 asyncResp->res.jsonValue["Entries"] = {
1046 {"@odata.id",
1047 "/redfish/v1/Systems/system/LogServices/EventLog/Entries"}};
1048 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = {
1049
George Liu0fda0f12021-11-16 10:06:17 +08001050 {"target",
1051 "/redfish/v1/Systems/system/LogServices/EventLog/Actions/LogService.ClearLog"}};
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001052 });
1053}
1054
1055inline void requestRoutesJournalEventLogClear(App& app)
1056{
Jason M. Bills4978b632022-02-22 14:17:43 -08001057 BMCWEB_ROUTE(
1058 app,
1059 "/redfish/v1/Systems/system/LogServices/EventLog/Actions/LogService.ClearLog/")
Ed Tanous432a8902021-06-14 15:28:56 -07001060 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001061 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001062 [&app](const crow::Request& req,
1063 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1064 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
1065 {
1066 return;
1067 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001068 // Clear the EventLog by deleting the log files
1069 std::vector<std::filesystem::path> redfishLogFiles;
1070 if (getRedfishLogFiles(redfishLogFiles))
ZhikuiRena3316fc2020-01-29 14:58:08 -08001071 {
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001072 for (const std::filesystem::path& file : redfishLogFiles)
ZhikuiRena3316fc2020-01-29 14:58:08 -08001073 {
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001074 std::error_code ec;
1075 std::filesystem::remove(file, ec);
ZhikuiRena3316fc2020-01-29 14:58:08 -08001076 }
1077 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001078
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001079 // Reload rsyslog so it knows to start new log files
1080 crow::connections::systemBus->async_method_call(
1081 [asyncResp](const boost::system::error_code ec) {
1082 if (ec)
1083 {
1084 BMCWEB_LOG_ERROR << "Failed to reload rsyslog: "
1085 << ec;
1086 messages::internalError(asyncResp->res);
1087 return;
1088 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001089
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001090 messages::success(asyncResp->res);
1091 },
1092 "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
1093 "org.freedesktop.systemd1.Manager", "ReloadUnit",
1094 "rsyslog.service", "replace");
1095 });
1096}
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001097
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001098static int fillEventLogEntryJson(const std::string& logEntryID,
Ed Tanousb5a76932020-09-29 16:16:58 -07001099 const std::string& logEntry,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001100 nlohmann::json& logEntryJson)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001101{
Jason M. Bills95820182019-04-22 16:25:34 -07001102 // The redfish log format is "<Timestamp> <MessageId>,<MessageArgs>"
Jason M. Billscd225da2019-05-08 15:31:57 -07001103 // First get the Timestamp
Ed Tanousf23b7292020-10-15 09:41:17 -07001104 size_t space = logEntry.find_first_of(' ');
Jason M. Billscd225da2019-05-08 15:31:57 -07001105 if (space == std::string::npos)
Jason M. Bills95820182019-04-22 16:25:34 -07001106 {
1107 return 1;
1108 }
Jason M. Billscd225da2019-05-08 15:31:57 -07001109 std::string timestamp = logEntry.substr(0, space);
1110 // Then get the log contents
Ed Tanousf23b7292020-10-15 09:41:17 -07001111 size_t entryStart = logEntry.find_first_not_of(' ', space);
Jason M. Billscd225da2019-05-08 15:31:57 -07001112 if (entryStart == std::string::npos)
1113 {
1114 return 1;
1115 }
1116 std::string_view entry(logEntry);
1117 entry.remove_prefix(entryStart);
1118 // Use split to separate the entry into its fields
1119 std::vector<std::string> logEntryFields;
1120 boost::split(logEntryFields, entry, boost::is_any_of(","),
1121 boost::token_compress_on);
1122 // We need at least a MessageId to be valid
Ed Tanous26f69762022-01-25 09:49:11 -08001123 if (logEntryFields.empty())
Jason M. Billscd225da2019-05-08 15:31:57 -07001124 {
1125 return 1;
1126 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001127 std::string& messageID = logEntryFields[0];
Jason M. Bills95820182019-04-22 16:25:34 -07001128
Jason M. Bills4851d452019-03-28 11:27:48 -07001129 // Get the Message from the MessageRegistry
Ed Tanousfffb8c12022-02-07 23:53:03 -08001130 const registries::Message* message = registries::getMessage(messageID);
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001131
Sui Chen54417b02022-03-24 14:59:52 -07001132 if (message == nullptr)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001133 {
Sui Chen54417b02022-03-24 14:59:52 -07001134 BMCWEB_LOG_WARNING << "Log entry not found in registry: " << logEntry;
1135 return 0;
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001136 }
1137
Sui Chen54417b02022-03-24 14:59:52 -07001138 std::string msg = message->message;
1139
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001140 // Get the MessageArgs from the log if there are any
Ed Tanous26702d02021-11-03 15:02:33 -07001141 std::span<std::string> messageArgs;
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001142 if (logEntryFields.size() > 1)
Jason M. Bills4851d452019-03-28 11:27:48 -07001143 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001144 std::string& messageArgsStart = logEntryFields[1];
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001145 // If the first string is empty, assume there are no MessageArgs
1146 std::size_t messageArgsSize = 0;
1147 if (!messageArgsStart.empty())
Jason M. Bills4851d452019-03-28 11:27:48 -07001148 {
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001149 messageArgsSize = logEntryFields.size() - 1;
1150 }
1151
Ed Tanous23a21a12020-07-25 04:45:05 +00001152 messageArgs = {&messageArgsStart, messageArgsSize};
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001153
1154 // Fill the MessageArgs into the Message
1155 int i = 0;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001156 for (const std::string& messageArg : messageArgs)
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001157 {
1158 std::string argStr = "%" + std::to_string(++i);
1159 size_t argPos = msg.find(argStr);
1160 if (argPos != std::string::npos)
1161 {
1162 msg.replace(argPos, argStr.length(), messageArg);
1163 }
Jason M. Bills4851d452019-03-28 11:27:48 -07001164 }
1165 }
1166
Jason M. Bills95820182019-04-22 16:25:34 -07001167 // Get the Created time from the timestamp. The log timestamp is in RFC3339
1168 // format which matches the Redfish format except for the fractional seconds
1169 // between the '.' and the '+', so just remove them.
Ed Tanousf23b7292020-10-15 09:41:17 -07001170 std::size_t dot = timestamp.find_first_of('.');
1171 std::size_t plus = timestamp.find_first_of('+');
Jason M. Bills95820182019-04-22 16:25:34 -07001172 if (dot != std::string::npos && plus != std::string::npos)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001173 {
Jason M. Bills95820182019-04-22 16:25:34 -07001174 timestamp.erase(dot, plus - dot);
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001175 }
1176
1177 // Fill in the log entry with the gathered data
Jason M. Bills95820182019-04-22 16:25:34 -07001178 logEntryJson = {
George Liu647b3cd2021-07-05 12:43:56 +08001179 {"@odata.type", "#LogEntry.v1_8_0.LogEntry"},
Ed Tanous029573d2019-02-01 10:57:49 -08001180 {"@odata.id",
Jason M. Bills897967d2019-07-29 17:05:30 -07001181 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
Jason M. Bills95820182019-04-22 16:25:34 -07001182 logEntryID},
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001183 {"Name", "System Event Log Entry"},
Jason M. Bills95820182019-04-22 16:25:34 -07001184 {"Id", logEntryID},
1185 {"Message", std::move(msg)},
1186 {"MessageId", std::move(messageID)},
Ed Tanousf23b7292020-10-15 09:41:17 -07001187 {"MessageArgs", messageArgs},
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001188 {"EntryType", "Event"},
Sui Chen54417b02022-03-24 14:59:52 -07001189 {"Severity", message->messageSeverity},
Jason M. Bills95820182019-04-22 16:25:34 -07001190 {"Created", std::move(timestamp)}};
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001191 return 0;
1192}
1193
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001194inline void requestRoutesJournalEventLogEntryCollection(App& app)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001195{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001196 BMCWEB_ROUTE(app,
1197 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/")
Gunnar Mills8b6a35f2021-07-30 14:52:53 -05001198 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous45ca1b82022-03-25 13:07:27 -07001199 .methods(boost::beast::http::verb::get)([&app](const crow::Request& req,
1200 const std::shared_ptr<
1201 bmcweb::AsyncResp>&
1202 asyncResp) {
1203 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
1204 {
1205 return;
1206 }
Jason M. Bills4978b632022-02-22 14:17:43 -08001207 uint64_t skip = 0;
1208 uint64_t top = maxEntriesPerPage; // Show max entries by default
1209 if (!getSkipParam(asyncResp, req, skip))
1210 {
1211 return;
1212 }
1213 if (!getTopParam(asyncResp, req, top))
1214 {
1215 return;
1216 }
1217 // Collections don't include the static data added by SubRoute
1218 // because it has a duplicate entry for members
1219 asyncResp->res.jsonValue["@odata.type"] =
1220 "#LogEntryCollection.LogEntryCollection";
1221 asyncResp->res.jsonValue["@odata.id"] =
1222 "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
1223 asyncResp->res.jsonValue["Name"] = "System Event Log Entries";
1224 asyncResp->res.jsonValue["Description"] =
1225 "Collection of System Event Log Entries";
Jason M. Bills897967d2019-07-29 17:05:30 -07001226
Jason M. Bills4978b632022-02-22 14:17:43 -08001227 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
1228 logEntryArray = nlohmann::json::array();
1229 // Go through the log files and create a unique ID for each
1230 // entry
1231 std::vector<std::filesystem::path> redfishLogFiles;
1232 getRedfishLogFiles(redfishLogFiles);
1233 uint64_t entryCount = 0;
1234 std::string logEntry;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001235
Jason M. Bills4978b632022-02-22 14:17:43 -08001236 // Oldest logs are in the last file, so start there and loop
1237 // backwards
1238 for (auto it = redfishLogFiles.rbegin();
1239 it < redfishLogFiles.rend(); it++)
1240 {
1241 std::ifstream logStream(*it);
1242 if (!logStream.is_open())
Andrew Geisslercb92c032018-08-17 07:56:14 -07001243 {
Jason M. Bills4978b632022-02-22 14:17:43 -08001244 continue;
1245 }
1246
1247 // Reset the unique ID on the first entry
1248 bool firstEntry = true;
1249 while (std::getline(logStream, logEntry))
1250 {
1251 entryCount++;
1252 // Handle paging using skip (number of entries to skip
1253 // from the start) and top (number of entries to
1254 // display)
1255 if (entryCount <= skip || entryCount > skip + top)
Adriana Kobylakf86bb902021-01-11 11:11:05 -06001256 {
1257 continue;
1258 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001259
Jason M. Bills4978b632022-02-22 14:17:43 -08001260 std::string idStr;
1261 if (!getUniqueEntryID(logEntry, idStr, firstEntry))
Adriana Kobylakf86bb902021-01-11 11:11:05 -06001262 {
Jason M. Bills4978b632022-02-22 14:17:43 -08001263 continue;
1264 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001265
Jason M. Bills4978b632022-02-22 14:17:43 -08001266 if (firstEntry)
1267 {
1268 firstEntry = false;
1269 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001270
Jason M. Bills4978b632022-02-22 14:17:43 -08001271 logEntryArray.push_back({});
1272 nlohmann::json& bmcLogEntry = logEntryArray.back();
1273 if (fillEventLogEntryJson(idStr, logEntry, bmcLogEntry) !=
1274 0)
1275 {
1276 messages::internalError(asyncResp->res);
1277 return;
Adriana Kobylakf86bb902021-01-11 11:11:05 -06001278 }
Andrew Geisslercb92c032018-08-17 07:56:14 -07001279 }
Jason M. Bills4978b632022-02-22 14:17:43 -08001280 }
1281 asyncResp->res.jsonValue["Members@odata.count"] = entryCount;
1282 if (skip + top < entryCount)
1283 {
1284 asyncResp->res.jsonValue["Members@odata.nextLink"] =
1285 "/redfish/v1/Systems/system/LogServices/EventLog/Entries?$skip=" +
1286 std::to_string(skip + top);
1287 }
1288 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001289}
Chicago Duan336e96c2019-07-15 14:22:08 +08001290
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001291inline void requestRoutesJournalEventLogEntry(App& app)
1292{
1293 BMCWEB_ROUTE(
1294 app, "/redfish/v1/Systems/system/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001295 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001296 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001297 [&app](const crow::Request& req,
1298 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1299 const std::string& param) {
1300 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
1301 {
1302 return;
1303 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001304 const std::string& targetID = param;
Xiaochao Ma75710de2021-01-21 17:56:02 +08001305
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001306 // Go through the log files and check the unique ID for each
1307 // entry to find the target entry
1308 std::vector<std::filesystem::path> redfishLogFiles;
1309 getRedfishLogFiles(redfishLogFiles);
1310 std::string logEntry;
Xiaochao Ma75710de2021-01-21 17:56:02 +08001311
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001312 // Oldest logs are in the last file, so start there and loop
1313 // backwards
1314 for (auto it = redfishLogFiles.rbegin();
1315 it < redfishLogFiles.rend(); it++)
1316 {
1317 std::ifstream logStream(*it);
1318 if (!logStream.is_open())
1319 {
1320 continue;
1321 }
Xiaochao Ma75710de2021-01-21 17:56:02 +08001322
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001323 // Reset the unique ID on the first entry
1324 bool firstEntry = true;
1325 while (std::getline(logStream, logEntry))
1326 {
1327 std::string idStr;
1328 if (!getUniqueEntryID(logEntry, idStr, firstEntry))
1329 {
1330 continue;
1331 }
Xiaochao Ma75710de2021-01-21 17:56:02 +08001332
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001333 if (firstEntry)
1334 {
1335 firstEntry = false;
1336 }
Xiaochao Ma75710de2021-01-21 17:56:02 +08001337
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001338 if (idStr == targetID)
1339 {
1340 if (fillEventLogEntryJson(
1341 idStr, logEntry,
1342 asyncResp->res.jsonValue) != 0)
1343 {
1344 messages::internalError(asyncResp->res);
1345 return;
1346 }
1347 return;
1348 }
1349 }
1350 }
1351 // Requested ID was not found
Ed Tanousace85d62021-10-26 12:45:59 -07001352 messages::resourceMissingAtURI(
1353 asyncResp->res, crow::utility::urlFromPieces(targetID));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001354 });
1355}
1356
1357inline void requestRoutesDBusEventLogEntryCollection(App& app)
1358{
1359 BMCWEB_ROUTE(app,
1360 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07001361 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous45ca1b82022-03-25 13:07:27 -07001362 .methods(boost::beast::http::verb::get)([&app](const crow::Request& req,
1363 const std::shared_ptr<
1364 bmcweb::AsyncResp>&
1365 asyncResp) {
1366 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
1367 {
1368 return;
1369 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001370 // Collections don't include the static data added by SubRoute
1371 // because it has a duplicate entry for members
1372 asyncResp->res.jsonValue["@odata.type"] =
1373 "#LogEntryCollection.LogEntryCollection";
1374 asyncResp->res.jsonValue["@odata.id"] =
1375 "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
1376 asyncResp->res.jsonValue["Name"] = "System Event Log Entries";
1377 asyncResp->res.jsonValue["Description"] =
1378 "Collection of System Event Log Entries";
1379
1380 // DBus implementation of EventLog/Entries
1381 // Make call to Logging Service to find all log entry objects
Xiaochao Ma75710de2021-01-21 17:56:02 +08001382 crow::connections::systemBus->async_method_call(
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001383 [asyncResp](const boost::system::error_code ec,
Ed Tanous914e2d52022-01-07 11:38:34 -08001384 const dbus::utility::ManagedObjectType& resp) {
Xiaochao Ma75710de2021-01-21 17:56:02 +08001385 if (ec)
1386 {
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001387 // TODO Handle for specific error code
1388 BMCWEB_LOG_ERROR
1389 << "getLogEntriesIfaceData resp_handler got error "
1390 << ec;
Xiaochao Ma75710de2021-01-21 17:56:02 +08001391 messages::internalError(asyncResp->res);
1392 return;
1393 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001394 nlohmann::json& entriesArray =
1395 asyncResp->res.jsonValue["Members"];
1396 entriesArray = nlohmann::json::array();
Ed Tanous9eb808c2022-01-25 10:19:23 -08001397 for (const auto& objectPath : resp)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001398 {
Ed Tanous914e2d52022-01-07 11:38:34 -08001399 const uint32_t* id = nullptr;
Ed Tanousc419c752022-01-26 12:19:54 -08001400 const uint64_t* timestamp = nullptr;
1401 const uint64_t* updateTimestamp = nullptr;
Ed Tanous914e2d52022-01-07 11:38:34 -08001402 const std::string* severity = nullptr;
1403 const std::string* message = nullptr;
1404 const std::string* filePath = nullptr;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001405 bool resolved = false;
Ed Tanous9eb808c2022-01-25 10:19:23 -08001406 for (const auto& interfaceMap : objectPath.second)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001407 {
1408 if (interfaceMap.first ==
1409 "xyz.openbmc_project.Logging.Entry")
1410 {
Ed Tanous9eb808c2022-01-25 10:19:23 -08001411 for (const auto& propertyMap :
1412 interfaceMap.second)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001413 {
1414 if (propertyMap.first == "Id")
1415 {
1416 id = std::get_if<uint32_t>(
1417 &propertyMap.second);
1418 }
1419 else if (propertyMap.first == "Timestamp")
1420 {
Ed Tanousc419c752022-01-26 12:19:54 -08001421 timestamp = std::get_if<uint64_t>(
1422 &propertyMap.second);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001423 }
1424 else if (propertyMap.first ==
1425 "UpdateTimestamp")
1426 {
Ed Tanousc419c752022-01-26 12:19:54 -08001427 updateTimestamp = std::get_if<uint64_t>(
1428 &propertyMap.second);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001429 }
1430 else if (propertyMap.first == "Severity")
1431 {
1432 severity = std::get_if<std::string>(
1433 &propertyMap.second);
1434 }
1435 else if (propertyMap.first == "Message")
1436 {
1437 message = std::get_if<std::string>(
1438 &propertyMap.second);
1439 }
1440 else if (propertyMap.first == "Resolved")
1441 {
Ed Tanous914e2d52022-01-07 11:38:34 -08001442 const bool* resolveptr =
1443 std::get_if<bool>(
1444 &propertyMap.second);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001445 if (resolveptr == nullptr)
1446 {
1447 messages::internalError(
1448 asyncResp->res);
1449 return;
1450 }
1451 resolved = *resolveptr;
1452 }
1453 }
1454 if (id == nullptr || message == nullptr ||
1455 severity == nullptr)
1456 {
1457 messages::internalError(asyncResp->res);
1458 return;
1459 }
1460 }
1461 else if (interfaceMap.first ==
1462 "xyz.openbmc_project.Common.FilePath")
1463 {
Ed Tanous9eb808c2022-01-25 10:19:23 -08001464 for (const auto& propertyMap :
1465 interfaceMap.second)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001466 {
1467 if (propertyMap.first == "Path")
1468 {
1469 filePath = std::get_if<std::string>(
1470 &propertyMap.second);
1471 }
1472 }
1473 }
1474 }
1475 // Object path without the
1476 // xyz.openbmc_project.Logging.Entry interface, ignore
1477 // and continue.
1478 if (id == nullptr || message == nullptr ||
Ed Tanousc419c752022-01-26 12:19:54 -08001479 severity == nullptr || timestamp == nullptr ||
1480 updateTimestamp == nullptr)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001481 {
1482 continue;
1483 }
1484 entriesArray.push_back({});
1485 nlohmann::json& thisEntry = entriesArray.back();
1486 thisEntry["@odata.type"] = "#LogEntry.v1_8_0.LogEntry";
1487 thisEntry["@odata.id"] =
George Liu0fda0f12021-11-16 10:06:17 +08001488 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001489 std::to_string(*id);
1490 thisEntry["Name"] = "System Event Log Entry";
1491 thisEntry["Id"] = std::to_string(*id);
1492 thisEntry["Message"] = *message;
1493 thisEntry["Resolved"] = resolved;
1494 thisEntry["EntryType"] = "Event";
1495 thisEntry["Severity"] =
1496 translateSeverityDbusToRedfish(*severity);
1497 thisEntry["Created"] =
Ed Tanousc419c752022-01-26 12:19:54 -08001498 crow::utility::getDateTimeUintMs(*timestamp);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001499 thisEntry["Modified"] =
Ed Tanousc419c752022-01-26 12:19:54 -08001500 crow::utility::getDateTimeUintMs(*updateTimestamp);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001501 if (filePath != nullptr)
1502 {
1503 thisEntry["AdditionalDataURI"] =
George Liu0fda0f12021-11-16 10:06:17 +08001504 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001505 std::to_string(*id) + "/attachment";
1506 }
1507 }
1508 std::sort(entriesArray.begin(), entriesArray.end(),
1509 [](const nlohmann::json& left,
1510 const nlohmann::json& right) {
1511 return (left["Id"] <= right["Id"]);
1512 });
1513 asyncResp->res.jsonValue["Members@odata.count"] =
1514 entriesArray.size();
Xiaochao Ma75710de2021-01-21 17:56:02 +08001515 },
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001516 "xyz.openbmc_project.Logging", "/xyz/openbmc_project/logging",
1517 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
1518 });
1519}
Xiaochao Ma75710de2021-01-21 17:56:02 +08001520
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001521inline void requestRoutesDBusEventLogEntry(App& app)
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001522{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001523 BMCWEB_ROUTE(
1524 app, "/redfish/v1/Systems/system/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001525 .privileges(redfish::privileges::getLogEntry)
Ed Tanous45ca1b82022-03-25 13:07:27 -07001526 .methods(
1527 boost::beast::http::verb::
1528 get)([&app](const crow::Request& req,
1529 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1530 const std::string& param) {
1531 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001532 {
Ed Tanous45ca1b82022-03-25 13:07:27 -07001533 return;
1534 }
1535 std::string entryID = param;
1536 dbus::utility::escapePathForDbus(entryID);
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001537
Ed Tanous45ca1b82022-03-25 13:07:27 -07001538 // DBus implementation of EventLog/Entries
1539 // Make call to Logging Service to find all log entry objects
1540 crow::connections::systemBus->async_method_call(
1541 [asyncResp,
1542 entryID](const boost::system::error_code ec,
1543 const dbus::utility::DBusPropertiesMap& resp) {
1544 if (ec.value() == EBADR)
1545 {
1546 messages::resourceNotFound(asyncResp->res,
1547 "EventLogEntry", entryID);
1548 return;
1549 }
1550 if (ec)
1551 {
1552 BMCWEB_LOG_ERROR
1553 << "EventLogEntry (DBus) resp_handler got error "
1554 << ec;
1555 messages::internalError(asyncResp->res);
1556 return;
1557 }
1558 const uint32_t* id = nullptr;
1559 const uint64_t* timestamp = nullptr;
1560 const uint64_t* updateTimestamp = nullptr;
1561 const std::string* severity = nullptr;
1562 const std::string* message = nullptr;
1563 const std::string* filePath = nullptr;
1564 bool resolved = false;
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001565
Ed Tanous45ca1b82022-03-25 13:07:27 -07001566 for (const auto& propertyMap : resp)
1567 {
1568 if (propertyMap.first == "Id")
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001569 {
Ed Tanous45ca1b82022-03-25 13:07:27 -07001570 id = std::get_if<uint32_t>(&propertyMap.second);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001571 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07001572 else if (propertyMap.first == "Timestamp")
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001573 {
Ed Tanous45ca1b82022-03-25 13:07:27 -07001574 timestamp =
1575 std::get_if<uint64_t>(&propertyMap.second);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001576 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07001577 else if (propertyMap.first == "UpdateTimestamp")
1578 {
1579 updateTimestamp =
1580 std::get_if<uint64_t>(&propertyMap.second);
1581 }
1582 else if (propertyMap.first == "Severity")
1583 {
1584 severity =
1585 std::get_if<std::string>(&propertyMap.second);
1586 }
1587 else if (propertyMap.first == "Message")
1588 {
1589 message =
1590 std::get_if<std::string>(&propertyMap.second);
1591 }
1592 else if (propertyMap.first == "Resolved")
1593 {
1594 const bool* resolveptr =
1595 std::get_if<bool>(&propertyMap.second);
1596 if (resolveptr == nullptr)
1597 {
1598 messages::internalError(asyncResp->res);
1599 return;
1600 }
1601 resolved = *resolveptr;
1602 }
1603 else if (propertyMap.first == "Path")
1604 {
1605 filePath =
1606 std::get_if<std::string>(&propertyMap.second);
1607 }
1608 }
1609 if (id == nullptr || message == nullptr ||
1610 severity == nullptr || timestamp == nullptr ||
1611 updateTimestamp == nullptr)
1612 {
1613 messages::internalError(asyncResp->res);
1614 return;
1615 }
1616 asyncResp->res.jsonValue["@odata.type"] =
1617 "#LogEntry.v1_8_0.LogEntry";
1618 asyncResp->res.jsonValue["@odata.id"] =
1619 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
1620 std::to_string(*id);
1621 asyncResp->res.jsonValue["Name"] = "System Event Log Entry";
1622 asyncResp->res.jsonValue["Id"] = std::to_string(*id);
1623 asyncResp->res.jsonValue["Message"] = *message;
1624 asyncResp->res.jsonValue["Resolved"] = resolved;
1625 asyncResp->res.jsonValue["EntryType"] = "Event";
1626 asyncResp->res.jsonValue["Severity"] =
1627 translateSeverityDbusToRedfish(*severity);
1628 asyncResp->res.jsonValue["Created"] =
1629 crow::utility::getDateTimeUintMs(*timestamp);
1630 asyncResp->res.jsonValue["Modified"] =
1631 crow::utility::getDateTimeUintMs(*updateTimestamp);
1632 if (filePath != nullptr)
1633 {
1634 asyncResp->res.jsonValue["AdditionalDataURI"] =
1635 "/redfish/v1/Systems/system/LogServices/EventLog/attachment/" +
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001636 std::to_string(*id);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001637 }
1638 },
1639 "xyz.openbmc_project.Logging",
1640 "/xyz/openbmc_project/logging/entry/" + entryID,
1641 "org.freedesktop.DBus.Properties", "GetAll", "");
1642 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001643
1644 BMCWEB_ROUTE(
1645 app, "/redfish/v1/Systems/system/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001646 .privileges(redfish::privileges::patchLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001647 .methods(boost::beast::http::verb::patch)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001648 [&app](const crow::Request& req,
1649 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1650 const std::string& entryId) {
1651 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
1652 {
1653 return;
1654 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001655 std::optional<bool> resolved;
1656
Willy Tu15ed6782021-12-14 11:03:16 -08001657 if (!json_util::readJsonPatch(req, asyncResp->res, "Resolved",
1658 resolved))
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001659 {
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001660 return;
1661 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001662 BMCWEB_LOG_DEBUG << "Set Resolved";
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001663
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001664 crow::connections::systemBus->async_method_call(
Ed Tanous4f48d5f2021-06-21 08:27:45 -07001665 [asyncResp, entryId](const boost::system::error_code ec) {
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001666 if (ec)
1667 {
1668 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1669 messages::internalError(asyncResp->res);
1670 return;
1671 }
1672 },
1673 "xyz.openbmc_project.Logging",
1674 "/xyz/openbmc_project/logging/entry/" + entryId,
1675 "org.freedesktop.DBus.Properties", "Set",
1676 "xyz.openbmc_project.Logging.Entry", "Resolved",
Ed Tanous168e20c2021-12-13 14:39:53 -08001677 dbus::utility::DbusVariantType(*resolved));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001678 });
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001679
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001680 BMCWEB_ROUTE(
1681 app, "/redfish/v1/Systems/system/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001682 .privileges(redfish::privileges::deleteLogEntry)
1683
Ed Tanous45ca1b82022-03-25 13:07:27 -07001684 .methods(boost::beast::http::verb::
1685 delete_)([&app](const crow::Request& req,
1686 const std::shared_ptr<bmcweb::AsyncResp>&
1687 asyncResp,
1688 const std::string& param) {
1689 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001690 {
Ed Tanous45ca1b82022-03-25 13:07:27 -07001691 return;
1692 }
1693 BMCWEB_LOG_DEBUG << "Do delete single event entries.";
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001694
Ed Tanous45ca1b82022-03-25 13:07:27 -07001695 std::string entryID = param;
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001696
Ed Tanous45ca1b82022-03-25 13:07:27 -07001697 dbus::utility::escapePathForDbus(entryID);
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001698
Ed Tanous45ca1b82022-03-25 13:07:27 -07001699 // Process response from Logging service.
1700 auto respHandler = [asyncResp,
1701 entryID](const boost::system::error_code ec) {
1702 BMCWEB_LOG_DEBUG
1703 << "EventLogEntry (DBus) doDelete callback: Done";
1704 if (ec)
1705 {
1706 if (ec.value() == EBADR)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001707 {
Ed Tanous45ca1b82022-03-25 13:07:27 -07001708 messages::resourceNotFound(asyncResp->res, "LogEntry",
1709 entryID);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001710 return;
1711 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07001712 // TODO Handle for specific error code
1713 BMCWEB_LOG_ERROR
1714 << "EventLogEntry (DBus) doDelete respHandler got error "
1715 << ec;
1716 asyncResp->res.result(
1717 boost::beast::http::status::internal_server_error);
1718 return;
1719 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001720
Ed Tanous45ca1b82022-03-25 13:07:27 -07001721 asyncResp->res.result(boost::beast::http::status::ok);
1722 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001723
Ed Tanous45ca1b82022-03-25 13:07:27 -07001724 // Make call to Logging service to request Delete Log
1725 crow::connections::systemBus->async_method_call(
1726 respHandler, "xyz.openbmc_project.Logging",
1727 "/xyz/openbmc_project/logging/entry/" + entryID,
1728 "xyz.openbmc_project.Object.Delete", "Delete");
1729 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001730}
1731
1732inline void requestRoutesDBusEventLogEntryDownload(App& app)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001733{
George Liu0fda0f12021-11-16 10:06:17 +08001734 BMCWEB_ROUTE(
1735 app,
1736 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/<str>/attachment")
Ed Tanoused398212021-06-09 17:05:54 -07001737 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001738 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001739 [&app](const crow::Request& req,
1740 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1741 const std::string& param) {
1742 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
1743 {
1744 return;
1745 }
George Liu647b3cd2021-07-05 12:43:56 +08001746 if (!http_helpers::isOctetAccepted(
1747 req.getHeaderValue("Accept")))
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001748 {
1749 asyncResp->res.result(
1750 boost::beast::http::status::bad_request);
1751 return;
1752 }
zhanghch058d1b46d2021-04-01 11:18:24 +08001753
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001754 std::string entryID = param;
1755 dbus::utility::escapePathForDbus(entryID);
1756
1757 crow::connections::systemBus->async_method_call(
1758 [asyncResp,
1759 entryID](const boost::system::error_code ec,
1760 const sdbusplus::message::unix_fd& unixfd) {
1761 if (ec.value() == EBADR)
1762 {
1763 messages::resourceNotFound(
1764 asyncResp->res, "EventLogAttachment", entryID);
1765 return;
1766 }
1767 if (ec)
1768 {
1769 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1770 messages::internalError(asyncResp->res);
1771 return;
1772 }
1773
1774 int fd = -1;
1775 fd = dup(unixfd);
1776 if (fd == -1)
1777 {
1778 messages::internalError(asyncResp->res);
1779 return;
1780 }
1781
1782 long long int size = lseek(fd, 0, SEEK_END);
1783 if (size == -1)
1784 {
1785 messages::internalError(asyncResp->res);
1786 return;
1787 }
1788
1789 // Arbitrary max size of 64kb
1790 constexpr int maxFileSize = 65536;
1791 if (size > maxFileSize)
1792 {
1793 BMCWEB_LOG_ERROR
1794 << "File size exceeds maximum allowed size of "
1795 << maxFileSize;
1796 messages::internalError(asyncResp->res);
1797 return;
1798 }
1799 std::vector<char> data(static_cast<size_t>(size));
1800 long long int rc = lseek(fd, 0, SEEK_SET);
1801 if (rc == -1)
1802 {
1803 messages::internalError(asyncResp->res);
1804 return;
1805 }
1806 rc = read(fd, data.data(), data.size());
1807 if ((rc == -1) || (rc != size))
1808 {
1809 messages::internalError(asyncResp->res);
1810 return;
1811 }
1812 close(fd);
1813
1814 std::string_view strData(data.data(), data.size());
1815 std::string output =
1816 crow::utility::base64encode(strData);
1817
1818 asyncResp->res.addHeader("Content-Type",
1819 "application/octet-stream");
1820 asyncResp->res.addHeader("Content-Transfer-Encoding",
1821 "Base64");
1822 asyncResp->res.body() = std::move(output);
1823 },
1824 "xyz.openbmc_project.Logging",
1825 "/xyz/openbmc_project/logging/entry/" + entryID,
1826 "xyz.openbmc_project.Logging.Entry", "GetEntry");
1827 });
1828}
1829
Spencer Kub7028eb2021-10-26 15:27:35 +08001830constexpr const char* hostLoggerFolderPath = "/var/log/console";
1831
1832inline bool
1833 getHostLoggerFiles(const std::string& hostLoggerFilePath,
1834 std::vector<std::filesystem::path>& hostLoggerFiles)
1835{
1836 std::error_code ec;
1837 std::filesystem::directory_iterator logPath(hostLoggerFilePath, ec);
1838 if (ec)
1839 {
1840 BMCWEB_LOG_ERROR << ec.message();
1841 return false;
1842 }
1843 for (const std::filesystem::directory_entry& it : logPath)
1844 {
1845 std::string filename = it.path().filename();
1846 // Prefix of each log files is "log". Find the file and save the
1847 // path
1848 if (boost::starts_with(filename, "log"))
1849 {
1850 hostLoggerFiles.emplace_back(it.path());
1851 }
1852 }
1853 // As the log files rotate, they are appended with a ".#" that is higher for
1854 // the older logs. Since we start from oldest logs, sort the name in
1855 // descending order.
1856 std::sort(hostLoggerFiles.rbegin(), hostLoggerFiles.rend(),
1857 AlphanumLess<std::string>());
1858
1859 return true;
1860}
1861
1862inline bool
1863 getHostLoggerEntries(std::vector<std::filesystem::path>& hostLoggerFiles,
1864 uint64_t& skip, uint64_t& top,
1865 std::vector<std::string>& logEntries, size_t& logCount)
1866{
1867 GzFileReader logFile;
1868
1869 // Go though all log files and expose host logs.
1870 for (const std::filesystem::path& it : hostLoggerFiles)
1871 {
1872 if (!logFile.gzGetLines(it.string(), skip, top, logEntries, logCount))
1873 {
1874 BMCWEB_LOG_ERROR << "fail to expose host logs";
1875 return false;
1876 }
1877 }
1878 // Get lastMessage from constructor by getter
1879 std::string lastMessage = logFile.getLastMessage();
1880 if (!lastMessage.empty())
1881 {
1882 logCount++;
1883 if (logCount > skip && logCount <= (skip + top))
1884 {
1885 logEntries.push_back(lastMessage);
1886 }
1887 }
1888 return true;
1889}
1890
1891inline void fillHostLoggerEntryJson(const std::string& logEntryID,
1892 const std::string& msg,
1893 nlohmann::json& logEntryJson)
1894{
1895 // Fill in the log entry with the gathered data.
1896 logEntryJson = {
1897 {"@odata.type", "#LogEntry.v1_4_0.LogEntry"},
1898 {"@odata.id",
1899 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries/" +
1900 logEntryID},
1901 {"Name", "Host Logger Entry"},
1902 {"Id", logEntryID},
1903 {"Message", msg},
1904 {"EntryType", "Oem"},
1905 {"Severity", "OK"},
1906 {"OemRecordFormat", "Host Logger Entry"}};
1907}
1908
1909inline void requestRoutesSystemHostLogger(App& app)
1910{
1911 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/HostLogger/")
1912 .privileges(redfish::privileges::getLogService)
Ed Tanous45ca1b82022-03-25 13:07:27 -07001913 .methods(boost::beast::http::verb::get)([&app](const crow::Request& req,
1914 const std::shared_ptr<
1915 bmcweb::AsyncResp>&
1916 asyncResp) {
1917 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
1918 {
1919 return;
1920 }
George Liu0fda0f12021-11-16 10:06:17 +08001921 asyncResp->res.jsonValue["@odata.id"] =
1922 "/redfish/v1/Systems/system/LogServices/HostLogger";
1923 asyncResp->res.jsonValue["@odata.type"] =
1924 "#LogService.v1_1_0.LogService";
1925 asyncResp->res.jsonValue["Name"] = "Host Logger Service";
1926 asyncResp->res.jsonValue["Description"] = "Host Logger Service";
1927 asyncResp->res.jsonValue["Id"] = "HostLogger";
1928 asyncResp->res.jsonValue["Entries"] = {
1929 {"@odata.id",
1930 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries"}};
1931 });
Spencer Kub7028eb2021-10-26 15:27:35 +08001932}
1933
1934inline void requestRoutesSystemHostLoggerCollection(App& app)
1935{
1936 BMCWEB_ROUTE(app,
1937 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries/")
1938 .privileges(redfish::privileges::getLogEntry)
Ed Tanous45ca1b82022-03-25 13:07:27 -07001939 .methods(boost::beast::http::verb::get)([&app](const crow::Request& req,
1940 const std::shared_ptr<
1941 bmcweb::AsyncResp>&
1942 asyncResp) {
1943 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
1944 {
1945 return;
1946 }
George Liu0fda0f12021-11-16 10:06:17 +08001947 uint64_t skip = 0;
1948 uint64_t top = maxEntriesPerPage; // Show max 1000 entries by
1949 // default, allow range 1 to
1950 // 1000 entries per page.
1951 if (!getSkipParam(asyncResp, req, skip))
1952 {
1953 return;
1954 }
1955 if (!getTopParam(asyncResp, req, top))
1956 {
1957 return;
1958 }
1959 asyncResp->res.jsonValue["@odata.id"] =
1960 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries";
1961 asyncResp->res.jsonValue["@odata.type"] =
1962 "#LogEntryCollection.LogEntryCollection";
1963 asyncResp->res.jsonValue["Name"] = "HostLogger Entries";
1964 asyncResp->res.jsonValue["Description"] =
1965 "Collection of HostLogger Entries";
1966 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
1967 logEntryArray = nlohmann::json::array();
1968 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Spencer Kub7028eb2021-10-26 15:27:35 +08001969
George Liu0fda0f12021-11-16 10:06:17 +08001970 std::vector<std::filesystem::path> hostLoggerFiles;
1971 if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles))
1972 {
1973 BMCWEB_LOG_ERROR << "fail to get host log file path";
1974 return;
1975 }
1976
1977 size_t logCount = 0;
1978 // This vector only store the entries we want to expose that
1979 // control by skip and top.
1980 std::vector<std::string> logEntries;
1981 if (!getHostLoggerEntries(hostLoggerFiles, skip, top, logEntries,
1982 logCount))
1983 {
1984 messages::internalError(asyncResp->res);
1985 return;
1986 }
1987 // If vector is empty, that means skip value larger than total
1988 // log count
Ed Tanous26f69762022-01-25 09:49:11 -08001989 if (logEntries.empty())
George Liu0fda0f12021-11-16 10:06:17 +08001990 {
1991 asyncResp->res.jsonValue["Members@odata.count"] = logCount;
1992 return;
1993 }
Ed Tanous26f69762022-01-25 09:49:11 -08001994 if (!logEntries.empty())
George Liu0fda0f12021-11-16 10:06:17 +08001995 {
1996 for (size_t i = 0; i < logEntries.size(); i++)
Spencer Kub7028eb2021-10-26 15:27:35 +08001997 {
George Liu0fda0f12021-11-16 10:06:17 +08001998 logEntryArray.push_back({});
1999 nlohmann::json& hostLogEntry = logEntryArray.back();
2000 fillHostLoggerEntryJson(std::to_string(skip + i),
2001 logEntries[i], hostLogEntry);
Spencer Kub7028eb2021-10-26 15:27:35 +08002002 }
2003
George Liu0fda0f12021-11-16 10:06:17 +08002004 asyncResp->res.jsonValue["Members@odata.count"] = logCount;
2005 if (skip + top < logCount)
Spencer Kub7028eb2021-10-26 15:27:35 +08002006 {
George Liu0fda0f12021-11-16 10:06:17 +08002007 asyncResp->res.jsonValue["Members@odata.nextLink"] =
2008 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries?$skip=" +
2009 std::to_string(skip + top);
Spencer Kub7028eb2021-10-26 15:27:35 +08002010 }
George Liu0fda0f12021-11-16 10:06:17 +08002011 }
2012 });
Spencer Kub7028eb2021-10-26 15:27:35 +08002013}
2014
2015inline void requestRoutesSystemHostLoggerLogEntry(App& app)
2016{
2017 BMCWEB_ROUTE(
2018 app, "/redfish/v1/Systems/system/LogServices/HostLogger/Entries/<str>/")
2019 .privileges(redfish::privileges::getLogEntry)
2020 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002021 [&app](const crow::Request& req,
2022 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2023 const std::string& param) {
2024 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2025 {
2026 return;
2027 }
Spencer Kub7028eb2021-10-26 15:27:35 +08002028 const std::string& targetID = param;
2029
2030 uint64_t idInt = 0;
Ed Tanousca45aa32022-01-07 09:28:45 -08002031
2032 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
2033 const char* end = targetID.data() + targetID.size();
2034
2035 auto [ptr, ec] = std::from_chars(targetID.data(), end, idInt);
Spencer Kub7028eb2021-10-26 15:27:35 +08002036 if (ec == std::errc::invalid_argument)
2037 {
Ed Tanousace85d62021-10-26 12:45:59 -07002038 messages::resourceMissingAtURI(asyncResp->res, req.urlView);
Spencer Kub7028eb2021-10-26 15:27:35 +08002039 return;
2040 }
2041 if (ec == std::errc::result_out_of_range)
2042 {
Ed Tanousace85d62021-10-26 12:45:59 -07002043 messages::resourceMissingAtURI(asyncResp->res, req.urlView);
Spencer Kub7028eb2021-10-26 15:27:35 +08002044 return;
2045 }
2046
2047 std::vector<std::filesystem::path> hostLoggerFiles;
2048 if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles))
2049 {
2050 BMCWEB_LOG_ERROR << "fail to get host log file path";
2051 return;
2052 }
2053
2054 size_t logCount = 0;
2055 uint64_t top = 1;
2056 std::vector<std::string> logEntries;
2057 // We can get specific entry by skip and top. For example, if we
2058 // want to get nth entry, we can set skip = n-1 and top = 1 to
2059 // get that entry
2060 if (!getHostLoggerEntries(hostLoggerFiles, idInt, top,
2061 logEntries, logCount))
2062 {
2063 messages::internalError(asyncResp->res);
2064 return;
2065 }
2066
2067 if (!logEntries.empty())
2068 {
2069 fillHostLoggerEntryJson(targetID, logEntries[0],
2070 asyncResp->res.jsonValue);
2071 return;
2072 }
2073
2074 // Requested ID was not found
Ed Tanousace85d62021-10-26 12:45:59 -07002075 messages::resourceMissingAtURI(asyncResp->res, req.urlView);
Spencer Kub7028eb2021-10-26 15:27:35 +08002076 });
2077}
2078
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002079inline void requestRoutesBMCLogServiceCollection(App& app)
2080{
2081 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/")
Gunnar Millsad89dcf2021-07-30 14:40:11 -05002082 .privileges(redfish::privileges::getLogServiceCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002083 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002084 [&app](const crow::Request& req,
2085 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2086 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2087 {
2088 return;
2089 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002090 // Collections don't include the static data added by SubRoute
2091 // because it has a duplicate entry for members
2092 asyncResp->res.jsonValue["@odata.type"] =
2093 "#LogServiceCollection.LogServiceCollection";
2094 asyncResp->res.jsonValue["@odata.id"] =
2095 "/redfish/v1/Managers/bmc/LogServices";
2096 asyncResp->res.jsonValue["Name"] =
2097 "Open BMC Log Services Collection";
2098 asyncResp->res.jsonValue["Description"] =
2099 "Collection of LogServices for this Manager";
2100 nlohmann::json& logServiceArray =
2101 asyncResp->res.jsonValue["Members"];
2102 logServiceArray = nlohmann::json::array();
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002103#ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002104 logServiceArray.push_back(
2105 {{"@odata.id",
2106 "/redfish/v1/Managers/bmc/LogServices/Dump"}});
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002107#endif
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002108#ifdef BMCWEB_ENABLE_REDFISH_BMC_JOURNAL
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002109 logServiceArray.push_back(
2110 {{"@odata.id",
2111 "/redfish/v1/Managers/bmc/LogServices/Journal"}});
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002112#endif
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002113 asyncResp->res.jsonValue["Members@odata.count"] =
2114 logServiceArray.size();
2115 });
2116}
Ed Tanous1da66f72018-07-27 16:13:37 -07002117
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002118inline void requestRoutesBMCJournalLogService(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07002119{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002120 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/")
Ed Tanoused398212021-06-09 17:05:54 -07002121 .privileges(redfish::privileges::getLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002122 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002123 [&app](const crow::Request& req,
2124 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2125 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2126 {
2127 return;
2128 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002129 asyncResp->res.jsonValue["@odata.type"] =
2130 "#LogService.v1_1_0.LogService";
2131 asyncResp->res.jsonValue["@odata.id"] =
2132 "/redfish/v1/Managers/bmc/LogServices/Journal";
2133 asyncResp->res.jsonValue["Name"] =
2134 "Open BMC Journal Log Service";
2135 asyncResp->res.jsonValue["Description"] =
2136 "BMC Journal Log Service";
2137 asyncResp->res.jsonValue["Id"] = "BMC Journal";
2138 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
Tejas Patil7c8c4052021-06-04 17:43:14 +05302139
2140 std::pair<std::string, std::string> redfishDateTimeOffset =
2141 crow::utility::getDateTimeOffsetNow();
2142 asyncResp->res.jsonValue["DateTime"] =
2143 redfishDateTimeOffset.first;
2144 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2145 redfishDateTimeOffset.second;
2146
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002147 asyncResp->res.jsonValue["Entries"] = {
2148 {"@odata.id",
2149 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries"}};
2150 });
2151}
Jason M. Billse1f26342018-07-18 12:12:00 -07002152
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002153static int fillBMCJournalLogEntryJson(const std::string& bmcJournalLogEntryID,
2154 sd_journal* journal,
2155 nlohmann::json& bmcJournalLogEntryJson)
Jason M. Billse1f26342018-07-18 12:12:00 -07002156{
2157 // Get the Log Entry contents
2158 int ret = 0;
Jason M. Billse1f26342018-07-18 12:12:00 -07002159
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08002160 std::string message;
2161 std::string_view syslogID;
2162 ret = getJournalMetadata(journal, "SYSLOG_IDENTIFIER", syslogID);
2163 if (ret < 0)
2164 {
2165 BMCWEB_LOG_ERROR << "Failed to read SYSLOG_IDENTIFIER field: "
2166 << strerror(-ret);
2167 }
2168 if (!syslogID.empty())
2169 {
2170 message += std::string(syslogID) + ": ";
2171 }
2172
Ed Tanous39e77502019-03-04 17:35:53 -08002173 std::string_view msg;
Jason M. Bills16428a12018-11-02 12:42:29 -07002174 ret = getJournalMetadata(journal, "MESSAGE", msg);
Jason M. Billse1f26342018-07-18 12:12:00 -07002175 if (ret < 0)
2176 {
2177 BMCWEB_LOG_ERROR << "Failed to read MESSAGE field: " << strerror(-ret);
2178 return 1;
2179 }
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08002180 message += std::string(msg);
Jason M. Billse1f26342018-07-18 12:12:00 -07002181
2182 // Get the severity from the PRIORITY field
Ed Tanous271584a2019-07-09 16:24:22 -07002183 long int severity = 8; // Default to an invalid priority
Jason M. Bills16428a12018-11-02 12:42:29 -07002184 ret = getJournalMetadata(journal, "PRIORITY", 10, severity);
Jason M. Billse1f26342018-07-18 12:12:00 -07002185 if (ret < 0)
2186 {
2187 BMCWEB_LOG_ERROR << "Failed to read PRIORITY field: " << strerror(-ret);
Jason M. Billse1f26342018-07-18 12:12:00 -07002188 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002189
2190 // Get the Created time from the timestamp
Jason M. Bills16428a12018-11-02 12:42:29 -07002191 std::string entryTimeStr;
2192 if (!getEntryTimestamp(journal, entryTimeStr))
Jason M. Billse1f26342018-07-18 12:12:00 -07002193 {
Jason M. Bills16428a12018-11-02 12:42:29 -07002194 return 1;
Jason M. Billse1f26342018-07-18 12:12:00 -07002195 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002196
2197 // Fill in the log entry with the gathered data
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002198 bmcJournalLogEntryJson = {
George Liu647b3cd2021-07-05 12:43:56 +08002199 {"@odata.type", "#LogEntry.v1_8_0.LogEntry"},
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002200 {"@odata.id", "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/" +
2201 bmcJournalLogEntryID},
Jason M. Billse1f26342018-07-18 12:12:00 -07002202 {"Name", "BMC Journal Entry"},
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002203 {"Id", bmcJournalLogEntryID},
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08002204 {"Message", std::move(message)},
Jason M. Billse1f26342018-07-18 12:12:00 -07002205 {"EntryType", "Oem"},
Patrick Williams738c1e62021-02-22 17:14:25 -06002206 {"Severity", severity <= 2 ? "Critical"
2207 : severity <= 4 ? "Warning"
2208 : "OK"},
Ed Tanous086be232019-05-23 11:47:09 -07002209 {"OemRecordFormat", "BMC Journal Entry"},
Jason M. Billse1f26342018-07-18 12:12:00 -07002210 {"Created", std::move(entryTimeStr)}};
2211 return 0;
2212}
2213
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002214inline void requestRoutesBMCJournalLogEntryCollection(App& app)
Jason M. Billse1f26342018-07-18 12:12:00 -07002215{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002216 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07002217 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous45ca1b82022-03-25 13:07:27 -07002218 .methods(boost::beast::http::verb::get)([&app](const crow::Request& req,
2219 const std::shared_ptr<
2220 bmcweb::AsyncResp>&
2221 asyncResp) {
2222 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2223 {
2224 return;
2225 }
George Liu0fda0f12021-11-16 10:06:17 +08002226 static constexpr const long maxEntriesPerPage = 1000;
2227 uint64_t skip = 0;
2228 uint64_t top = maxEntriesPerPage; // Show max entries by default
2229 if (!getSkipParam(asyncResp, req, skip))
2230 {
2231 return;
2232 }
2233 if (!getTopParam(asyncResp, req, top))
2234 {
2235 return;
2236 }
2237 // Collections don't include the static data added by SubRoute
2238 // because it has a duplicate entry for members
2239 asyncResp->res.jsonValue["@odata.type"] =
2240 "#LogEntryCollection.LogEntryCollection";
2241 asyncResp->res.jsonValue["@odata.id"] =
2242 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries";
2243 asyncResp->res.jsonValue["Name"] = "Open BMC Journal Entries";
2244 asyncResp->res.jsonValue["Description"] =
2245 "Collection of BMC Journal Entries";
2246 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
2247 logEntryArray = nlohmann::json::array();
Jason M. Billse1f26342018-07-18 12:12:00 -07002248
George Liu0fda0f12021-11-16 10:06:17 +08002249 // Go through the journal and use the timestamp to create a
2250 // unique ID for each entry
2251 sd_journal* journalTmp = nullptr;
2252 int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY);
2253 if (ret < 0)
2254 {
2255 BMCWEB_LOG_ERROR << "failed to open journal: "
2256 << strerror(-ret);
2257 messages::internalError(asyncResp->res);
2258 return;
2259 }
2260 std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal(
2261 journalTmp, sd_journal_close);
2262 journalTmp = nullptr;
2263 uint64_t entryCount = 0;
2264 // Reset the unique ID on the first entry
2265 bool firstEntry = true;
2266 SD_JOURNAL_FOREACH(journal.get())
2267 {
2268 entryCount++;
2269 // Handle paging using skip (number of entries to skip from
2270 // the start) and top (number of entries to display)
2271 if (entryCount <= skip || entryCount > skip + top)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002272 {
George Liu0fda0f12021-11-16 10:06:17 +08002273 continue;
2274 }
2275
2276 std::string idStr;
2277 if (!getUniqueEntryID(journal.get(), idStr, firstEntry))
2278 {
2279 continue;
2280 }
2281
2282 if (firstEntry)
2283 {
2284 firstEntry = false;
2285 }
2286
2287 logEntryArray.push_back({});
2288 nlohmann::json& bmcJournalLogEntry = logEntryArray.back();
2289 if (fillBMCJournalLogEntryJson(idStr, journal.get(),
2290 bmcJournalLogEntry) != 0)
2291 {
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002292 messages::internalError(asyncResp->res);
2293 return;
2294 }
George Liu0fda0f12021-11-16 10:06:17 +08002295 }
2296 asyncResp->res.jsonValue["Members@odata.count"] = entryCount;
2297 if (skip + top < entryCount)
2298 {
2299 asyncResp->res.jsonValue["Members@odata.nextLink"] =
2300 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries?$skip=" +
2301 std::to_string(skip + top);
2302 }
2303 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002304}
Jason M. Billse1f26342018-07-18 12:12:00 -07002305
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002306inline void requestRoutesBMCJournalLogEntry(App& app)
Jason M. Billse1f26342018-07-18 12:12:00 -07002307{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002308 BMCWEB_ROUTE(app,
2309 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002310 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002311 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002312 [&app](const crow::Request& req,
2313 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2314 const std::string& entryID) {
2315 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2316 {
2317 return;
2318 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002319 // Convert the unique ID back to a timestamp to find the entry
2320 uint64_t ts = 0;
2321 uint64_t index = 0;
2322 if (!getTimestampFromID(asyncResp, entryID, ts, index))
2323 {
2324 return;
2325 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002326
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002327 sd_journal* journalTmp = nullptr;
2328 int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY);
2329 if (ret < 0)
2330 {
2331 BMCWEB_LOG_ERROR << "failed to open journal: "
2332 << strerror(-ret);
2333 messages::internalError(asyncResp->res);
2334 return;
2335 }
2336 std::unique_ptr<sd_journal, decltype(&sd_journal_close)>
2337 journal(journalTmp, sd_journal_close);
2338 journalTmp = nullptr;
2339 // Go to the timestamp in the log and move to the entry at the
2340 // index tracking the unique ID
2341 std::string idStr;
2342 bool firstEntry = true;
2343 ret = sd_journal_seek_realtime_usec(journal.get(), ts);
2344 if (ret < 0)
2345 {
2346 BMCWEB_LOG_ERROR << "failed to seek to an entry in journal"
2347 << strerror(-ret);
2348 messages::internalError(asyncResp->res);
2349 return;
2350 }
2351 for (uint64_t i = 0; i <= index; i++)
2352 {
2353 sd_journal_next(journal.get());
2354 if (!getUniqueEntryID(journal.get(), idStr, firstEntry))
2355 {
2356 messages::internalError(asyncResp->res);
2357 return;
2358 }
2359 if (firstEntry)
2360 {
2361 firstEntry = false;
2362 }
2363 }
2364 // Confirm that the entry ID matches what was requested
2365 if (idStr != entryID)
2366 {
Ed Tanousace85d62021-10-26 12:45:59 -07002367 messages::resourceMissingAtURI(asyncResp->res, req.urlView);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002368 return;
2369 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002370
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002371 if (fillBMCJournalLogEntryJson(entryID, journal.get(),
2372 asyncResp->res.jsonValue) != 0)
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07002373 {
2374 messages::internalError(asyncResp->res);
2375 return;
2376 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002377 });
2378}
2379
2380inline void requestRoutesBMCDumpService(App& app)
2381{
2382 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/")
Ed Tanoused398212021-06-09 17:05:54 -07002383 .privileges(redfish::privileges::getLogService)
Ed Tanous45ca1b82022-03-25 13:07:27 -07002384 .methods(boost::beast::http::verb::get)([&app](const crow::Request& req,
2385 const std::shared_ptr<
2386 bmcweb::AsyncResp>&
2387 asyncResp) {
2388 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2389 {
2390 return;
2391 }
George Liu0fda0f12021-11-16 10:06:17 +08002392 asyncResp->res.jsonValue["@odata.id"] =
2393 "/redfish/v1/Managers/bmc/LogServices/Dump";
2394 asyncResp->res.jsonValue["@odata.type"] =
2395 "#LogService.v1_2_0.LogService";
2396 asyncResp->res.jsonValue["Name"] = "Dump LogService";
2397 asyncResp->res.jsonValue["Description"] = "BMC Dump LogService";
2398 asyncResp->res.jsonValue["Id"] = "Dump";
2399 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
Tejas Patil7c8c4052021-06-04 17:43:14 +05302400
George Liu0fda0f12021-11-16 10:06:17 +08002401 std::pair<std::string, std::string> redfishDateTimeOffset =
2402 crow::utility::getDateTimeOffsetNow();
2403 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2404 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2405 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05302406
George Liu0fda0f12021-11-16 10:06:17 +08002407 asyncResp->res.jsonValue["Entries"] = {
2408 {"@odata.id",
2409 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries"}};
2410 asyncResp->res.jsonValue["Actions"] = {
2411 {"#LogService.ClearLog",
2412 {{"target",
2413 "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.ClearLog"}}},
2414 {"#LogService.CollectDiagnosticData",
2415 {{"target",
2416 "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.CollectDiagnosticData"}}}};
2417 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002418}
2419
2420inline void requestRoutesBMCDumpEntryCollection(App& app)
2421{
2422
2423 /**
2424 * Functions triggers appropriate requests on DBus
2425 */
2426 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07002427 .privileges(redfish::privileges::getLogEntryCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002428 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002429 [&app](const crow::Request& req,
2430 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2431 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2432 {
2433 return;
2434 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002435 asyncResp->res.jsonValue["@odata.type"] =
2436 "#LogEntryCollection.LogEntryCollection";
2437 asyncResp->res.jsonValue["@odata.id"] =
2438 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries";
2439 asyncResp->res.jsonValue["Name"] = "BMC Dump Entries";
2440 asyncResp->res.jsonValue["Description"] =
2441 "Collection of BMC Dump Entries";
2442
2443 getDumpEntryCollection(asyncResp, "BMC");
2444 });
2445}
2446
2447inline void requestRoutesBMCDumpEntry(App& app)
2448{
2449 BMCWEB_ROUTE(app,
2450 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002451 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002452 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002453 [&app](const crow::Request& req,
2454 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2455 const std::string& param) {
2456 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2457 {
2458 return;
2459 }
2460
2461 getDumpEntryById(app, req, asyncResp, param, "BMC");
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002462 });
2463 BMCWEB_ROUTE(app,
2464 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002465 .privileges(redfish::privileges::deleteLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002466 .methods(boost::beast::http::verb::delete_)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002467 [&app](const crow::Request& req,
2468 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2469 const std::string& param) {
2470 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2471 {
2472 return;
2473 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002474 deleteDumpEntry(asyncResp, param, "bmc");
2475 });
2476}
2477
2478inline void requestRoutesBMCDumpCreate(App& app)
2479{
George Liu0fda0f12021-11-16 10:06:17 +08002480 BMCWEB_ROUTE(
2481 app,
2482 "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07002483 .privileges(redfish::privileges::postLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002484 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002485 [&app](const crow::Request& req,
2486 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2487 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2488 {
2489 return;
2490 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002491 createDump(asyncResp, req, "BMC");
2492 });
2493}
2494
2495inline void requestRoutesBMCDumpClear(App& app)
2496{
George Liu0fda0f12021-11-16 10:06:17 +08002497 BMCWEB_ROUTE(
2498 app,
2499 "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07002500 .privileges(redfish::privileges::postLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002501 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002502 [&app](const crow::Request& req,
2503 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2504 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2505 {
2506 return;
2507 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002508 clearDump(asyncResp, "BMC");
2509 });
2510}
2511
2512inline void requestRoutesSystemDumpService(App& app)
2513{
2514 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/Dump/")
Ed Tanoused398212021-06-09 17:05:54 -07002515 .privileges(redfish::privileges::getLogService)
Ed Tanous45ca1b82022-03-25 13:07:27 -07002516 .methods(boost::beast::http::verb::get)([&app](const crow::Request& req,
2517 const std::shared_ptr<
2518 bmcweb::AsyncResp>&
2519 asyncResp) {
2520 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002521 {
Ed Tanous45ca1b82022-03-25 13:07:27 -07002522 return;
2523 }
2524 asyncResp->res.jsonValue["@odata.id"] =
2525 "/redfish/v1/Systems/system/LogServices/Dump";
2526 asyncResp->res.jsonValue["@odata.type"] =
2527 "#LogService.v1_2_0.LogService";
2528 asyncResp->res.jsonValue["Name"] = "Dump LogService";
2529 asyncResp->res.jsonValue["Description"] = "System Dump LogService";
2530 asyncResp->res.jsonValue["Id"] = "Dump";
2531 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
Tejas Patil7c8c4052021-06-04 17:43:14 +05302532
Ed Tanous45ca1b82022-03-25 13:07:27 -07002533 std::pair<std::string, std::string> redfishDateTimeOffset =
2534 crow::utility::getDateTimeOffsetNow();
2535 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2536 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2537 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05302538
Ed Tanous45ca1b82022-03-25 13:07:27 -07002539 asyncResp->res.jsonValue["Entries"] = {
2540 {"@odata.id",
2541 "/redfish/v1/Systems/system/LogServices/Dump/Entries"}};
2542 asyncResp->res.jsonValue["Actions"] = {
2543 {"#LogService.ClearLog",
2544 {{"target",
2545 "/redfish/v1/Systems/system/LogServices/Dump/Actions/LogService.ClearLog"}}},
2546 {"#LogService.CollectDiagnosticData",
2547 {{"target",
2548 "/redfish/v1/Systems/system/LogServices/Dump/Actions/LogService.CollectDiagnosticData"}}}};
2549 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002550}
2551
2552inline void requestRoutesSystemDumpEntryCollection(App& app)
2553{
2554
2555 /**
2556 * Functions triggers appropriate requests on DBus
2557 */
Asmitha Karunanithib2a32892021-07-13 11:56:15 -05002558 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/Dump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07002559 .privileges(redfish::privileges::getLogEntryCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002560 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002561 [&app](const crow::Request& req,
2562 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2563 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2564 {
2565 return;
2566 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002567 asyncResp->res.jsonValue["@odata.type"] =
2568 "#LogEntryCollection.LogEntryCollection";
2569 asyncResp->res.jsonValue["@odata.id"] =
2570 "/redfish/v1/Systems/system/LogServices/Dump/Entries";
2571 asyncResp->res.jsonValue["Name"] = "System Dump Entries";
2572 asyncResp->res.jsonValue["Description"] =
2573 "Collection of System Dump Entries";
2574
2575 getDumpEntryCollection(asyncResp, "System");
2576 });
2577}
2578
2579inline void requestRoutesSystemDumpEntry(App& app)
2580{
2581 BMCWEB_ROUTE(app,
John Edward Broadbent864d6a12021-06-09 10:12:48 -07002582 "/redfish/v1/Systems/system/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002583 .privileges(redfish::privileges::getLogEntry)
2584
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002585 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002586 [&app](const crow::Request& req,
2587 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2588 const std::string& param) {
2589 getDumpEntryById(app, req, asyncResp, param, "System");
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002590 });
2591
2592 BMCWEB_ROUTE(app,
John Edward Broadbent864d6a12021-06-09 10:12:48 -07002593 "/redfish/v1/Systems/system/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002594 .privileges(redfish::privileges::deleteLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002595 .methods(boost::beast::http::verb::delete_)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002596 [&app](const crow::Request& req,
2597 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2598 const std::string& param) {
2599 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2600 {
2601 return;
2602 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002603 deleteDumpEntry(asyncResp, param, "system");
2604 });
2605}
2606
2607inline void requestRoutesSystemDumpCreate(App& app)
2608{
George Liu0fda0f12021-11-16 10:06:17 +08002609 BMCWEB_ROUTE(
2610 app,
2611 "/redfish/v1/Systems/system/LogServices/Dump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07002612 .privileges(redfish::privileges::postLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002613 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002614 [&app](const crow::Request& req,
2615 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2616 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2617 {
2618 return;
2619 }
2620 createDump(asyncResp, req, "System");
2621 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002622}
2623
2624inline void requestRoutesSystemDumpClear(App& app)
2625{
George Liu0fda0f12021-11-16 10:06:17 +08002626 BMCWEB_ROUTE(
2627 app,
2628 "/redfish/v1/Systems/system/LogServices/Dump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07002629 .privileges(redfish::privileges::postLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002630 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002631 [&app](const crow::Request& req,
2632 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002633
Ed Tanous45ca1b82022-03-25 13:07:27 -07002634 {
2635 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2636 {
2637 return;
2638 }
2639 clearDump(asyncResp, "System");
2640 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002641}
2642
2643inline void requestRoutesCrashdumpService(App& app)
2644{
2645 // Note: Deviated from redfish privilege registry for GET & HEAD
2646 // method for security reasons.
2647 /**
2648 * Functions triggers appropriate requests on DBus
2649 */
2650 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/Crashdump/")
Ed Tanoused398212021-06-09 17:05:54 -07002651 // This is incorrect, should be:
2652 //.privileges(redfish::privileges::getLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07002653 .privileges({{"ConfigureManager"}})
Ed Tanous45ca1b82022-03-25 13:07:27 -07002654 .methods(boost::beast::http::verb::get)([&app](const crow::Request& req,
2655 const std::shared_ptr<
2656 bmcweb::AsyncResp>&
2657 asyncResp) {
2658 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2659 {
2660 return;
2661 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002662 // Copy over the static data to include the entries added by
2663 // SubRoute
2664 asyncResp->res.jsonValue["@odata.id"] =
2665 "/redfish/v1/Systems/system/LogServices/Crashdump";
2666 asyncResp->res.jsonValue["@odata.type"] =
2667 "#LogService.v1_2_0.LogService";
2668 asyncResp->res.jsonValue["Name"] = "Open BMC Oem Crashdump Service";
2669 asyncResp->res.jsonValue["Description"] = "Oem Crashdump Service";
2670 asyncResp->res.jsonValue["Id"] = "Oem Crashdump";
2671 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
2672 asyncResp->res.jsonValue["MaxNumberOfRecords"] = 3;
Tejas Patil7c8c4052021-06-04 17:43:14 +05302673
2674 std::pair<std::string, std::string> redfishDateTimeOffset =
2675 crow::utility::getDateTimeOffsetNow();
2676 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2677 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2678 redfishDateTimeOffset.second;
2679
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002680 asyncResp->res.jsonValue["Entries"] = {
2681 {"@odata.id",
2682 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries"}};
2683 asyncResp->res.jsonValue["Actions"] = {
2684 {"#LogService.ClearLog",
George Liu0fda0f12021-11-16 10:06:17 +08002685 {{"target",
2686 "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.ClearLog"}}},
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002687 {"#LogService.CollectDiagnosticData",
George Liu0fda0f12021-11-16 10:06:17 +08002688 {{"target",
2689 "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData"}}}};
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002690 });
2691}
2692
2693void inline requestRoutesCrashdumpClear(App& app)
2694{
George Liu0fda0f12021-11-16 10:06:17 +08002695 BMCWEB_ROUTE(
2696 app,
2697 "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07002698 // This is incorrect, should be:
2699 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07002700 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002701 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002702 [&app](const crow::Request& req,
2703 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2704 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2705 {
2706 return;
2707 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002708 crow::connections::systemBus->async_method_call(
2709 [asyncResp](const boost::system::error_code ec,
2710 const std::string&) {
2711 if (ec)
2712 {
2713 messages::internalError(asyncResp->res);
2714 return;
2715 }
2716 messages::success(asyncResp->res);
2717 },
2718 crashdumpObject, crashdumpPath, deleteAllInterface,
2719 "DeleteAll");
2720 });
2721}
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07002722
zhanghch058d1b46d2021-04-01 11:18:24 +08002723static void
2724 logCrashdumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2725 const std::string& logID, nlohmann::json& logEntryJson)
Jason M. Billse855dd22019-10-08 11:37:48 -07002726{
Johnathan Mantey043a0532020-03-10 17:15:28 -07002727 auto getStoredLogCallback =
Ed Tanousb9d36b42022-02-26 21:42:46 -08002728 [asyncResp, logID,
2729 &logEntryJson](const boost::system::error_code ec,
2730 const dbus::utility::DBusPropertiesMap& params) {
Johnathan Mantey043a0532020-03-10 17:15:28 -07002731 if (ec)
Jason M. Bills1ddcf012019-11-26 14:59:21 -08002732 {
Johnathan Mantey043a0532020-03-10 17:15:28 -07002733 BMCWEB_LOG_DEBUG << "failed to get log ec: " << ec.message();
2734 if (ec.value() ==
2735 boost::system::linux_error::bad_request_descriptor)
2736 {
2737 messages::resourceNotFound(asyncResp->res, "LogEntry",
2738 logID);
2739 }
2740 else
2741 {
2742 messages::internalError(asyncResp->res);
2743 }
2744 return;
Jason M. Bills1ddcf012019-11-26 14:59:21 -08002745 }
Jason M. Billse855dd22019-10-08 11:37:48 -07002746
Johnathan Mantey043a0532020-03-10 17:15:28 -07002747 std::string timestamp{};
2748 std::string filename{};
2749 std::string logfile{};
Ed Tanous2c70f802020-09-28 14:29:23 -07002750 parseCrashdumpParameters(params, filename, timestamp, logfile);
Johnathan Mantey043a0532020-03-10 17:15:28 -07002751
2752 if (filename.empty() || timestamp.empty())
2753 {
Ed Tanousace85d62021-10-26 12:45:59 -07002754 messages::resourceMissingAtURI(
2755 asyncResp->res, crow::utility::urlFromPieces(logID));
Johnathan Mantey043a0532020-03-10 17:15:28 -07002756 return;
2757 }
2758
2759 std::string crashdumpURI =
2760 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" +
2761 logID + "/" + filename;
Jason M. Bills2b20ef62022-01-06 15:48:07 -08002762 nlohmann::json logEntry = {
Jason M. Bills4978b632022-02-22 14:17:43 -08002763 {"@odata.type", "#LogEntry.v1_7_0.LogEntry"},
2764 {"@odata.id",
2765 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" +
2766 logID},
2767 {"Name", "CPU Crashdump"},
2768 {"Id", logID},
2769 {"EntryType", "Oem"},
2770 {"AdditionalDataURI", std::move(crashdumpURI)},
2771 {"DiagnosticDataType", "OEM"},
2772 {"OEMDiagnosticDataType", "PECICrashdump"},
2773 {"Created", std::move(timestamp)}};
Jason M. Bills2b20ef62022-01-06 15:48:07 -08002774
2775 // If logEntryJson references an array of LogEntry resources
2776 // ('Members' list), then push this as a new entry, otherwise set it
2777 // directly
2778 if (logEntryJson.is_array())
2779 {
2780 logEntryJson.push_back(logEntry);
2781 asyncResp->res.jsonValue["Members@odata.count"] =
2782 logEntryJson.size();
2783 }
2784 else
2785 {
2786 logEntryJson = logEntry;
2787 }
Johnathan Mantey043a0532020-03-10 17:15:28 -07002788 };
Jason M. Billse855dd22019-10-08 11:37:48 -07002789 crow::connections::systemBus->async_method_call(
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07002790 std::move(getStoredLogCallback), crashdumpObject,
2791 crashdumpPath + std::string("/") + logID,
Johnathan Mantey043a0532020-03-10 17:15:28 -07002792 "org.freedesktop.DBus.Properties", "GetAll", crashdumpInterface);
Jason M. Billse855dd22019-10-08 11:37:48 -07002793}
2794
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002795inline void requestRoutesCrashdumpEntryCollection(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07002796{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002797 // Note: Deviated from redfish privilege registry for GET & HEAD
2798 // method for security reasons.
Ed Tanous1da66f72018-07-27 16:13:37 -07002799 /**
2800 * Functions triggers appropriate requests on DBus
2801 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002802 BMCWEB_ROUTE(app,
2803 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07002804 // This is incorrect, should be.
2805 //.privileges(redfish::privileges::postLogEntryCollection)
Ed Tanous432a8902021-06-14 15:28:56 -07002806 .privileges({{"ConfigureComponents"}})
Ed Tanous45ca1b82022-03-25 13:07:27 -07002807 .methods(boost::beast::http::verb::get)([&app](const crow::Request& req,
2808 const std::shared_ptr<
2809 bmcweb::AsyncResp>&
2810 asyncResp) {
2811 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2812 {
2813 return;
2814 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002815 crow::connections::systemBus->async_method_call(
Jason M. Bills2b20ef62022-01-06 15:48:07 -08002816 [asyncResp](const boost::system::error_code ec,
2817 const std::vector<std::string>& resp) {
2818 if (ec)
2819 {
2820 if (ec.value() !=
2821 boost::system::errc::no_such_file_or_directory)
2822 {
2823 BMCWEB_LOG_DEBUG << "failed to get entries ec: "
2824 << ec.message();
2825 messages::internalError(asyncResp->res);
2826 return;
2827 }
2828 }
2829 asyncResp->res.jsonValue["@odata.type"] =
2830 "#LogEntryCollection.LogEntryCollection";
2831 asyncResp->res.jsonValue["@odata.id"] =
2832 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries";
2833 asyncResp->res.jsonValue["Name"] =
2834 "Open BMC Crashdump Entries";
2835 asyncResp->res.jsonValue["Description"] =
2836 "Collection of Crashdump Entries";
2837 asyncResp->res.jsonValue["Members"] =
2838 nlohmann::json::array();
Brandon Kima2dd60a2022-03-14 11:42:34 -07002839 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Jason M. Bills2b20ef62022-01-06 15:48:07 -08002840
2841 for (const std::string& path : resp)
2842 {
2843 const sdbusplus::message::object_path objPath(path);
2844 // Get the log ID
2845 std::string logID = objPath.filename();
2846 if (logID.empty())
2847 {
2848 continue;
2849 }
2850 // Add the log entry to the array
2851 logCrashdumpEntry(asyncResp, logID,
2852 asyncResp->res.jsonValue["Members"]);
2853 }
2854 },
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002855 "xyz.openbmc_project.ObjectMapper",
2856 "/xyz/openbmc_project/object_mapper",
2857 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "", 0,
2858 std::array<const char*, 1>{crashdumpInterface});
2859 });
2860}
Ed Tanous1da66f72018-07-27 16:13:37 -07002861
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002862inline void requestRoutesCrashdumpEntry(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07002863{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002864 // Note: Deviated from redfish privilege registry for GET & HEAD
2865 // method for security reasons.
Ed Tanous1da66f72018-07-27 16:13:37 -07002866
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002867 BMCWEB_ROUTE(
2868 app, "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002869 // this is incorrect, should be
2870 // .privileges(redfish::privileges::getLogEntry)
Ed Tanous432a8902021-06-14 15:28:56 -07002871 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002872 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002873 [&app](const crow::Request& req,
2874 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2875 const std::string& param) {
2876 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2877 {
2878 return;
2879 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002880 const std::string& logID = param;
2881 logCrashdumpEntry(asyncResp, logID, asyncResp->res.jsonValue);
2882 });
2883}
Ed Tanous1da66f72018-07-27 16:13:37 -07002884
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002885inline void requestRoutesCrashdumpFile(App& app)
2886{
2887 // Note: Deviated from redfish privilege registry for GET & HEAD
2888 // method for security reasons.
2889 BMCWEB_ROUTE(
2890 app,
2891 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/<str>/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002892 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002893 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002894 [&app](const crow::Request& req,
2895 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2896 const std::string& logID, const std::string& fileName) {
2897 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2898 {
2899 return;
2900 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002901 auto getStoredLogCallback =
Ed Tanousace85d62021-10-26 12:45:59 -07002902 [asyncResp, logID, fileName,
2903 url(boost::urls::url(req.urlView))](
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002904 const boost::system::error_code ec,
Ed Tanous168e20c2021-12-13 14:39:53 -08002905 const std::vector<std::pair<
2906 std::string, dbus::utility::DbusVariantType>>&
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002907 resp) {
2908 if (ec)
2909 {
2910 BMCWEB_LOG_DEBUG << "failed to get log ec: "
2911 << ec.message();
2912 messages::internalError(asyncResp->res);
2913 return;
2914 }
Jason M. Bills8e6c0992021-03-11 16:26:53 -08002915
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002916 std::string dbusFilename{};
2917 std::string dbusTimestamp{};
2918 std::string dbusFilepath{};
Jason M. Bills8e6c0992021-03-11 16:26:53 -08002919
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002920 parseCrashdumpParameters(resp, dbusFilename,
2921 dbusTimestamp, dbusFilepath);
2922
2923 if (dbusFilename.empty() || dbusTimestamp.empty() ||
2924 dbusFilepath.empty())
2925 {
Ed Tanousace85d62021-10-26 12:45:59 -07002926 messages::resourceMissingAtURI(asyncResp->res, url);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002927 return;
2928 }
2929
2930 // Verify the file name parameter is correct
2931 if (fileName != dbusFilename)
2932 {
Ed Tanousace85d62021-10-26 12:45:59 -07002933 messages::resourceMissingAtURI(asyncResp->res, url);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002934 return;
2935 }
2936
2937 if (!std::filesystem::exists(dbusFilepath))
2938 {
Ed Tanousace85d62021-10-26 12:45:59 -07002939 messages::resourceMissingAtURI(asyncResp->res, url);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002940 return;
2941 }
Jason M. Bills2d314912022-01-12 13:59:01 -08002942 std::ifstream ifs(dbusFilepath,
2943 std::ios::in | std::ios::binary);
2944 asyncResp->res.body() = std::string(
2945 std::istreambuf_iterator<char>{ifs}, {});
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002946
2947 // Configure this to be a file download when accessed
2948 // from a browser
2949 asyncResp->res.addHeader("Content-Disposition",
2950 "attachment");
2951 };
2952 crow::connections::systemBus->async_method_call(
2953 std::move(getStoredLogCallback), crashdumpObject,
2954 crashdumpPath + std::string("/") + logID,
2955 "org.freedesktop.DBus.Properties", "GetAll",
2956 crashdumpInterface);
2957 });
2958}
2959
Jason M. Billsc5a4c822022-01-06 15:51:23 -08002960enum class OEMDiagnosticType
2961{
2962 onDemand,
2963 telemetry,
2964 invalid,
2965};
2966
Ed Tanousf7725d72022-03-07 12:46:00 -08002967inline OEMDiagnosticType
2968 getOEMDiagnosticType(const std::string_view& oemDiagStr)
Jason M. Billsc5a4c822022-01-06 15:51:23 -08002969{
2970 if (oemDiagStr == "OnDemand")
2971 {
2972 return OEMDiagnosticType::onDemand;
2973 }
2974 if (oemDiagStr == "Telemetry")
2975 {
2976 return OEMDiagnosticType::telemetry;
2977 }
2978
2979 return OEMDiagnosticType::invalid;
2980}
2981
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002982inline void requestRoutesCrashdumpCollect(App& app)
2983{
2984 // Note: Deviated from redfish privilege registry for GET & HEAD
2985 // method for security reasons.
George Liu0fda0f12021-11-16 10:06:17 +08002986 BMCWEB_ROUTE(
2987 app,
2988 "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07002989 // The below is incorrect; Should be ConfigureManager
2990 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07002991 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002992 .methods(
2993 boost::beast::http::verb::
Ed Tanous45ca1b82022-03-25 13:07:27 -07002994 post)([&app](
2995 const crow::Request& req,
2996 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2997 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2998 {
2999 return;
3000 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003001 std::string diagnosticDataType;
3002 std::string oemDiagnosticDataType;
Willy Tu15ed6782021-12-14 11:03:16 -08003003 if (!redfish::json_util::readJsonAction(
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003004 req, asyncResp->res, "DiagnosticDataType",
3005 diagnosticDataType, "OEMDiagnosticDataType",
3006 oemDiagnosticDataType))
James Feist46229572020-02-19 15:11:58 -08003007 {
James Feist46229572020-02-19 15:11:58 -08003008 return;
3009 }
Ed Tanous1da66f72018-07-27 16:13:37 -07003010
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003011 if (diagnosticDataType != "OEM")
3012 {
3013 BMCWEB_LOG_ERROR
3014 << "Only OEM DiagnosticDataType supported for Crashdump";
3015 messages::actionParameterValueFormatError(
3016 asyncResp->res, diagnosticDataType, "DiagnosticDataType",
3017 "CollectDiagnosticData");
3018 return;
3019 }
3020
Jason M. Billsc5a4c822022-01-06 15:51:23 -08003021 OEMDiagnosticType oemDiagType =
3022 getOEMDiagnosticType(oemDiagnosticDataType);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003023
Jason M. Billsc5a4c822022-01-06 15:51:23 -08003024 std::string iface;
3025 std::string method;
3026 std::string taskMatchStr;
3027 if (oemDiagType == OEMDiagnosticType::onDemand)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003028 {
Jason M. Billsc5a4c822022-01-06 15:51:23 -08003029 iface = crashdumpOnDemandInterface;
3030 method = "GenerateOnDemandLog";
3031 taskMatchStr = "type='signal',"
3032 "interface='org.freedesktop.DBus.Properties',"
3033 "member='PropertiesChanged',"
3034 "arg0namespace='com.intel.crashdump'";
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003035 }
Jason M. Billsc5a4c822022-01-06 15:51:23 -08003036 else if (oemDiagType == OEMDiagnosticType::telemetry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003037 {
Jason M. Billsc5a4c822022-01-06 15:51:23 -08003038 iface = crashdumpTelemetryInterface;
3039 method = "GenerateTelemetryLog";
3040 taskMatchStr = "type='signal',"
3041 "interface='org.freedesktop.DBus.Properties',"
3042 "member='PropertiesChanged',"
3043 "arg0namespace='com.intel.crashdump'";
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003044 }
3045 else
3046 {
3047 BMCWEB_LOG_ERROR << "Unsupported OEMDiagnosticDataType: "
3048 << oemDiagnosticDataType;
3049 messages::actionParameterValueFormatError(
3050 asyncResp->res, oemDiagnosticDataType,
3051 "OEMDiagnosticDataType", "CollectDiagnosticData");
3052 return;
3053 }
Jason M. Billsc5a4c822022-01-06 15:51:23 -08003054
3055 auto collectCrashdumpCallback =
3056 [asyncResp, payload(task::Payload(req)),
3057 taskMatchStr](const boost::system::error_code ec,
3058 const std::string&) mutable {
3059 if (ec)
3060 {
3061 if (ec.value() ==
3062 boost::system::errc::operation_not_supported)
3063 {
3064 messages::resourceInStandby(asyncResp->res);
3065 }
3066 else if (ec.value() ==
3067 boost::system::errc::device_or_resource_busy)
3068 {
3069 messages::serviceTemporarilyUnavailable(
3070 asyncResp->res, "60");
3071 }
3072 else
3073 {
3074 messages::internalError(asyncResp->res);
3075 }
3076 return;
3077 }
3078 std::shared_ptr<task::TaskData> task =
3079 task::TaskData::createTask(
3080 [](boost::system::error_code err,
3081 sdbusplus::message::message&,
3082 const std::shared_ptr<task::TaskData>&
3083 taskData) {
3084 if (!err)
3085 {
3086 taskData->messages.emplace_back(
3087 messages::taskCompletedOK(
3088 std::to_string(taskData->index)));
3089 taskData->state = "Completed";
3090 }
3091 return task::completed;
3092 },
3093 taskMatchStr);
3094
3095 task->startTimer(std::chrono::minutes(5));
3096 task->populateResp(asyncResp->res);
3097 task->payload.emplace(std::move(payload));
3098 };
3099
3100 crow::connections::systemBus->async_method_call(
3101 std::move(collectCrashdumpCallback), crashdumpObject,
3102 crashdumpPath, iface, method);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003103 });
3104}
Kenny L. Ku6eda7682020-06-19 09:48:36 -07003105
Andrew Geisslercb92c032018-08-17 07:56:14 -07003106/**
3107 * DBusLogServiceActionsClear class supports POST method for ClearLog action.
3108 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003109inline void requestRoutesDBusLogServiceActionsClear(App& app)
Andrew Geisslercb92c032018-08-17 07:56:14 -07003110{
Andrew Geisslercb92c032018-08-17 07:56:14 -07003111 /**
3112 * Function handles POST method request.
3113 * The Clear Log actions does not require any parameter.The action deletes
3114 * all entries found in the Entries collection for this Log Service.
3115 */
Andrew Geisslercb92c032018-08-17 07:56:14 -07003116
George Liu0fda0f12021-11-16 10:06:17 +08003117 BMCWEB_ROUTE(
3118 app,
3119 "/redfish/v1/Systems/system/LogServices/EventLog/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07003120 .privileges(redfish::privileges::postLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003121 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003122 [&app](const crow::Request& req,
3123 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
3124 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
3125 {
3126 return;
3127 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003128 BMCWEB_LOG_DEBUG << "Do delete all entries.";
Andrew Geisslercb92c032018-08-17 07:56:14 -07003129
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003130 // Process response from Logging service.
3131 auto respHandler = [asyncResp](
3132 const boost::system::error_code ec) {
3133 BMCWEB_LOG_DEBUG
3134 << "doClearLog resp_handler callback: Done";
3135 if (ec)
3136 {
3137 // TODO Handle for specific error code
3138 BMCWEB_LOG_ERROR << "doClearLog resp_handler got error "
3139 << ec;
3140 asyncResp->res.result(
3141 boost::beast::http::status::internal_server_error);
3142 return;
3143 }
Andrew Geisslercb92c032018-08-17 07:56:14 -07003144
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003145 asyncResp->res.result(
3146 boost::beast::http::status::no_content);
3147 };
3148
3149 // Make call to Logging service to request Clear Log
3150 crow::connections::systemBus->async_method_call(
3151 respHandler, "xyz.openbmc_project.Logging",
3152 "/xyz/openbmc_project/logging",
3153 "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
3154 });
3155}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003156
3157/****************************************************
3158 * Redfish PostCode interfaces
3159 * using DBUS interface: getPostCodesTS
3160 ******************************************************/
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003161inline void requestRoutesPostCodesLogService(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003162{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003163 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/PostCodes/")
Ed Tanoused398212021-06-09 17:05:54 -07003164 .privileges(redfish::privileges::getLogService)
Ed Tanous45ca1b82022-03-25 13:07:27 -07003165 .methods(boost::beast::http::verb::get)([&app](const crow::Request& req,
3166 const std::shared_ptr<
3167 bmcweb::AsyncResp>&
3168 asyncResp) {
3169 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
3170 {
3171 return;
3172 }
George Liu0fda0f12021-11-16 10:06:17 +08003173 asyncResp->res.jsonValue = {
3174 {"@odata.id",
3175 "/redfish/v1/Systems/system/LogServices/PostCodes"},
3176 {"@odata.type", "#LogService.v1_1_0.LogService"},
3177 {"Name", "POST Code Log Service"},
3178 {"Description", "POST Code Log Service"},
3179 {"Id", "BIOS POST Code Log"},
3180 {"OverWritePolicy", "WrapsWhenFull"},
3181 {"Entries",
3182 {{"@odata.id",
3183 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries"}}}};
Tejas Patil7c8c4052021-06-04 17:43:14 +05303184
George Liu0fda0f12021-11-16 10:06:17 +08003185 std::pair<std::string, std::string> redfishDateTimeOffset =
3186 crow::utility::getDateTimeOffsetNow();
3187 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
3188 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
3189 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05303190
George Liu0fda0f12021-11-16 10:06:17 +08003191 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = {
3192 {"target",
3193 "/redfish/v1/Systems/system/LogServices/PostCodes/Actions/LogService.ClearLog"}};
3194 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003195}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003196
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003197inline void requestRoutesPostCodesClear(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003198{
George Liu0fda0f12021-11-16 10:06:17 +08003199 BMCWEB_ROUTE(
3200 app,
3201 "/redfish/v1/Systems/system/LogServices/PostCodes/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07003202 // The following privilege is incorrect; It should be ConfigureManager
3203 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07003204 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003205 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003206 [&app](const crow::Request& req,
3207 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
3208 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
3209 {
3210 return;
3211 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003212 BMCWEB_LOG_DEBUG << "Do delete all postcodes entries.";
ZhikuiRena3316fc2020-01-29 14:58:08 -08003213
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003214 // Make call to post-code service to request clear all
3215 crow::connections::systemBus->async_method_call(
3216 [asyncResp](const boost::system::error_code ec) {
3217 if (ec)
3218 {
3219 // TODO Handle for specific error code
3220 BMCWEB_LOG_ERROR
3221 << "doClearPostCodes resp_handler got error "
3222 << ec;
3223 asyncResp->res.result(boost::beast::http::status::
3224 internal_server_error);
3225 messages::internalError(asyncResp->res);
3226 return;
3227 }
3228 },
3229 "xyz.openbmc_project.State.Boot.PostCode0",
3230 "/xyz/openbmc_project/State/Boot/PostCode0",
3231 "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
3232 });
3233}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003234
3235static void fillPostCodeEntry(
zhanghch058d1b46d2021-04-01 11:18:24 +08003236 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303237 const boost::container::flat_map<
3238 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& postcode,
ZhikuiRena3316fc2020-01-29 14:58:08 -08003239 const uint16_t bootIndex, const uint64_t codeIndex = 0,
3240 const uint64_t skip = 0, const uint64_t top = 0)
3241{
3242 // Get the Message from the MessageRegistry
Ed Tanousfffb8c12022-02-07 23:53:03 -08003243 const registries::Message* message =
3244 registries::getMessage("OpenBMC.0.2.BIOSPOSTCode");
ZhikuiRena3316fc2020-01-29 14:58:08 -08003245
3246 uint64_t currentCodeIndex = 0;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003247 nlohmann::json& logEntryArray = aResp->res.jsonValue["Members"];
ZhikuiRena3316fc2020-01-29 14:58:08 -08003248
3249 uint64_t firstCodeTimeUs = 0;
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303250 for (const std::pair<uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
3251 code : postcode)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003252 {
3253 currentCodeIndex++;
3254 std::string postcodeEntryID =
3255 "B" + std::to_string(bootIndex) + "-" +
3256 std::to_string(currentCodeIndex); // 1 based index in EntryID string
3257
3258 uint64_t usecSinceEpoch = code.first;
3259 uint64_t usTimeOffset = 0;
3260
3261 if (1 == currentCodeIndex)
3262 { // already incremented
3263 firstCodeTimeUs = code.first;
3264 }
3265 else
3266 {
3267 usTimeOffset = code.first - firstCodeTimeUs;
3268 }
3269
3270 // skip if no specific codeIndex is specified and currentCodeIndex does
3271 // not fall between top and skip
3272 if ((codeIndex == 0) &&
3273 (currentCodeIndex <= skip || currentCodeIndex > top))
3274 {
3275 continue;
3276 }
3277
Gunnar Mills4e0453b2020-07-08 14:00:30 -05003278 // skip if a specific codeIndex is specified and does not match the
ZhikuiRena3316fc2020-01-29 14:58:08 -08003279 // currentIndex
3280 if ((codeIndex > 0) && (currentCodeIndex != codeIndex))
3281 {
3282 // This is done for simplicity. 1st entry is needed to calculate
3283 // time offset. To improve efficiency, one can get to the entry
3284 // directly (possibly with flatmap's nth method)
3285 continue;
3286 }
3287
3288 // currentCodeIndex is within top and skip or equal to specified code
3289 // index
3290
3291 // Get the Created time from the timestamp
3292 std::string entryTimeStr;
Nan Zhou1d8782e2021-11-29 22:23:18 -08003293 entryTimeStr =
3294 crow::utility::getDateTimeUint(usecSinceEpoch / 1000 / 1000);
ZhikuiRena3316fc2020-01-29 14:58:08 -08003295
3296 // assemble messageArgs: BootIndex, TimeOffset(100us), PostCode(hex)
3297 std::ostringstream hexCode;
3298 hexCode << "0x" << std::setfill('0') << std::setw(2) << std::hex
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303299 << std::get<0>(code.second);
ZhikuiRena3316fc2020-01-29 14:58:08 -08003300 std::ostringstream timeOffsetStr;
3301 // Set Fixed -Point Notation
3302 timeOffsetStr << std::fixed;
3303 // Set precision to 4 digits
3304 timeOffsetStr << std::setprecision(4);
3305 // Add double to stream
3306 timeOffsetStr << static_cast<double>(usTimeOffset) / 1000 / 1000;
3307 std::vector<std::string> messageArgs = {
3308 std::to_string(bootIndex), timeOffsetStr.str(), hexCode.str()};
3309
3310 // Get MessageArgs template from message registry
3311 std::string msg;
3312 if (message != nullptr)
3313 {
3314 msg = message->message;
3315
3316 // fill in this post code value
3317 int i = 0;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003318 for (const std::string& messageArg : messageArgs)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003319 {
3320 std::string argStr = "%" + std::to_string(++i);
3321 size_t argPos = msg.find(argStr);
3322 if (argPos != std::string::npos)
3323 {
3324 msg.replace(argPos, argStr.length(), messageArg);
3325 }
3326 }
3327 }
3328
Tim Leed4342a92020-04-27 11:47:58 +08003329 // Get Severity template from message registry
3330 std::string severity;
3331 if (message != nullptr)
3332 {
Ed Tanous5f2b84e2022-02-08 00:41:53 -08003333 severity = message->messageSeverity;
Tim Leed4342a92020-04-27 11:47:58 +08003334 }
3335
ZhikuiRena3316fc2020-01-29 14:58:08 -08003336 // add to AsyncResp
3337 logEntryArray.push_back({});
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003338 nlohmann::json& bmcLogEntry = logEntryArray.back();
George Liu0fda0f12021-11-16 10:06:17 +08003339 bmcLogEntry = {
3340 {"@odata.type", "#LogEntry.v1_8_0.LogEntry"},
3341 {"@odata.id",
3342 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/" +
3343 postcodeEntryID},
3344 {"Name", "POST Code Log Entry"},
3345 {"Id", postcodeEntryID},
3346 {"Message", std::move(msg)},
3347 {"MessageId", "OpenBMC.0.2.BIOSPOSTCode"},
3348 {"MessageArgs", std::move(messageArgs)},
3349 {"EntryType", "Event"},
3350 {"Severity", std::move(severity)},
3351 {"Created", entryTimeStr}};
George Liu647b3cd2021-07-05 12:43:56 +08003352 if (!std::get<std::vector<uint8_t>>(code.second).empty())
3353 {
3354 bmcLogEntry["AdditionalDataURI"] =
3355 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/" +
3356 postcodeEntryID + "/attachment";
3357 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003358 }
3359}
3360
zhanghch058d1b46d2021-04-01 11:18:24 +08003361static void getPostCodeForEntry(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
ZhikuiRena3316fc2020-01-29 14:58:08 -08003362 const uint16_t bootIndex,
3363 const uint64_t codeIndex)
3364{
3365 crow::connections::systemBus->async_method_call(
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303366 [aResp, bootIndex,
3367 codeIndex](const boost::system::error_code ec,
3368 const boost::container::flat_map<
3369 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
3370 postcode) {
ZhikuiRena3316fc2020-01-29 14:58:08 -08003371 if (ec)
3372 {
3373 BMCWEB_LOG_DEBUG << "DBUS POST CODE PostCode response error";
3374 messages::internalError(aResp->res);
3375 return;
3376 }
3377
3378 // skip the empty postcode boots
3379 if (postcode.empty())
3380 {
3381 return;
3382 }
3383
3384 fillPostCodeEntry(aResp, postcode, bootIndex, codeIndex);
3385
3386 aResp->res.jsonValue["Members@odata.count"] =
3387 aResp->res.jsonValue["Members"].size();
3388 },
Jonathan Doman15124762021-01-07 17:54:17 -08003389 "xyz.openbmc_project.State.Boot.PostCode0",
3390 "/xyz/openbmc_project/State/Boot/PostCode0",
ZhikuiRena3316fc2020-01-29 14:58:08 -08003391 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
3392 bootIndex);
3393}
3394
zhanghch058d1b46d2021-04-01 11:18:24 +08003395static void getPostCodeForBoot(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
ZhikuiRena3316fc2020-01-29 14:58:08 -08003396 const uint16_t bootIndex,
3397 const uint16_t bootCount,
3398 const uint64_t entryCount, const uint64_t skip,
3399 const uint64_t top)
3400{
3401 crow::connections::systemBus->async_method_call(
3402 [aResp, bootIndex, bootCount, entryCount, skip,
3403 top](const boost::system::error_code ec,
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303404 const boost::container::flat_map<
3405 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
3406 postcode) {
ZhikuiRena3316fc2020-01-29 14:58:08 -08003407 if (ec)
3408 {
3409 BMCWEB_LOG_DEBUG << "DBUS POST CODE PostCode response error";
3410 messages::internalError(aResp->res);
3411 return;
3412 }
3413
3414 uint64_t endCount = entryCount;
3415 if (!postcode.empty())
3416 {
3417 endCount = entryCount + postcode.size();
3418
3419 if ((skip < endCount) && ((top + skip) > entryCount))
3420 {
3421 uint64_t thisBootSkip =
3422 std::max(skip, entryCount) - entryCount;
3423 uint64_t thisBootTop =
3424 std::min(top + skip, endCount) - entryCount;
3425
3426 fillPostCodeEntry(aResp, postcode, bootIndex, 0,
3427 thisBootSkip, thisBootTop);
3428 }
3429 aResp->res.jsonValue["Members@odata.count"] = endCount;
3430 }
3431
3432 // continue to previous bootIndex
3433 if (bootIndex < bootCount)
3434 {
3435 getPostCodeForBoot(aResp, static_cast<uint16_t>(bootIndex + 1),
3436 bootCount, endCount, skip, top);
3437 }
3438 else
3439 {
3440 aResp->res.jsonValue["Members@odata.nextLink"] =
George Liu0fda0f12021-11-16 10:06:17 +08003441 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries?$skip=" +
ZhikuiRena3316fc2020-01-29 14:58:08 -08003442 std::to_string(skip + top);
3443 }
3444 },
Jonathan Doman15124762021-01-07 17:54:17 -08003445 "xyz.openbmc_project.State.Boot.PostCode0",
3446 "/xyz/openbmc_project/State/Boot/PostCode0",
ZhikuiRena3316fc2020-01-29 14:58:08 -08003447 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
3448 bootIndex);
3449}
3450
zhanghch058d1b46d2021-04-01 11:18:24 +08003451static void
3452 getCurrentBootNumber(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
3453 const uint64_t skip, const uint64_t top)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003454{
3455 uint64_t entryCount = 0;
Jonathan Doman1e1e5982021-06-11 09:36:17 -07003456 sdbusplus::asio::getProperty<uint16_t>(
3457 *crow::connections::systemBus,
3458 "xyz.openbmc_project.State.Boot.PostCode0",
3459 "/xyz/openbmc_project/State/Boot/PostCode0",
3460 "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount",
3461 [aResp, entryCount, skip, top](const boost::system::error_code ec,
3462 const uint16_t bootCount) {
ZhikuiRena3316fc2020-01-29 14:58:08 -08003463 if (ec)
3464 {
3465 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
3466 messages::internalError(aResp->res);
3467 return;
3468 }
Jonathan Doman1e1e5982021-06-11 09:36:17 -07003469 getPostCodeForBoot(aResp, 1, bootCount, entryCount, skip, top);
3470 });
ZhikuiRena3316fc2020-01-29 14:58:08 -08003471}
3472
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003473inline void requestRoutesPostCodesEntryCollection(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003474{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003475 BMCWEB_ROUTE(app,
3476 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07003477 .privileges(redfish::privileges::getLogEntryCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003478 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003479 [&app](const crow::Request& req,
3480 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
3481 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
3482 {
3483 return;
3484 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003485 asyncResp->res.jsonValue["@odata.type"] =
3486 "#LogEntryCollection.LogEntryCollection";
3487 asyncResp->res.jsonValue["@odata.id"] =
3488 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries";
3489 asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries";
3490 asyncResp->res.jsonValue["Description"] =
3491 "Collection of POST Code Log Entries";
3492 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
3493 asyncResp->res.jsonValue["Members@odata.count"] = 0;
ZhikuiRena3316fc2020-01-29 14:58:08 -08003494
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003495 uint64_t skip = 0;
3496 uint64_t top = maxEntriesPerPage; // Show max entries by default
3497 if (!getSkipParam(asyncResp, req, skip))
3498 {
3499 return;
3500 }
3501 if (!getTopParam(asyncResp, req, top))
3502 {
3503 return;
3504 }
3505 getCurrentBootNumber(asyncResp, skip, top);
3506 });
3507}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003508
George Liu647b3cd2021-07-05 12:43:56 +08003509/**
3510 * @brief Parse post code ID and get the current value and index value
3511 * eg: postCodeID=B1-2, currentValue=1, index=2
3512 *
3513 * @param[in] postCodeID Post Code ID
3514 * @param[out] currentValue Current value
3515 * @param[out] index Index value
3516 *
3517 * @return bool true if the parsing is successful, false the parsing fails
3518 */
3519inline static bool parsePostCode(const std::string& postCodeID,
3520 uint64_t& currentValue, uint16_t& index)
3521{
3522 std::vector<std::string> split;
3523 boost::algorithm::split(split, postCodeID, boost::is_any_of("-"));
3524 if (split.size() != 2 || split[0].length() < 2 || split[0].front() != 'B')
3525 {
3526 return false;
3527 }
3528
Ed Tanousca45aa32022-01-07 09:28:45 -08003529 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
George Liu647b3cd2021-07-05 12:43:56 +08003530 const char* start = split[0].data() + 1;
Ed Tanousca45aa32022-01-07 09:28:45 -08003531 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
George Liu647b3cd2021-07-05 12:43:56 +08003532 const char* end = split[0].data() + split[0].size();
3533 auto [ptrIndex, ecIndex] = std::from_chars(start, end, index);
3534
3535 if (ptrIndex != end || ecIndex != std::errc())
3536 {
3537 return false;
3538 }
3539
3540 start = split[1].data();
Ed Tanousca45aa32022-01-07 09:28:45 -08003541
3542 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
George Liu647b3cd2021-07-05 12:43:56 +08003543 end = split[1].data() + split[1].size();
3544 auto [ptrValue, ecValue] = std::from_chars(start, end, currentValue);
George Liu647b3cd2021-07-05 12:43:56 +08003545
Ed Tanousdcf2ebc2022-01-25 10:07:45 -08003546 return ptrValue == end && ecValue != std::errc();
George Liu647b3cd2021-07-05 12:43:56 +08003547}
3548
3549inline void requestRoutesPostCodesEntryAdditionalData(App& app)
3550{
George Liu0fda0f12021-11-16 10:06:17 +08003551 BMCWEB_ROUTE(
3552 app,
3553 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/<str>/attachment/")
George Liu647b3cd2021-07-05 12:43:56 +08003554 .privileges(redfish::privileges::getLogEntry)
3555 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003556 [&app](const crow::Request& req,
3557 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3558 const std::string& postCodeID) {
3559 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
3560 {
3561 return;
3562 }
George Liu647b3cd2021-07-05 12:43:56 +08003563 if (!http_helpers::isOctetAccepted(
3564 req.getHeaderValue("Accept")))
3565 {
3566 asyncResp->res.result(
3567 boost::beast::http::status::bad_request);
3568 return;
3569 }
3570
3571 uint64_t currentValue = 0;
3572 uint16_t index = 0;
3573 if (!parsePostCode(postCodeID, currentValue, index))
3574 {
3575 messages::resourceNotFound(asyncResp->res, "LogEntry",
3576 postCodeID);
3577 return;
3578 }
3579
3580 crow::connections::systemBus->async_method_call(
3581 [asyncResp, postCodeID, currentValue](
3582 const boost::system::error_code ec,
3583 const std::vector<std::tuple<
3584 uint64_t, std::vector<uint8_t>>>& postcodes) {
3585 if (ec.value() == EBADR)
3586 {
3587 messages::resourceNotFound(asyncResp->res,
3588 "LogEntry", postCodeID);
3589 return;
3590 }
3591 if (ec)
3592 {
3593 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
3594 messages::internalError(asyncResp->res);
3595 return;
3596 }
3597
3598 size_t value = static_cast<size_t>(currentValue) - 1;
3599 if (value == std::string::npos ||
3600 postcodes.size() < currentValue)
3601 {
3602 BMCWEB_LOG_ERROR << "Wrong currentValue value";
3603 messages::resourceNotFound(asyncResp->res,
3604 "LogEntry", postCodeID);
3605 return;
3606 }
3607
Ed Tanous9eb808c2022-01-25 10:19:23 -08003608 const auto& [tID, c] = postcodes[value];
Ed Tanous46ff87b2022-01-07 09:25:51 -08003609 if (c.empty())
George Liu647b3cd2021-07-05 12:43:56 +08003610 {
3611 BMCWEB_LOG_INFO << "No found post code data";
3612 messages::resourceNotFound(asyncResp->res,
3613 "LogEntry", postCodeID);
3614 return;
3615 }
Ed Tanous46ff87b2022-01-07 09:25:51 -08003616 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
3617 const char* d = reinterpret_cast<const char*>(c.data());
3618 std::string_view strData(d, c.size());
George Liu647b3cd2021-07-05 12:43:56 +08003619
3620 asyncResp->res.addHeader("Content-Type",
3621 "application/octet-stream");
3622 asyncResp->res.addHeader("Content-Transfer-Encoding",
3623 "Base64");
3624 asyncResp->res.body() =
3625 crow::utility::base64encode(strData);
3626 },
3627 "xyz.openbmc_project.State.Boot.PostCode0",
3628 "/xyz/openbmc_project/State/Boot/PostCode0",
3629 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodes",
3630 index);
3631 });
3632}
3633
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003634inline void requestRoutesPostCodesEntry(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003635{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003636 BMCWEB_ROUTE(
3637 app, "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003638 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003639 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003640 [&app](const crow::Request& req,
3641 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3642 const std::string& targetID) {
3643 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
3644 {
3645 return;
3646 }
George Liu647b3cd2021-07-05 12:43:56 +08003647 uint16_t bootIndex = 0;
3648 uint64_t codeIndex = 0;
3649 if (!parsePostCode(targetID, codeIndex, bootIndex))
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003650 {
3651 // Requested ID was not found
Ed Tanousace85d62021-10-26 12:45:59 -07003652 messages::resourceMissingAtURI(asyncResp->res, req.urlView);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003653 return;
3654 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003655 if (bootIndex == 0 || codeIndex == 0)
3656 {
3657 BMCWEB_LOG_DEBUG << "Get Post Code invalid entry string "
3658 << targetID;
3659 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003660
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003661 asyncResp->res.jsonValue["@odata.type"] =
3662 "#LogEntry.v1_4_0.LogEntry";
3663 asyncResp->res.jsonValue["@odata.id"] =
George Liu0fda0f12021-11-16 10:06:17 +08003664 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries";
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003665 asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries";
3666 asyncResp->res.jsonValue["Description"] =
3667 "Collection of POST Code Log Entries";
3668 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
3669 asyncResp->res.jsonValue["Members@odata.count"] = 0;
ZhikuiRena3316fc2020-01-29 14:58:08 -08003670
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003671 getPostCodeForEntry(asyncResp, bootIndex, codeIndex);
3672 });
3673}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003674
Ed Tanous1da66f72018-07-27 16:13:37 -07003675} // namespace redfish