blob: da2d1b55ad605bb33fccb995f6cf3187f9aaec27 [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
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080018#include "app.hpp"
George Liu7a1dbc42022-12-07 16:03:22 +080019#include "dbus_utility.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080020#include "error_messages.hpp"
Asmitha Karunanithi68dd0752022-11-15 11:33:46 -060021#include "generated/enums/log_entry.hpp"
Spencer Kub7028eb2021-10-26 15:27:35 +080022#include "gzfile.hpp"
George Liu647b3cd2021-07-05 12:43:56 +080023#include "http_utility.hpp"
Spencer Kub7028eb2021-10-26 15:27:35 +080024#include "human_sort.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080025#include "query.hpp"
Jason M. Bills4851d452019-03-28 11:27:48 -070026#include "registries.hpp"
27#include "registries/base_message_registry.hpp"
28#include "registries/openbmc_message_registry.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080029#include "registries/privilege_registry.hpp"
James Feist46229572020-02-19 15:11:58 -080030#include "task.hpp"
Ed Tanous5b904292024-04-16 11:10:17 -070031#include "task_messages.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080032#include "utils/dbus_utils.hpp"
Ed Tanous5b904292024-04-16 11:10:17 -070033#include "utils/json_utils.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080034#include "utils/time_utils.hpp"
Ed Tanous1da66f72018-07-27 16:13:37 -070035
Myung Bae75e8e212023-11-30 12:53:46 -080036#include <systemd/sd-id128.h>
Jason M. Billse1f26342018-07-18 12:12:00 -070037#include <systemd/sd-journal.h>
Asmitha Karunanithi8e317782020-12-10 03:35:05 -060038#include <tinyxml2.h>
Adriana Kobylak400fd1f2021-01-29 09:01:30 -060039#include <unistd.h>
Jason M. Billse1f26342018-07-18 12:12:00 -070040
Ed Tanous07c8c202022-07-11 10:08:08 -070041#include <boost/beast/http/verb.hpp>
Ed Tanous1da66f72018-07-27 16:13:37 -070042#include <boost/container/flat_map.hpp>
Jason M. Bills1ddcf012019-11-26 14:59:21 -080043#include <boost/system/linux_error.hpp>
Ed Tanousef4c65b2023-04-24 15:28:50 -070044#include <boost/url/format.hpp>
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +020045#include <sdbusplus/asio/property.hpp>
46#include <sdbusplus/unpack_properties.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050047
George Liu7a1dbc42022-12-07 16:03:22 +080048#include <array>
George Liu647b3cd2021-07-05 12:43:56 +080049#include <charconv>
Abhilash Rajub5f288d2023-11-08 22:32:44 -060050#include <cstddef>
James Feist4418c7f2019-04-15 11:09:15 -070051#include <filesystem>
Ed Tanous18f8f602023-07-18 10:07:23 -070052#include <iterator>
Xiaochao Ma75710de2021-01-21 17:56:02 +080053#include <optional>
Ed Tanous3544d2a2023-08-06 18:12:20 -070054#include <ranges>
Ed Tanous26702d02021-11-03 15:02:33 -070055#include <span>
Ed Tanous18f8f602023-07-18 10:07:23 -070056#include <string>
Jason M. Billscd225da2019-05-08 15:31:57 -070057#include <string_view>
Ed Tanousabf2add2019-01-22 16:40:12 -080058#include <variant>
Ed Tanous1da66f72018-07-27 16:13:37 -070059
60namespace redfish
61{
62
Patrick Williams89492a12023-05-10 07:51:34 -050063constexpr const char* crashdumpObject = "com.intel.crashdump";
64constexpr const char* crashdumpPath = "/com/intel/crashdump";
65constexpr const char* crashdumpInterface = "com.intel.crashdump";
66constexpr const char* deleteAllInterface =
Jason M. Bills5b61b5e2019-10-16 10:59:02 -070067 "xyz.openbmc_project.Collection.DeleteAll";
Patrick Williams89492a12023-05-10 07:51:34 -050068constexpr const char* crashdumpOnDemandInterface =
Jason M. Bills424c4172019-03-21 13:50:33 -070069 "com.intel.crashdump.OnDemand";
Patrick Williams89492a12023-05-10 07:51:34 -050070constexpr const char* crashdumpTelemetryInterface =
Kenny L. Ku6eda7682020-06-19 09:48:36 -070071 "com.intel.crashdump.Telemetry";
Ed Tanous1da66f72018-07-27 16:13:37 -070072
Asmitha Karunanithi8e317782020-12-10 03:35:05 -060073enum class DumpCreationProgress
74{
75 DUMP_CREATE_SUCCESS,
76 DUMP_CREATE_FAILED,
77 DUMP_CREATE_INPROGRESS
78};
79
James Feistf6150402019-01-08 10:36:20 -080080namespace fs = std::filesystem;
Ed Tanous1da66f72018-07-27 16:13:37 -070081
Gunnar Mills1214b7e2020-06-04 10:11:30 -050082inline std::string translateSeverityDbusToRedfish(const std::string& s)
Andrew Geisslercb92c032018-08-17 07:56:14 -070083{
Ed Tanousd4d25792020-09-29 15:15:03 -070084 if ((s == "xyz.openbmc_project.Logging.Entry.Level.Alert") ||
85 (s == "xyz.openbmc_project.Logging.Entry.Level.Critical") ||
86 (s == "xyz.openbmc_project.Logging.Entry.Level.Emergency") ||
87 (s == "xyz.openbmc_project.Logging.Entry.Level.Error"))
Andrew Geisslercb92c032018-08-17 07:56:14 -070088 {
89 return "Critical";
90 }
Ed Tanous3174e4d2020-10-07 11:41:22 -070091 if ((s == "xyz.openbmc_project.Logging.Entry.Level.Debug") ||
92 (s == "xyz.openbmc_project.Logging.Entry.Level.Informational") ||
93 (s == "xyz.openbmc_project.Logging.Entry.Level.Notice"))
Andrew Geisslercb92c032018-08-17 07:56:14 -070094 {
95 return "OK";
96 }
Ed Tanous3174e4d2020-10-07 11:41:22 -070097 if (s == "xyz.openbmc_project.Logging.Entry.Level.Warning")
Andrew Geisslercb92c032018-08-17 07:56:14 -070098 {
99 return "Warning";
100 }
101 return "";
102}
103
Abhishek Patel9017faf2021-09-14 22:48:55 -0500104inline std::optional<bool> getProviderNotifyAction(const std::string& notify)
105{
106 std::optional<bool> notifyAction;
107 if (notify == "xyz.openbmc_project.Logging.Entry.Notify.Notify")
108 {
109 notifyAction = true;
110 }
111 else if (notify == "xyz.openbmc_project.Logging.Entry.Notify.Inhibit")
112 {
113 notifyAction = false;
114 }
115
116 return notifyAction;
117}
118
Ed Tanous18f8f602023-07-18 10:07:23 -0700119inline std::string getDumpPath(std::string_view dumpType)
120{
121 std::string dbusDumpPath = "/xyz/openbmc_project/dump/";
122 std::ranges::transform(dumpType, std::back_inserter(dbusDumpPath),
123 bmcweb::asciiToLower);
124
125 return dbusDumpPath;
126}
127
Ed Tanousdf254f22024-04-01 13:25:46 -0700128inline int getJournalMetadata(sd_journal* journal, std::string_view field,
129 std::string_view& contents)
Jason M. Bills16428a12018-11-02 12:42:29 -0700130{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500131 const char* data = nullptr;
Jason M. Bills16428a12018-11-02 12:42:29 -0700132 size_t length = 0;
133 int ret = 0;
134 // Get the metadata from the requested field of the journal entry
Ed Tanous46ff87b2022-01-07 09:25:51 -0800135 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
136 const void** dataVoid = reinterpret_cast<const void**>(&data);
137
138 ret = sd_journal_get_data(journal, field.data(), dataVoid, &length);
Jason M. Bills16428a12018-11-02 12:42:29 -0700139 if (ret < 0)
140 {
141 return ret;
142 }
Ed Tanous39e77502019-03-04 17:35:53 -0800143 contents = std::string_view(data, length);
Jason M. Bills16428a12018-11-02 12:42:29 -0700144 // Only use the content after the "=" character.
Ed Tanous81ce6092020-12-17 16:54:55 +0000145 contents.remove_prefix(std::min(contents.find('=') + 1, contents.size()));
Jason M. Bills16428a12018-11-02 12:42:29 -0700146 return ret;
147}
148
Ed Tanousdf254f22024-04-01 13:25:46 -0700149inline int getJournalMetadata(sd_journal* journal, std::string_view field,
150 const int& base, long int& contents)
Jason M. Bills16428a12018-11-02 12:42:29 -0700151{
152 int ret = 0;
Ed Tanous39e77502019-03-04 17:35:53 -0800153 std::string_view metadata;
Jason M. Bills16428a12018-11-02 12:42:29 -0700154 // Get the metadata from the requested field of the journal entry
155 ret = getJournalMetadata(journal, field, metadata);
156 if (ret < 0)
157 {
158 return ret;
159 }
Ed Tanousb01bf292019-03-25 19:25:26 +0000160 contents = strtol(metadata.data(), nullptr, base);
Jason M. Bills16428a12018-11-02 12:42:29 -0700161 return ret;
162}
163
Ed Tanousdf254f22024-04-01 13:25:46 -0700164inline bool getEntryTimestamp(sd_journal* journal, std::string& entryTimestamp)
ZhikuiRena3316fc2020-01-29 14:58:08 -0800165{
166 int ret = 0;
167 uint64_t timestamp = 0;
168 ret = sd_journal_get_realtime_usec(journal, &timestamp);
169 if (ret < 0)
170 {
Ed Tanous62598e32023-07-17 17:06:25 -0700171 BMCWEB_LOG_ERROR("Failed to read entry timestamp: {}", strerror(-ret));
ZhikuiRena3316fc2020-01-29 14:58:08 -0800172 return false;
173 }
Konstantin Aladysheve645c5e2023-02-17 13:09:53 +0300174 entryTimestamp = redfish::time_utils::getDateTimeUintUs(timestamp);
Asmitha Karunanithi9c620e22020-08-02 11:55:21 -0500175 return true;
ZhikuiRena3316fc2020-01-29 14:58:08 -0800176}
Ed Tanous50b8a432022-02-03 16:29:50 -0800177
Ed Tanousdf254f22024-04-01 13:25:46 -0700178inline bool getUniqueEntryID(sd_journal* journal, std::string& entryID,
179 const bool firstEntry = true)
Jason M. Bills16428a12018-11-02 12:42:29 -0700180{
181 int ret = 0;
Myung Bae75e8e212023-11-30 12:53:46 -0800182 static sd_id128_t prevBootID{};
Jason M. Bills16428a12018-11-02 12:42:29 -0700183 static uint64_t prevTs = 0;
184 static int index = 0;
Jason M. Billse85d6b12019-07-29 17:01:15 -0700185 if (firstEntry)
186 {
Myung Bae75e8e212023-11-30 12:53:46 -0800187 prevBootID = {};
Jason M. Billse85d6b12019-07-29 17:01:15 -0700188 prevTs = 0;
189 }
190
Jason M. Bills16428a12018-11-02 12:42:29 -0700191 // Get the entry timestamp
192 uint64_t curTs = 0;
Myung Bae75e8e212023-11-30 12:53:46 -0800193 sd_id128_t curBootID{};
194 ret = sd_journal_get_monotonic_usec(journal, &curTs, &curBootID);
Jason M. Bills16428a12018-11-02 12:42:29 -0700195 if (ret < 0)
196 {
Ed Tanous62598e32023-07-17 17:06:25 -0700197 BMCWEB_LOG_ERROR("Failed to read entry timestamp: {}", strerror(-ret));
Jason M. Bills16428a12018-11-02 12:42:29 -0700198 return false;
199 }
Myung Bae75e8e212023-11-30 12:53:46 -0800200 // If the timestamp isn't unique on the same boot, increment the index
201 bool sameBootIDs = sd_id128_equal(curBootID, prevBootID) != 0;
202 if (sameBootIDs && (curTs == prevTs))
Jason M. Bills16428a12018-11-02 12:42:29 -0700203 {
204 index++;
205 }
206 else
207 {
208 // Otherwise, reset it
209 index = 0;
210 }
Myung Bae75e8e212023-11-30 12:53:46 -0800211
212 if (!sameBootIDs)
213 {
214 // Save the bootID
215 prevBootID = curBootID;
216 }
Jason M. Bills16428a12018-11-02 12:42:29 -0700217 // Save the timestamp
218 prevTs = curTs;
219
Myung Bae75e8e212023-11-30 12:53:46 -0800220 // make entryID as <bootID>_<timestamp>[_<index>]
221 std::array<char, SD_ID128_STRING_MAX> bootIDStr{};
222 sd_id128_to_string(curBootID, bootIDStr.data());
223 entryID = std::format("{}_{}", bootIDStr.data(), curTs);
Jason M. Bills16428a12018-11-02 12:42:29 -0700224 if (index > 0)
225 {
226 entryID += "_" + std::to_string(index);
227 }
228 return true;
229}
230
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500231static bool getUniqueEntryID(const std::string& logEntry, std::string& entryID,
Jason M. Billse85d6b12019-07-29 17:01:15 -0700232 const bool firstEntry = true)
Jason M. Bills95820182019-04-22 16:25:34 -0700233{
Ed Tanous271584a2019-07-09 16:24:22 -0700234 static time_t prevTs = 0;
Jason M. Bills95820182019-04-22 16:25:34 -0700235 static int index = 0;
Jason M. Billse85d6b12019-07-29 17:01:15 -0700236 if (firstEntry)
237 {
238 prevTs = 0;
239 }
240
Jason M. Bills95820182019-04-22 16:25:34 -0700241 // Get the entry timestamp
Ed Tanous271584a2019-07-09 16:24:22 -0700242 std::time_t curTs = 0;
Jason M. Bills95820182019-04-22 16:25:34 -0700243 std::tm timeStruct = {};
244 std::istringstream entryStream(logEntry);
245 if (entryStream >> std::get_time(&timeStruct, "%Y-%m-%dT%H:%M:%S"))
246 {
247 curTs = std::mktime(&timeStruct);
248 }
249 // If the timestamp isn't unique, increment the index
250 if (curTs == prevTs)
251 {
252 index++;
253 }
254 else
255 {
256 // Otherwise, reset it
257 index = 0;
258 }
259 // Save the timestamp
260 prevTs = curTs;
261
262 entryID = std::to_string(curTs);
263 if (index > 0)
264 {
265 entryID += "_" + std::to_string(index);
266 }
267 return true;
268}
269
Myung Bae75e8e212023-11-30 12:53:46 -0800270// Entry is formed like "BootID_timestamp" or "BootID_timestamp_index"
Ed Tanousdf254f22024-04-01 13:25:46 -0700271inline bool
zhanghch058d1b46d2021-04-01 11:18:24 +0800272 getTimestampFromID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous099984c2024-04-01 13:23:11 -0700273 std::string_view entryIDStrView, sd_id128_t& bootID,
Myung Bae75e8e212023-11-30 12:53:46 -0800274 uint64_t& timestamp, uint64_t& index)
Jason M. Bills16428a12018-11-02 12:42:29 -0700275{
Myung Bae75e8e212023-11-30 12:53:46 -0800276 // Convert the unique ID back to a bootID + timestamp to find the entry
Myung Bae75e8e212023-11-30 12:53:46 -0800277 auto underscore1Pos = entryIDStrView.find('_');
278 if (underscore1Pos == std::string_view::npos)
279 {
280 // EntryID has no bootID or timestamp
Ed Tanous099984c2024-04-01 13:23:11 -0700281 messages::resourceNotFound(asyncResp->res, "LogEntry", entryIDStrView);
Myung Bae75e8e212023-11-30 12:53:46 -0800282 return false;
283 }
284
285 // EntryID has bootID + timestamp
286
287 // Convert entryIDViewString to BootID
288 // NOTE: bootID string which needs to be null-terminated for
289 // sd_id128_from_string()
Ed Tanous099984c2024-04-01 13:23:11 -0700290 std::string bootIDStr(entryIDStrView.substr(0, underscore1Pos));
Myung Bae75e8e212023-11-30 12:53:46 -0800291 if (sd_id128_from_string(bootIDStr.c_str(), &bootID) < 0)
292 {
Ed Tanous099984c2024-04-01 13:23:11 -0700293 messages::resourceNotFound(asyncResp->res, "LogEntry", entryIDStrView);
Myung Bae75e8e212023-11-30 12:53:46 -0800294 return false;
295 }
296
297 // Get the timestamp from entryID
Ed Tanous099984c2024-04-01 13:23:11 -0700298 entryIDStrView.remove_prefix(underscore1Pos + 1);
Myung Bae75e8e212023-11-30 12:53:46 -0800299
Ed Tanous099984c2024-04-01 13:23:11 -0700300 auto [timestampEnd, tstampEc] = std::from_chars(
301 entryIDStrView.begin(), entryIDStrView.end(), timestamp);
302 if (tstampEc != std::errc())
Jason M. Bills16428a12018-11-02 12:42:29 -0700303 {
Ed Tanous099984c2024-04-01 13:23:11 -0700304 messages::resourceNotFound(asyncResp->res, "LogEntry", entryIDStrView);
305 return false;
Jason M. Bills16428a12018-11-02 12:42:29 -0700306 }
Ed Tanous099984c2024-04-01 13:23:11 -0700307 entryIDStrView = std::string_view(
308 timestampEnd,
309 static_cast<size_t>(std::distance(timestampEnd, entryIDStrView.end())));
310 if (entryIDStrView.empty())
Jason M. Bills16428a12018-11-02 12:42:29 -0700311 {
Ed Tanous099984c2024-04-01 13:23:11 -0700312 index = 0U;
313 return true;
314 }
315 // Timestamp might include optional index, if two events happened at the
316 // same "time".
317 if (entryIDStrView[0] != '_')
318 {
319 messages::resourceNotFound(asyncResp->res, "LogEntry", entryIDStrView);
320 return false;
321 }
322 entryIDStrView.remove_prefix(1);
323 auto [ptr, indexEc] = std::from_chars(entryIDStrView.begin(),
324 entryIDStrView.end(), index);
325 if (indexEc != std::errc() || ptr != entryIDStrView.end())
326 {
327 messages::resourceNotFound(asyncResp->res, "LogEntry", entryIDStrView);
Jason M. Bills16428a12018-11-02 12:42:29 -0700328 return false;
329 }
330 return true;
331}
332
Jason M. Bills95820182019-04-22 16:25:34 -0700333static bool
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500334 getRedfishLogFiles(std::vector<std::filesystem::path>& redfishLogFiles)
Jason M. Bills95820182019-04-22 16:25:34 -0700335{
336 static const std::filesystem::path redfishLogDir = "/var/log";
337 static const std::string redfishLogFilename = "redfish";
338
339 // Loop through the directory looking for redfish log files
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500340 for (const std::filesystem::directory_entry& dirEnt :
Jason M. Bills95820182019-04-22 16:25:34 -0700341 std::filesystem::directory_iterator(redfishLogDir))
342 {
343 // If we find a redfish log file, save the path
344 std::string filename = dirEnt.path().filename();
Ed Tanous11ba3972022-07-11 09:50:41 -0700345 if (filename.starts_with(redfishLogFilename))
Jason M. Bills95820182019-04-22 16:25:34 -0700346 {
347 redfishLogFiles.emplace_back(redfishLogDir / filename);
348 }
349 }
350 // As the log files rotate, they are appended with a ".#" that is higher for
351 // the older logs. Since we don't expect more than 10 log files, we
352 // can just sort the list to get them in order from newest to oldest
Ed Tanous3544d2a2023-08-06 18:12:20 -0700353 std::ranges::sort(redfishLogFiles);
Jason M. Bills95820182019-04-22 16:25:34 -0700354
355 return !redfishLogFiles.empty();
356}
357
Asmitha Karunanithi68dd0752022-11-15 11:33:46 -0600358inline log_entry::OriginatorTypes
359 mapDbusOriginatorTypeToRedfish(const std::string& originatorType)
360{
361 if (originatorType ==
362 "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.Client")
363 {
364 return log_entry::OriginatorTypes::Client;
365 }
366 if (originatorType ==
367 "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.Internal")
368 {
369 return log_entry::OriginatorTypes::Internal;
370 }
371 if (originatorType ==
372 "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.SupportingService")
373 {
374 return log_entry::OriginatorTypes::SupportingService;
375 }
376 return log_entry::OriginatorTypes::Invalid;
377}
378
Claire Weinanaefe3782022-07-15 19:17:19 -0700379inline void parseDumpEntryFromDbusObject(
Jiaqing Zhao2d613eb2022-08-15 16:03:00 +0800380 const dbus::utility::ManagedObjectType::value_type& object,
Claire Weinanc6fecda2022-07-15 10:43:25 -0700381 std::string& dumpStatus, uint64_t& size, uint64_t& timestampUs,
Asmitha Karunanithi68dd0752022-11-15 11:33:46 -0600382 std::string& originatorId, log_entry::OriginatorTypes& originatorType,
Claire Weinanaefe3782022-07-15 19:17:19 -0700383 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
384{
385 for (const auto& interfaceMap : object.second)
386 {
387 if (interfaceMap.first == "xyz.openbmc_project.Common.Progress")
388 {
389 for (const auto& propertyMap : interfaceMap.second)
390 {
391 if (propertyMap.first == "Status")
392 {
393 const auto* status =
394 std::get_if<std::string>(&propertyMap.second);
395 if (status == nullptr)
396 {
397 messages::internalError(asyncResp->res);
398 break;
399 }
400 dumpStatus = *status;
401 }
402 }
403 }
404 else if (interfaceMap.first == "xyz.openbmc_project.Dump.Entry")
405 {
406 for (const auto& propertyMap : interfaceMap.second)
407 {
408 if (propertyMap.first == "Size")
409 {
410 const auto* sizePtr =
411 std::get_if<uint64_t>(&propertyMap.second);
412 if (sizePtr == nullptr)
413 {
414 messages::internalError(asyncResp->res);
415 break;
416 }
417 size = *sizePtr;
418 break;
419 }
420 }
421 }
422 else if (interfaceMap.first == "xyz.openbmc_project.Time.EpochTime")
423 {
424 for (const auto& propertyMap : interfaceMap.second)
425 {
426 if (propertyMap.first == "Elapsed")
427 {
428 const uint64_t* usecsTimeStamp =
429 std::get_if<uint64_t>(&propertyMap.second);
430 if (usecsTimeStamp == nullptr)
431 {
432 messages::internalError(asyncResp->res);
433 break;
434 }
Claire Weinanc6fecda2022-07-15 10:43:25 -0700435 timestampUs = *usecsTimeStamp;
Claire Weinanaefe3782022-07-15 19:17:19 -0700436 break;
437 }
438 }
439 }
Asmitha Karunanithi68dd0752022-11-15 11:33:46 -0600440 else if (interfaceMap.first ==
441 "xyz.openbmc_project.Common.OriginatedBy")
442 {
443 for (const auto& propertyMap : interfaceMap.second)
444 {
445 if (propertyMap.first == "OriginatorId")
446 {
447 const std::string* id =
448 std::get_if<std::string>(&propertyMap.second);
449 if (id == nullptr)
450 {
451 messages::internalError(asyncResp->res);
452 break;
453 }
454 originatorId = *id;
455 }
456
457 if (propertyMap.first == "OriginatorType")
458 {
459 const std::string* type =
460 std::get_if<std::string>(&propertyMap.second);
461 if (type == nullptr)
462 {
463 messages::internalError(asyncResp->res);
464 break;
465 }
466
467 originatorType = mapDbusOriginatorTypeToRedfish(*type);
468 if (originatorType == log_entry::OriginatorTypes::Invalid)
469 {
470 messages::internalError(asyncResp->res);
471 break;
472 }
473 }
474 }
475 }
Claire Weinanaefe3782022-07-15 19:17:19 -0700476 }
477}
478
Nan Zhou21ab4042022-06-26 23:07:40 +0000479static std::string getDumpEntriesPath(const std::string& dumpType)
Claire Weinanfdd26902022-03-01 14:18:25 -0800480{
481 std::string entriesPath;
482
483 if (dumpType == "BMC")
484 {
Ed Tanous253f11b2024-05-16 09:38:31 -0700485 entriesPath =
486 std::format("/redfish/v1/Managers/{}/LogServices/Dump/Entries/",
487 BMCWEB_REDFISH_MANAGER_URI_NAME);
Claire Weinanfdd26902022-03-01 14:18:25 -0800488 }
489 else if (dumpType == "FaultLog")
490 {
Ed Tanous253f11b2024-05-16 09:38:31 -0700491 entriesPath =
492 std::format("/redfish/v1/Managers/{}/LogServices/FaultLog/Entries/",
493 BMCWEB_REDFISH_MANAGER_URI_NAME);
Claire Weinanfdd26902022-03-01 14:18:25 -0800494 }
495 else if (dumpType == "System")
496 {
Ed Tanous253f11b2024-05-16 09:38:31 -0700497 entriesPath =
498 std::format("/redfish/v1/Systems/{}/LogServices/Dump/Entries/",
499 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Claire Weinanfdd26902022-03-01 14:18:25 -0800500 }
501 else
502 {
Ed Tanous62598e32023-07-17 17:06:25 -0700503 BMCWEB_LOG_ERROR("getDumpEntriesPath() invalid dump type: {}",
504 dumpType);
Claire Weinanfdd26902022-03-01 14:18:25 -0800505 }
506
507 // Returns empty string on error
508 return entriesPath;
509}
510
zhanghch058d1b46d2021-04-01 11:18:24 +0800511inline void
512 getDumpEntryCollection(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
513 const std::string& dumpType)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500514{
Claire Weinanfdd26902022-03-01 14:18:25 -0800515 std::string entriesPath = getDumpEntriesPath(dumpType);
516 if (entriesPath.empty())
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500517 {
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500518 messages::internalError(asyncResp->res);
519 return;
520 }
521
George Liu5eb468d2023-06-20 17:03:24 +0800522 sdbusplus::message::object_path path("/xyz/openbmc_project/dump");
523 dbus::utility::getManagedObjects(
524 "xyz.openbmc_project.Dump.Manager", path,
Claire Weinanfdd26902022-03-01 14:18:25 -0800525 [asyncResp, entriesPath,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800526 dumpType](const boost::system::error_code& ec,
George Liu5eb468d2023-06-20 17:03:24 +0800527 const dbus::utility::ManagedObjectType& objects) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700528 if (ec)
529 {
Ed Tanous62598e32023-07-17 17:06:25 -0700530 BMCWEB_LOG_ERROR("DumpEntry resp_handler got error {}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -0700531 messages::internalError(asyncResp->res);
532 return;
533 }
534
Claire Weinanfdd26902022-03-01 14:18:25 -0800535 // Remove ending slash
536 std::string odataIdStr = entriesPath;
537 if (!odataIdStr.empty())
538 {
539 odataIdStr.pop_back();
540 }
541
542 asyncResp->res.jsonValue["@odata.type"] =
543 "#LogEntryCollection.LogEntryCollection";
544 asyncResp->res.jsonValue["@odata.id"] = std::move(odataIdStr);
545 asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entries";
Patrick Williams89492a12023-05-10 07:51:34 -0500546 asyncResp->res.jsonValue["Description"] = "Collection of " + dumpType +
547 " Dump Entries";
Claire Weinanfdd26902022-03-01 14:18:25 -0800548
Ed Tanous3544d2a2023-08-06 18:12:20 -0700549 nlohmann::json::array_t entriesArray;
Ed Tanous18f8f602023-07-18 10:07:23 -0700550 std::string dumpEntryPath = getDumpPath(dumpType) + "/entry/";
Ed Tanous002d39b2022-05-31 08:59:27 -0700551
George Liu5eb468d2023-06-20 17:03:24 +0800552 dbus::utility::ManagedObjectType resp(objects);
Ed Tanous3544d2a2023-08-06 18:12:20 -0700553 std::ranges::sort(resp, [](const auto& l, const auto& r) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700554 return AlphanumLess<std::string>()(l.first.filename(),
555 r.first.filename());
556 });
557
558 for (auto& object : resp)
559 {
560 if (object.first.str.find(dumpEntryPath) == std::string::npos)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500561 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700562 continue;
563 }
Claire Weinanc6fecda2022-07-15 10:43:25 -0700564 uint64_t timestampUs = 0;
Ed Tanous002d39b2022-05-31 08:59:27 -0700565 uint64_t size = 0;
566 std::string dumpStatus;
Asmitha Karunanithi68dd0752022-11-15 11:33:46 -0600567 std::string originatorId;
568 log_entry::OriginatorTypes originatorType =
569 log_entry::OriginatorTypes::Internal;
Jason M. Bills433b68b2022-06-28 12:24:26 -0700570 nlohmann::json::object_t thisEntry;
Ed Tanous002d39b2022-05-31 08:59:27 -0700571
572 std::string entryID = object.first.filename();
573 if (entryID.empty())
574 {
575 continue;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500576 }
577
Claire Weinanc6fecda2022-07-15 10:43:25 -0700578 parseDumpEntryFromDbusObject(object, dumpStatus, size, timestampUs,
Asmitha Karunanithi68dd0752022-11-15 11:33:46 -0600579 originatorId, originatorType,
Claire Weinanaefe3782022-07-15 19:17:19 -0700580 asyncResp);
Ed Tanous002d39b2022-05-31 08:59:27 -0700581
582 if (dumpStatus !=
583 "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" &&
584 !dumpStatus.empty())
585 {
586 // Dump status is not Complete, no need to enumerate
587 continue;
588 }
589
Asmitha Karunanithi68dd0752022-11-15 11:33:46 -0600590 thisEntry["@odata.type"] = "#LogEntry.v1_11_0.LogEntry";
Claire Weinanfdd26902022-03-01 14:18:25 -0800591 thisEntry["@odata.id"] = entriesPath + entryID;
Ed Tanous002d39b2022-05-31 08:59:27 -0700592 thisEntry["Id"] = entryID;
593 thisEntry["EntryType"] = "Event";
Ed Tanous002d39b2022-05-31 08:59:27 -0700594 thisEntry["Name"] = dumpType + " Dump Entry";
Claire Weinanbbd80db2022-10-26 16:55:52 -0700595 thisEntry["Created"] =
596 redfish::time_utils::getDateTimeUintUs(timestampUs);
Ed Tanous002d39b2022-05-31 08:59:27 -0700597
Asmitha Karunanithi68dd0752022-11-15 11:33:46 -0600598 if (!originatorId.empty())
599 {
600 thisEntry["Originator"] = originatorId;
601 thisEntry["OriginatorType"] = originatorType;
602 }
603
Ed Tanous002d39b2022-05-31 08:59:27 -0700604 if (dumpType == "BMC")
605 {
606 thisEntry["DiagnosticDataType"] = "Manager";
Patrick Williams89492a12023-05-10 07:51:34 -0500607 thisEntry["AdditionalDataURI"] = entriesPath + entryID +
608 "/attachment";
Claire Weinanfdd26902022-03-01 14:18:25 -0800609 thisEntry["AdditionalDataSizeBytes"] = size;
Ed Tanous002d39b2022-05-31 08:59:27 -0700610 }
611 else if (dumpType == "System")
612 {
613 thisEntry["DiagnosticDataType"] = "OEM";
614 thisEntry["OEMDiagnosticDataType"] = "System";
Patrick Williams89492a12023-05-10 07:51:34 -0500615 thisEntry["AdditionalDataURI"] = entriesPath + entryID +
616 "/attachment";
Claire Weinanfdd26902022-03-01 14:18:25 -0800617 thisEntry["AdditionalDataSizeBytes"] = size;
Ed Tanous002d39b2022-05-31 08:59:27 -0700618 }
Patrick Williamsb2ba3072023-05-12 10:27:39 -0500619 entriesArray.emplace_back(std::move(thisEntry));
Ed Tanous002d39b2022-05-31 08:59:27 -0700620 }
621 asyncResp->res.jsonValue["Members@odata.count"] = entriesArray.size();
Ed Tanous3544d2a2023-08-06 18:12:20 -0700622 asyncResp->res.jsonValue["Members"] = std::move(entriesArray);
Patrick Williams5a39f772023-10-20 11:20:21 -0500623 });
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500624}
625
zhanghch058d1b46d2021-04-01 11:18:24 +0800626inline void
Claire Weinanc7a6d662022-06-13 16:36:39 -0700627 getDumpEntryById(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
zhanghch058d1b46d2021-04-01 11:18:24 +0800628 const std::string& entryID, const std::string& dumpType)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500629{
Claire Weinanfdd26902022-03-01 14:18:25 -0800630 std::string entriesPath = getDumpEntriesPath(dumpType);
631 if (entriesPath.empty())
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500632 {
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500633 messages::internalError(asyncResp->res);
634 return;
635 }
636
George Liu5eb468d2023-06-20 17:03:24 +0800637 sdbusplus::message::object_path path("/xyz/openbmc_project/dump");
638 dbus::utility::getManagedObjects(
639 "xyz.openbmc_project.Dump.Manager", path,
Claire Weinanfdd26902022-03-01 14:18:25 -0800640 [asyncResp, entryID, dumpType,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800641 entriesPath](const boost::system::error_code& ec,
Ed Tanous02cad962022-06-30 16:50:15 -0700642 const dbus::utility::ManagedObjectType& resp) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700643 if (ec)
644 {
Ed Tanous62598e32023-07-17 17:06:25 -0700645 BMCWEB_LOG_ERROR("DumpEntry resp_handler got error {}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -0700646 messages::internalError(asyncResp->res);
647 return;
648 }
649
650 bool foundDumpEntry = false;
Ed Tanous18f8f602023-07-18 10:07:23 -0700651 std::string dumpEntryPath = getDumpPath(dumpType) + "/entry/";
Ed Tanous002d39b2022-05-31 08:59:27 -0700652
653 for (const auto& objectPath : resp)
654 {
655 if (objectPath.first.str != dumpEntryPath + entryID)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500656 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700657 continue;
658 }
659
660 foundDumpEntry = true;
Claire Weinanc6fecda2022-07-15 10:43:25 -0700661 uint64_t timestampUs = 0;
Ed Tanous002d39b2022-05-31 08:59:27 -0700662 uint64_t size = 0;
663 std::string dumpStatus;
Asmitha Karunanithi68dd0752022-11-15 11:33:46 -0600664 std::string originatorId;
665 log_entry::OriginatorTypes originatorType =
666 log_entry::OriginatorTypes::Internal;
Ed Tanous002d39b2022-05-31 08:59:27 -0700667
Claire Weinanaefe3782022-07-15 19:17:19 -0700668 parseDumpEntryFromDbusObject(objectPath, dumpStatus, size,
Asmitha Karunanithi68dd0752022-11-15 11:33:46 -0600669 timestampUs, originatorId,
670 originatorType, asyncResp);
Ed Tanous002d39b2022-05-31 08:59:27 -0700671
672 if (dumpStatus !=
673 "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" &&
674 !dumpStatus.empty())
675 {
676 // Dump status is not Complete
677 // return not found until status is changed to Completed
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200678 messages::resourceNotFound(asyncResp->res, dumpType + " dump",
679 entryID);
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500680 return;
681 }
682
Ed Tanous002d39b2022-05-31 08:59:27 -0700683 asyncResp->res.jsonValue["@odata.type"] =
Asmitha Karunanithi68dd0752022-11-15 11:33:46 -0600684 "#LogEntry.v1_11_0.LogEntry";
Claire Weinanfdd26902022-03-01 14:18:25 -0800685 asyncResp->res.jsonValue["@odata.id"] = entriesPath + entryID;
Ed Tanous002d39b2022-05-31 08:59:27 -0700686 asyncResp->res.jsonValue["Id"] = entryID;
687 asyncResp->res.jsonValue["EntryType"] = "Event";
Ed Tanous002d39b2022-05-31 08:59:27 -0700688 asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entry";
Claire Weinanbbd80db2022-10-26 16:55:52 -0700689 asyncResp->res.jsonValue["Created"] =
690 redfish::time_utils::getDateTimeUintUs(timestampUs);
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500691
Asmitha Karunanithi68dd0752022-11-15 11:33:46 -0600692 if (!originatorId.empty())
693 {
694 asyncResp->res.jsonValue["Originator"] = originatorId;
695 asyncResp->res.jsonValue["OriginatorType"] = originatorType;
696 }
697
Ed Tanous002d39b2022-05-31 08:59:27 -0700698 if (dumpType == "BMC")
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500699 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700700 asyncResp->res.jsonValue["DiagnosticDataType"] = "Manager";
701 asyncResp->res.jsonValue["AdditionalDataURI"] =
Claire Weinanfdd26902022-03-01 14:18:25 -0800702 entriesPath + entryID + "/attachment";
703 asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500704 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700705 else if (dumpType == "System")
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500706 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700707 asyncResp->res.jsonValue["DiagnosticDataType"] = "OEM";
708 asyncResp->res.jsonValue["OEMDiagnosticDataType"] = "System";
709 asyncResp->res.jsonValue["AdditionalDataURI"] =
Claire Weinanfdd26902022-03-01 14:18:25 -0800710 entriesPath + entryID + "/attachment";
711 asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size;
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500712 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700713 }
714 if (!foundDumpEntry)
715 {
Ed Tanous62598e32023-07-17 17:06:25 -0700716 BMCWEB_LOG_WARNING("Can't find Dump Entry {}", entryID);
Myung Baeb90d14f2023-05-31 14:40:39 -0500717 messages::resourceNotFound(asyncResp->res, dumpType + " dump",
718 entryID);
Ed Tanous002d39b2022-05-31 08:59:27 -0700719 return;
720 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500721 });
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500722}
723
zhanghch058d1b46d2021-04-01 11:18:24 +0800724inline void deleteDumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Stanley Chu98782562020-11-04 16:10:24 +0800725 const std::string& entryID,
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500726 const std::string& dumpType)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500727{
Patrick Williams5a39f772023-10-20 11:20:21 -0500728 auto respHandler = [asyncResp,
729 entryID](const boost::system::error_code& ec) {
Ed Tanous62598e32023-07-17 17:06:25 -0700730 BMCWEB_LOG_DEBUG("Dump Entry doDelete callback: Done");
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500731 if (ec)
732 {
George Liu3de8d8b2021-03-22 17:49:39 +0800733 if (ec.value() == EBADR)
734 {
735 messages::resourceNotFound(asyncResp->res, "LogEntry", entryID);
736 return;
737 }
Ed Tanous62598e32023-07-17 17:06:25 -0700738 BMCWEB_LOG_ERROR(
739 "Dump (DBus) doDelete respHandler got error {} entryID={}", ec,
740 entryID);
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500741 messages::internalError(asyncResp->res);
742 return;
743 }
744 };
Ed Tanous18f8f602023-07-18 10:07:23 -0700745
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500746 crow::connections::systemBus->async_method_call(
747 respHandler, "xyz.openbmc_project.Dump.Manager",
Ed Tanous18f8f602023-07-18 10:07:23 -0700748 std::format("{}/entry/{}", getDumpPath(dumpType), entryID),
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500749 "xyz.openbmc_project.Object.Delete", "Delete");
750}
Abhilash Rajub5f288d2023-11-08 22:32:44 -0600751inline bool checkSizeLimit(int fd, crow::Response& res)
752{
753 long long int size = lseek(fd, 0, SEEK_END);
754 if (size <= 0)
755 {
756 BMCWEB_LOG_ERROR("Failed to get size of file, lseek() returned {}",
757 size);
758 messages::internalError(res);
759 return false;
760 }
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500761
Abhilash Rajub5f288d2023-11-08 22:32:44 -0600762 // Arbitrary max size of 20MB to accommodate BMC dumps
763 constexpr long long int maxFileSize = 20LL * 1024LL * 1024LL;
764 if (size > maxFileSize)
765 {
766 BMCWEB_LOG_ERROR("File size {} exceeds maximum allowed size of {}",
767 size, maxFileSize);
768 messages::internalError(res);
769 return false;
770 }
771 off_t rc = lseek(fd, 0, SEEK_SET);
772 if (rc < 0)
773 {
774 BMCWEB_LOG_ERROR("Failed to reset file offset to 0");
775 messages::internalError(res);
776 return false;
777 }
778 return true;
779}
Carson Labrado168d1b12023-03-27 17:04:46 +0000780inline void
781 downloadEntryCallback(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
782 const std::string& entryID,
783 const std::string& downloadEntryType,
784 const boost::system::error_code& ec,
785 const sdbusplus::message::unix_fd& unixfd)
786{
787 if (ec.value() == EBADR)
788 {
789 messages::resourceNotFound(asyncResp->res, "EntryAttachment", entryID);
790 return;
791 }
792 if (ec)
793 {
794 BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
795 messages::internalError(asyncResp->res);
796 return;
797 }
798
799 // Make sure we know how to process the retrieved entry attachment
800 if ((downloadEntryType != "BMC") && (downloadEntryType != "System"))
801 {
802 BMCWEB_LOG_ERROR("downloadEntryCallback() invalid entry type: {}",
803 downloadEntryType);
804 messages::internalError(asyncResp->res);
805 }
806
807 int fd = -1;
808 fd = dup(unixfd);
809 if (fd < 0)
810 {
811 BMCWEB_LOG_ERROR("Failed to open file");
812 messages::internalError(asyncResp->res);
813 return;
814 }
Abhilash Rajub5f288d2023-11-08 22:32:44 -0600815 if (!checkSizeLimit(fd, asyncResp->res))
Carson Labrado168d1b12023-03-27 17:04:46 +0000816 {
Carson Labrado168d1b12023-03-27 17:04:46 +0000817 close(fd);
818 return;
819 }
Carson Labrado168d1b12023-03-27 17:04:46 +0000820 if (downloadEntryType == "System")
821 {
Abhilash Rajub5f288d2023-11-08 22:32:44 -0600822 if (!asyncResp->res.openFd(fd, bmcweb::EncodingType::Base64))
823 {
824 messages::internalError(asyncResp->res);
825 close(fd);
826 return;
827 }
Carson Labrado168d1b12023-03-27 17:04:46 +0000828 asyncResp->res.addHeader(
829 boost::beast::http::field::content_transfer_encoding, "Base64");
Abhilash Rajub5f288d2023-11-08 22:32:44 -0600830 return;
Carson Labrado168d1b12023-03-27 17:04:46 +0000831 }
Abhilash Rajub5f288d2023-11-08 22:32:44 -0600832 if (!asyncResp->res.openFd(fd))
Ed Tanous27b0cf92023-08-07 12:02:40 -0700833 {
Abhilash Rajub5f288d2023-11-08 22:32:44 -0600834 messages::internalError(asyncResp->res);
835 close(fd);
836 return;
Ed Tanous27b0cf92023-08-07 12:02:40 -0700837 }
Carson Labrado168d1b12023-03-27 17:04:46 +0000838 asyncResp->res.addHeader(boost::beast::http::field::content_type,
839 "application/octet-stream");
840}
841
842inline void
843 downloadDumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
844 const std::string& entryID, const std::string& dumpType)
845{
846 if (dumpType != "BMC")
847 {
848 BMCWEB_LOG_WARNING("Can't find Dump Entry {}", entryID);
849 messages::resourceNotFound(asyncResp->res, dumpType + " dump", entryID);
850 return;
851 }
852
Ed Tanous18f8f602023-07-18 10:07:23 -0700853 std::string dumpEntryPath = std::format("{}/entry/{}",
854 getDumpPath(dumpType), entryID);
Carson Labrado168d1b12023-03-27 17:04:46 +0000855
856 auto downloadDumpEntryHandler =
857 [asyncResp, entryID,
858 dumpType](const boost::system::error_code& ec,
859 const sdbusplus::message::unix_fd& unixfd) {
860 downloadEntryCallback(asyncResp, entryID, dumpType, ec, unixfd);
861 };
862
863 crow::connections::systemBus->async_method_call(
864 std::move(downloadDumpEntryHandler), "xyz.openbmc_project.Dump.Manager",
865 dumpEntryPath, "xyz.openbmc_project.Dump.Entry", "GetFileHandle");
866}
867
868inline void
869 downloadEventLogEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
870 const std::string& systemName,
871 const std::string& entryID,
872 const std::string& dumpType)
873{
Ed Tanous25b54db2024-04-17 15:40:31 -0700874 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Carson Labrado168d1b12023-03-27 17:04:46 +0000875 {
876 // Option currently returns no systems. TBD
877 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
878 systemName);
879 return;
880 }
Ed Tanous253f11b2024-05-16 09:38:31 -0700881 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Carson Labrado168d1b12023-03-27 17:04:46 +0000882 {
883 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
884 systemName);
885 return;
886 }
887
888 std::string entryPath =
889 sdbusplus::message::object_path("/xyz/openbmc_project/logging/entry") /
890 entryID;
891
892 auto downloadEventLogEntryHandler =
893 [asyncResp, entryID,
894 dumpType](const boost::system::error_code& ec,
895 const sdbusplus::message::unix_fd& unixfd) {
896 downloadEntryCallback(asyncResp, entryID, dumpType, ec, unixfd);
897 };
898
899 crow::connections::systemBus->async_method_call(
900 std::move(downloadEventLogEntryHandler), "xyz.openbmc_project.Logging",
901 entryPath, "xyz.openbmc_project.Logging.Entry", "GetEntry");
902}
903
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600904inline DumpCreationProgress
905 mapDbusStatusToDumpProgress(const std::string& status)
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500906{
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600907 if (status ==
908 "xyz.openbmc_project.Common.Progress.OperationStatus.Failed" ||
909 status == "xyz.openbmc_project.Common.Progress.OperationStatus.Aborted")
910 {
911 return DumpCreationProgress::DUMP_CREATE_FAILED;
912 }
913 if (status ==
914 "xyz.openbmc_project.Common.Progress.OperationStatus.Completed")
915 {
916 return DumpCreationProgress::DUMP_CREATE_SUCCESS;
917 }
918 return DumpCreationProgress::DUMP_CREATE_INPROGRESS;
919}
920
921inline DumpCreationProgress
922 getDumpCompletionStatus(const dbus::utility::DBusPropertiesMap& values)
923{
924 for (const auto& [key, val] : values)
925 {
926 if (key == "Status")
Ed Tanous002d39b2022-05-31 08:59:27 -0700927 {
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600928 const std::string* value = std::get_if<std::string>(&val);
929 if (value == nullptr)
930 {
Ed Tanous62598e32023-07-17 17:06:25 -0700931 BMCWEB_LOG_ERROR("Status property value is null");
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600932 return DumpCreationProgress::DUMP_CREATE_FAILED;
933 }
934 return mapDbusStatusToDumpProgress(*value);
935 }
936 }
937 return DumpCreationProgress::DUMP_CREATE_INPROGRESS;
938}
939
940inline std::string getDumpEntryPath(const std::string& dumpPath)
941{
942 if (dumpPath == "/xyz/openbmc_project/dump/bmc/entry")
943 {
Ed Tanous253f11b2024-05-16 09:38:31 -0700944 return std::format("/redfish/v1/Managers/{}/LogServices/Dump/Entries/",
945 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600946 }
947 if (dumpPath == "/xyz/openbmc_project/dump/system/entry")
948 {
Ed Tanous253f11b2024-05-16 09:38:31 -0700949 return std::format("/redfish/v1/Systems/{}/LogServices/Dump/Entries/",
950 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600951 }
952 return "";
953}
954
955inline void createDumpTaskCallback(
956 task::Payload&& payload,
957 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
958 const sdbusplus::message::object_path& createdObjPath)
959{
960 const std::string dumpPath = createdObjPath.parent_path().str;
961 const std::string dumpId = createdObjPath.filename();
962
963 std::string dumpEntryPath = getDumpEntryPath(dumpPath);
964
965 if (dumpEntryPath.empty())
966 {
Ed Tanous62598e32023-07-17 17:06:25 -0700967 BMCWEB_LOG_ERROR("Invalid dump type received");
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600968 messages::internalError(asyncResp->res);
969 return;
970 }
971
972 crow::connections::systemBus->async_method_call(
Ed Tanous8cb2c022024-03-27 16:31:46 -0700973 [asyncResp, payload = std::move(payload), createdObjPath,
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600974 dumpEntryPath{std::move(dumpEntryPath)},
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800975 dumpId](const boost::system::error_code& ec,
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600976 const std::string& introspectXml) {
977 if (ec)
978 {
Ed Tanous62598e32023-07-17 17:06:25 -0700979 BMCWEB_LOG_ERROR("Introspect call failed with error: {}",
980 ec.message());
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600981 messages::internalError(asyncResp->res);
982 return;
Ed Tanous002d39b2022-05-31 08:59:27 -0700983 }
984
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600985 // Check if the created dump object has implemented Progress
986 // interface to track dump completion. If yes, fetch the "Status"
987 // property of the interface, modify the task state accordingly.
988 // Else, return task completed.
989 tinyxml2::XMLDocument doc;
Ed Tanous002d39b2022-05-31 08:59:27 -0700990
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600991 doc.Parse(introspectXml.data(), introspectXml.size());
992 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
993 if (pRoot == nullptr)
Ed Tanous002d39b2022-05-31 08:59:27 -0700994 {
Ed Tanous62598e32023-07-17 17:06:25 -0700995 BMCWEB_LOG_ERROR("XML document failed to parse");
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600996 messages::internalError(asyncResp->res);
997 return;
998 }
999 tinyxml2::XMLElement* interfaceNode =
1000 pRoot->FirstChildElement("interface");
1001
1002 bool isProgressIntfPresent = false;
1003 while (interfaceNode != nullptr)
1004 {
1005 const char* thisInterfaceName = interfaceNode->Attribute("name");
1006 if (thisInterfaceName != nullptr)
1007 {
1008 if (thisInterfaceName ==
1009 std::string_view("xyz.openbmc_project.Common.Progress"))
1010 {
1011 interfaceNode =
1012 interfaceNode->NextSiblingElement("interface");
1013 continue;
1014 }
1015 isProgressIntfPresent = true;
1016 break;
1017 }
1018 interfaceNode = interfaceNode->NextSiblingElement("interface");
1019 }
1020
1021 std::shared_ptr<task::TaskData> task = task::TaskData::createTask(
1022 [createdObjPath, dumpEntryPath, dumpId, isProgressIntfPresent](
Ed Tanous8b242752023-06-27 17:17:13 -07001023 const boost::system::error_code& ec2, sdbusplus::message_t& msg,
Asmitha Karunanithi8e317782020-12-10 03:35:05 -06001024 const std::shared_ptr<task::TaskData>& taskData) {
Ed Tanous8b242752023-06-27 17:17:13 -07001025 if (ec2)
Asmitha Karunanithi8e317782020-12-10 03:35:05 -06001026 {
Ed Tanous62598e32023-07-17 17:06:25 -07001027 BMCWEB_LOG_ERROR("{}: Error in creating dump",
1028 createdObjPath.str);
Asmitha Karunanithi8e317782020-12-10 03:35:05 -06001029 taskData->messages.emplace_back(messages::internalError());
1030 taskData->state = "Cancelled";
1031 return task::completed;
1032 }
1033
1034 if (isProgressIntfPresent)
1035 {
1036 dbus::utility::DBusPropertiesMap values;
1037 std::string prop;
1038 msg.read(prop, values);
1039
1040 DumpCreationProgress dumpStatus =
1041 getDumpCompletionStatus(values);
1042 if (dumpStatus == DumpCreationProgress::DUMP_CREATE_FAILED)
1043 {
Ed Tanous62598e32023-07-17 17:06:25 -07001044 BMCWEB_LOG_ERROR("{}: Error in creating dump",
1045 createdObjPath.str);
Asmitha Karunanithi8e317782020-12-10 03:35:05 -06001046 taskData->state = "Cancelled";
1047 return task::completed;
1048 }
1049
1050 if (dumpStatus == DumpCreationProgress::DUMP_CREATE_INPROGRESS)
1051 {
Ed Tanous62598e32023-07-17 17:06:25 -07001052 BMCWEB_LOG_DEBUG("{}: Dump creation task is in progress",
1053 createdObjPath.str);
Asmitha Karunanithi8e317782020-12-10 03:35:05 -06001054 return !task::completed;
1055 }
1056 }
1057
Ed Tanous002d39b2022-05-31 08:59:27 -07001058 nlohmann::json retMessage = messages::success();
1059 taskData->messages.emplace_back(retMessage);
1060
Ed Tanousc51a58e2023-03-27 14:43:19 -07001061 boost::urls::url url = boost::urls::format(
Ed Tanous253f11b2024-05-16 09:38:31 -07001062 "/redfish/v1/Managers/{}/LogServices/Dump/Entries/{}",
1063 BMCWEB_REDFISH_MANAGER_URI_NAME, dumpId);
Ed Tanousc51a58e2023-03-27 14:43:19 -07001064
1065 std::string headerLoc = "Location: ";
1066 headerLoc += url.buffer();
1067
Ed Tanous002d39b2022-05-31 08:59:27 -07001068 taskData->payload->httpHeaders.emplace_back(std::move(headerLoc));
1069
Ed Tanous62598e32023-07-17 17:06:25 -07001070 BMCWEB_LOG_DEBUG("{}: Dump creation task completed",
1071 createdObjPath.str);
Ed Tanous002d39b2022-05-31 08:59:27 -07001072 taskData->state = "Completed";
1073 return task::completed;
Patrick Williams5a39f772023-10-20 11:20:21 -05001074 },
Asmitha Karunanithi8e317782020-12-10 03:35:05 -06001075 "type='signal',interface='org.freedesktop.DBus.Properties',"
1076 "member='PropertiesChanged',path='" +
1077 createdObjPath.str + "'");
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001078
Asmitha Karunanithi8e317782020-12-10 03:35:05 -06001079 // The task timer is set to max time limit within which the
1080 // requested dump will be collected.
1081 task->startTimer(std::chrono::minutes(6));
1082 task->populateResp(asyncResp->res);
1083 task->payload.emplace(payload);
Patrick Williams5a39f772023-10-20 11:20:21 -05001084 },
Asmitha Karunanithi8e317782020-12-10 03:35:05 -06001085 "xyz.openbmc_project.Dump.Manager", createdObjPath,
1086 "org.freedesktop.DBus.Introspectable", "Introspect");
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001087}
1088
zhanghch058d1b46d2021-04-01 11:18:24 +08001089inline void createDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1090 const crow::Request& req, const std::string& dumpType)
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001091{
Claire Weinanfdd26902022-03-01 14:18:25 -08001092 std::string dumpPath = getDumpEntriesPath(dumpType);
1093 if (dumpPath.empty())
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001094 {
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001095 messages::internalError(asyncResp->res);
1096 return;
1097 }
1098
1099 std::optional<std::string> diagnosticDataType;
1100 std::optional<std::string> oemDiagnosticDataType;
1101
Willy Tu15ed6782021-12-14 11:03:16 -08001102 if (!redfish::json_util::readJsonAction(
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001103 req, asyncResp->res, "DiagnosticDataType", diagnosticDataType,
1104 "OEMDiagnosticDataType", oemDiagnosticDataType))
1105 {
1106 return;
1107 }
1108
1109 if (dumpType == "System")
1110 {
1111 if (!oemDiagnosticDataType || !diagnosticDataType)
1112 {
Ed Tanous62598e32023-07-17 17:06:25 -07001113 BMCWEB_LOG_ERROR(
1114 "CreateDump action parameter 'DiagnosticDataType'/'OEMDiagnosticDataType' value not found!");
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001115 messages::actionParameterMissing(
1116 asyncResp->res, "CollectDiagnosticData",
1117 "DiagnosticDataType & OEMDiagnosticDataType");
1118 return;
1119 }
Ed Tanous3174e4d2020-10-07 11:41:22 -07001120 if ((*oemDiagnosticDataType != "System") ||
1121 (*diagnosticDataType != "OEM"))
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001122 {
Ed Tanous62598e32023-07-17 17:06:25 -07001123 BMCWEB_LOG_ERROR("Wrong parameter values passed");
Ed Tanousace85d62021-10-26 12:45:59 -07001124 messages::internalError(asyncResp->res);
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001125 return;
1126 }
Ed Tanous253f11b2024-05-16 09:38:31 -07001127 dumpPath = std::format("/redfish/v1/Systems/{}/LogServices/Dump/",
1128 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001129 }
1130 else if (dumpType == "BMC")
1131 {
1132 if (!diagnosticDataType)
1133 {
Ed Tanous62598e32023-07-17 17:06:25 -07001134 BMCWEB_LOG_ERROR(
1135 "CreateDump action parameter 'DiagnosticDataType' not found!");
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001136 messages::actionParameterMissing(
1137 asyncResp->res, "CollectDiagnosticData", "DiagnosticDataType");
1138 return;
1139 }
Ed Tanous3174e4d2020-10-07 11:41:22 -07001140 if (*diagnosticDataType != "Manager")
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001141 {
Ed Tanous62598e32023-07-17 17:06:25 -07001142 BMCWEB_LOG_ERROR(
1143 "Wrong parameter value passed for 'DiagnosticDataType'");
Ed Tanousace85d62021-10-26 12:45:59 -07001144 messages::internalError(asyncResp->res);
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001145 return;
1146 }
Ed Tanous253f11b2024-05-16 09:38:31 -07001147 dumpPath = std::format("/redfish/v1/Managers/{}/LogServices/Dump/",
1148 BMCWEB_REDFISH_MANAGER_URI_NAME);
Asmitha Karunanithi59075712021-10-22 01:17:41 -05001149 }
1150 else
1151 {
Ed Tanous62598e32023-07-17 17:06:25 -07001152 BMCWEB_LOG_ERROR("CreateDump failed. Unknown dump type");
Asmitha Karunanithi59075712021-10-22 01:17:41 -05001153 messages::internalError(asyncResp->res);
1154 return;
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001155 }
1156
Asmitha Karunanithi8e317782020-12-10 03:35:05 -06001157 std::vector<std::pair<std::string, std::variant<std::string, uint64_t>>>
1158 createDumpParamVec;
1159
Carson Labradof574a8e2023-03-22 02:26:00 +00001160 if (req.session != nullptr)
1161 {
1162 createDumpParamVec.emplace_back(
1163 "xyz.openbmc_project.Dump.Create.CreateParameters.OriginatorId",
1164 req.session->clientIp);
1165 createDumpParamVec.emplace_back(
1166 "xyz.openbmc_project.Dump.Create.CreateParameters.OriginatorType",
1167 "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.Client");
1168 }
Asmitha Karunanithi68dd0752022-11-15 11:33:46 -06001169
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001170 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001171 [asyncResp, payload(task::Payload(req)),
1172 dumpPath](const boost::system::error_code& ec,
1173 const sdbusplus::message_t& msg,
1174 const sdbusplus::message::object_path& objPath) mutable {
Ed Tanous002d39b2022-05-31 08:59:27 -07001175 if (ec)
1176 {
Ed Tanous62598e32023-07-17 17:06:25 -07001177 BMCWEB_LOG_ERROR("CreateDump resp_handler got error {}", ec);
Asmitha Karunanithi59075712021-10-22 01:17:41 -05001178 const sd_bus_error* dbusError = msg.get_error();
1179 if (dbusError == nullptr)
1180 {
1181 messages::internalError(asyncResp->res);
1182 return;
1183 }
1184
Ed Tanous62598e32023-07-17 17:06:25 -07001185 BMCWEB_LOG_ERROR("CreateDump DBus error: {} and error msg: {}",
1186 dbusError->name, dbusError->message);
Asmitha Karunanithi59075712021-10-22 01:17:41 -05001187 if (std::string_view(
1188 "xyz.openbmc_project.Common.Error.NotAllowed") ==
1189 dbusError->name)
1190 {
1191 messages::resourceInStandby(asyncResp->res);
1192 return;
1193 }
1194 if (std::string_view(
1195 "xyz.openbmc_project.Dump.Create.Error.Disabled") ==
1196 dbusError->name)
1197 {
1198 messages::serviceDisabled(asyncResp->res, dumpPath);
1199 return;
1200 }
1201 if (std::string_view(
1202 "xyz.openbmc_project.Common.Error.Unavailable") ==
1203 dbusError->name)
1204 {
1205 messages::resourceInUse(asyncResp->res);
1206 return;
1207 }
1208 // Other Dbus errors such as:
1209 // xyz.openbmc_project.Common.Error.InvalidArgument &
1210 // org.freedesktop.DBus.Error.InvalidArgs are all related to
1211 // the dbus call that is made here in the bmcweb
1212 // implementation and has nothing to do with the client's
1213 // input in the request. Hence, returning internal error
1214 // back to the client.
Ed Tanous002d39b2022-05-31 08:59:27 -07001215 messages::internalError(asyncResp->res);
1216 return;
1217 }
Ed Tanous62598e32023-07-17 17:06:25 -07001218 BMCWEB_LOG_DEBUG("Dump Created. Path: {}", objPath.str);
Asmitha Karunanithi8e317782020-12-10 03:35:05 -06001219 createDumpTaskCallback(std::move(payload), asyncResp, objPath);
Patrick Williams5a39f772023-10-20 11:20:21 -05001220 },
Ed Tanous18f8f602023-07-18 10:07:23 -07001221 "xyz.openbmc_project.Dump.Manager", getDumpPath(dumpType),
Asmitha Karunanithi8e317782020-12-10 03:35:05 -06001222 "xyz.openbmc_project.Dump.Create", "CreateDump", createDumpParamVec);
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001223}
1224
zhanghch058d1b46d2021-04-01 11:18:24 +08001225inline void clearDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1226 const std::string& dumpType)
Asmitha Karunanithi80319af2020-05-07 05:30:21 -05001227{
Claire Weinan0d946212022-07-13 19:40:19 -07001228 crow::connections::systemBus->async_method_call(
1229 [asyncResp](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001230 if (ec)
1231 {
Ed Tanous62598e32023-07-17 17:06:25 -07001232 BMCWEB_LOG_ERROR("clearDump resp_handler got error {}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -07001233 messages::internalError(asyncResp->res);
1234 return;
1235 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001236 },
Ed Tanous18f8f602023-07-18 10:07:23 -07001237 "xyz.openbmc_project.Dump.Manager", getDumpPath(dumpType),
Claire Weinan0d946212022-07-13 19:40:19 -07001238 "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
Asmitha Karunanithi80319af2020-05-07 05:30:21 -05001239}
1240
Ed Tanousdf254f22024-04-01 13:25:46 -07001241inline void
Ed Tanousb9d36b42022-02-26 21:42:46 -08001242 parseCrashdumpParameters(const dbus::utility::DBusPropertiesMap& params,
1243 std::string& filename, std::string& timestamp,
1244 std::string& logfile)
Johnathan Mantey043a0532020-03-10 17:15:28 -07001245{
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001246 const std::string* filenamePtr = nullptr;
1247 const std::string* timestampPtr = nullptr;
1248 const std::string* logfilePtr = nullptr;
1249
1250 const bool success = sdbusplus::unpackPropertiesNoThrow(
1251 dbus_utils::UnpackErrorPrinter(), params, "Timestamp", timestampPtr,
1252 "Filename", filenamePtr, "Log", logfilePtr);
1253
1254 if (!success)
Johnathan Mantey043a0532020-03-10 17:15:28 -07001255 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001256 return;
1257 }
1258
1259 if (filenamePtr != nullptr)
1260 {
1261 filename = *filenamePtr;
1262 }
1263
1264 if (timestampPtr != nullptr)
1265 {
1266 timestamp = *timestampPtr;
1267 }
1268
1269 if (logfilePtr != nullptr)
1270 {
1271 logfile = *logfilePtr;
Johnathan Mantey043a0532020-03-10 17:15:28 -07001272 }
1273}
1274
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001275inline void requestRoutesSystemLogServiceCollection(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07001276{
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001277 /**
1278 * Functions triggers appropriate requests on DBus
1279 */
Ed Tanous22d268c2022-05-19 09:39:07 -07001280 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/")
Ed Tanoused398212021-06-09 17:05:54 -07001281 .privileges(redfish::privileges::getLogServiceCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07001282 .methods(boost::beast::http::verb::get)(
1283 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001284 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1285 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001286 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001287 {
1288 return;
1289 }
Ed Tanous25b54db2024-04-17 15:40:31 -07001290 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08001291 {
1292 // Option currently returns no systems. TBD
1293 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1294 systemName);
1295 return;
1296 }
Ed Tanous253f11b2024-05-16 09:38:31 -07001297 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07001298 {
1299 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1300 systemName);
1301 return;
1302 }
1303
Ed Tanous002d39b2022-05-31 08:59:27 -07001304 // Collections don't include the static data added by SubRoute
1305 // because it has a duplicate entry for members
1306 asyncResp->res.jsonValue["@odata.type"] =
1307 "#LogServiceCollection.LogServiceCollection";
1308 asyncResp->res.jsonValue["@odata.id"] =
Ed Tanous253f11b2024-05-16 09:38:31 -07001309 std::format("/redfish/v1/Systems/{}/LogServices",
1310 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Ed Tanous002d39b2022-05-31 08:59:27 -07001311 asyncResp->res.jsonValue["Name"] = "System Log Services Collection";
1312 asyncResp->res.jsonValue["Description"] =
1313 "Collection of LogServices for this Computer System";
1314 nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"];
1315 logServiceArray = nlohmann::json::array();
1316 nlohmann::json::object_t eventLog;
1317 eventLog["@odata.id"] =
Ed Tanous253f11b2024-05-16 09:38:31 -07001318 std::format("/redfish/v1/Systems/{}/LogServices/EventLog",
1319 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001320 logServiceArray.emplace_back(std::move(eventLog));
Ed Tanous25b54db2024-04-17 15:40:31 -07001321 if constexpr (BMCWEB_REDFISH_DUMP_LOG)
1322 {
1323 nlohmann::json::object_t dumpLog;
1324 dumpLog["@odata.id"] =
Ed Tanous253f11b2024-05-16 09:38:31 -07001325 std::format("/redfish/v1/Systems/{}/LogServices/Dump",
1326 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Ed Tanous25b54db2024-04-17 15:40:31 -07001327 logServiceArray.emplace_back(std::move(dumpLog));
1328 }
raviteja-bc9bb6862020-02-03 11:53:32 -06001329
Gunnar Mills5ffd11f2024-05-02 08:26:12 -05001330 if constexpr (BMCWEB_REDFISH_CPU_LOG)
Ed Tanous25b54db2024-04-17 15:40:31 -07001331 {
1332 nlohmann::json::object_t crashdump;
1333 crashdump["@odata.id"] =
Ed Tanous253f11b2024-05-16 09:38:31 -07001334 std::format("/redfish/v1/Systems/{}/LogServices/Crashdump",
1335 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Ed Tanous25b54db2024-04-17 15:40:31 -07001336 logServiceArray.emplace_back(std::move(crashdump));
1337 }
Spencer Kub7028eb2021-10-26 15:27:35 +08001338
Ed Tanous25b54db2024-04-17 15:40:31 -07001339 if constexpr (BMCWEB_REDFISH_HOST_LOGGER)
1340 {
1341 nlohmann::json::object_t hostlogger;
1342 hostlogger["@odata.id"] =
Ed Tanous253f11b2024-05-16 09:38:31 -07001343 std::format("/redfish/v1/Systems/{}/LogServices/HostLogger",
1344 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Ed Tanous25b54db2024-04-17 15:40:31 -07001345 logServiceArray.emplace_back(std::move(hostlogger));
1346 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001347 asyncResp->res.jsonValue["Members@odata.count"] =
1348 logServiceArray.size();
ZhikuiRena3316fc2020-01-29 14:58:08 -08001349
George Liu7a1dbc42022-12-07 16:03:22 +08001350 constexpr std::array<std::string_view, 1> interfaces = {
1351 "xyz.openbmc_project.State.Boot.PostCode"};
1352 dbus::utility::getSubTreePaths(
1353 "/", 0, interfaces,
1354 [asyncResp](const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -07001355 const dbus::utility::MapperGetSubTreePathsResponse&
1356 subtreePath) {
1357 if (ec)
1358 {
Ed Tanous62598e32023-07-17 17:06:25 -07001359 BMCWEB_LOG_ERROR("{}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -07001360 return;
1361 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07001362
Ed Tanous002d39b2022-05-31 08:59:27 -07001363 for (const auto& pathStr : subtreePath)
1364 {
1365 if (pathStr.find("PostCode") != std::string::npos)
1366 {
1367 nlohmann::json& logServiceArrayLocal =
1368 asyncResp->res.jsonValue["Members"];
Ed Tanous613dabe2022-07-09 11:17:36 -07001369 nlohmann::json::object_t member;
Ed Tanous253f11b2024-05-16 09:38:31 -07001370 member["@odata.id"] = std::format(
1371 "/redfish/v1/Systems/{}/LogServices/PostCodes",
1372 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Ed Tanous613dabe2022-07-09 11:17:36 -07001373
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001374 logServiceArrayLocal.emplace_back(std::move(member));
Ed Tanous613dabe2022-07-09 11:17:36 -07001375
Ed Tanous002d39b2022-05-31 08:59:27 -07001376 asyncResp->res.jsonValue["Members@odata.count"] =
1377 logServiceArrayLocal.size();
1378 return;
1379 }
1380 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07001381 });
Patrick Williams5a39f772023-10-20 11:20:21 -05001382 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001383}
1384
1385inline void requestRoutesEventLogService(App& app)
1386{
Ed Tanous22d268c2022-05-19 09:39:07 -07001387 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/")
Ed Tanoused398212021-06-09 17:05:54 -07001388 .privileges(redfish::privileges::getLogService)
Ed Tanous002d39b2022-05-31 08:59:27 -07001389 .methods(boost::beast::http::verb::get)(
1390 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001391 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1392 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001393 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001394 {
1395 return;
1396 }
Ed Tanous253f11b2024-05-16 09:38:31 -07001397 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07001398 {
1399 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1400 systemName);
1401 return;
1402 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001403 asyncResp->res.jsonValue["@odata.id"] =
Ed Tanous253f11b2024-05-16 09:38:31 -07001404 std::format("/redfish/v1/Systems/{}/LogServices/EventLog",
1405 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Ed Tanous002d39b2022-05-31 08:59:27 -07001406 asyncResp->res.jsonValue["@odata.type"] =
Janet Adkinsb25644a2023-08-16 11:23:45 -05001407 "#LogService.v1_2_0.LogService";
Ed Tanous002d39b2022-05-31 08:59:27 -07001408 asyncResp->res.jsonValue["Name"] = "Event Log Service";
1409 asyncResp->res.jsonValue["Description"] = "System Event Log Service";
1410 asyncResp->res.jsonValue["Id"] = "EventLog";
1411 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
Tejas Patil7c8c4052021-06-04 17:43:14 +05301412
Ed Tanous002d39b2022-05-31 08:59:27 -07001413 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07001414 redfish::time_utils::getDateTimeOffsetNow();
Tejas Patil7c8c4052021-06-04 17:43:14 +05301415
Ed Tanous002d39b2022-05-31 08:59:27 -07001416 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
1417 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
1418 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05301419
Ed Tanous002d39b2022-05-31 08:59:27 -07001420 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
Ed Tanous253f11b2024-05-16 09:38:31 -07001421 std::format("/redfish/v1/Systems/{}/LogServices/EventLog/Entries",
1422 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Ed Tanous20fa6a22024-05-20 18:02:58 -07001423 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"]
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001424
Ed Tanous20fa6a22024-05-20 18:02:58 -07001425 = std::format(
1426 "/redfish/v1/Systems/{}/LogServices/EventLog/Actions/LogService.ClearLog",
1427 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Patrick Williams5a39f772023-10-20 11:20:21 -05001428 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001429}
1430
1431inline void requestRoutesJournalEventLogClear(App& app)
1432{
Jason M. Bills4978b632022-02-22 14:17:43 -08001433 BMCWEB_ROUTE(
1434 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07001435 "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/")
Ed Tanous432a8902021-06-14 15:28:56 -07001436 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001437 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001438 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001439 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1440 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001441 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001442 {
1443 return;
1444 }
Ed Tanous253f11b2024-05-16 09:38:31 -07001445 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07001446 {
1447 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1448 systemName);
1449 return;
1450 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001451 // Clear the EventLog by deleting the log files
1452 std::vector<std::filesystem::path> redfishLogFiles;
1453 if (getRedfishLogFiles(redfishLogFiles))
1454 {
1455 for (const std::filesystem::path& file : redfishLogFiles)
1456 {
1457 std::error_code ec;
1458 std::filesystem::remove(file, ec);
1459 }
1460 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001461
Ed Tanous002d39b2022-05-31 08:59:27 -07001462 // Reload rsyslog so it knows to start new log files
1463 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001464 [asyncResp](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001465 if (ec)
1466 {
Ed Tanous62598e32023-07-17 17:06:25 -07001467 BMCWEB_LOG_ERROR("Failed to reload rsyslog: {}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -07001468 messages::internalError(asyncResp->res);
1469 return;
1470 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001471
Ed Tanous002d39b2022-05-31 08:59:27 -07001472 messages::success(asyncResp->res);
Patrick Williams5a39f772023-10-20 11:20:21 -05001473 },
Ed Tanous002d39b2022-05-31 08:59:27 -07001474 "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
1475 "org.freedesktop.systemd1.Manager", "ReloadUnit", "rsyslog.service",
1476 "replace");
Patrick Williams5a39f772023-10-20 11:20:21 -05001477 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001478}
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001479
Jason M. Billsac992cd2022-06-24 13:31:46 -07001480enum class LogParseError
1481{
1482 success,
1483 parseFailed,
1484 messageIdNotInRegistry,
1485};
1486
1487static LogParseError
1488 fillEventLogEntryJson(const std::string& logEntryID,
1489 const std::string& logEntry,
1490 nlohmann::json::object_t& logEntryJson)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001491{
Jason M. Bills95820182019-04-22 16:25:34 -07001492 // The redfish log format is "<Timestamp> <MessageId>,<MessageArgs>"
Jason M. Billscd225da2019-05-08 15:31:57 -07001493 // First get the Timestamp
Ed Tanousf23b7292020-10-15 09:41:17 -07001494 size_t space = logEntry.find_first_of(' ');
Jason M. Billscd225da2019-05-08 15:31:57 -07001495 if (space == std::string::npos)
Jason M. Bills95820182019-04-22 16:25:34 -07001496 {
Jason M. Billsac992cd2022-06-24 13:31:46 -07001497 return LogParseError::parseFailed;
Jason M. Bills95820182019-04-22 16:25:34 -07001498 }
Jason M. Billscd225da2019-05-08 15:31:57 -07001499 std::string timestamp = logEntry.substr(0, space);
1500 // Then get the log contents
Ed Tanousf23b7292020-10-15 09:41:17 -07001501 size_t entryStart = logEntry.find_first_not_of(' ', space);
Jason M. Billscd225da2019-05-08 15:31:57 -07001502 if (entryStart == std::string::npos)
1503 {
Jason M. Billsac992cd2022-06-24 13:31:46 -07001504 return LogParseError::parseFailed;
Jason M. Billscd225da2019-05-08 15:31:57 -07001505 }
1506 std::string_view entry(logEntry);
1507 entry.remove_prefix(entryStart);
1508 // Use split to separate the entry into its fields
1509 std::vector<std::string> logEntryFields;
Ed Tanous50ebd4a2023-01-19 19:03:17 -08001510 bmcweb::split(logEntryFields, entry, ',');
Jason M. Billscd225da2019-05-08 15:31:57 -07001511 // We need at least a MessageId to be valid
Ed Tanous1e6deaf2022-02-17 11:32:37 -08001512 auto logEntryIter = logEntryFields.begin();
1513 if (logEntryIter == logEntryFields.end())
Jason M. Billscd225da2019-05-08 15:31:57 -07001514 {
Jason M. Billsac992cd2022-06-24 13:31:46 -07001515 return LogParseError::parseFailed;
Jason M. Billscd225da2019-05-08 15:31:57 -07001516 }
Ed Tanous1e6deaf2022-02-17 11:32:37 -08001517 std::string& messageID = *logEntryIter;
Jason M. Bills4851d452019-03-28 11:27:48 -07001518 // Get the Message from the MessageRegistry
Ed Tanousfffb8c12022-02-07 23:53:03 -08001519 const registries::Message* message = registries::getMessage(messageID);
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001520
Ed Tanous1e6deaf2022-02-17 11:32:37 -08001521 logEntryIter++;
Sui Chen54417b02022-03-24 14:59:52 -07001522 if (message == nullptr)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001523 {
Ed Tanous62598e32023-07-17 17:06:25 -07001524 BMCWEB_LOG_WARNING("Log entry not found in registry: {}", logEntry);
Jason M. Billsac992cd2022-06-24 13:31:46 -07001525 return LogParseError::messageIdNotInRegistry;
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001526 }
1527
Ed Tanous1e6deaf2022-02-17 11:32:37 -08001528 std::vector<std::string_view> messageArgs(logEntryIter,
1529 logEntryFields.end());
Ed Tanousc05bba42023-06-28 08:33:29 -07001530 messageArgs.resize(message->numberOfArgs);
1531
Ed Tanous1e6deaf2022-02-17 11:32:37 -08001532 std::string msg = redfish::registries::fillMessageArgs(messageArgs,
1533 message->message);
1534 if (msg.empty())
Jason M. Bills4851d452019-03-28 11:27:48 -07001535 {
Ed Tanous1e6deaf2022-02-17 11:32:37 -08001536 return LogParseError::parseFailed;
Jason M. Bills4851d452019-03-28 11:27:48 -07001537 }
1538
Jason M. Bills95820182019-04-22 16:25:34 -07001539 // Get the Created time from the timestamp. The log timestamp is in RFC3339
1540 // format which matches the Redfish format except for the fractional seconds
1541 // between the '.' and the '+', so just remove them.
Ed Tanousf23b7292020-10-15 09:41:17 -07001542 std::size_t dot = timestamp.find_first_of('.');
1543 std::size_t plus = timestamp.find_first_of('+');
Jason M. Bills95820182019-04-22 16:25:34 -07001544 if (dot != std::string::npos && plus != std::string::npos)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001545 {
Jason M. Bills95820182019-04-22 16:25:34 -07001546 timestamp.erase(dot, plus - dot);
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001547 }
1548
1549 // Fill in the log entry with the gathered data
Vijay Lobo9c11a172021-10-07 16:53:16 -05001550 logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Ed Tanousef4c65b2023-04-24 15:28:50 -07001551 logEntryJson["@odata.id"] = boost::urls::format(
Ed Tanous253f11b2024-05-16 09:38:31 -07001552 "/redfish/v1/Systems/{}/LogServices/EventLog/Entries/{}",
1553 BMCWEB_REDFISH_SYSTEM_URI_NAME, logEntryID);
Jason M. Bills84afc482022-06-24 12:38:23 -07001554 logEntryJson["Name"] = "System Event Log Entry";
1555 logEntryJson["Id"] = logEntryID;
1556 logEntryJson["Message"] = std::move(msg);
1557 logEntryJson["MessageId"] = std::move(messageID);
1558 logEntryJson["MessageArgs"] = messageArgs;
1559 logEntryJson["EntryType"] = "Event";
1560 logEntryJson["Severity"] = message->messageSeverity;
1561 logEntryJson["Created"] = std::move(timestamp);
Jason M. Billsac992cd2022-06-24 13:31:46 -07001562 return LogParseError::success;
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001563}
1564
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001565inline void requestRoutesJournalEventLogEntryCollection(App& app)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001566{
Ed Tanous22d268c2022-05-19 09:39:07 -07001567 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/")
Gunnar Mills8b6a35f2021-07-30 14:52:53 -05001568 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07001569 .methods(boost::beast::http::verb::get)(
1570 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001571 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1572 const std::string& systemName) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001573 query_param::QueryCapabilities capabilities = {
1574 .canDelegateTop = true,
1575 .canDelegateSkip = true,
1576 };
1577 query_param::Query delegatedQuery;
1578 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00001579 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07001580 {
1581 return;
1582 }
Ed Tanous25b54db2024-04-17 15:40:31 -07001583 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08001584 {
1585 // Option currently returns no systems. TBD
1586 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1587 systemName);
1588 return;
1589 }
Ed Tanous253f11b2024-05-16 09:38:31 -07001590 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07001591 {
1592 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1593 systemName);
1594 return;
1595 }
1596
Jiaqing Zhao5143f7a2022-07-22 09:33:33 +08001597 size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
Ed Tanous3648c8b2022-07-25 13:39:59 -07001598 size_t skip = delegatedQuery.skip.value_or(0);
1599
Ed Tanous002d39b2022-05-31 08:59:27 -07001600 // Collections don't include the static data added by SubRoute
1601 // because it has a duplicate entry for members
1602 asyncResp->res.jsonValue["@odata.type"] =
1603 "#LogEntryCollection.LogEntryCollection";
1604 asyncResp->res.jsonValue["@odata.id"] =
Ed Tanous253f11b2024-05-16 09:38:31 -07001605 std::format("/redfish/v1/Systems/{}/LogServices/EventLog/Entries",
1606 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Ed Tanous002d39b2022-05-31 08:59:27 -07001607 asyncResp->res.jsonValue["Name"] = "System Event Log Entries";
1608 asyncResp->res.jsonValue["Description"] =
1609 "Collection of System Event Log Entries";
1610
1611 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
1612 logEntryArray = nlohmann::json::array();
1613 // Go through the log files and create a unique ID for each
1614 // entry
1615 std::vector<std::filesystem::path> redfishLogFiles;
1616 getRedfishLogFiles(redfishLogFiles);
1617 uint64_t entryCount = 0;
1618 std::string logEntry;
1619
1620 // Oldest logs are in the last file, so start there and loop
1621 // backwards
1622 for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend();
1623 it++)
1624 {
1625 std::ifstream logStream(*it);
1626 if (!logStream.is_open())
Jason M. Bills4978b632022-02-22 14:17:43 -08001627 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001628 continue;
Jason M. Bills4978b632022-02-22 14:17:43 -08001629 }
Jason M. Bills897967d2019-07-29 17:05:30 -07001630
Ed Tanous002d39b2022-05-31 08:59:27 -07001631 // Reset the unique ID on the first entry
1632 bool firstEntry = true;
1633 while (std::getline(logStream, logEntry))
Jason M. Bills4978b632022-02-22 14:17:43 -08001634 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001635 std::string idStr;
1636 if (!getUniqueEntryID(logEntry, idStr, firstEntry))
Jason M. Bills4978b632022-02-22 14:17:43 -08001637 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001638 continue;
1639 }
Jason M. Billsefde4ec2022-06-24 08:59:52 -07001640 firstEntry = false;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001641
Jason M. Billsde703c52022-06-23 14:19:04 -07001642 nlohmann::json::object_t bmcLogEntry;
Patrick Williams89492a12023-05-10 07:51:34 -05001643 LogParseError status = fillEventLogEntryJson(idStr, logEntry,
1644 bmcLogEntry);
Jason M. Billsac992cd2022-06-24 13:31:46 -07001645 if (status == LogParseError::messageIdNotInRegistry)
1646 {
1647 continue;
1648 }
1649 if (status != LogParseError::success)
Ed Tanous002d39b2022-05-31 08:59:27 -07001650 {
1651 messages::internalError(asyncResp->res);
1652 return;
Andrew Geisslercb92c032018-08-17 07:56:14 -07001653 }
Jason M. Billsde703c52022-06-23 14:19:04 -07001654
Jason M. Billsde703c52022-06-23 14:19:04 -07001655 entryCount++;
1656 // Handle paging using skip (number of entries to skip from the
1657 // start) and top (number of entries to display)
Ed Tanous3648c8b2022-07-25 13:39:59 -07001658 if (entryCount <= skip || entryCount > skip + top)
Jason M. Billsde703c52022-06-23 14:19:04 -07001659 {
1660 continue;
1661 }
1662
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001663 logEntryArray.emplace_back(std::move(bmcLogEntry));
Jason M. Bills4978b632022-02-22 14:17:43 -08001664 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001665 }
1666 asyncResp->res.jsonValue["Members@odata.count"] = entryCount;
Ed Tanous3648c8b2022-07-25 13:39:59 -07001667 if (skip + top < entryCount)
Ed Tanous002d39b2022-05-31 08:59:27 -07001668 {
Ed Tanous253f11b2024-05-16 09:38:31 -07001669 asyncResp->res
1670 .jsonValue["Members@odata.nextLink"] = boost::urls::format(
1671 "/redfish/v1/Systems/{}/LogServices/EventLog/Entries?$skip={}",
1672 BMCWEB_REDFISH_SYSTEM_URI_NAME, std::to_string(skip + top));
Ed Tanous002d39b2022-05-31 08:59:27 -07001673 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001674 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001675}
Chicago Duan336e96c2019-07-15 14:22:08 +08001676
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001677inline void requestRoutesJournalEventLogEntry(App& app)
1678{
1679 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07001680 app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001681 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001682 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001683 [&app](const crow::Request& req,
1684 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07001685 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001686 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001687 {
1688 return;
1689 }
Ed Tanous25b54db2024-04-17 15:40:31 -07001690 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08001691 {
1692 // Option currently returns no systems. TBD
1693 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1694 systemName);
1695 return;
1696 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001697
Ed Tanous253f11b2024-05-16 09:38:31 -07001698 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07001699 {
1700 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1701 systemName);
1702 return;
1703 }
1704
Ed Tanous002d39b2022-05-31 08:59:27 -07001705 const std::string& targetID = param;
1706
1707 // Go through the log files and check the unique ID for each
1708 // entry to find the target entry
1709 std::vector<std::filesystem::path> redfishLogFiles;
1710 getRedfishLogFiles(redfishLogFiles);
1711 std::string logEntry;
1712
1713 // Oldest logs are in the last file, so start there and loop
1714 // backwards
1715 for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend();
1716 it++)
1717 {
1718 std::ifstream logStream(*it);
1719 if (!logStream.is_open())
1720 {
1721 continue;
1722 }
1723
1724 // Reset the unique ID on the first entry
1725 bool firstEntry = true;
1726 while (std::getline(logStream, logEntry))
1727 {
1728 std::string idStr;
1729 if (!getUniqueEntryID(logEntry, idStr, firstEntry))
Ed Tanous45ca1b82022-03-25 13:07:27 -07001730 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001731 continue;
1732 }
Jason M. Billsefde4ec2022-06-24 08:59:52 -07001733 firstEntry = false;
Ed Tanous002d39b2022-05-31 08:59:27 -07001734
1735 if (idStr == targetID)
1736 {
Jason M. Billsde703c52022-06-23 14:19:04 -07001737 nlohmann::json::object_t bmcLogEntry;
Jason M. Billsac992cd2022-06-24 13:31:46 -07001738 LogParseError status =
1739 fillEventLogEntryJson(idStr, logEntry, bmcLogEntry);
1740 if (status != LogParseError::success)
Ed Tanous002d39b2022-05-31 08:59:27 -07001741 {
1742 messages::internalError(asyncResp->res);
1743 return;
1744 }
Jason M. Billsd405bb52022-06-24 10:52:05 -07001745 asyncResp->res.jsonValue.update(bmcLogEntry);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001746 return;
1747 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001748 }
1749 }
1750 // Requested ID was not found
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08001751 messages::resourceNotFound(asyncResp->res, "LogEntry", targetID);
Patrick Williams5a39f772023-10-20 11:20:21 -05001752 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001753}
1754
1755inline void requestRoutesDBusEventLogEntryCollection(App& app)
1756{
Ed Tanous22d268c2022-05-19 09:39:07 -07001757 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07001758 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07001759 .methods(boost::beast::http::verb::get)(
1760 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001761 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1762 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001763 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001764 {
1765 return;
1766 }
Ed Tanous25b54db2024-04-17 15:40:31 -07001767 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08001768 {
1769 // Option currently returns no systems. TBD
1770 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1771 systemName);
1772 return;
1773 }
Ed Tanous253f11b2024-05-16 09:38:31 -07001774 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07001775 {
1776 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1777 systemName);
1778 return;
1779 }
1780
Ed Tanous002d39b2022-05-31 08:59:27 -07001781 // Collections don't include the static data added by SubRoute
1782 // because it has a duplicate entry for members
1783 asyncResp->res.jsonValue["@odata.type"] =
1784 "#LogEntryCollection.LogEntryCollection";
1785 asyncResp->res.jsonValue["@odata.id"] =
Ed Tanous253f11b2024-05-16 09:38:31 -07001786 std::format("/redfish/v1/Systems/{}/LogServices/EventLog/Entries",
1787 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Ed Tanous002d39b2022-05-31 08:59:27 -07001788 asyncResp->res.jsonValue["Name"] = "System Event Log Entries";
1789 asyncResp->res.jsonValue["Description"] =
1790 "Collection of System Event Log Entries";
1791
1792 // DBus implementation of EventLog/Entries
1793 // Make call to Logging Service to find all log entry objects
George Liu5eb468d2023-06-20 17:03:24 +08001794 sdbusplus::message::object_path path("/xyz/openbmc_project/logging");
1795 dbus::utility::getManagedObjects(
1796 "xyz.openbmc_project.Logging", path,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001797 [asyncResp](const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -07001798 const dbus::utility::ManagedObjectType& resp) {
1799 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -07001800 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001801 // TODO Handle for specific error code
Ed Tanous62598e32023-07-17 17:06:25 -07001802 BMCWEB_LOG_ERROR(
1803 "getLogEntriesIfaceData resp_handler got error {}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -07001804 messages::internalError(asyncResp->res);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001805 return;
1806 }
Ed Tanous3544d2a2023-08-06 18:12:20 -07001807 nlohmann::json::array_t entriesArray;
Ed Tanous002d39b2022-05-31 08:59:27 -07001808 for (const auto& objectPath : resp)
1809 {
1810 const uint32_t* id = nullptr;
1811 const uint64_t* timestamp = nullptr;
1812 const uint64_t* updateTimestamp = nullptr;
1813 const std::string* severity = nullptr;
1814 const std::string* message = nullptr;
1815 const std::string* filePath = nullptr;
Vijay Lobo9c11a172021-10-07 16:53:16 -05001816 const std::string* resolution = nullptr;
Ed Tanous002d39b2022-05-31 08:59:27 -07001817 bool resolved = false;
Abhishek Patel9017faf2021-09-14 22:48:55 -05001818 const std::string* notify = nullptr;
1819
Ed Tanous002d39b2022-05-31 08:59:27 -07001820 for (const auto& interfaceMap : objectPath.second)
1821 {
1822 if (interfaceMap.first ==
1823 "xyz.openbmc_project.Logging.Entry")
Xiaochao Ma75710de2021-01-21 17:56:02 +08001824 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001825 for (const auto& propertyMap : interfaceMap.second)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001826 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001827 if (propertyMap.first == "Id")
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001828 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001829 id = std::get_if<uint32_t>(&propertyMap.second);
1830 }
1831 else if (propertyMap.first == "Timestamp")
1832 {
1833 timestamp =
1834 std::get_if<uint64_t>(&propertyMap.second);
1835 }
1836 else if (propertyMap.first == "UpdateTimestamp")
1837 {
1838 updateTimestamp =
1839 std::get_if<uint64_t>(&propertyMap.second);
1840 }
1841 else if (propertyMap.first == "Severity")
1842 {
1843 severity = std::get_if<std::string>(
1844 &propertyMap.second);
1845 }
Vijay Lobo9c11a172021-10-07 16:53:16 -05001846 else if (propertyMap.first == "Resolution")
1847 {
1848 resolution = std::get_if<std::string>(
1849 &propertyMap.second);
1850 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001851 else if (propertyMap.first == "Message")
1852 {
1853 message = std::get_if<std::string>(
1854 &propertyMap.second);
1855 }
1856 else if (propertyMap.first == "Resolved")
1857 {
1858 const bool* resolveptr =
1859 std::get_if<bool>(&propertyMap.second);
1860 if (resolveptr == nullptr)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001861 {
1862 messages::internalError(asyncResp->res);
1863 return;
1864 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001865 resolved = *resolveptr;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001866 }
Abhishek Patel9017faf2021-09-14 22:48:55 -05001867 else if (propertyMap.first ==
1868 "ServiceProviderNotify")
1869 {
1870 notify = std::get_if<std::string>(
1871 &propertyMap.second);
1872 if (notify == nullptr)
1873 {
1874 messages::internalError(asyncResp->res);
1875 return;
1876 }
1877 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001878 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001879 if (id == nullptr || message == nullptr ||
Ed Tanous002d39b2022-05-31 08:59:27 -07001880 severity == nullptr)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001881 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001882 messages::internalError(asyncResp->res);
1883 return;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001884 }
1885 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001886 else if (interfaceMap.first ==
1887 "xyz.openbmc_project.Common.FilePath")
1888 {
1889 for (const auto& propertyMap : interfaceMap.second)
1890 {
1891 if (propertyMap.first == "Path")
1892 {
1893 filePath = std::get_if<std::string>(
1894 &propertyMap.second);
1895 }
1896 }
1897 }
1898 }
1899 // Object path without the
1900 // xyz.openbmc_project.Logging.Entry interface, ignore
1901 // and continue.
1902 if (id == nullptr || message == nullptr ||
1903 severity == nullptr || timestamp == nullptr ||
1904 updateTimestamp == nullptr)
1905 {
1906 continue;
1907 }
Ed Tanous3544d2a2023-08-06 18:12:20 -07001908 nlohmann::json& thisEntry = entriesArray.emplace_back();
Vijay Lobo9c11a172021-10-07 16:53:16 -05001909 thisEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Ed Tanousef4c65b2023-04-24 15:28:50 -07001910 thisEntry["@odata.id"] = boost::urls::format(
Ed Tanous253f11b2024-05-16 09:38:31 -07001911 "/redfish/v1/Systems/{}/LogServices/EventLog/Entries/{}",
1912 BMCWEB_REDFISH_SYSTEM_URI_NAME, std::to_string(*id));
Ed Tanous002d39b2022-05-31 08:59:27 -07001913 thisEntry["Name"] = "System Event Log Entry";
1914 thisEntry["Id"] = std::to_string(*id);
1915 thisEntry["Message"] = *message;
1916 thisEntry["Resolved"] = resolved;
Vijay Lobo9c11a172021-10-07 16:53:16 -05001917 if ((resolution != nullptr) && (!(*resolution).empty()))
1918 {
1919 thisEntry["Resolution"] = *resolution;
1920 }
Abhishek Patel9017faf2021-09-14 22:48:55 -05001921 std::optional<bool> notifyAction =
1922 getProviderNotifyAction(*notify);
1923 if (notifyAction)
1924 {
1925 thisEntry["ServiceProviderNotified"] = *notifyAction;
1926 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001927 thisEntry["EntryType"] = "Event";
1928 thisEntry["Severity"] =
1929 translateSeverityDbusToRedfish(*severity);
1930 thisEntry["Created"] =
Ed Tanous2b829372022-08-03 14:22:34 -07001931 redfish::time_utils::getDateTimeUintMs(*timestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07001932 thisEntry["Modified"] =
Ed Tanous2b829372022-08-03 14:22:34 -07001933 redfish::time_utils::getDateTimeUintMs(*updateTimestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07001934 if (filePath != nullptr)
1935 {
1936 thisEntry["AdditionalDataURI"] =
Ed Tanous253f11b2024-05-16 09:38:31 -07001937 std::format(
1938 "/redfish/v1/Systems/{}/LogServices/EventLog/Entries/",
1939 BMCWEB_REDFISH_SYSTEM_URI_NAME) +
Ed Tanous002d39b2022-05-31 08:59:27 -07001940 std::to_string(*id) + "/attachment";
1941 }
1942 }
Ed Tanous3544d2a2023-08-06 18:12:20 -07001943 std::ranges::sort(entriesArray, [](const nlohmann::json& left,
1944 const nlohmann::json& right) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001945 return (left["Id"] <= right["Id"]);
Ed Tanous3544d2a2023-08-06 18:12:20 -07001946 });
Ed Tanous002d39b2022-05-31 08:59:27 -07001947 asyncResp->res.jsonValue["Members@odata.count"] =
1948 entriesArray.size();
Ed Tanous3544d2a2023-08-06 18:12:20 -07001949 asyncResp->res.jsonValue["Members"] = std::move(entriesArray);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001950 });
Patrick Williams5a39f772023-10-20 11:20:21 -05001951 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001952}
Xiaochao Ma75710de2021-01-21 17:56:02 +08001953
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001954inline void requestRoutesDBusEventLogEntry(App& app)
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001955{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001956 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07001957 app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001958 .privileges(redfish::privileges::getLogEntry)
Ed Tanous002d39b2022-05-31 08:59:27 -07001959 .methods(boost::beast::http::verb::get)(
1960 [&app](const crow::Request& req,
1961 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07001962 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001963 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001964 {
1965 return;
1966 }
Ed Tanous25b54db2024-04-17 15:40:31 -07001967 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08001968 {
1969 // Option currently returns no systems. TBD
1970 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1971 systemName);
1972 return;
1973 }
Ed Tanous253f11b2024-05-16 09:38:31 -07001974 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07001975 {
1976 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1977 systemName);
1978 return;
1979 }
1980
Ed Tanous002d39b2022-05-31 08:59:27 -07001981 std::string entryID = param;
1982 dbus::utility::escapePathForDbus(entryID);
1983
1984 // DBus implementation of EventLog/Entries
1985 // Make call to Logging Service to find all log entry objects
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001986 sdbusplus::asio::getAllProperties(
1987 *crow::connections::systemBus, "xyz.openbmc_project.Logging",
1988 "/xyz/openbmc_project/logging/entry/" + entryID, "",
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001989 [asyncResp, entryID](const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -07001990 const dbus::utility::DBusPropertiesMap& resp) {
1991 if (ec.value() == EBADR)
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001992 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001993 messages::resourceNotFound(asyncResp->res, "EventLogEntry",
1994 entryID);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001995 return;
1996 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001997 if (ec)
1998 {
Ed Tanous62598e32023-07-17 17:06:25 -07001999 BMCWEB_LOG_ERROR(
2000 "EventLogEntry (DBus) resp_handler got error {}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -07002001 messages::internalError(asyncResp->res);
2002 return;
2003 }
2004 const uint32_t* id = nullptr;
2005 const uint64_t* timestamp = nullptr;
2006 const uint64_t* updateTimestamp = nullptr;
2007 const std::string* severity = nullptr;
2008 const std::string* message = nullptr;
2009 const std::string* filePath = nullptr;
Vijay Lobo9c11a172021-10-07 16:53:16 -05002010 const std::string* resolution = nullptr;
Ed Tanous002d39b2022-05-31 08:59:27 -07002011 bool resolved = false;
Abhishek Patel9017faf2021-09-14 22:48:55 -05002012 const std::string* notify = nullptr;
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06002013
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02002014 const bool success = sdbusplus::unpackPropertiesNoThrow(
2015 dbus_utils::UnpackErrorPrinter(), resp, "Id", id, "Timestamp",
2016 timestamp, "UpdateTimestamp", updateTimestamp, "Severity",
Vijay Lobo9c11a172021-10-07 16:53:16 -05002017 severity, "Message", message, "Resolved", resolved,
Abhishek Patel9017faf2021-09-14 22:48:55 -05002018 "Resolution", resolution, "Path", filePath,
2019 "ServiceProviderNotify", notify);
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02002020
2021 if (!success)
Ed Tanous002d39b2022-05-31 08:59:27 -07002022 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02002023 messages::internalError(asyncResp->res);
2024 return;
Ed Tanous002d39b2022-05-31 08:59:27 -07002025 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02002026
Ed Tanous002d39b2022-05-31 08:59:27 -07002027 if (id == nullptr || message == nullptr || severity == nullptr ||
Abhishek Patel9017faf2021-09-14 22:48:55 -05002028 timestamp == nullptr || updateTimestamp == nullptr ||
2029 notify == nullptr)
Ed Tanous002d39b2022-05-31 08:59:27 -07002030 {
2031 messages::internalError(asyncResp->res);
2032 return;
2033 }
Abhishek Patel9017faf2021-09-14 22:48:55 -05002034
Ed Tanous002d39b2022-05-31 08:59:27 -07002035 asyncResp->res.jsonValue["@odata.type"] =
Vijay Lobo9c11a172021-10-07 16:53:16 -05002036 "#LogEntry.v1_9_0.LogEntry";
Ed Tanousef4c65b2023-04-24 15:28:50 -07002037 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
Ed Tanous253f11b2024-05-16 09:38:31 -07002038 "/redfish/v1/Systems/{}/LogServices/EventLog/Entries/{}",
2039 BMCWEB_REDFISH_SYSTEM_URI_NAME, std::to_string(*id));
Ed Tanous002d39b2022-05-31 08:59:27 -07002040 asyncResp->res.jsonValue["Name"] = "System Event Log Entry";
2041 asyncResp->res.jsonValue["Id"] = std::to_string(*id);
2042 asyncResp->res.jsonValue["Message"] = *message;
2043 asyncResp->res.jsonValue["Resolved"] = resolved;
Abhishek Patel9017faf2021-09-14 22:48:55 -05002044 std::optional<bool> notifyAction = getProviderNotifyAction(*notify);
2045 if (notifyAction)
2046 {
2047 asyncResp->res.jsonValue["ServiceProviderNotified"] =
2048 *notifyAction;
2049 }
Vijay Lobo9c11a172021-10-07 16:53:16 -05002050 if ((resolution != nullptr) && (!(*resolution).empty()))
2051 {
2052 asyncResp->res.jsonValue["Resolution"] = *resolution;
2053 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002054 asyncResp->res.jsonValue["EntryType"] = "Event";
2055 asyncResp->res.jsonValue["Severity"] =
2056 translateSeverityDbusToRedfish(*severity);
2057 asyncResp->res.jsonValue["Created"] =
Ed Tanous2b829372022-08-03 14:22:34 -07002058 redfish::time_utils::getDateTimeUintMs(*timestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07002059 asyncResp->res.jsonValue["Modified"] =
Ed Tanous2b829372022-08-03 14:22:34 -07002060 redfish::time_utils::getDateTimeUintMs(*updateTimestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07002061 if (filePath != nullptr)
2062 {
2063 asyncResp->res.jsonValue["AdditionalDataURI"] =
Ed Tanous253f11b2024-05-16 09:38:31 -07002064 std::format(
2065 "/redfish/v1/Systems/{}/LogServices/EventLog/Entries/",
2066 BMCWEB_REDFISH_SYSTEM_URI_NAME) +
Ed Tanous002d39b2022-05-31 08:59:27 -07002067 std::to_string(*id) + "/attachment";
2068 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07002069 });
Patrick Williams5a39f772023-10-20 11:20:21 -05002070 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002071
2072 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07002073 app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002074 .privileges(redfish::privileges::patchLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002075 .methods(boost::beast::http::verb::patch)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002076 [&app](const crow::Request& req,
2077 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07002078 const std::string& systemName, const std::string& entryId) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002079 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002080 {
2081 return;
2082 }
Ed Tanous25b54db2024-04-17 15:40:31 -07002083 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08002084 {
2085 // Option currently returns no systems. TBD
2086 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2087 systemName);
2088 return;
2089 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002090 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07002091 {
2092 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2093 systemName);
2094 return;
2095 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002096 std::optional<bool> resolved;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002097
Ed Tanous002d39b2022-05-31 08:59:27 -07002098 if (!json_util::readJsonPatch(req, asyncResp->res, "Resolved",
2099 resolved))
2100 {
2101 return;
2102 }
Ed Tanous62598e32023-07-17 17:06:25 -07002103 BMCWEB_LOG_DEBUG("Set Resolved");
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06002104
Ginu Georgee93abac2024-06-14 17:35:27 +05302105 setDbusProperty(asyncResp, "Resolved", "xyz.openbmc_project.Logging",
Asmitha Karunanithi3eb66652024-04-02 16:34:36 +00002106 "/xyz/openbmc_project/logging/entry/" + entryId,
2107 "xyz.openbmc_project.Logging.Entry", "Resolved",
Ginu Georgee93abac2024-06-14 17:35:27 +05302108 *resolved);
Patrick Williams5a39f772023-10-20 11:20:21 -05002109 });
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06002110
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002111 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07002112 app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002113 .privileges(redfish::privileges::deleteLogEntry)
2114
Ed Tanous002d39b2022-05-31 08:59:27 -07002115 .methods(boost::beast::http::verb::delete_)(
2116 [&app](const crow::Request& req,
2117 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07002118 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002119 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002120 {
2121 return;
2122 }
Ed Tanous25b54db2024-04-17 15:40:31 -07002123 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08002124 {
2125 // Option currently returns no systems. TBD
2126 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2127 systemName);
2128 return;
2129 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002130 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07002131 {
2132 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2133 systemName);
2134 return;
2135 }
Ed Tanous62598e32023-07-17 17:06:25 -07002136 BMCWEB_LOG_DEBUG("Do delete single event entries.");
Ed Tanous002d39b2022-05-31 08:59:27 -07002137
2138 std::string entryID = param;
2139
2140 dbus::utility::escapePathForDbus(entryID);
2141
2142 // Process response from Logging service.
Patrick Williams5a39f772023-10-20 11:20:21 -05002143 auto respHandler = [asyncResp,
2144 entryID](const boost::system::error_code& ec) {
Ed Tanous62598e32023-07-17 17:06:25 -07002145 BMCWEB_LOG_DEBUG("EventLogEntry (DBus) doDelete callback: Done");
Ed Tanous002d39b2022-05-31 08:59:27 -07002146 if (ec)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002147 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002148 if (ec.value() == EBADR)
Ed Tanous45ca1b82022-03-25 13:07:27 -07002149 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002150 messages::resourceNotFound(asyncResp->res, "LogEntry",
2151 entryID);
Ed Tanous45ca1b82022-03-25 13:07:27 -07002152 return;
2153 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002154 // TODO Handle for specific error code
Ed Tanous62598e32023-07-17 17:06:25 -07002155 BMCWEB_LOG_ERROR(
2156 "EventLogEntry (DBus) doDelete respHandler got error {}",
2157 ec);
Ed Tanous002d39b2022-05-31 08:59:27 -07002158 asyncResp->res.result(
2159 boost::beast::http::status::internal_server_error);
2160 return;
2161 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002162
Ed Tanous002d39b2022-05-31 08:59:27 -07002163 asyncResp->res.result(boost::beast::http::status::ok);
2164 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002165
Ed Tanous002d39b2022-05-31 08:59:27 -07002166 // Make call to Logging service to request Delete Log
2167 crow::connections::systemBus->async_method_call(
2168 respHandler, "xyz.openbmc_project.Logging",
2169 "/xyz/openbmc_project/logging/entry/" + entryID,
2170 "xyz.openbmc_project.Object.Delete", "Delete");
Patrick Williams5a39f772023-10-20 11:20:21 -05002171 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002172}
2173
Spencer Kub7028eb2021-10-26 15:27:35 +08002174constexpr const char* hostLoggerFolderPath = "/var/log/console";
2175
2176inline bool
2177 getHostLoggerFiles(const std::string& hostLoggerFilePath,
2178 std::vector<std::filesystem::path>& hostLoggerFiles)
2179{
2180 std::error_code ec;
2181 std::filesystem::directory_iterator logPath(hostLoggerFilePath, ec);
2182 if (ec)
2183 {
Carson Labradobf2dded2023-08-10 00:37:06 +00002184 BMCWEB_LOG_WARNING("{}", ec.message());
Spencer Kub7028eb2021-10-26 15:27:35 +08002185 return false;
2186 }
2187 for (const std::filesystem::directory_entry& it : logPath)
2188 {
2189 std::string filename = it.path().filename();
2190 // Prefix of each log files is "log". Find the file and save the
2191 // path
Ed Tanous11ba3972022-07-11 09:50:41 -07002192 if (filename.starts_with("log"))
Spencer Kub7028eb2021-10-26 15:27:35 +08002193 {
2194 hostLoggerFiles.emplace_back(it.path());
2195 }
2196 }
2197 // As the log files rotate, they are appended with a ".#" that is higher for
2198 // the older logs. Since we start from oldest logs, sort the name in
2199 // descending order.
2200 std::sort(hostLoggerFiles.rbegin(), hostLoggerFiles.rend(),
2201 AlphanumLess<std::string>());
2202
2203 return true;
2204}
2205
Ed Tanous02cad962022-06-30 16:50:15 -07002206inline bool getHostLoggerEntries(
2207 const std::vector<std::filesystem::path>& hostLoggerFiles, uint64_t skip,
2208 uint64_t top, std::vector<std::string>& logEntries, size_t& logCount)
Spencer Kub7028eb2021-10-26 15:27:35 +08002209{
2210 GzFileReader logFile;
2211
2212 // Go though all log files and expose host logs.
2213 for (const std::filesystem::path& it : hostLoggerFiles)
2214 {
2215 if (!logFile.gzGetLines(it.string(), skip, top, logEntries, logCount))
2216 {
Ed Tanous62598e32023-07-17 17:06:25 -07002217 BMCWEB_LOG_ERROR("fail to expose host logs");
Spencer Kub7028eb2021-10-26 15:27:35 +08002218 return false;
2219 }
2220 }
2221 // Get lastMessage from constructor by getter
2222 std::string lastMessage = logFile.getLastMessage();
2223 if (!lastMessage.empty())
2224 {
2225 logCount++;
2226 if (logCount > skip && logCount <= (skip + top))
2227 {
2228 logEntries.push_back(lastMessage);
2229 }
2230 }
2231 return true;
2232}
2233
Ed Tanous6f056f22024-04-07 13:35:51 -07002234inline void fillHostLoggerEntryJson(std::string_view logEntryID,
2235 std::string_view msg,
Jason M. Bills6d6574c2022-06-28 12:30:16 -07002236 nlohmann::json::object_t& logEntryJson)
Spencer Kub7028eb2021-10-26 15:27:35 +08002237{
2238 // Fill in the log entry with the gathered data.
Vijay Lobo9c11a172021-10-07 16:53:16 -05002239 logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Ed Tanousef4c65b2023-04-24 15:28:50 -07002240 logEntryJson["@odata.id"] = boost::urls::format(
Ed Tanous253f11b2024-05-16 09:38:31 -07002241 "/redfish/v1/Systems/{}/LogServices/HostLogger/Entries/{}",
2242 BMCWEB_REDFISH_SYSTEM_URI_NAME, logEntryID);
Jason M. Bills6d6574c2022-06-28 12:30:16 -07002243 logEntryJson["Name"] = "Host Logger Entry";
2244 logEntryJson["Id"] = logEntryID;
2245 logEntryJson["Message"] = msg;
2246 logEntryJson["EntryType"] = "Oem";
2247 logEntryJson["Severity"] = "OK";
2248 logEntryJson["OemRecordFormat"] = "Host Logger Entry";
Spencer Kub7028eb2021-10-26 15:27:35 +08002249}
2250
2251inline void requestRoutesSystemHostLogger(App& app)
2252{
Ed Tanous22d268c2022-05-19 09:39:07 -07002253 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/")
Spencer Kub7028eb2021-10-26 15:27:35 +08002254 .privileges(redfish::privileges::getLogService)
Ed Tanous14766872022-03-15 10:44:42 -07002255 .methods(boost::beast::http::verb::get)(
2256 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07002257 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2258 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002259 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002260 {
2261 return;
2262 }
Ed Tanous25b54db2024-04-17 15:40:31 -07002263 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08002264 {
2265 // Option currently returns no systems. TBD
2266 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2267 systemName);
2268 return;
2269 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002270 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07002271 {
2272 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2273 systemName);
2274 return;
2275 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002276 asyncResp->res.jsonValue["@odata.id"] =
Ed Tanous253f11b2024-05-16 09:38:31 -07002277 std::format("/redfish/v1/Systems/{}/LogServices/HostLogger",
2278 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Ed Tanous002d39b2022-05-31 08:59:27 -07002279 asyncResp->res.jsonValue["@odata.type"] =
Janet Adkinsb25644a2023-08-16 11:23:45 -05002280 "#LogService.v1_2_0.LogService";
Ed Tanous002d39b2022-05-31 08:59:27 -07002281 asyncResp->res.jsonValue["Name"] = "Host Logger Service";
2282 asyncResp->res.jsonValue["Description"] = "Host Logger Service";
2283 asyncResp->res.jsonValue["Id"] = "HostLogger";
2284 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
Ed Tanous253f11b2024-05-16 09:38:31 -07002285 std::format("/redfish/v1/Systems/{}/LogServices/HostLogger/Entries",
2286 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Patrick Williams5a39f772023-10-20 11:20:21 -05002287 });
Spencer Kub7028eb2021-10-26 15:27:35 +08002288}
2289
2290inline void requestRoutesSystemHostLoggerCollection(App& app)
2291{
2292 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07002293 "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/")
Spencer Kub7028eb2021-10-26 15:27:35 +08002294 .privileges(redfish::privileges::getLogEntry)
Ed Tanous002d39b2022-05-31 08:59:27 -07002295 .methods(boost::beast::http::verb::get)(
2296 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07002297 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2298 const std::string& systemName) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002299 query_param::QueryCapabilities capabilities = {
2300 .canDelegateTop = true,
2301 .canDelegateSkip = true,
2302 };
2303 query_param::Query delegatedQuery;
2304 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00002305 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07002306 {
2307 return;
2308 }
Ed Tanous25b54db2024-04-17 15:40:31 -07002309 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08002310 {
2311 // Option currently returns no systems. TBD
2312 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2313 systemName);
2314 return;
2315 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002316 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07002317 {
2318 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2319 systemName);
2320 return;
2321 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002322 asyncResp->res.jsonValue["@odata.id"] =
Ed Tanous253f11b2024-05-16 09:38:31 -07002323 std::format("/redfish/v1/Systems/{}/LogServices/HostLogger/Entries",
2324 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Ed Tanous002d39b2022-05-31 08:59:27 -07002325 asyncResp->res.jsonValue["@odata.type"] =
2326 "#LogEntryCollection.LogEntryCollection";
2327 asyncResp->res.jsonValue["Name"] = "HostLogger Entries";
2328 asyncResp->res.jsonValue["Description"] =
2329 "Collection of HostLogger Entries";
2330 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
2331 logEntryArray = nlohmann::json::array();
2332 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Spencer Kub7028eb2021-10-26 15:27:35 +08002333
Ed Tanous002d39b2022-05-31 08:59:27 -07002334 std::vector<std::filesystem::path> hostLoggerFiles;
2335 if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles))
2336 {
Carson Labradobf2dded2023-08-10 00:37:06 +00002337 BMCWEB_LOG_DEBUG("Failed to get host log file path");
Ed Tanous002d39b2022-05-31 08:59:27 -07002338 return;
2339 }
Ed Tanous3648c8b2022-07-25 13:39:59 -07002340 // If we weren't provided top and skip limits, use the defaults.
2341 size_t skip = delegatedQuery.skip.value_or(0);
Jiaqing Zhao5143f7a2022-07-22 09:33:33 +08002342 size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
Ed Tanous002d39b2022-05-31 08:59:27 -07002343 size_t logCount = 0;
2344 // This vector only store the entries we want to expose that
2345 // control by skip and top.
2346 std::vector<std::string> logEntries;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002347 if (!getHostLoggerEntries(hostLoggerFiles, skip, top, logEntries,
2348 logCount))
Ed Tanous002d39b2022-05-31 08:59:27 -07002349 {
2350 messages::internalError(asyncResp->res);
2351 return;
2352 }
2353 // If vector is empty, that means skip value larger than total
2354 // log count
2355 if (logEntries.empty())
2356 {
2357 asyncResp->res.jsonValue["Members@odata.count"] = logCount;
2358 return;
2359 }
2360 if (!logEntries.empty())
2361 {
2362 for (size_t i = 0; i < logEntries.size(); i++)
George Liu0fda0f12021-11-16 10:06:17 +08002363 {
Jason M. Bills6d6574c2022-06-28 12:30:16 -07002364 nlohmann::json::object_t hostLogEntry;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002365 fillHostLoggerEntryJson(std::to_string(skip + i), logEntries[i],
2366 hostLogEntry);
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002367 logEntryArray.emplace_back(std::move(hostLogEntry));
George Liu0fda0f12021-11-16 10:06:17 +08002368 }
2369
Ed Tanous002d39b2022-05-31 08:59:27 -07002370 asyncResp->res.jsonValue["Members@odata.count"] = logCount;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002371 if (skip + top < logCount)
George Liu0fda0f12021-11-16 10:06:17 +08002372 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002373 asyncResp->res.jsonValue["Members@odata.nextLink"] =
Ed Tanous253f11b2024-05-16 09:38:31 -07002374 std::format(
2375 "/redfish/v1/Systems/{}/LogServices/HostLogger/Entries?$skip=",
2376 BMCWEB_REDFISH_SYSTEM_URI_NAME) +
Ed Tanous3648c8b2022-07-25 13:39:59 -07002377 std::to_string(skip + top);
George Liu0fda0f12021-11-16 10:06:17 +08002378 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002379 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002380 });
Spencer Kub7028eb2021-10-26 15:27:35 +08002381}
2382
2383inline void requestRoutesSystemHostLoggerLogEntry(App& app)
2384{
2385 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07002386 app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/<str>/")
Spencer Kub7028eb2021-10-26 15:27:35 +08002387 .privileges(redfish::privileges::getLogEntry)
2388 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002389 [&app](const crow::Request& req,
2390 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07002391 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002392 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002393 {
2394 return;
2395 }
Ed Tanous25b54db2024-04-17 15:40:31 -07002396 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08002397 {
2398 // Option currently returns no systems. TBD
2399 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2400 systemName);
2401 return;
2402 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002403 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07002404 {
2405 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2406 systemName);
2407 return;
2408 }
Ed Tanous6f056f22024-04-07 13:35:51 -07002409 std::string_view targetID = param;
Spencer Kub7028eb2021-10-26 15:27:35 +08002410
Ed Tanous002d39b2022-05-31 08:59:27 -07002411 uint64_t idInt = 0;
Ed Tanousca45aa32022-01-07 09:28:45 -08002412
Ed Tanous6f056f22024-04-07 13:35:51 -07002413 auto [ptr, ec] = std::from_chars(targetID.begin(), targetID.end(),
Patrick Williams84396af2023-05-11 11:47:45 -05002414 idInt);
Ed Tanous6f056f22024-04-07 13:35:51 -07002415 if (ec != std::errc{} || ptr != targetID.end())
Ed Tanous002d39b2022-05-31 08:59:27 -07002416 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08002417 messages::resourceNotFound(asyncResp->res, "LogEntry", param);
Ed Tanous002d39b2022-05-31 08:59:27 -07002418 return;
2419 }
Spencer Kub7028eb2021-10-26 15:27:35 +08002420
Ed Tanous002d39b2022-05-31 08:59:27 -07002421 std::vector<std::filesystem::path> hostLoggerFiles;
2422 if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles))
2423 {
Carson Labradobf2dded2023-08-10 00:37:06 +00002424 BMCWEB_LOG_DEBUG("Failed to get host log file path");
Ed Tanous002d39b2022-05-31 08:59:27 -07002425 return;
2426 }
Spencer Kub7028eb2021-10-26 15:27:35 +08002427
Ed Tanous002d39b2022-05-31 08:59:27 -07002428 size_t logCount = 0;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002429 size_t top = 1;
Ed Tanous002d39b2022-05-31 08:59:27 -07002430 std::vector<std::string> logEntries;
2431 // We can get specific entry by skip and top. For example, if we
2432 // want to get nth entry, we can set skip = n-1 and top = 1 to
2433 // get that entry
2434 if (!getHostLoggerEntries(hostLoggerFiles, idInt, top, logEntries,
2435 logCount))
2436 {
2437 messages::internalError(asyncResp->res);
2438 return;
2439 }
Spencer Kub7028eb2021-10-26 15:27:35 +08002440
Ed Tanous002d39b2022-05-31 08:59:27 -07002441 if (!logEntries.empty())
2442 {
Jason M. Bills6d6574c2022-06-28 12:30:16 -07002443 nlohmann::json::object_t hostLogEntry;
2444 fillHostLoggerEntryJson(targetID, logEntries[0], hostLogEntry);
2445 asyncResp->res.jsonValue.update(hostLogEntry);
Ed Tanous002d39b2022-05-31 08:59:27 -07002446 return;
2447 }
Spencer Kub7028eb2021-10-26 15:27:35 +08002448
Ed Tanous002d39b2022-05-31 08:59:27 -07002449 // Requested ID was not found
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08002450 messages::resourceNotFound(asyncResp->res, "LogEntry", param);
Patrick Williams5a39f772023-10-20 11:20:21 -05002451 });
Spencer Kub7028eb2021-10-26 15:27:35 +08002452}
2453
Claire Weinandd72e872022-08-15 14:20:06 -07002454inline void handleBMCLogServicesCollectionGet(
Claire Weinanfdd26902022-03-01 14:18:25 -08002455 crow::App& app, const crow::Request& req,
Ed Tanous253f11b2024-05-16 09:38:31 -07002456 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2457 const std::string& managerId)
Claire Weinanfdd26902022-03-01 14:18:25 -08002458{
2459 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2460 {
2461 return;
2462 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002463
2464 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
2465 {
2466 messages::resourceNotFound(asyncResp->res, "Manager", managerId);
2467 return;
2468 }
2469
Claire Weinanfdd26902022-03-01 14:18:25 -08002470 // Collections don't include the static data added by SubRoute
2471 // because it has a duplicate entry for members
2472 asyncResp->res.jsonValue["@odata.type"] =
2473 "#LogServiceCollection.LogServiceCollection";
Ed Tanous253f11b2024-05-16 09:38:31 -07002474 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
2475 "/redfish/v1/Managers/{}/LogServices", BMCWEB_REDFISH_MANAGER_URI_NAME);
Claire Weinanfdd26902022-03-01 14:18:25 -08002476 asyncResp->res.jsonValue["Name"] = "Open BMC Log Services Collection";
2477 asyncResp->res.jsonValue["Description"] =
2478 "Collection of LogServices for this Manager";
2479 nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"];
2480 logServiceArray = nlohmann::json::array();
2481
Ed Tanous25b54db2024-04-17 15:40:31 -07002482 if constexpr (BMCWEB_REDFISH_BMC_JOURNAL)
2483 {
2484 nlohmann::json::object_t journal;
Ed Tanous253f11b2024-05-16 09:38:31 -07002485 journal["@odata.id"] =
2486 boost::urls::format("/redfish/v1/Managers/{}/LogServices/Journal",
2487 BMCWEB_REDFISH_MANAGER_URI_NAME);
Ed Tanous25b54db2024-04-17 15:40:31 -07002488 logServiceArray.emplace_back(std::move(journal));
2489 }
Claire Weinanfdd26902022-03-01 14:18:25 -08002490
2491 asyncResp->res.jsonValue["Members@odata.count"] = logServiceArray.size();
2492
Ed Tanous25b54db2024-04-17 15:40:31 -07002493 if constexpr (BMCWEB_REDFISH_DUMP_LOG)
2494 {
2495 constexpr std::array<std::string_view, 1> interfaces = {
2496 "xyz.openbmc_project.Collection.DeleteAll"};
2497 dbus::utility::getSubTreePaths(
2498 "/xyz/openbmc_project/dump", 0, interfaces,
2499 [asyncResp](const boost::system::error_code& ec,
2500 const dbus::utility::MapperGetSubTreePathsResponse&
2501 subTreePaths) {
2502 if (ec)
Claire Weinanfdd26902022-03-01 14:18:25 -08002503 {
Ed Tanous25b54db2024-04-17 15:40:31 -07002504 BMCWEB_LOG_ERROR(
2505 "handleBMCLogServicesCollectionGet respHandler got error {}",
2506 ec);
2507 // Assume that getting an error simply means there are no dump
2508 // LogServices. Return without adding any error response.
2509 return;
Claire Weinanfdd26902022-03-01 14:18:25 -08002510 }
Claire Weinanfdd26902022-03-01 14:18:25 -08002511
Ed Tanous25b54db2024-04-17 15:40:31 -07002512 nlohmann::json& logServiceArrayLocal =
2513 asyncResp->res.jsonValue["Members"];
2514
2515 for (const std::string& path : subTreePaths)
2516 {
2517 if (path == "/xyz/openbmc_project/dump/bmc")
2518 {
2519 nlohmann::json::object_t member;
Ed Tanous253f11b2024-05-16 09:38:31 -07002520 member["@odata.id"] = boost::urls::format(
2521 "/redfish/v1/Managers/{}/LogServices/Dump",
2522 BMCWEB_REDFISH_MANAGER_URI_NAME);
Ed Tanous25b54db2024-04-17 15:40:31 -07002523 logServiceArrayLocal.emplace_back(std::move(member));
2524 }
2525 else if (path == "/xyz/openbmc_project/dump/faultlog")
2526 {
2527 nlohmann::json::object_t member;
Ed Tanous253f11b2024-05-16 09:38:31 -07002528 member["@odata.id"] = boost::urls::format(
2529 "/redfish/v1/Managers/{}/LogServices/FaultLog",
2530 BMCWEB_REDFISH_MANAGER_URI_NAME);
Ed Tanous25b54db2024-04-17 15:40:31 -07002531 logServiceArrayLocal.emplace_back(std::move(member));
2532 }
2533 }
2534
2535 asyncResp->res.jsonValue["Members@odata.count"] =
2536 logServiceArrayLocal.size();
2537 });
2538 }
Claire Weinanfdd26902022-03-01 14:18:25 -08002539}
2540
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002541inline void requestRoutesBMCLogServiceCollection(App& app)
2542{
Ed Tanous253f11b2024-05-16 09:38:31 -07002543 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/LogServices/")
Gunnar Millsad89dcf2021-07-30 14:40:11 -05002544 .privileges(redfish::privileges::getLogServiceCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002545 .methods(boost::beast::http::verb::get)(
Claire Weinandd72e872022-08-15 14:20:06 -07002546 std::bind_front(handleBMCLogServicesCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002547}
Ed Tanous1da66f72018-07-27 16:13:37 -07002548
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002549inline void requestRoutesBMCJournalLogService(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07002550{
Ed Tanous253f11b2024-05-16 09:38:31 -07002551 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/LogServices/Journal/")
Ed Tanoused398212021-06-09 17:05:54 -07002552 .privileges(redfish::privileges::getLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002553 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002554 [&app](const crow::Request& req,
Ed Tanous253f11b2024-05-16 09:38:31 -07002555 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2556 const std::string& managerId) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002557 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002558 {
2559 return;
2560 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002561
2562 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
2563 {
2564 messages::resourceNotFound(asyncResp->res, "Manager", managerId);
2565 return;
2566 }
2567
Ed Tanous002d39b2022-05-31 08:59:27 -07002568 asyncResp->res.jsonValue["@odata.type"] =
Janet Adkinsb25644a2023-08-16 11:23:45 -05002569 "#LogService.v1_2_0.LogService";
Ed Tanous002d39b2022-05-31 08:59:27 -07002570 asyncResp->res.jsonValue["@odata.id"] =
Ed Tanous253f11b2024-05-16 09:38:31 -07002571 boost::urls::format("/redfish/v1/Managers/{}/LogServices/Journal",
2572 BMCWEB_REDFISH_MANAGER_URI_NAME);
Ed Tanous002d39b2022-05-31 08:59:27 -07002573 asyncResp->res.jsonValue["Name"] = "Open BMC Journal Log Service";
2574 asyncResp->res.jsonValue["Description"] = "BMC Journal Log Service";
Ed Tanoused34a4a2023-02-08 15:43:27 -08002575 asyncResp->res.jsonValue["Id"] = "Journal";
Ed Tanous002d39b2022-05-31 08:59:27 -07002576 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
Tejas Patil7c8c4052021-06-04 17:43:14 +05302577
Ed Tanous002d39b2022-05-31 08:59:27 -07002578 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07002579 redfish::time_utils::getDateTimeOffsetNow();
Ed Tanous002d39b2022-05-31 08:59:27 -07002580 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2581 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2582 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05302583
Ed Tanous253f11b2024-05-16 09:38:31 -07002584 asyncResp->res.jsonValue["Entries"]["@odata.id"] = boost::urls::format(
2585 "/redfish/v1/Managers/{}/LogServices/Journal/Entries",
2586 BMCWEB_REDFISH_MANAGER_URI_NAME);
Patrick Williams5a39f772023-10-20 11:20:21 -05002587 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002588}
Jason M. Billse1f26342018-07-18 12:12:00 -07002589
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002590static int
2591 fillBMCJournalLogEntryJson(const std::string& bmcJournalLogEntryID,
2592 sd_journal* journal,
2593 nlohmann::json::object_t& bmcJournalLogEntryJson)
Jason M. Billse1f26342018-07-18 12:12:00 -07002594{
2595 // Get the Log Entry contents
2596 int ret = 0;
Jason M. Billse1f26342018-07-18 12:12:00 -07002597
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08002598 std::string message;
2599 std::string_view syslogID;
2600 ret = getJournalMetadata(journal, "SYSLOG_IDENTIFIER", syslogID);
2601 if (ret < 0)
2602 {
Carson Labradobf2dded2023-08-10 00:37:06 +00002603 BMCWEB_LOG_DEBUG("Failed to read SYSLOG_IDENTIFIER field: {}",
Ed Tanous62598e32023-07-17 17:06:25 -07002604 strerror(-ret));
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08002605 }
2606 if (!syslogID.empty())
2607 {
2608 message += std::string(syslogID) + ": ";
2609 }
2610
Ed Tanous39e77502019-03-04 17:35:53 -08002611 std::string_view msg;
Jason M. Bills16428a12018-11-02 12:42:29 -07002612 ret = getJournalMetadata(journal, "MESSAGE", msg);
Jason M. Billse1f26342018-07-18 12:12:00 -07002613 if (ret < 0)
2614 {
Ed Tanous62598e32023-07-17 17:06:25 -07002615 BMCWEB_LOG_ERROR("Failed to read MESSAGE field: {}", strerror(-ret));
Jason M. Billse1f26342018-07-18 12:12:00 -07002616 return 1;
2617 }
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08002618 message += std::string(msg);
Jason M. Billse1f26342018-07-18 12:12:00 -07002619
2620 // Get the severity from the PRIORITY field
Ed Tanous271584a2019-07-09 16:24:22 -07002621 long int severity = 8; // Default to an invalid priority
Jason M. Bills16428a12018-11-02 12:42:29 -07002622 ret = getJournalMetadata(journal, "PRIORITY", 10, severity);
Jason M. Billse1f26342018-07-18 12:12:00 -07002623 if (ret < 0)
2624 {
Carson Labradobf2dded2023-08-10 00:37:06 +00002625 BMCWEB_LOG_DEBUG("Failed to read PRIORITY field: {}", strerror(-ret));
Jason M. Billse1f26342018-07-18 12:12:00 -07002626 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002627
2628 // Get the Created time from the timestamp
Jason M. Bills16428a12018-11-02 12:42:29 -07002629 std::string entryTimeStr;
2630 if (!getEntryTimestamp(journal, entryTimeStr))
Jason M. Billse1f26342018-07-18 12:12:00 -07002631 {
Jason M. Bills16428a12018-11-02 12:42:29 -07002632 return 1;
Jason M. Billse1f26342018-07-18 12:12:00 -07002633 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002634
2635 // Fill in the log entry with the gathered data
Vijay Lobo9c11a172021-10-07 16:53:16 -05002636 bmcJournalLogEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Ed Tanousef4c65b2023-04-24 15:28:50 -07002637 bmcJournalLogEntryJson["@odata.id"] = boost::urls::format(
Ed Tanous253f11b2024-05-16 09:38:31 -07002638 "/redfish/v1/Managers/{}/LogServices/Journal/Entries/{}",
2639 BMCWEB_REDFISH_MANAGER_URI_NAME, bmcJournalLogEntryID);
Jason M. Bills84afc482022-06-24 12:38:23 -07002640 bmcJournalLogEntryJson["Name"] = "BMC Journal Entry";
2641 bmcJournalLogEntryJson["Id"] = bmcJournalLogEntryID;
2642 bmcJournalLogEntryJson["Message"] = std::move(message);
2643 bmcJournalLogEntryJson["EntryType"] = "Oem";
Ed Tanousddf35642024-03-27 14:12:21 -07002644 log_entry::EventSeverity severityEnum = log_entry::EventSeverity::OK;
2645 if (severity <= 2)
2646 {
2647 severityEnum = log_entry::EventSeverity::Critical;
2648 }
2649 else if (severity <= 4)
2650 {
2651 severityEnum = log_entry::EventSeverity::Warning;
2652 }
2653
2654 bmcJournalLogEntryJson["Severity"] = severityEnum;
Jason M. Bills84afc482022-06-24 12:38:23 -07002655 bmcJournalLogEntryJson["OemRecordFormat"] = "BMC Journal Entry";
2656 bmcJournalLogEntryJson["Created"] = std::move(entryTimeStr);
Jason M. Billse1f26342018-07-18 12:12:00 -07002657 return 0;
2658}
2659
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002660inline void requestRoutesBMCJournalLogEntryCollection(App& app)
Jason M. Billse1f26342018-07-18 12:12:00 -07002661{
Ed Tanous253f11b2024-05-16 09:38:31 -07002662 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/LogServices/Journal/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07002663 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07002664 .methods(boost::beast::http::verb::get)(
2665 [&app](const crow::Request& req,
Ed Tanous253f11b2024-05-16 09:38:31 -07002666 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2667 const std::string& managerId) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002668 query_param::QueryCapabilities capabilities = {
2669 .canDelegateTop = true,
2670 .canDelegateSkip = true,
2671 };
2672 query_param::Query delegatedQuery;
2673 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00002674 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07002675 {
2676 return;
2677 }
Ed Tanous3648c8b2022-07-25 13:39:59 -07002678
Ed Tanous253f11b2024-05-16 09:38:31 -07002679 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
2680 {
2681 messages::resourceNotFound(asyncResp->res, "Manager", managerId);
2682 return;
2683 }
2684
Ed Tanous3648c8b2022-07-25 13:39:59 -07002685 size_t skip = delegatedQuery.skip.value_or(0);
Jiaqing Zhao5143f7a2022-07-22 09:33:33 +08002686 size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
Ed Tanous3648c8b2022-07-25 13:39:59 -07002687
Ed Tanous002d39b2022-05-31 08:59:27 -07002688 // Collections don't include the static data added by SubRoute
2689 // because it has a duplicate entry for members
2690 asyncResp->res.jsonValue["@odata.type"] =
2691 "#LogEntryCollection.LogEntryCollection";
Ed Tanous253f11b2024-05-16 09:38:31 -07002692 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
2693 "/redfish/v1/Managers/{}/LogServices/Journal/Entries",
2694 BMCWEB_REDFISH_MANAGER_URI_NAME);
Ed Tanous002d39b2022-05-31 08:59:27 -07002695 asyncResp->res.jsonValue["Name"] = "Open BMC Journal Entries";
2696 asyncResp->res.jsonValue["Description"] =
2697 "Collection of BMC Journal Entries";
2698 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
2699 logEntryArray = nlohmann::json::array();
Jason M. Billse1f26342018-07-18 12:12:00 -07002700
Ed Tanous002d39b2022-05-31 08:59:27 -07002701 // Go through the journal and use the timestamp to create a
2702 // unique ID for each entry
2703 sd_journal* journalTmp = nullptr;
2704 int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY);
2705 if (ret < 0)
2706 {
Ed Tanous62598e32023-07-17 17:06:25 -07002707 BMCWEB_LOG_ERROR("failed to open journal: {}", strerror(-ret));
Ed Tanous002d39b2022-05-31 08:59:27 -07002708 messages::internalError(asyncResp->res);
2709 return;
2710 }
2711 std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal(
2712 journalTmp, sd_journal_close);
2713 journalTmp = nullptr;
2714 uint64_t entryCount = 0;
2715 // Reset the unique ID on the first entry
2716 bool firstEntry = true;
2717 SD_JOURNAL_FOREACH(journal.get())
2718 {
2719 entryCount++;
2720 // Handle paging using skip (number of entries to skip from
2721 // the start) and top (number of entries to display)
Ed Tanous3648c8b2022-07-25 13:39:59 -07002722 if (entryCount <= skip || entryCount > skip + top)
George Liu0fda0f12021-11-16 10:06:17 +08002723 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002724 continue;
2725 }
2726
2727 std::string idStr;
2728 if (!getUniqueEntryID(journal.get(), idStr, firstEntry))
2729 {
2730 continue;
2731 }
Jason M. Billsefde4ec2022-06-24 08:59:52 -07002732 firstEntry = false;
Ed Tanous002d39b2022-05-31 08:59:27 -07002733
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002734 nlohmann::json::object_t bmcJournalLogEntry;
Ed Tanous002d39b2022-05-31 08:59:27 -07002735 if (fillBMCJournalLogEntryJson(idStr, journal.get(),
2736 bmcJournalLogEntry) != 0)
2737 {
George Liu0fda0f12021-11-16 10:06:17 +08002738 messages::internalError(asyncResp->res);
2739 return;
2740 }
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002741 logEntryArray.emplace_back(std::move(bmcJournalLogEntry));
Ed Tanous002d39b2022-05-31 08:59:27 -07002742 }
2743 asyncResp->res.jsonValue["Members@odata.count"] = entryCount;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002744 if (skip + top < entryCount)
Ed Tanous002d39b2022-05-31 08:59:27 -07002745 {
Ed Tanous253f11b2024-05-16 09:38:31 -07002746 asyncResp->res
2747 .jsonValue["Members@odata.nextLink"] = boost::urls::format(
2748 "/redfish/v1/Managers/{}/LogServices/Journal/Entries?$skip={}",
2749 BMCWEB_REDFISH_MANAGER_URI_NAME, std::to_string(skip + top));
Ed Tanous002d39b2022-05-31 08:59:27 -07002750 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002751 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002752}
Jason M. Billse1f26342018-07-18 12:12:00 -07002753
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002754inline void requestRoutesBMCJournalLogEntry(App& app)
Jason M. Billse1f26342018-07-18 12:12:00 -07002755{
Ed Tanous253f11b2024-05-16 09:38:31 -07002756 BMCWEB_ROUTE(
2757 app, "/redfish/v1/Managers/<str>/LogServices/Journal/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002758 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002759 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002760 [&app](const crow::Request& req,
2761 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous253f11b2024-05-16 09:38:31 -07002762 const std::string& managerId, const std::string& entryID) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002763 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002764 {
2765 return;
2766 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002767
2768 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
2769 {
2770 messages::resourceNotFound(asyncResp->res, "Manager", managerId);
2771 return;
2772 }
2773
Ed Tanous002d39b2022-05-31 08:59:27 -07002774 // Convert the unique ID back to a timestamp to find the entry
Myung Bae75e8e212023-11-30 12:53:46 -08002775 sd_id128_t bootID{};
Ed Tanous002d39b2022-05-31 08:59:27 -07002776 uint64_t ts = 0;
2777 uint64_t index = 0;
Myung Bae75e8e212023-11-30 12:53:46 -08002778 if (!getTimestampFromID(asyncResp, entryID, bootID, ts, index))
Ed Tanous002d39b2022-05-31 08:59:27 -07002779 {
2780 return;
2781 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002782
Ed Tanous002d39b2022-05-31 08:59:27 -07002783 sd_journal* journalTmp = nullptr;
2784 int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY);
2785 if (ret < 0)
2786 {
Ed Tanous62598e32023-07-17 17:06:25 -07002787 BMCWEB_LOG_ERROR("failed to open journal: {}", strerror(-ret));
Ed Tanous002d39b2022-05-31 08:59:27 -07002788 messages::internalError(asyncResp->res);
2789 return;
2790 }
2791 std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal(
2792 journalTmp, sd_journal_close);
2793 journalTmp = nullptr;
2794 // Go to the timestamp in the log and move to the entry at the
2795 // index tracking the unique ID
2796 std::string idStr;
2797 bool firstEntry = true;
Myung Bae75e8e212023-11-30 12:53:46 -08002798 ret = sd_journal_seek_monotonic_usec(journal.get(), bootID, ts);
Ed Tanous002d39b2022-05-31 08:59:27 -07002799 if (ret < 0)
2800 {
Ed Tanous62598e32023-07-17 17:06:25 -07002801 BMCWEB_LOG_ERROR("failed to seek to an entry in journal{}",
2802 strerror(-ret));
Ed Tanous002d39b2022-05-31 08:59:27 -07002803 messages::internalError(asyncResp->res);
2804 return;
2805 }
2806 for (uint64_t i = 0; i <= index; i++)
2807 {
2808 sd_journal_next(journal.get());
2809 if (!getUniqueEntryID(journal.get(), idStr, firstEntry))
2810 {
2811 messages::internalError(asyncResp->res);
2812 return;
2813 }
Jason M. Billsefde4ec2022-06-24 08:59:52 -07002814 firstEntry = false;
Ed Tanous002d39b2022-05-31 08:59:27 -07002815 }
2816 // Confirm that the entry ID matches what was requested
2817 if (idStr != entryID)
2818 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08002819 messages::resourceNotFound(asyncResp->res, "LogEntry", entryID);
Ed Tanous002d39b2022-05-31 08:59:27 -07002820 return;
2821 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002822
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002823 nlohmann::json::object_t bmcJournalLogEntry;
Ed Tanous002d39b2022-05-31 08:59:27 -07002824 if (fillBMCJournalLogEntryJson(entryID, journal.get(),
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002825 bmcJournalLogEntry) != 0)
Ed Tanous002d39b2022-05-31 08:59:27 -07002826 {
2827 messages::internalError(asyncResp->res);
2828 return;
2829 }
Jason M. Billsd405bb52022-06-24 10:52:05 -07002830 asyncResp->res.jsonValue.update(bmcJournalLogEntry);
Patrick Williams5a39f772023-10-20 11:20:21 -05002831 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002832}
2833
Claire Weinanfdd26902022-03-01 14:18:25 -08002834inline void
2835 getDumpServiceInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2836 const std::string& dumpType)
2837{
2838 std::string dumpPath;
2839 std::string overWritePolicy;
2840 bool collectDiagnosticDataSupported = false;
2841
2842 if (dumpType == "BMC")
2843 {
Ed Tanous253f11b2024-05-16 09:38:31 -07002844 dumpPath = std::format("/redfish/v1/Managers/{}/LogServices/Dump",
2845 BMCWEB_REDFISH_MANAGER_URI_NAME);
Claire Weinanfdd26902022-03-01 14:18:25 -08002846 overWritePolicy = "WrapsWhenFull";
2847 collectDiagnosticDataSupported = true;
2848 }
2849 else if (dumpType == "FaultLog")
2850 {
Ed Tanous253f11b2024-05-16 09:38:31 -07002851 dumpPath = std::format("/redfish/v1/Managers/{}/LogServices/FaultLog",
2852 BMCWEB_REDFISH_MANAGER_URI_NAME);
Claire Weinanfdd26902022-03-01 14:18:25 -08002853 overWritePolicy = "Unknown";
2854 collectDiagnosticDataSupported = false;
2855 }
2856 else if (dumpType == "System")
2857 {
Ed Tanous253f11b2024-05-16 09:38:31 -07002858 dumpPath = std::format("/redfish/v1/Systems/{}/LogServices/Dump",
2859 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Claire Weinanfdd26902022-03-01 14:18:25 -08002860 overWritePolicy = "WrapsWhenFull";
2861 collectDiagnosticDataSupported = true;
2862 }
2863 else
2864 {
Ed Tanous62598e32023-07-17 17:06:25 -07002865 BMCWEB_LOG_ERROR("getDumpServiceInfo() invalid dump type: {}",
2866 dumpType);
Claire Weinanfdd26902022-03-01 14:18:25 -08002867 messages::internalError(asyncResp->res);
2868 return;
2869 }
2870
2871 asyncResp->res.jsonValue["@odata.id"] = dumpPath;
2872 asyncResp->res.jsonValue["@odata.type"] = "#LogService.v1_2_0.LogService";
2873 asyncResp->res.jsonValue["Name"] = "Dump LogService";
2874 asyncResp->res.jsonValue["Description"] = dumpType + " Dump LogService";
2875 asyncResp->res.jsonValue["Id"] = std::filesystem::path(dumpPath).filename();
2876 asyncResp->res.jsonValue["OverWritePolicy"] = std::move(overWritePolicy);
2877
2878 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07002879 redfish::time_utils::getDateTimeOffsetNow();
Claire Weinanfdd26902022-03-01 14:18:25 -08002880 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2881 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2882 redfishDateTimeOffset.second;
2883
2884 asyncResp->res.jsonValue["Entries"]["@odata.id"] = dumpPath + "/Entries";
Claire Weinanfdd26902022-03-01 14:18:25 -08002885
2886 if (collectDiagnosticDataSupported)
2887 {
2888 asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"]
2889 ["target"] =
2890 dumpPath + "/Actions/LogService.CollectDiagnosticData";
2891 }
Claire Weinan0d946212022-07-13 19:40:19 -07002892
2893 constexpr std::array<std::string_view, 1> interfaces = {deleteAllInterface};
2894 dbus::utility::getSubTreePaths(
2895 "/xyz/openbmc_project/dump", 0, interfaces,
2896 [asyncResp, dumpType, dumpPath](
2897 const boost::system::error_code& ec,
2898 const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) {
2899 if (ec)
2900 {
Ed Tanous62598e32023-07-17 17:06:25 -07002901 BMCWEB_LOG_ERROR("getDumpServiceInfo respHandler got error {}", ec);
Claire Weinan0d946212022-07-13 19:40:19 -07002902 // Assume that getting an error simply means there are no dump
2903 // LogServices. Return without adding any error response.
2904 return;
2905 }
Ed Tanous18f8f602023-07-18 10:07:23 -07002906 std::string dbusDumpPath = getDumpPath(dumpType);
Claire Weinan0d946212022-07-13 19:40:19 -07002907 for (const std::string& path : subTreePaths)
2908 {
2909 if (path == dbusDumpPath)
2910 {
2911 asyncResp->res
2912 .jsonValue["Actions"]["#LogService.ClearLog"]["target"] =
2913 dumpPath + "/Actions/LogService.ClearLog";
2914 break;
2915 }
2916 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002917 });
Claire Weinanfdd26902022-03-01 14:18:25 -08002918}
2919
2920inline void handleLogServicesDumpServiceGet(
2921 crow::App& app, const std::string& dumpType, const crow::Request& req,
Ed Tanous253f11b2024-05-16 09:38:31 -07002922 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2923 const std::string& managerId)
Claire Weinanfdd26902022-03-01 14:18:25 -08002924{
2925 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2926 {
2927 return;
2928 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002929
2930 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
2931 {
2932 messages::resourceNotFound(asyncResp->res, "Manager", managerId);
2933 return;
2934 }
2935
Claire Weinanfdd26902022-03-01 14:18:25 -08002936 getDumpServiceInfo(asyncResp, dumpType);
2937}
2938
Ed Tanous22d268c2022-05-19 09:39:07 -07002939inline void handleLogServicesDumpServiceComputerSystemGet(
2940 crow::App& app, const crow::Request& req,
2941 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2942 const std::string& chassisId)
2943{
2944 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2945 {
2946 return;
2947 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002948 if (chassisId != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07002949 {
2950 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2951 return;
2952 }
2953 getDumpServiceInfo(asyncResp, "System");
2954}
2955
Claire Weinanfdd26902022-03-01 14:18:25 -08002956inline void handleLogServicesDumpEntriesCollectionGet(
2957 crow::App& app, const std::string& dumpType, const crow::Request& req,
Ed Tanous253f11b2024-05-16 09:38:31 -07002958 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2959 const std::string& managerId)
Claire Weinanfdd26902022-03-01 14:18:25 -08002960{
2961 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2962 {
2963 return;
2964 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002965
2966 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
2967 {
2968 messages::resourceNotFound(asyncResp->res, "Manager", managerId);
2969 return;
2970 }
Claire Weinanfdd26902022-03-01 14:18:25 -08002971 getDumpEntryCollection(asyncResp, dumpType);
2972}
2973
Ed Tanous22d268c2022-05-19 09:39:07 -07002974inline void handleLogServicesDumpEntriesCollectionComputerSystemGet(
2975 crow::App& app, const crow::Request& req,
2976 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2977 const std::string& chassisId)
2978{
2979 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2980 {
2981 return;
2982 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002983 if (chassisId != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07002984 {
2985 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2986 return;
2987 }
2988 getDumpEntryCollection(asyncResp, "System");
2989}
2990
Claire Weinanfdd26902022-03-01 14:18:25 -08002991inline void handleLogServicesDumpEntryGet(
2992 crow::App& app, const std::string& dumpType, const crow::Request& req,
2993 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous253f11b2024-05-16 09:38:31 -07002994 const std::string& managerId, const std::string& dumpId)
Claire Weinanfdd26902022-03-01 14:18:25 -08002995{
2996 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2997 {
2998 return;
2999 }
Ed Tanous253f11b2024-05-16 09:38:31 -07003000 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
3001 {
3002 messages::resourceNotFound(asyncResp->res, "Manager", managerId);
3003 return;
3004 }
Claire Weinanfdd26902022-03-01 14:18:25 -08003005 getDumpEntryById(asyncResp, dumpId, dumpType);
3006}
Carson Labrado168d1b12023-03-27 17:04:46 +00003007
Ed Tanous22d268c2022-05-19 09:39:07 -07003008inline void handleLogServicesDumpEntryComputerSystemGet(
3009 crow::App& app, const crow::Request& req,
3010 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3011 const std::string& chassisId, const std::string& dumpId)
3012{
3013 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
3014 {
3015 return;
3016 }
Ed Tanous253f11b2024-05-16 09:38:31 -07003017 if (chassisId != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07003018 {
3019 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
3020 return;
3021 }
3022 getDumpEntryById(asyncResp, dumpId, "System");
3023}
Claire Weinanfdd26902022-03-01 14:18:25 -08003024
3025inline void handleLogServicesDumpEntryDelete(
3026 crow::App& app, const std::string& dumpType, const crow::Request& req,
3027 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous253f11b2024-05-16 09:38:31 -07003028 const std::string& managerId, const std::string& dumpId)
Claire Weinanfdd26902022-03-01 14:18:25 -08003029{
3030 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
3031 {
3032 return;
3033 }
Ed Tanous253f11b2024-05-16 09:38:31 -07003034
3035 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
3036 {
3037 messages::resourceNotFound(asyncResp->res, "Manager", managerId);
3038 return;
3039 }
Claire Weinanfdd26902022-03-01 14:18:25 -08003040 deleteDumpEntry(asyncResp, dumpId, dumpType);
3041}
3042
Ed Tanous22d268c2022-05-19 09:39:07 -07003043inline void handleLogServicesDumpEntryComputerSystemDelete(
3044 crow::App& app, const crow::Request& req,
3045 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3046 const std::string& chassisId, const std::string& dumpId)
3047{
3048 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
3049 {
3050 return;
3051 }
Ed Tanous253f11b2024-05-16 09:38:31 -07003052 if (chassisId != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07003053 {
3054 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
3055 return;
3056 }
3057 deleteDumpEntry(asyncResp, dumpId, "System");
3058}
3059
Carson Labrado168d1b12023-03-27 17:04:46 +00003060inline void handleLogServicesDumpEntryDownloadGet(
3061 crow::App& app, const std::string& dumpType, const crow::Request& req,
3062 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous253f11b2024-05-16 09:38:31 -07003063 const std::string& managerId, const std::string& dumpId)
Carson Labrado168d1b12023-03-27 17:04:46 +00003064{
3065 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
3066 {
3067 return;
3068 }
Ed Tanous253f11b2024-05-16 09:38:31 -07003069
3070 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
3071 {
3072 messages::resourceNotFound(asyncResp->res, "Manager", managerId);
3073 return;
3074 }
Carson Labrado168d1b12023-03-27 17:04:46 +00003075 downloadDumpEntry(asyncResp, dumpId, dumpType);
3076}
3077
3078inline void handleDBusEventLogEntryDownloadGet(
3079 crow::App& app, const std::string& dumpType, const crow::Request& req,
3080 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3081 const std::string& systemName, const std::string& entryID)
3082{
3083 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
3084 {
3085 return;
3086 }
3087 if (!http_helpers::isContentTypeAllowed(
3088 req.getHeaderValue("Accept"),
3089 http_helpers::ContentType::OctetStream, true))
3090 {
3091 asyncResp->res.result(boost::beast::http::status::bad_request);
3092 return;
3093 }
3094 downloadEventLogEntry(asyncResp, systemName, entryID, dumpType);
3095}
3096
Claire Weinanfdd26902022-03-01 14:18:25 -08003097inline void handleLogServicesDumpCollectDiagnosticDataPost(
3098 crow::App& app, const std::string& dumpType, const crow::Request& req,
Ed Tanous253f11b2024-05-16 09:38:31 -07003099 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3100 const std::string& managerId)
Claire Weinanfdd26902022-03-01 14:18:25 -08003101{
3102 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
3103 {
3104 return;
3105 }
Ed Tanous253f11b2024-05-16 09:38:31 -07003106 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
3107 {
3108 messages::resourceNotFound(asyncResp->res, "Manager", managerId);
3109 return;
3110 }
3111
Claire Weinanfdd26902022-03-01 14:18:25 -08003112 createDump(asyncResp, req, dumpType);
3113}
3114
Ed Tanous22d268c2022-05-19 09:39:07 -07003115inline void handleLogServicesDumpCollectDiagnosticDataComputerSystemPost(
3116 crow::App& app, const crow::Request& req,
3117 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003118 const std::string& systemName)
Ed Tanous22d268c2022-05-19 09:39:07 -07003119{
3120 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
3121 {
3122 return;
3123 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003124
Ed Tanous25b54db2024-04-17 15:40:31 -07003125 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous22d268c2022-05-19 09:39:07 -07003126 {
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003127 // Option currently returns no systems. TBD
3128 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3129 systemName);
3130 return;
3131 }
Ed Tanous253f11b2024-05-16 09:38:31 -07003132 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003133 {
3134 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3135 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003136 return;
3137 }
3138 createDump(asyncResp, req, "System");
3139}
3140
Claire Weinanfdd26902022-03-01 14:18:25 -08003141inline void handleLogServicesDumpClearLogPost(
3142 crow::App& app, const std::string& dumpType, const crow::Request& req,
Ed Tanous253f11b2024-05-16 09:38:31 -07003143 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3144 const std::string& managerId)
Claire Weinanfdd26902022-03-01 14:18:25 -08003145{
3146 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
3147 {
3148 return;
3149 }
Ed Tanous253f11b2024-05-16 09:38:31 -07003150
3151 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
3152 {
3153 messages::resourceNotFound(asyncResp->res, "Manager", managerId);
3154 return;
3155 }
Claire Weinanfdd26902022-03-01 14:18:25 -08003156 clearDump(asyncResp, dumpType);
3157}
3158
Ed Tanous22d268c2022-05-19 09:39:07 -07003159inline void handleLogServicesDumpClearLogComputerSystemPost(
3160 crow::App& app, const crow::Request& req,
3161 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003162 const std::string& systemName)
Ed Tanous22d268c2022-05-19 09:39:07 -07003163{
3164 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
3165 {
3166 return;
3167 }
Ed Tanous25b54db2024-04-17 15:40:31 -07003168 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous22d268c2022-05-19 09:39:07 -07003169 {
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003170 // Option currently returns no systems. TBD
3171 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3172 systemName);
3173 return;
3174 }
Ed Tanous253f11b2024-05-16 09:38:31 -07003175 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003176 {
3177 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3178 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003179 return;
3180 }
3181 clearDump(asyncResp, "System");
3182}
3183
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003184inline void requestRoutesBMCDumpService(App& app)
3185{
Ed Tanous253f11b2024-05-16 09:38:31 -07003186 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/LogServices/Dump/")
Ed Tanoused398212021-06-09 17:05:54 -07003187 .privileges(redfish::privileges::getLogService)
Claire Weinanfdd26902022-03-01 14:18:25 -08003188 .methods(boost::beast::http::verb::get)(std::bind_front(
3189 handleLogServicesDumpServiceGet, std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003190}
3191
3192inline void requestRoutesBMCDumpEntryCollection(App& app)
3193{
Ed Tanous253f11b2024-05-16 09:38:31 -07003194 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/LogServices/Dump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07003195 .privileges(redfish::privileges::getLogEntryCollection)
Claire Weinanfdd26902022-03-01 14:18:25 -08003196 .methods(boost::beast::http::verb::get)(std::bind_front(
3197 handleLogServicesDumpEntriesCollectionGet, std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003198}
3199
3200inline void requestRoutesBMCDumpEntry(App& app)
3201{
3202 BMCWEB_ROUTE(app,
Ed Tanous253f11b2024-05-16 09:38:31 -07003203 "/redfish/v1/Managers/<str>/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003204 .privileges(redfish::privileges::getLogEntry)
Claire Weinanfdd26902022-03-01 14:18:25 -08003205 .methods(boost::beast::http::verb::get)(std::bind_front(
3206 handleLogServicesDumpEntryGet, std::ref(app), "BMC"));
3207
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003208 BMCWEB_ROUTE(app,
Ed Tanous253f11b2024-05-16 09:38:31 -07003209 "/redfish/v1/Managers/<str>/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003210 .privileges(redfish::privileges::deleteLogEntry)
Claire Weinanfdd26902022-03-01 14:18:25 -08003211 .methods(boost::beast::http::verb::delete_)(std::bind_front(
3212 handleLogServicesDumpEntryDelete, std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003213}
3214
Carson Labrado168d1b12023-03-27 17:04:46 +00003215inline void requestRoutesBMCDumpEntryDownload(App& app)
3216{
3217 BMCWEB_ROUTE(
3218 app,
Ed Tanous253f11b2024-05-16 09:38:31 -07003219 "/redfish/v1/Managers/<str>/LogServices/Dump/Entries/<str>/attachment/")
Carson Labrado168d1b12023-03-27 17:04:46 +00003220 .privileges(redfish::privileges::getLogEntry)
3221 .methods(boost::beast::http::verb::get)(std::bind_front(
3222 handleLogServicesDumpEntryDownloadGet, std::ref(app), "BMC"));
3223}
3224
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003225inline void requestRoutesBMCDumpCreate(App& app)
3226{
George Liu0fda0f12021-11-16 10:06:17 +08003227 BMCWEB_ROUTE(
3228 app,
Ed Tanous253f11b2024-05-16 09:38:31 -07003229 "/redfish/v1/Managers/<str>/LogServices/Dump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07003230 .privileges(redfish::privileges::postLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003231 .methods(boost::beast::http::verb::post)(
Claire Weinanfdd26902022-03-01 14:18:25 -08003232 std::bind_front(handleLogServicesDumpCollectDiagnosticDataPost,
3233 std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003234}
3235
3236inline void requestRoutesBMCDumpClear(App& app)
3237{
George Liu0fda0f12021-11-16 10:06:17 +08003238 BMCWEB_ROUTE(
3239 app,
Ed Tanous253f11b2024-05-16 09:38:31 -07003240 "/redfish/v1/Managers/<str>/LogServices/Dump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07003241 .privileges(redfish::privileges::postLogService)
Claire Weinanfdd26902022-03-01 14:18:25 -08003242 .methods(boost::beast::http::verb::post)(std::bind_front(
3243 handleLogServicesDumpClearLogPost, std::ref(app), "BMC"));
3244}
3245
Carson Labrado168d1b12023-03-27 17:04:46 +00003246inline void requestRoutesDBusEventLogEntryDownload(App& app)
3247{
3248 BMCWEB_ROUTE(
3249 app,
Ravi Teja9e9d99d2023-11-08 05:33:59 -06003250 "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/attachment/")
Carson Labrado168d1b12023-03-27 17:04:46 +00003251 .privileges(redfish::privileges::getLogEntry)
3252 .methods(boost::beast::http::verb::get)(std::bind_front(
3253 handleDBusEventLogEntryDownloadGet, std::ref(app), "System"));
3254}
3255
Claire Weinanfdd26902022-03-01 14:18:25 -08003256inline void requestRoutesFaultLogDumpService(App& app)
3257{
Ed Tanous253f11b2024-05-16 09:38:31 -07003258 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/LogServices/FaultLog/")
Claire Weinanfdd26902022-03-01 14:18:25 -08003259 .privileges(redfish::privileges::getLogService)
3260 .methods(boost::beast::http::verb::get)(std::bind_front(
3261 handleLogServicesDumpServiceGet, std::ref(app), "FaultLog"));
3262}
3263
3264inline void requestRoutesFaultLogDumpEntryCollection(App& app)
3265{
Ed Tanous253f11b2024-05-16 09:38:31 -07003266 BMCWEB_ROUTE(app,
3267 "/redfish/v1/Managers/<str>/LogServices/FaultLog/Entries/")
Claire Weinanfdd26902022-03-01 14:18:25 -08003268 .privileges(redfish::privileges::getLogEntryCollection)
3269 .methods(boost::beast::http::verb::get)(
3270 std::bind_front(handleLogServicesDumpEntriesCollectionGet,
3271 std::ref(app), "FaultLog"));
3272}
3273
3274inline void requestRoutesFaultLogDumpEntry(App& app)
3275{
Ed Tanous253f11b2024-05-16 09:38:31 -07003276 BMCWEB_ROUTE(
3277 app, "/redfish/v1/Managers/<str>/LogServices/FaultLog/Entries/<str>/")
Claire Weinanfdd26902022-03-01 14:18:25 -08003278 .privileges(redfish::privileges::getLogEntry)
3279 .methods(boost::beast::http::verb::get)(std::bind_front(
3280 handleLogServicesDumpEntryGet, std::ref(app), "FaultLog"));
3281
Ed Tanous253f11b2024-05-16 09:38:31 -07003282 BMCWEB_ROUTE(
3283 app, "/redfish/v1/Managers/<str>/LogServices/FaultLog/Entries/<str>/")
Claire Weinanfdd26902022-03-01 14:18:25 -08003284 .privileges(redfish::privileges::deleteLogEntry)
3285 .methods(boost::beast::http::verb::delete_)(std::bind_front(
3286 handleLogServicesDumpEntryDelete, std::ref(app), "FaultLog"));
3287}
3288
3289inline void requestRoutesFaultLogDumpClear(App& app)
3290{
3291 BMCWEB_ROUTE(
3292 app,
Ed Tanous253f11b2024-05-16 09:38:31 -07003293 "/redfish/v1/Managers/<str>/LogServices/FaultLog/Actions/LogService.ClearLog/")
Claire Weinanfdd26902022-03-01 14:18:25 -08003294 .privileges(redfish::privileges::postLogService)
3295 .methods(boost::beast::http::verb::post)(std::bind_front(
3296 handleLogServicesDumpClearLogPost, std::ref(app), "FaultLog"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003297}
3298
3299inline void requestRoutesSystemDumpService(App& app)
3300{
Ed Tanous22d268c2022-05-19 09:39:07 -07003301 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/")
Ed Tanoused398212021-06-09 17:05:54 -07003302 .privileges(redfish::privileges::getLogService)
Claire Weinan6ab9ad52022-08-12 18:20:17 -07003303 .methods(boost::beast::http::verb::get)(std::bind_front(
Ed Tanous22d268c2022-05-19 09:39:07 -07003304 handleLogServicesDumpServiceComputerSystemGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003305}
3306
3307inline void requestRoutesSystemDumpEntryCollection(App& app)
3308{
Ed Tanous22d268c2022-05-19 09:39:07 -07003309 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07003310 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous22d268c2022-05-19 09:39:07 -07003311 .methods(boost::beast::http::verb::get)(std::bind_front(
3312 handleLogServicesDumpEntriesCollectionComputerSystemGet,
3313 std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003314}
3315
3316inline void requestRoutesSystemDumpEntry(App& app)
3317{
3318 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003319 "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003320 .privileges(redfish::privileges::getLogEntry)
Claire Weinan6ab9ad52022-08-12 18:20:17 -07003321 .methods(boost::beast::http::verb::get)(std::bind_front(
Ed Tanous22d268c2022-05-19 09:39:07 -07003322 handleLogServicesDumpEntryComputerSystemGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003323
3324 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003325 "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003326 .privileges(redfish::privileges::deleteLogEntry)
Claire Weinan6ab9ad52022-08-12 18:20:17 -07003327 .methods(boost::beast::http::verb::delete_)(std::bind_front(
Ed Tanous22d268c2022-05-19 09:39:07 -07003328 handleLogServicesDumpEntryComputerSystemDelete, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003329}
3330
3331inline void requestRoutesSystemDumpCreate(App& app)
3332{
George Liu0fda0f12021-11-16 10:06:17 +08003333 BMCWEB_ROUTE(
3334 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003335 "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07003336 .privileges(redfish::privileges::postLogService)
Ed Tanous22d268c2022-05-19 09:39:07 -07003337 .methods(boost::beast::http::verb::post)(std::bind_front(
3338 handleLogServicesDumpCollectDiagnosticDataComputerSystemPost,
3339 std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003340}
3341
3342inline void requestRoutesSystemDumpClear(App& app)
3343{
George Liu0fda0f12021-11-16 10:06:17 +08003344 BMCWEB_ROUTE(
3345 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003346 "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07003347 .privileges(redfish::privileges::postLogService)
Claire Weinan6ab9ad52022-08-12 18:20:17 -07003348 .methods(boost::beast::http::verb::post)(std::bind_front(
Ed Tanous22d268c2022-05-19 09:39:07 -07003349 handleLogServicesDumpClearLogComputerSystemPost, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003350}
3351
3352inline void requestRoutesCrashdumpService(App& app)
3353{
3354 // Note: Deviated from redfish privilege registry for GET & HEAD
3355 // method for security reasons.
3356 /**
3357 * Functions triggers appropriate requests on DBus
3358 */
Ed Tanous22d268c2022-05-19 09:39:07 -07003359 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/")
Ed Tanoused398212021-06-09 17:05:54 -07003360 // This is incorrect, should be:
3361 //.privileges(redfish::privileges::getLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07003362 .privileges({{"ConfigureManager"}})
Ed Tanous002d39b2022-05-31 08:59:27 -07003363 .methods(boost::beast::http::verb::get)(
3364 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003365 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3366 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003367 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003368 {
3369 return;
3370 }
Ed Tanous25b54db2024-04-17 15:40:31 -07003371 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003372 {
3373 // Option currently returns no systems. TBD
3374 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3375 systemName);
3376 return;
3377 }
Ed Tanous253f11b2024-05-16 09:38:31 -07003378 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07003379 {
3380 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3381 systemName);
3382 return;
3383 }
3384
Ed Tanous002d39b2022-05-31 08:59:27 -07003385 // Copy over the static data to include the entries added by
3386 // SubRoute
3387 asyncResp->res.jsonValue["@odata.id"] =
Ed Tanous253f11b2024-05-16 09:38:31 -07003388 std::format("/redfish/v1/Systems/{}/LogServices/Crashdump",
3389 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Ed Tanous002d39b2022-05-31 08:59:27 -07003390 asyncResp->res.jsonValue["@odata.type"] =
3391 "#LogService.v1_2_0.LogService";
3392 asyncResp->res.jsonValue["Name"] = "Open BMC Oem Crashdump Service";
3393 asyncResp->res.jsonValue["Description"] = "Oem Crashdump Service";
V-Sanjana15b89722023-05-11 16:27:03 +05303394 asyncResp->res.jsonValue["Id"] = "Crashdump";
Ed Tanous002d39b2022-05-31 08:59:27 -07003395 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
3396 asyncResp->res.jsonValue["MaxNumberOfRecords"] = 3;
Tejas Patil7c8c4052021-06-04 17:43:14 +05303397
Ed Tanous002d39b2022-05-31 08:59:27 -07003398 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07003399 redfish::time_utils::getDateTimeOffsetNow();
Ed Tanous002d39b2022-05-31 08:59:27 -07003400 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
3401 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
3402 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05303403
Ed Tanous002d39b2022-05-31 08:59:27 -07003404 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
Ed Tanous253f11b2024-05-16 09:38:31 -07003405 std::format("/redfish/v1/Systems/{}/LogServices/Crashdump/Entries",
3406 BMCWEB_REDFISH_SYSTEM_URI_NAME);
3407 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]
3408 ["target"] = std::format(
3409 "/redfish/v1/Systems/{}/LogServices/Crashdump/Actions/LogService.ClearLog",
3410 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Ed Tanous002d39b2022-05-31 08:59:27 -07003411 asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"]
Ed Tanous253f11b2024-05-16 09:38:31 -07003412 ["target"] = std::format(
3413 "/redfish/v1/Systems/{}/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData",
3414 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Patrick Williams5a39f772023-10-20 11:20:21 -05003415 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003416}
3417
3418void inline requestRoutesCrashdumpClear(App& app)
3419{
George Liu0fda0f12021-11-16 10:06:17 +08003420 BMCWEB_ROUTE(
3421 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003422 "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07003423 // This is incorrect, should be:
3424 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07003425 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003426 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003427 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003428 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3429 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003430 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003431 {
3432 return;
3433 }
Ed Tanous25b54db2024-04-17 15:40:31 -07003434 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003435 {
3436 // Option currently returns no systems. TBD
3437 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3438 systemName);
3439 return;
3440 }
Ed Tanous253f11b2024-05-16 09:38:31 -07003441 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07003442 {
3443 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3444 systemName);
3445 return;
3446 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003447 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08003448 [asyncResp](const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -07003449 const std::string&) {
3450 if (ec)
3451 {
3452 messages::internalError(asyncResp->res);
3453 return;
3454 }
3455 messages::success(asyncResp->res);
Patrick Williams5a39f772023-10-20 11:20:21 -05003456 },
Ed Tanous002d39b2022-05-31 08:59:27 -07003457 crashdumpObject, crashdumpPath, deleteAllInterface, "DeleteAll");
Patrick Williams5a39f772023-10-20 11:20:21 -05003458 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003459}
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07003460
zhanghch058d1b46d2021-04-01 11:18:24 +08003461static void
3462 logCrashdumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3463 const std::string& logID, nlohmann::json& logEntryJson)
Jason M. Billse855dd22019-10-08 11:37:48 -07003464{
Johnathan Mantey043a0532020-03-10 17:15:28 -07003465 auto getStoredLogCallback =
Ed Tanousb9d36b42022-02-26 21:42:46 -08003466 [asyncResp, logID,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08003467 &logEntryJson](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08003468 const dbus::utility::DBusPropertiesMap& params) {
Ed Tanous002d39b2022-05-31 08:59:27 -07003469 if (ec)
3470 {
Ed Tanous62598e32023-07-17 17:06:25 -07003471 BMCWEB_LOG_DEBUG("failed to get log ec: {}", ec.message());
Ed Tanous002d39b2022-05-31 08:59:27 -07003472 if (ec.value() ==
3473 boost::system::linux_error::bad_request_descriptor)
Jason M. Bills1ddcf012019-11-26 14:59:21 -08003474 {
Ed Tanous002d39b2022-05-31 08:59:27 -07003475 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Jason M. Bills2b20ef62022-01-06 15:48:07 -08003476 }
3477 else
3478 {
Ed Tanous002d39b2022-05-31 08:59:27 -07003479 messages::internalError(asyncResp->res);
Jason M. Bills2b20ef62022-01-06 15:48:07 -08003480 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003481 return;
3482 }
3483
3484 std::string timestamp{};
3485 std::string filename{};
3486 std::string logfile{};
3487 parseCrashdumpParameters(params, filename, timestamp, logfile);
3488
3489 if (filename.empty() || timestamp.empty())
3490 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08003491 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Ed Tanous002d39b2022-05-31 08:59:27 -07003492 return;
3493 }
3494
3495 std::string crashdumpURI =
Ed Tanous253f11b2024-05-16 09:38:31 -07003496 std::format("/redfish/v1/Systems/{}/LogServices/Crashdump/Entries/",
3497 BMCWEB_REDFISH_SYSTEM_URI_NAME) +
Ed Tanous002d39b2022-05-31 08:59:27 -07003498 logID + "/" + filename;
Jason M. Bills84afc482022-06-24 12:38:23 -07003499 nlohmann::json::object_t logEntry;
Vijay Lobo9c11a172021-10-07 16:53:16 -05003500 logEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Ed Tanousef4c65b2023-04-24 15:28:50 -07003501 logEntry["@odata.id"] = boost::urls::format(
Ed Tanous253f11b2024-05-16 09:38:31 -07003502 "/redfish/v1/Systems/{}/LogServices/Crashdump/Entries/{}",
3503 BMCWEB_REDFISH_SYSTEM_URI_NAME, logID);
Jason M. Bills84afc482022-06-24 12:38:23 -07003504 logEntry["Name"] = "CPU Crashdump";
3505 logEntry["Id"] = logID;
3506 logEntry["EntryType"] = "Oem";
3507 logEntry["AdditionalDataURI"] = std::move(crashdumpURI);
3508 logEntry["DiagnosticDataType"] = "OEM";
3509 logEntry["OEMDiagnosticDataType"] = "PECICrashdump";
3510 logEntry["Created"] = std::move(timestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07003511
3512 // If logEntryJson references an array of LogEntry resources
3513 // ('Members' list), then push this as a new entry, otherwise set it
3514 // directly
3515 if (logEntryJson.is_array())
3516 {
3517 logEntryJson.push_back(logEntry);
3518 asyncResp->res.jsonValue["Members@odata.count"] =
3519 logEntryJson.size();
3520 }
3521 else
3522 {
Jason M. Billsd405bb52022-06-24 10:52:05 -07003523 logEntryJson.update(logEntry);
Ed Tanous002d39b2022-05-31 08:59:27 -07003524 }
3525 };
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02003526 sdbusplus::asio::getAllProperties(
3527 *crow::connections::systemBus, crashdumpObject,
3528 crashdumpPath + std::string("/") + logID, crashdumpInterface,
3529 std::move(getStoredLogCallback));
Jason M. Billse855dd22019-10-08 11:37:48 -07003530}
3531
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003532inline void requestRoutesCrashdumpEntryCollection(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07003533{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003534 // Note: Deviated from redfish privilege registry for GET & HEAD
3535 // method for security reasons.
Ed Tanous1da66f72018-07-27 16:13:37 -07003536 /**
3537 * Functions triggers appropriate requests on DBus
3538 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003539 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003540 "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07003541 // This is incorrect, should be.
3542 //.privileges(redfish::privileges::postLogEntryCollection)
Ed Tanous432a8902021-06-14 15:28:56 -07003543 .privileges({{"ConfigureComponents"}})
Ed Tanous002d39b2022-05-31 08:59:27 -07003544 .methods(boost::beast::http::verb::get)(
3545 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003546 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3547 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003548 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003549 {
3550 return;
3551 }
Ed Tanous25b54db2024-04-17 15:40:31 -07003552 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003553 {
3554 // Option currently returns no systems. TBD
3555 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3556 systemName);
3557 return;
3558 }
Ed Tanous253f11b2024-05-16 09:38:31 -07003559 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07003560 {
3561 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3562 systemName);
3563 return;
3564 }
3565
George Liu7a1dbc42022-12-07 16:03:22 +08003566 constexpr std::array<std::string_view, 1> interfaces = {
3567 crashdumpInterface};
3568 dbus::utility::getSubTreePaths(
3569 "/", 0, interfaces,
3570 [asyncResp](const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -07003571 const std::vector<std::string>& resp) {
3572 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -07003573 {
Ed Tanous002d39b2022-05-31 08:59:27 -07003574 if (ec.value() !=
3575 boost::system::errc::no_such_file_or_directory)
3576 {
Ed Tanous62598e32023-07-17 17:06:25 -07003577 BMCWEB_LOG_DEBUG("failed to get entries ec: {}",
3578 ec.message());
Ed Tanous002d39b2022-05-31 08:59:27 -07003579 messages::internalError(asyncResp->res);
3580 return;
3581 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07003582 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003583 asyncResp->res.jsonValue["@odata.type"] =
3584 "#LogEntryCollection.LogEntryCollection";
Ed Tanous253f11b2024-05-16 09:38:31 -07003585 asyncResp->res.jsonValue["@odata.id"] = std::format(
3586 "/redfish/v1/Systems/{}/LogServices/Crashdump/Entries",
3587 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Ed Tanous002d39b2022-05-31 08:59:27 -07003588 asyncResp->res.jsonValue["Name"] = "Open BMC Crashdump Entries";
3589 asyncResp->res.jsonValue["Description"] =
3590 "Collection of Crashdump Entries";
3591 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
3592 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Jason M. Bills2b20ef62022-01-06 15:48:07 -08003593
Ed Tanous002d39b2022-05-31 08:59:27 -07003594 for (const std::string& path : resp)
3595 {
3596 const sdbusplus::message::object_path objPath(path);
3597 // Get the log ID
3598 std::string logID = objPath.filename();
3599 if (logID.empty())
3600 {
3601 continue;
3602 }
3603 // Add the log entry to the array
3604 logCrashdumpEntry(asyncResp, logID,
3605 asyncResp->res.jsonValue["Members"]);
3606 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003607 });
Patrick Williams5a39f772023-10-20 11:20:21 -05003608 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003609}
Ed Tanous1da66f72018-07-27 16:13:37 -07003610
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003611inline void requestRoutesCrashdumpEntry(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07003612{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003613 // Note: Deviated from redfish privilege registry for GET & HEAD
3614 // method for security reasons.
Ed Tanous1da66f72018-07-27 16:13:37 -07003615
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003616 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07003617 app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003618 // this is incorrect, should be
3619 // .privileges(redfish::privileges::getLogEntry)
Ed Tanous432a8902021-06-14 15:28:56 -07003620 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003621 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003622 [&app](const crow::Request& req,
3623 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07003624 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003625 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003626 {
3627 return;
3628 }
Ed Tanous25b54db2024-04-17 15:40:31 -07003629 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003630 {
3631 // Option currently returns no systems. TBD
3632 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3633 systemName);
3634 return;
3635 }
Ed Tanous253f11b2024-05-16 09:38:31 -07003636 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07003637 {
3638 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3639 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003640 return;
3641 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003642 const std::string& logID = param;
3643 logCrashdumpEntry(asyncResp, logID, asyncResp->res.jsonValue);
Patrick Williams5a39f772023-10-20 11:20:21 -05003644 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003645}
Ed Tanous1da66f72018-07-27 16:13:37 -07003646
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003647inline void requestRoutesCrashdumpFile(App& app)
3648{
3649 // Note: Deviated from redfish privilege registry for GET & HEAD
3650 // method for security reasons.
3651 BMCWEB_ROUTE(
3652 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003653 "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003654 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003655 .methods(boost::beast::http::verb::get)(
Nan Zhoua4ce1142022-08-02 18:45:25 +00003656 [](const crow::Request& req,
3657 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07003658 const std::string& systemName, const std::string& logID,
3659 const std::string& fileName) {
Shounak Mitra2a9beee2022-07-20 18:41:30 +00003660 // Do not call getRedfishRoute here since the crashdump file is not a
3661 // Redfish resource.
Ed Tanous22d268c2022-05-19 09:39:07 -07003662
Ed Tanous25b54db2024-04-17 15:40:31 -07003663 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003664 {
3665 // Option currently returns no systems. TBD
3666 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3667 systemName);
3668 return;
3669 }
Ed Tanous253f11b2024-05-16 09:38:31 -07003670 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07003671 {
3672 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3673 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003674 return;
3675 }
3676
Ed Tanous002d39b2022-05-31 08:59:27 -07003677 auto getStoredLogCallback =
Ed Tanous39662a32023-02-06 15:09:46 -08003678 [asyncResp, logID, fileName, url(boost::urls::url(req.url()))](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08003679 const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -07003680 const std::vector<
3681 std::pair<std::string, dbus::utility::DbusVariantType>>&
3682 resp) {
3683 if (ec)
3684 {
Ed Tanous62598e32023-07-17 17:06:25 -07003685 BMCWEB_LOG_DEBUG("failed to get log ec: {}", ec.message());
Ed Tanous002d39b2022-05-31 08:59:27 -07003686 messages::internalError(asyncResp->res);
3687 return;
3688 }
Jason M. Bills8e6c0992021-03-11 16:26:53 -08003689
Ed Tanous002d39b2022-05-31 08:59:27 -07003690 std::string dbusFilename{};
3691 std::string dbusTimestamp{};
3692 std::string dbusFilepath{};
Jason M. Bills8e6c0992021-03-11 16:26:53 -08003693
Ed Tanous002d39b2022-05-31 08:59:27 -07003694 parseCrashdumpParameters(resp, dbusFilename, dbusTimestamp,
3695 dbusFilepath);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003696
Ed Tanous002d39b2022-05-31 08:59:27 -07003697 if (dbusFilename.empty() || dbusTimestamp.empty() ||
3698 dbusFilepath.empty())
3699 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08003700 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Ed Tanous002d39b2022-05-31 08:59:27 -07003701 return;
3702 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003703
Ed Tanous002d39b2022-05-31 08:59:27 -07003704 // Verify the file name parameter is correct
3705 if (fileName != dbusFilename)
3706 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08003707 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Ed Tanous002d39b2022-05-31 08:59:27 -07003708 return;
3709 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003710
Ed Tanous27b0cf92023-08-07 12:02:40 -07003711 if (!asyncResp->res.openFile(dbusFilepath))
Ed Tanous002d39b2022-05-31 08:59:27 -07003712 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08003713 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Ed Tanous002d39b2022-05-31 08:59:27 -07003714 return;
3715 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003716
Ed Tanous002d39b2022-05-31 08:59:27 -07003717 // Configure this to be a file download when accessed
3718 // from a browser
Ed Tanousd9f6c622022-03-17 09:12:17 -07003719 asyncResp->res.addHeader(
3720 boost::beast::http::field::content_disposition, "attachment");
Ed Tanous002d39b2022-05-31 08:59:27 -07003721 };
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02003722 sdbusplus::asio::getAllProperties(
3723 *crow::connections::systemBus, crashdumpObject,
3724 crashdumpPath + std::string("/") + logID, crashdumpInterface,
3725 std::move(getStoredLogCallback));
Patrick Williams5a39f772023-10-20 11:20:21 -05003726 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003727}
3728
Jason M. Billsc5a4c822022-01-06 15:51:23 -08003729enum class OEMDiagnosticType
3730{
3731 onDemand,
3732 telemetry,
3733 invalid,
3734};
3735
Ed Tanous26ccae32023-02-16 10:28:44 -08003736inline OEMDiagnosticType getOEMDiagnosticType(std::string_view oemDiagStr)
Jason M. Billsc5a4c822022-01-06 15:51:23 -08003737{
3738 if (oemDiagStr == "OnDemand")
3739 {
3740 return OEMDiagnosticType::onDemand;
3741 }
3742 if (oemDiagStr == "Telemetry")
3743 {
3744 return OEMDiagnosticType::telemetry;
3745 }
3746
3747 return OEMDiagnosticType::invalid;
3748}
3749
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003750inline void requestRoutesCrashdumpCollect(App& app)
3751{
3752 // Note: Deviated from redfish privilege registry for GET & HEAD
3753 // method for security reasons.
George Liu0fda0f12021-11-16 10:06:17 +08003754 BMCWEB_ROUTE(
3755 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003756 "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07003757 // The below is incorrect; Should be ConfigureManager
3758 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07003759 .privileges({{"ConfigureComponents"}})
Ed Tanous002d39b2022-05-31 08:59:27 -07003760 .methods(boost::beast::http::verb::post)(
3761 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003762 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3763 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003764 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003765 {
3766 return;
3767 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003768
Ed Tanous25b54db2024-04-17 15:40:31 -07003769 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003770 {
3771 // Option currently returns no systems. TBD
3772 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3773 systemName);
3774 return;
3775 }
Ed Tanous253f11b2024-05-16 09:38:31 -07003776 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07003777 {
3778 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3779 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003780 return;
3781 }
3782
Ed Tanous002d39b2022-05-31 08:59:27 -07003783 std::string diagnosticDataType;
3784 std::string oemDiagnosticDataType;
3785 if (!redfish::json_util::readJsonAction(
3786 req, asyncResp->res, "DiagnosticDataType", diagnosticDataType,
3787 "OEMDiagnosticDataType", oemDiagnosticDataType))
3788 {
3789 return;
3790 }
3791
3792 if (diagnosticDataType != "OEM")
3793 {
Ed Tanous62598e32023-07-17 17:06:25 -07003794 BMCWEB_LOG_ERROR(
3795 "Only OEM DiagnosticDataType supported for Crashdump");
Ed Tanous002d39b2022-05-31 08:59:27 -07003796 messages::actionParameterValueFormatError(
3797 asyncResp->res, diagnosticDataType, "DiagnosticDataType",
3798 "CollectDiagnosticData");
3799 return;
3800 }
3801
3802 OEMDiagnosticType oemDiagType =
3803 getOEMDiagnosticType(oemDiagnosticDataType);
3804
3805 std::string iface;
3806 std::string method;
3807 std::string taskMatchStr;
3808 if (oemDiagType == OEMDiagnosticType::onDemand)
3809 {
3810 iface = crashdumpOnDemandInterface;
3811 method = "GenerateOnDemandLog";
3812 taskMatchStr = "type='signal',"
3813 "interface='org.freedesktop.DBus.Properties',"
3814 "member='PropertiesChanged',"
3815 "arg0namespace='com.intel.crashdump'";
3816 }
3817 else if (oemDiagType == OEMDiagnosticType::telemetry)
3818 {
3819 iface = crashdumpTelemetryInterface;
3820 method = "GenerateTelemetryLog";
3821 taskMatchStr = "type='signal',"
3822 "interface='org.freedesktop.DBus.Properties',"
3823 "member='PropertiesChanged',"
3824 "arg0namespace='com.intel.crashdump'";
3825 }
3826 else
3827 {
Ed Tanous62598e32023-07-17 17:06:25 -07003828 BMCWEB_LOG_ERROR("Unsupported OEMDiagnosticDataType: {}",
3829 oemDiagnosticDataType);
Ed Tanous002d39b2022-05-31 08:59:27 -07003830 messages::actionParameterValueFormatError(
3831 asyncResp->res, oemDiagnosticDataType, "OEMDiagnosticDataType",
3832 "CollectDiagnosticData");
3833 return;
3834 }
3835
3836 auto collectCrashdumpCallback =
3837 [asyncResp, payload(task::Payload(req)),
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08003838 taskMatchStr](const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -07003839 const std::string&) mutable {
3840 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -07003841 {
Ed Tanous002d39b2022-05-31 08:59:27 -07003842 if (ec.value() == boost::system::errc::operation_not_supported)
3843 {
3844 messages::resourceInStandby(asyncResp->res);
3845 }
3846 else if (ec.value() ==
3847 boost::system::errc::device_or_resource_busy)
3848 {
3849 messages::serviceTemporarilyUnavailable(asyncResp->res,
3850 "60");
3851 }
3852 else
3853 {
3854 messages::internalError(asyncResp->res);
3855 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07003856 return;
3857 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003858 std::shared_ptr<task::TaskData> task = task::TaskData::createTask(
Ed Tanous8b242752023-06-27 17:17:13 -07003859 [](const boost::system::error_code& ec2, sdbusplus::message_t&,
Ed Tanous002d39b2022-05-31 08:59:27 -07003860 const std::shared_ptr<task::TaskData>& taskData) {
Ed Tanous8b242752023-06-27 17:17:13 -07003861 if (!ec2)
Ed Tanous002d39b2022-05-31 08:59:27 -07003862 {
3863 taskData->messages.emplace_back(messages::taskCompletedOK(
3864 std::to_string(taskData->index)));
3865 taskData->state = "Completed";
3866 }
3867 return task::completed;
Patrick Williams5a39f772023-10-20 11:20:21 -05003868 },
Ed Tanous002d39b2022-05-31 08:59:27 -07003869 taskMatchStr);
Ed Tanous1da66f72018-07-27 16:13:37 -07003870
Ed Tanous002d39b2022-05-31 08:59:27 -07003871 task->startTimer(std::chrono::minutes(5));
3872 task->populateResp(asyncResp->res);
3873 task->payload.emplace(std::move(payload));
3874 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003875
Ed Tanous002d39b2022-05-31 08:59:27 -07003876 crow::connections::systemBus->async_method_call(
3877 std::move(collectCrashdumpCallback), crashdumpObject, crashdumpPath,
3878 iface, method);
Patrick Williams5a39f772023-10-20 11:20:21 -05003879 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003880}
Kenny L. Ku6eda7682020-06-19 09:48:36 -07003881
Andrew Geisslercb92c032018-08-17 07:56:14 -07003882/**
3883 * DBusLogServiceActionsClear class supports POST method for ClearLog action.
3884 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003885inline void requestRoutesDBusLogServiceActionsClear(App& app)
Andrew Geisslercb92c032018-08-17 07:56:14 -07003886{
Andrew Geisslercb92c032018-08-17 07:56:14 -07003887 /**
3888 * Function handles POST method request.
3889 * The Clear Log actions does not require any parameter.The action deletes
3890 * all entries found in the Entries collection for this Log Service.
3891 */
Andrew Geisslercb92c032018-08-17 07:56:14 -07003892
George Liu0fda0f12021-11-16 10:06:17 +08003893 BMCWEB_ROUTE(
3894 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003895 "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07003896 .privileges(redfish::privileges::postLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003897 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003898 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003899 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3900 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003901 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003902 {
3903 return;
3904 }
Ed Tanous25b54db2024-04-17 15:40:31 -07003905 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003906 {
3907 // Option currently returns no systems. TBD
3908 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3909 systemName);
3910 return;
3911 }
Ed Tanous253f11b2024-05-16 09:38:31 -07003912 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07003913 {
3914 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3915 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003916 return;
3917 }
Ed Tanous62598e32023-07-17 17:06:25 -07003918 BMCWEB_LOG_DEBUG("Do delete all entries.");
Andrew Geisslercb92c032018-08-17 07:56:14 -07003919
Ed Tanous002d39b2022-05-31 08:59:27 -07003920 // Process response from Logging service.
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08003921 auto respHandler = [asyncResp](const boost::system::error_code& ec) {
Ed Tanous62598e32023-07-17 17:06:25 -07003922 BMCWEB_LOG_DEBUG("doClearLog resp_handler callback: Done");
Ed Tanous002d39b2022-05-31 08:59:27 -07003923 if (ec)
3924 {
3925 // TODO Handle for specific error code
Ed Tanous62598e32023-07-17 17:06:25 -07003926 BMCWEB_LOG_ERROR("doClearLog resp_handler got error {}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -07003927 asyncResp->res.result(
3928 boost::beast::http::status::internal_server_error);
3929 return;
3930 }
Andrew Geisslercb92c032018-08-17 07:56:14 -07003931
Ed Tanous002d39b2022-05-31 08:59:27 -07003932 asyncResp->res.result(boost::beast::http::status::no_content);
3933 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003934
Ed Tanous002d39b2022-05-31 08:59:27 -07003935 // Make call to Logging service to request Clear Log
3936 crow::connections::systemBus->async_method_call(
3937 respHandler, "xyz.openbmc_project.Logging",
3938 "/xyz/openbmc_project/logging",
3939 "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
Patrick Williams5a39f772023-10-20 11:20:21 -05003940 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003941}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003942
3943/****************************************************
3944 * Redfish PostCode interfaces
3945 * using DBUS interface: getPostCodesTS
3946 ******************************************************/
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003947inline void requestRoutesPostCodesLogService(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003948{
Ed Tanous22d268c2022-05-19 09:39:07 -07003949 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/")
Ed Tanoused398212021-06-09 17:05:54 -07003950 .privileges(redfish::privileges::getLogService)
Ed Tanous002d39b2022-05-31 08:59:27 -07003951 .methods(boost::beast::http::verb::get)(
3952 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003953 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3954 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003955 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003956 {
3957 return;
3958 }
Ed Tanous25b54db2024-04-17 15:40:31 -07003959 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003960 {
3961 // Option currently returns no systems. TBD
3962 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3963 systemName);
3964 return;
3965 }
Ed Tanous253f11b2024-05-16 09:38:31 -07003966 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07003967 {
3968 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3969 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003970 return;
3971 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003972 asyncResp->res.jsonValue["@odata.id"] =
Ed Tanous253f11b2024-05-16 09:38:31 -07003973 std::format("/redfish/v1/Systems/{}/LogServices/PostCodes",
3974 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Ed Tanous002d39b2022-05-31 08:59:27 -07003975 asyncResp->res.jsonValue["@odata.type"] =
Janet Adkinsb25644a2023-08-16 11:23:45 -05003976 "#LogService.v1_2_0.LogService";
Ed Tanous002d39b2022-05-31 08:59:27 -07003977 asyncResp->res.jsonValue["Name"] = "POST Code Log Service";
3978 asyncResp->res.jsonValue["Description"] = "POST Code Log Service";
Ed Tanoused34a4a2023-02-08 15:43:27 -08003979 asyncResp->res.jsonValue["Id"] = "PostCodes";
Ed Tanous002d39b2022-05-31 08:59:27 -07003980 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
3981 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
Ed Tanous253f11b2024-05-16 09:38:31 -07003982 std::format("/redfish/v1/Systems/{}/LogServices/PostCodes/Entries",
3983 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Tejas Patil7c8c4052021-06-04 17:43:14 +05303984
Ed Tanous002d39b2022-05-31 08:59:27 -07003985 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07003986 redfish::time_utils::getDateTimeOffsetNow();
Ed Tanous002d39b2022-05-31 08:59:27 -07003987 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
3988 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
3989 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05303990
Ed Tanous20fa6a22024-05-20 18:02:58 -07003991 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]
3992 ["target"] = std::format(
3993 "/redfish/v1/Systems/{}/LogServices/PostCodes/Actions/LogService.ClearLog",
3994 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Patrick Williams5a39f772023-10-20 11:20:21 -05003995 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003996}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003997
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003998inline void requestRoutesPostCodesClear(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003999{
George Liu0fda0f12021-11-16 10:06:17 +08004000 BMCWEB_ROUTE(
4001 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07004002 "/redfish/v1/Systems/<str>/LogServices/PostCodes/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07004003 // The following privilege is incorrect; It should be ConfigureManager
4004 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07004005 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004006 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07004007 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07004008 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
4009 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00004010 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07004011 {
4012 return;
4013 }
Ed Tanous25b54db2024-04-17 15:40:31 -07004014 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08004015 {
4016 // Option currently returns no systems. TBD
4017 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
4018 systemName);
4019 return;
4020 }
Ed Tanous253f11b2024-05-16 09:38:31 -07004021 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07004022 {
4023 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
4024 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07004025 return;
4026 }
Ed Tanous62598e32023-07-17 17:06:25 -07004027 BMCWEB_LOG_DEBUG("Do delete all postcodes entries.");
ZhikuiRena3316fc2020-01-29 14:58:08 -08004028
Ed Tanous002d39b2022-05-31 08:59:27 -07004029 // Make call to post-code service to request clear all
4030 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08004031 [asyncResp](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -07004032 if (ec)
4033 {
4034 // TODO Handle for specific error code
Ed Tanous62598e32023-07-17 17:06:25 -07004035 BMCWEB_LOG_ERROR("doClearPostCodes resp_handler got error {}",
4036 ec);
Ed Tanous002d39b2022-05-31 08:59:27 -07004037 asyncResp->res.result(
4038 boost::beast::http::status::internal_server_error);
4039 messages::internalError(asyncResp->res);
4040 return;
4041 }
Tony Lee18fc70c2023-08-24 16:15:54 +08004042 messages::success(asyncResp->res);
Patrick Williams5a39f772023-10-20 11:20:21 -05004043 },
Ed Tanous002d39b2022-05-31 08:59:27 -07004044 "xyz.openbmc_project.State.Boot.PostCode0",
4045 "/xyz/openbmc_project/State/Boot/PostCode0",
4046 "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
Patrick Williams5a39f772023-10-20 11:20:21 -05004047 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004048}
ZhikuiRena3316fc2020-01-29 14:58:08 -08004049
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004050/**
4051 * @brief Parse post code ID and get the current value and index value
4052 * eg: postCodeID=B1-2, currentValue=1, index=2
4053 *
4054 * @param[in] postCodeID Post Code ID
4055 * @param[out] currentValue Current value
4056 * @param[out] index Index value
4057 *
4058 * @return bool true if the parsing is successful, false the parsing fails
4059 */
Ed Tanous6f056f22024-04-07 13:35:51 -07004060inline bool parsePostCode(std::string_view postCodeID, uint64_t& currentValue,
Ed Tanousdf254f22024-04-01 13:25:46 -07004061 uint16_t& index)
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004062{
4063 std::vector<std::string> split;
Ed Tanous50ebd4a2023-01-19 19:03:17 -08004064 bmcweb::split(split, postCodeID, '-');
Ed Tanous6f056f22024-04-07 13:35:51 -07004065 if (split.size() != 2)
4066 {
4067 return false;
4068 }
4069 std::string_view postCodeNumber = split[0];
4070 if (postCodeNumber.size() < 2)
4071 {
4072 return false;
4073 }
4074 if (postCodeNumber[0] != 'B')
4075 {
4076 return false;
4077 }
4078 postCodeNumber.remove_prefix(1);
4079 auto [ptrIndex, ecIndex] = std::from_chars(postCodeNumber.begin(),
4080 postCodeNumber.end(), index);
4081 if (ptrIndex != postCodeNumber.end() || ecIndex != std::errc())
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004082 {
4083 return false;
4084 }
4085
Ed Tanous6f056f22024-04-07 13:35:51 -07004086 std::string_view postCodeIndex = split[1];
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004087
Ed Tanous6f056f22024-04-07 13:35:51 -07004088 auto [ptrValue, ecValue] = std::from_chars(
4089 postCodeIndex.begin(), postCodeIndex.end(), currentValue);
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004090
Ed Tanous6f056f22024-04-07 13:35:51 -07004091 return ptrValue == postCodeIndex.end() && ecValue == std::errc();
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004092}
4093
4094static bool fillPostCodeEntry(
Ed Tanousac106bf2023-06-07 09:24:59 -07004095 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05304096 const boost::container::flat_map<
4097 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& postcode,
ZhikuiRena3316fc2020-01-29 14:58:08 -08004098 const uint16_t bootIndex, const uint64_t codeIndex = 0,
4099 const uint64_t skip = 0, const uint64_t top = 0)
4100{
4101 // Get the Message from the MessageRegistry
Ed Tanousfffb8c12022-02-07 23:53:03 -08004102 const registries::Message* message =
4103 registries::getMessage("OpenBMC.0.2.BIOSPOSTCode");
Ed Tanousdc8cfa62024-04-07 13:37:25 -07004104 if (message == nullptr)
4105 {
4106 BMCWEB_LOG_ERROR("Couldn't find known message?");
4107 return false;
4108 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08004109 uint64_t currentCodeIndex = 0;
ZhikuiRena3316fc2020-01-29 14:58:08 -08004110 uint64_t firstCodeTimeUs = 0;
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05304111 for (const std::pair<uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
4112 code : postcode)
ZhikuiRena3316fc2020-01-29 14:58:08 -08004113 {
4114 currentCodeIndex++;
4115 std::string postcodeEntryID =
4116 "B" + std::to_string(bootIndex) + "-" +
4117 std::to_string(currentCodeIndex); // 1 based index in EntryID string
4118
4119 uint64_t usecSinceEpoch = code.first;
4120 uint64_t usTimeOffset = 0;
4121
4122 if (1 == currentCodeIndex)
4123 { // already incremented
4124 firstCodeTimeUs = code.first;
4125 }
4126 else
4127 {
4128 usTimeOffset = code.first - firstCodeTimeUs;
4129 }
4130
4131 // skip if no specific codeIndex is specified and currentCodeIndex does
4132 // not fall between top and skip
4133 if ((codeIndex == 0) &&
4134 (currentCodeIndex <= skip || currentCodeIndex > top))
4135 {
4136 continue;
4137 }
4138
Gunnar Mills4e0453b2020-07-08 14:00:30 -05004139 // skip if a specific codeIndex is specified and does not match the
ZhikuiRena3316fc2020-01-29 14:58:08 -08004140 // currentIndex
4141 if ((codeIndex > 0) && (currentCodeIndex != codeIndex))
4142 {
4143 // This is done for simplicity. 1st entry is needed to calculate
4144 // time offset. To improve efficiency, one can get to the entry
4145 // directly (possibly with flatmap's nth method)
4146 continue;
4147 }
4148
4149 // currentCodeIndex is within top and skip or equal to specified code
4150 // index
4151
4152 // Get the Created time from the timestamp
4153 std::string entryTimeStr;
Konstantin Aladyshev2a025612023-02-15 11:52:58 +03004154 entryTimeStr = redfish::time_utils::getDateTimeUintUs(usecSinceEpoch);
ZhikuiRena3316fc2020-01-29 14:58:08 -08004155
4156 // assemble messageArgs: BootIndex, TimeOffset(100us), PostCode(hex)
4157 std::ostringstream hexCode;
4158 hexCode << "0x" << std::setfill('0') << std::setw(2) << std::hex
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05304159 << std::get<0>(code.second);
ZhikuiRena3316fc2020-01-29 14:58:08 -08004160 std::ostringstream timeOffsetStr;
4161 // Set Fixed -Point Notation
4162 timeOffsetStr << std::fixed;
4163 // Set precision to 4 digits
4164 timeOffsetStr << std::setprecision(4);
4165 // Add double to stream
4166 timeOffsetStr << static_cast<double>(usTimeOffset) / 1000 / 1000;
ZhikuiRena3316fc2020-01-29 14:58:08 -08004167
Ed Tanous1e6deaf2022-02-17 11:32:37 -08004168 std::string bootIndexStr = std::to_string(bootIndex);
4169 std::string timeOffsetString = timeOffsetStr.str();
4170 std::string hexCodeStr = hexCode.str();
4171
4172 std::array<std::string_view, 3> messageArgs = {
4173 bootIndexStr, timeOffsetString, hexCodeStr};
4174
4175 std::string msg =
4176 redfish::registries::fillMessageArgs(messageArgs, message->message);
4177 if (msg.empty())
ZhikuiRena3316fc2020-01-29 14:58:08 -08004178 {
Ed Tanous1e6deaf2022-02-17 11:32:37 -08004179 messages::internalError(asyncResp->res);
4180 return false;
ZhikuiRena3316fc2020-01-29 14:58:08 -08004181 }
4182
Tim Leed4342a92020-04-27 11:47:58 +08004183 // Get Severity template from message registry
4184 std::string severity;
4185 if (message != nullptr)
4186 {
Ed Tanous5f2b84e2022-02-08 00:41:53 -08004187 severity = message->messageSeverity;
Tim Leed4342a92020-04-27 11:47:58 +08004188 }
4189
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004190 // Format entry
4191 nlohmann::json::object_t bmcLogEntry;
Vijay Lobo9c11a172021-10-07 16:53:16 -05004192 bmcLogEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Ed Tanousef4c65b2023-04-24 15:28:50 -07004193 bmcLogEntry["@odata.id"] = boost::urls::format(
Ed Tanous253f11b2024-05-16 09:38:31 -07004194 "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries/{}",
4195 BMCWEB_REDFISH_SYSTEM_URI_NAME, postcodeEntryID);
Jason M. Bills84afc482022-06-24 12:38:23 -07004196 bmcLogEntry["Name"] = "POST Code Log Entry";
4197 bmcLogEntry["Id"] = postcodeEntryID;
4198 bmcLogEntry["Message"] = std::move(msg);
4199 bmcLogEntry["MessageId"] = "OpenBMC.0.2.BIOSPOSTCode";
Ed Tanous1e6deaf2022-02-17 11:32:37 -08004200 bmcLogEntry["MessageArgs"] = messageArgs;
Jason M. Bills84afc482022-06-24 12:38:23 -07004201 bmcLogEntry["EntryType"] = "Event";
4202 bmcLogEntry["Severity"] = std::move(severity);
4203 bmcLogEntry["Created"] = entryTimeStr;
George Liu647b3cd2021-07-05 12:43:56 +08004204 if (!std::get<std::vector<uint8_t>>(code.second).empty())
4205 {
4206 bmcLogEntry["AdditionalDataURI"] =
Ed Tanous253f11b2024-05-16 09:38:31 -07004207 std::format(
4208 "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries/",
4209 BMCWEB_REDFISH_SYSTEM_URI_NAME) +
George Liu647b3cd2021-07-05 12:43:56 +08004210 postcodeEntryID + "/attachment";
4211 }
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004212
4213 // codeIndex is only specified when querying single entry, return only
4214 // that entry in this case
4215 if (codeIndex != 0)
4216 {
Ed Tanousac106bf2023-06-07 09:24:59 -07004217 asyncResp->res.jsonValue.update(bmcLogEntry);
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004218 return true;
4219 }
4220
Ed Tanousac106bf2023-06-07 09:24:59 -07004221 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
Patrick Williamsb2ba3072023-05-12 10:27:39 -05004222 logEntryArray.emplace_back(std::move(bmcLogEntry));
ZhikuiRena3316fc2020-01-29 14:58:08 -08004223 }
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004224
4225 // Return value is always false when querying multiple entries
4226 return false;
ZhikuiRena3316fc2020-01-29 14:58:08 -08004227}
4228
Ed Tanousac106bf2023-06-07 09:24:59 -07004229static void
4230 getPostCodeForEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
4231 const std::string& entryId)
ZhikuiRena3316fc2020-01-29 14:58:08 -08004232{
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004233 uint16_t bootIndex = 0;
4234 uint64_t codeIndex = 0;
4235 if (!parsePostCode(entryId, codeIndex, bootIndex))
4236 {
4237 // Requested ID was not found
Ed Tanousac106bf2023-06-07 09:24:59 -07004238 messages::resourceNotFound(asyncResp->res, "LogEntry", entryId);
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004239 return;
4240 }
4241
4242 if (bootIndex == 0 || codeIndex == 0)
4243 {
4244 // 0 is an invalid index
Ed Tanousac106bf2023-06-07 09:24:59 -07004245 messages::resourceNotFound(asyncResp->res, "LogEntry", entryId);
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004246 return;
4247 }
4248
ZhikuiRena3316fc2020-01-29 14:58:08 -08004249 crow::connections::systemBus->async_method_call(
Ed Tanousac106bf2023-06-07 09:24:59 -07004250 [asyncResp, entryId, bootIndex,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08004251 codeIndex](const boost::system::error_code& ec,
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05304252 const boost::container::flat_map<
4253 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
4254 postcode) {
Ed Tanous002d39b2022-05-31 08:59:27 -07004255 if (ec)
4256 {
Ed Tanous62598e32023-07-17 17:06:25 -07004257 BMCWEB_LOG_DEBUG("DBUS POST CODE PostCode response error");
Ed Tanousac106bf2023-06-07 09:24:59 -07004258 messages::internalError(asyncResp->res);
Ed Tanous002d39b2022-05-31 08:59:27 -07004259 return;
4260 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08004261
Ed Tanous002d39b2022-05-31 08:59:27 -07004262 if (postcode.empty())
4263 {
Ed Tanousac106bf2023-06-07 09:24:59 -07004264 messages::resourceNotFound(asyncResp->res, "LogEntry", entryId);
Ed Tanous002d39b2022-05-31 08:59:27 -07004265 return;
4266 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08004267
Ed Tanousac106bf2023-06-07 09:24:59 -07004268 if (!fillPostCodeEntry(asyncResp, postcode, bootIndex, codeIndex))
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004269 {
Ed Tanousac106bf2023-06-07 09:24:59 -07004270 messages::resourceNotFound(asyncResp->res, "LogEntry", entryId);
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004271 return;
4272 }
Patrick Williams5a39f772023-10-20 11:20:21 -05004273 },
Jonathan Doman15124762021-01-07 17:54:17 -08004274 "xyz.openbmc_project.State.Boot.PostCode0",
4275 "/xyz/openbmc_project/State/Boot/PostCode0",
ZhikuiRena3316fc2020-01-29 14:58:08 -08004276 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
4277 bootIndex);
4278}
4279
Ed Tanousac106bf2023-06-07 09:24:59 -07004280static void
4281 getPostCodeForBoot(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
4282 const uint16_t bootIndex, const uint16_t bootCount,
4283 const uint64_t entryCount, size_t skip, size_t top)
ZhikuiRena3316fc2020-01-29 14:58:08 -08004284{
4285 crow::connections::systemBus->async_method_call(
Ed Tanousac106bf2023-06-07 09:24:59 -07004286 [asyncResp, bootIndex, bootCount, entryCount, skip,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08004287 top](const boost::system::error_code& ec,
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05304288 const boost::container::flat_map<
4289 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
4290 postcode) {
Ed Tanous002d39b2022-05-31 08:59:27 -07004291 if (ec)
4292 {
Ed Tanous62598e32023-07-17 17:06:25 -07004293 BMCWEB_LOG_DEBUG("DBUS POST CODE PostCode response error");
Ed Tanousac106bf2023-06-07 09:24:59 -07004294 messages::internalError(asyncResp->res);
Ed Tanous002d39b2022-05-31 08:59:27 -07004295 return;
4296 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08004297
Ed Tanous002d39b2022-05-31 08:59:27 -07004298 uint64_t endCount = entryCount;
4299 if (!postcode.empty())
4300 {
4301 endCount = entryCount + postcode.size();
Ed Tanous3648c8b2022-07-25 13:39:59 -07004302 if (skip < endCount && (top + skip) > entryCount)
ZhikuiRena3316fc2020-01-29 14:58:08 -08004303 {
Patrick Williams89492a12023-05-10 07:51:34 -05004304 uint64_t thisBootSkip = std::max(static_cast<uint64_t>(skip),
4305 entryCount) -
4306 entryCount;
Ed Tanous002d39b2022-05-31 08:59:27 -07004307 uint64_t thisBootTop =
Ed Tanous3648c8b2022-07-25 13:39:59 -07004308 std::min(static_cast<uint64_t>(top + skip), endCount) -
4309 entryCount;
Ed Tanous002d39b2022-05-31 08:59:27 -07004310
Ed Tanousac106bf2023-06-07 09:24:59 -07004311 fillPostCodeEntry(asyncResp, postcode, bootIndex, 0,
4312 thisBootSkip, thisBootTop);
ZhikuiRena3316fc2020-01-29 14:58:08 -08004313 }
Ed Tanousac106bf2023-06-07 09:24:59 -07004314 asyncResp->res.jsonValue["Members@odata.count"] = endCount;
Ed Tanous002d39b2022-05-31 08:59:27 -07004315 }
4316
4317 // continue to previous bootIndex
4318 if (bootIndex < bootCount)
4319 {
Ed Tanousac106bf2023-06-07 09:24:59 -07004320 getPostCodeForBoot(asyncResp, static_cast<uint16_t>(bootIndex + 1),
Ed Tanous002d39b2022-05-31 08:59:27 -07004321 bootCount, endCount, skip, top);
4322 }
Jiaqing Zhao81584ab2022-07-28 00:33:45 +08004323 else if (skip + top < endCount)
Ed Tanous002d39b2022-05-31 08:59:27 -07004324 {
Ed Tanousac106bf2023-06-07 09:24:59 -07004325 asyncResp->res.jsonValue["Members@odata.nextLink"] =
Ed Tanous253f11b2024-05-16 09:38:31 -07004326 std::format(
4327 "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries?$skip=",
4328 BMCWEB_REDFISH_SYSTEM_URI_NAME) +
Ed Tanous002d39b2022-05-31 08:59:27 -07004329 std::to_string(skip + top);
4330 }
Patrick Williams5a39f772023-10-20 11:20:21 -05004331 },
Jonathan Doman15124762021-01-07 17:54:17 -08004332 "xyz.openbmc_project.State.Boot.PostCode0",
4333 "/xyz/openbmc_project/State/Boot/PostCode0",
ZhikuiRena3316fc2020-01-29 14:58:08 -08004334 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
4335 bootIndex);
4336}
4337
zhanghch058d1b46d2021-04-01 11:18:24 +08004338static void
Ed Tanousac106bf2023-06-07 09:24:59 -07004339 getCurrentBootNumber(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous3648c8b2022-07-25 13:39:59 -07004340 size_t skip, size_t top)
ZhikuiRena3316fc2020-01-29 14:58:08 -08004341{
4342 uint64_t entryCount = 0;
Jonathan Doman1e1e5982021-06-11 09:36:17 -07004343 sdbusplus::asio::getProperty<uint16_t>(
4344 *crow::connections::systemBus,
4345 "xyz.openbmc_project.State.Boot.PostCode0",
4346 "/xyz/openbmc_project/State/Boot/PostCode0",
4347 "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount",
Ed Tanousac106bf2023-06-07 09:24:59 -07004348 [asyncResp, entryCount, skip, top](const boost::system::error_code& ec,
4349 const uint16_t bootCount) {
Ed Tanous002d39b2022-05-31 08:59:27 -07004350 if (ec)
4351 {
Ed Tanous62598e32023-07-17 17:06:25 -07004352 BMCWEB_LOG_DEBUG("DBUS response error {}", ec);
Ed Tanousac106bf2023-06-07 09:24:59 -07004353 messages::internalError(asyncResp->res);
Ed Tanous002d39b2022-05-31 08:59:27 -07004354 return;
4355 }
Ed Tanousac106bf2023-06-07 09:24:59 -07004356 getPostCodeForBoot(asyncResp, 1, bootCount, entryCount, skip, top);
Patrick Williams5a39f772023-10-20 11:20:21 -05004357 });
ZhikuiRena3316fc2020-01-29 14:58:08 -08004358}
4359
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004360inline void requestRoutesPostCodesEntryCollection(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08004361{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004362 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07004363 "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07004364 .privileges(redfish::privileges::getLogEntryCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004365 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07004366 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07004367 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
4368 const std::string& systemName) {
Ed Tanous002d39b2022-05-31 08:59:27 -07004369 query_param::QueryCapabilities capabilities = {
4370 .canDelegateTop = true,
4371 .canDelegateSkip = true,
4372 };
4373 query_param::Query delegatedQuery;
4374 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00004375 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07004376 {
4377 return;
4378 }
Ed Tanous25b54db2024-04-17 15:40:31 -07004379 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08004380 {
4381 // Option currently returns no systems. TBD
4382 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
4383 systemName);
4384 return;
4385 }
Ed Tanous22d268c2022-05-19 09:39:07 -07004386
Ed Tanous253f11b2024-05-16 09:38:31 -07004387 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07004388 {
4389 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
4390 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07004391 return;
4392 }
Ed Tanous002d39b2022-05-31 08:59:27 -07004393 asyncResp->res.jsonValue["@odata.type"] =
4394 "#LogEntryCollection.LogEntryCollection";
4395 asyncResp->res.jsonValue["@odata.id"] =
Ed Tanous253f11b2024-05-16 09:38:31 -07004396 std::format("/redfish/v1/Systems/{}/LogServices/PostCodes/Entries",
4397 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Ed Tanous002d39b2022-05-31 08:59:27 -07004398 asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries";
4399 asyncResp->res.jsonValue["Description"] =
4400 "Collection of POST Code Log Entries";
4401 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
4402 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Ed Tanous3648c8b2022-07-25 13:39:59 -07004403 size_t skip = delegatedQuery.skip.value_or(0);
Jiaqing Zhao5143f7a2022-07-22 09:33:33 +08004404 size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
Ed Tanous3648c8b2022-07-25 13:39:59 -07004405 getCurrentBootNumber(asyncResp, skip, top);
Patrick Williams5a39f772023-10-20 11:20:21 -05004406 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004407}
ZhikuiRena3316fc2020-01-29 14:58:08 -08004408
George Liu647b3cd2021-07-05 12:43:56 +08004409inline void requestRoutesPostCodesEntryAdditionalData(App& app)
4410{
George Liu0fda0f12021-11-16 10:06:17 +08004411 BMCWEB_ROUTE(
4412 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07004413 "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/attachment/")
George Liu647b3cd2021-07-05 12:43:56 +08004414 .privileges(redfish::privileges::getLogEntry)
4415 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07004416 [&app](const crow::Request& req,
4417 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07004418 const std::string& systemName,
Ed Tanous45ca1b82022-03-25 13:07:27 -07004419 const std::string& postCodeID) {
Carson Labrado3ba00072022-06-06 19:40:56 +00004420 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07004421 {
4422 return;
4423 }
Matt Spinler72e21372023-04-19 12:53:33 -05004424 if (!http_helpers::isContentTypeAllowed(
Ed Tanous99351cd2022-08-07 16:42:51 -07004425 req.getHeaderValue("Accept"),
Ed Tanous4a0e1a02022-09-21 15:28:04 -07004426 http_helpers::ContentType::OctetStream, true))
Ed Tanous002d39b2022-05-31 08:59:27 -07004427 {
4428 asyncResp->res.result(boost::beast::http::status::bad_request);
4429 return;
4430 }
Ed Tanous25b54db2024-04-17 15:40:31 -07004431 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08004432 {
4433 // Option currently returns no systems. TBD
4434 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
4435 systemName);
4436 return;
4437 }
Ed Tanous253f11b2024-05-16 09:38:31 -07004438 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07004439 {
4440 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
4441 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07004442 return;
4443 }
George Liu647b3cd2021-07-05 12:43:56 +08004444
Ed Tanous002d39b2022-05-31 08:59:27 -07004445 uint64_t currentValue = 0;
4446 uint16_t index = 0;
4447 if (!parsePostCode(postCodeID, currentValue, index))
4448 {
4449 messages::resourceNotFound(asyncResp->res, "LogEntry", postCodeID);
4450 return;
4451 }
George Liu647b3cd2021-07-05 12:43:56 +08004452
Ed Tanous002d39b2022-05-31 08:59:27 -07004453 crow::connections::systemBus->async_method_call(
4454 [asyncResp, postCodeID, currentValue](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08004455 const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -07004456 const std::vector<std::tuple<uint64_t, std::vector<uint8_t>>>&
4457 postcodes) {
4458 if (ec.value() == EBADR)
4459 {
4460 messages::resourceNotFound(asyncResp->res, "LogEntry",
4461 postCodeID);
4462 return;
4463 }
4464 if (ec)
4465 {
Ed Tanous62598e32023-07-17 17:06:25 -07004466 BMCWEB_LOG_DEBUG("DBUS response error {}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -07004467 messages::internalError(asyncResp->res);
4468 return;
4469 }
George Liu647b3cd2021-07-05 12:43:56 +08004470
Ed Tanous002d39b2022-05-31 08:59:27 -07004471 size_t value = static_cast<size_t>(currentValue) - 1;
4472 if (value == std::string::npos || postcodes.size() < currentValue)
4473 {
Ed Tanous62598e32023-07-17 17:06:25 -07004474 BMCWEB_LOG_WARNING("Wrong currentValue value");
Ed Tanous002d39b2022-05-31 08:59:27 -07004475 messages::resourceNotFound(asyncResp->res, "LogEntry",
4476 postCodeID);
4477 return;
4478 }
George Liu647b3cd2021-07-05 12:43:56 +08004479
Ed Tanous002d39b2022-05-31 08:59:27 -07004480 const auto& [tID, c] = postcodes[value];
4481 if (c.empty())
4482 {
Ed Tanous62598e32023-07-17 17:06:25 -07004483 BMCWEB_LOG_WARNING("No found post code data");
Ed Tanous002d39b2022-05-31 08:59:27 -07004484 messages::resourceNotFound(asyncResp->res, "LogEntry",
4485 postCodeID);
4486 return;
4487 }
4488 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
4489 const char* d = reinterpret_cast<const char*>(c.data());
4490 std::string_view strData(d, c.size());
George Liu647b3cd2021-07-05 12:43:56 +08004491
Ed Tanousd9f6c622022-03-17 09:12:17 -07004492 asyncResp->res.addHeader(boost::beast::http::field::content_type,
Ed Tanous002d39b2022-05-31 08:59:27 -07004493 "application/octet-stream");
Ed Tanousd9f6c622022-03-17 09:12:17 -07004494 asyncResp->res.addHeader(
4495 boost::beast::http::field::content_transfer_encoding, "Base64");
Ed Tanous27b0cf92023-08-07 12:02:40 -07004496 asyncResp->res.write(crow::utility::base64encode(strData));
Patrick Williams5a39f772023-10-20 11:20:21 -05004497 },
Ed Tanous002d39b2022-05-31 08:59:27 -07004498 "xyz.openbmc_project.State.Boot.PostCode0",
4499 "/xyz/openbmc_project/State/Boot/PostCode0",
4500 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodes", index);
Patrick Williams5a39f772023-10-20 11:20:21 -05004501 });
George Liu647b3cd2021-07-05 12:43:56 +08004502}
4503
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004504inline void requestRoutesPostCodesEntry(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08004505{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004506 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07004507 app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07004508 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004509 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07004510 [&app](const crow::Request& req,
4511 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07004512 const std::string& systemName, const std::string& targetID) {
Carson Labrado3ba00072022-06-06 19:40:56 +00004513 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07004514 {
4515 return;
4516 }
Ed Tanous25b54db2024-04-17 15:40:31 -07004517 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08004518 {
4519 // Option currently returns no systems. TBD
4520 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
4521 systemName);
4522 return;
4523 }
Ed Tanous253f11b2024-05-16 09:38:31 -07004524 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07004525 {
4526 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
4527 systemName);
4528 return;
4529 }
4530
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004531 getPostCodeForEntry(asyncResp, targetID);
Patrick Williams5a39f772023-10-20 11:20:21 -05004532 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004533}
ZhikuiRena3316fc2020-01-29 14:58:08 -08004534
Ed Tanous1da66f72018-07-27 16:13:37 -07004535} // namespace redfish