blob: 2524502d5189b3cec57d19d422790b5a759c8626 [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 Tanous002d39b2022-05-31 08:59:27 -07001423 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = {
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001424
Ed Tanous002d39b2022-05-31 08:59:27 -07001425 {"target",
Ed Tanous253f11b2024-05-16 09:38:31 -07001426 std::format(
1427 "/redfish/v1/Systems/{}/LogServices/EventLog/Actions/LogService.ClearLog",
1428 BMCWEB_REDFISH_SYSTEM_URI_NAME)}};
Patrick Williams5a39f772023-10-20 11:20:21 -05001429 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001430}
1431
1432inline void requestRoutesJournalEventLogClear(App& app)
1433{
Jason M. Bills4978b632022-02-22 14:17:43 -08001434 BMCWEB_ROUTE(
1435 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07001436 "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/")
Ed Tanous432a8902021-06-14 15:28:56 -07001437 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001438 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001439 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001440 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1441 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001442 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001443 {
1444 return;
1445 }
Ed Tanous253f11b2024-05-16 09:38:31 -07001446 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07001447 {
1448 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1449 systemName);
1450 return;
1451 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001452 // Clear the EventLog by deleting the log files
1453 std::vector<std::filesystem::path> redfishLogFiles;
1454 if (getRedfishLogFiles(redfishLogFiles))
1455 {
1456 for (const std::filesystem::path& file : redfishLogFiles)
1457 {
1458 std::error_code ec;
1459 std::filesystem::remove(file, ec);
1460 }
1461 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001462
Ed Tanous002d39b2022-05-31 08:59:27 -07001463 // Reload rsyslog so it knows to start new log files
1464 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001465 [asyncResp](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001466 if (ec)
1467 {
Ed Tanous62598e32023-07-17 17:06:25 -07001468 BMCWEB_LOG_ERROR("Failed to reload rsyslog: {}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -07001469 messages::internalError(asyncResp->res);
1470 return;
1471 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001472
Ed Tanous002d39b2022-05-31 08:59:27 -07001473 messages::success(asyncResp->res);
Patrick Williams5a39f772023-10-20 11:20:21 -05001474 },
Ed Tanous002d39b2022-05-31 08:59:27 -07001475 "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
1476 "org.freedesktop.systemd1.Manager", "ReloadUnit", "rsyslog.service",
1477 "replace");
Patrick Williams5a39f772023-10-20 11:20:21 -05001478 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001479}
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001480
Jason M. Billsac992cd2022-06-24 13:31:46 -07001481enum class LogParseError
1482{
1483 success,
1484 parseFailed,
1485 messageIdNotInRegistry,
1486};
1487
1488static LogParseError
1489 fillEventLogEntryJson(const std::string& logEntryID,
1490 const std::string& logEntry,
1491 nlohmann::json::object_t& logEntryJson)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001492{
Jason M. Bills95820182019-04-22 16:25:34 -07001493 // The redfish log format is "<Timestamp> <MessageId>,<MessageArgs>"
Jason M. Billscd225da2019-05-08 15:31:57 -07001494 // First get the Timestamp
Ed Tanousf23b7292020-10-15 09:41:17 -07001495 size_t space = logEntry.find_first_of(' ');
Jason M. Billscd225da2019-05-08 15:31:57 -07001496 if (space == std::string::npos)
Jason M. Bills95820182019-04-22 16:25:34 -07001497 {
Jason M. Billsac992cd2022-06-24 13:31:46 -07001498 return LogParseError::parseFailed;
Jason M. Bills95820182019-04-22 16:25:34 -07001499 }
Jason M. Billscd225da2019-05-08 15:31:57 -07001500 std::string timestamp = logEntry.substr(0, space);
1501 // Then get the log contents
Ed Tanousf23b7292020-10-15 09:41:17 -07001502 size_t entryStart = logEntry.find_first_not_of(' ', space);
Jason M. Billscd225da2019-05-08 15:31:57 -07001503 if (entryStart == std::string::npos)
1504 {
Jason M. Billsac992cd2022-06-24 13:31:46 -07001505 return LogParseError::parseFailed;
Jason M. Billscd225da2019-05-08 15:31:57 -07001506 }
1507 std::string_view entry(logEntry);
1508 entry.remove_prefix(entryStart);
1509 // Use split to separate the entry into its fields
1510 std::vector<std::string> logEntryFields;
Ed Tanous50ebd4a2023-01-19 19:03:17 -08001511 bmcweb::split(logEntryFields, entry, ',');
Jason M. Billscd225da2019-05-08 15:31:57 -07001512 // We need at least a MessageId to be valid
Ed Tanous1e6deaf2022-02-17 11:32:37 -08001513 auto logEntryIter = logEntryFields.begin();
1514 if (logEntryIter == logEntryFields.end())
Jason M. Billscd225da2019-05-08 15:31:57 -07001515 {
Jason M. Billsac992cd2022-06-24 13:31:46 -07001516 return LogParseError::parseFailed;
Jason M. Billscd225da2019-05-08 15:31:57 -07001517 }
Ed Tanous1e6deaf2022-02-17 11:32:37 -08001518 std::string& messageID = *logEntryIter;
Jason M. Bills4851d452019-03-28 11:27:48 -07001519 // Get the Message from the MessageRegistry
Ed Tanousfffb8c12022-02-07 23:53:03 -08001520 const registries::Message* message = registries::getMessage(messageID);
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001521
Ed Tanous1e6deaf2022-02-17 11:32:37 -08001522 logEntryIter++;
Sui Chen54417b02022-03-24 14:59:52 -07001523 if (message == nullptr)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001524 {
Ed Tanous62598e32023-07-17 17:06:25 -07001525 BMCWEB_LOG_WARNING("Log entry not found in registry: {}", logEntry);
Jason M. Billsac992cd2022-06-24 13:31:46 -07001526 return LogParseError::messageIdNotInRegistry;
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001527 }
1528
Ed Tanous1e6deaf2022-02-17 11:32:37 -08001529 std::vector<std::string_view> messageArgs(logEntryIter,
1530 logEntryFields.end());
Ed Tanousc05bba42023-06-28 08:33:29 -07001531 messageArgs.resize(message->numberOfArgs);
1532
Ed Tanous1e6deaf2022-02-17 11:32:37 -08001533 std::string msg = redfish::registries::fillMessageArgs(messageArgs,
1534 message->message);
1535 if (msg.empty())
Jason M. Bills4851d452019-03-28 11:27:48 -07001536 {
Ed Tanous1e6deaf2022-02-17 11:32:37 -08001537 return LogParseError::parseFailed;
Jason M. Bills4851d452019-03-28 11:27:48 -07001538 }
1539
Jason M. Bills95820182019-04-22 16:25:34 -07001540 // Get the Created time from the timestamp. The log timestamp is in RFC3339
1541 // format which matches the Redfish format except for the fractional seconds
1542 // between the '.' and the '+', so just remove them.
Ed Tanousf23b7292020-10-15 09:41:17 -07001543 std::size_t dot = timestamp.find_first_of('.');
1544 std::size_t plus = timestamp.find_first_of('+');
Jason M. Bills95820182019-04-22 16:25:34 -07001545 if (dot != std::string::npos && plus != std::string::npos)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001546 {
Jason M. Bills95820182019-04-22 16:25:34 -07001547 timestamp.erase(dot, plus - dot);
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001548 }
1549
1550 // Fill in the log entry with the gathered data
Vijay Lobo9c11a172021-10-07 16:53:16 -05001551 logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Ed Tanousef4c65b2023-04-24 15:28:50 -07001552 logEntryJson["@odata.id"] = boost::urls::format(
Ed Tanous253f11b2024-05-16 09:38:31 -07001553 "/redfish/v1/Systems/{}/LogServices/EventLog/Entries/{}",
1554 BMCWEB_REDFISH_SYSTEM_URI_NAME, logEntryID);
Jason M. Bills84afc482022-06-24 12:38:23 -07001555 logEntryJson["Name"] = "System Event Log Entry";
1556 logEntryJson["Id"] = logEntryID;
1557 logEntryJson["Message"] = std::move(msg);
1558 logEntryJson["MessageId"] = std::move(messageID);
1559 logEntryJson["MessageArgs"] = messageArgs;
1560 logEntryJson["EntryType"] = "Event";
1561 logEntryJson["Severity"] = message->messageSeverity;
1562 logEntryJson["Created"] = std::move(timestamp);
Jason M. Billsac992cd2022-06-24 13:31:46 -07001563 return LogParseError::success;
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001564}
1565
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001566inline void requestRoutesJournalEventLogEntryCollection(App& app)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001567{
Ed Tanous22d268c2022-05-19 09:39:07 -07001568 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/")
Gunnar Mills8b6a35f2021-07-30 14:52:53 -05001569 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07001570 .methods(boost::beast::http::verb::get)(
1571 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001572 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1573 const std::string& systemName) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001574 query_param::QueryCapabilities capabilities = {
1575 .canDelegateTop = true,
1576 .canDelegateSkip = true,
1577 };
1578 query_param::Query delegatedQuery;
1579 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00001580 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07001581 {
1582 return;
1583 }
Ed Tanous25b54db2024-04-17 15:40:31 -07001584 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08001585 {
1586 // Option currently returns no systems. TBD
1587 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1588 systemName);
1589 return;
1590 }
Ed Tanous253f11b2024-05-16 09:38:31 -07001591 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07001592 {
1593 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1594 systemName);
1595 return;
1596 }
1597
Jiaqing Zhao5143f7a2022-07-22 09:33:33 +08001598 size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
Ed Tanous3648c8b2022-07-25 13:39:59 -07001599 size_t skip = delegatedQuery.skip.value_or(0);
1600
Ed Tanous002d39b2022-05-31 08:59:27 -07001601 // Collections don't include the static data added by SubRoute
1602 // because it has a duplicate entry for members
1603 asyncResp->res.jsonValue["@odata.type"] =
1604 "#LogEntryCollection.LogEntryCollection";
1605 asyncResp->res.jsonValue["@odata.id"] =
Ed Tanous253f11b2024-05-16 09:38:31 -07001606 std::format("/redfish/v1/Systems/{}/LogServices/EventLog/Entries",
1607 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Ed Tanous002d39b2022-05-31 08:59:27 -07001608 asyncResp->res.jsonValue["Name"] = "System Event Log Entries";
1609 asyncResp->res.jsonValue["Description"] =
1610 "Collection of System Event Log Entries";
1611
1612 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
1613 logEntryArray = nlohmann::json::array();
1614 // Go through the log files and create a unique ID for each
1615 // entry
1616 std::vector<std::filesystem::path> redfishLogFiles;
1617 getRedfishLogFiles(redfishLogFiles);
1618 uint64_t entryCount = 0;
1619 std::string logEntry;
1620
1621 // Oldest logs are in the last file, so start there and loop
1622 // backwards
1623 for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend();
1624 it++)
1625 {
1626 std::ifstream logStream(*it);
1627 if (!logStream.is_open())
Jason M. Bills4978b632022-02-22 14:17:43 -08001628 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001629 continue;
Jason M. Bills4978b632022-02-22 14:17:43 -08001630 }
Jason M. Bills897967d2019-07-29 17:05:30 -07001631
Ed Tanous002d39b2022-05-31 08:59:27 -07001632 // Reset the unique ID on the first entry
1633 bool firstEntry = true;
1634 while (std::getline(logStream, logEntry))
Jason M. Bills4978b632022-02-22 14:17:43 -08001635 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001636 std::string idStr;
1637 if (!getUniqueEntryID(logEntry, idStr, firstEntry))
Jason M. Bills4978b632022-02-22 14:17:43 -08001638 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001639 continue;
1640 }
Jason M. Billsefde4ec2022-06-24 08:59:52 -07001641 firstEntry = false;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001642
Jason M. Billsde703c52022-06-23 14:19:04 -07001643 nlohmann::json::object_t bmcLogEntry;
Patrick Williams89492a12023-05-10 07:51:34 -05001644 LogParseError status = fillEventLogEntryJson(idStr, logEntry,
1645 bmcLogEntry);
Jason M. Billsac992cd2022-06-24 13:31:46 -07001646 if (status == LogParseError::messageIdNotInRegistry)
1647 {
1648 continue;
1649 }
1650 if (status != LogParseError::success)
Ed Tanous002d39b2022-05-31 08:59:27 -07001651 {
1652 messages::internalError(asyncResp->res);
1653 return;
Andrew Geisslercb92c032018-08-17 07:56:14 -07001654 }
Jason M. Billsde703c52022-06-23 14:19:04 -07001655
Jason M. Billsde703c52022-06-23 14:19:04 -07001656 entryCount++;
1657 // Handle paging using skip (number of entries to skip from the
1658 // start) and top (number of entries to display)
Ed Tanous3648c8b2022-07-25 13:39:59 -07001659 if (entryCount <= skip || entryCount > skip + top)
Jason M. Billsde703c52022-06-23 14:19:04 -07001660 {
1661 continue;
1662 }
1663
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001664 logEntryArray.emplace_back(std::move(bmcLogEntry));
Jason M. Bills4978b632022-02-22 14:17:43 -08001665 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001666 }
1667 asyncResp->res.jsonValue["Members@odata.count"] = entryCount;
Ed Tanous3648c8b2022-07-25 13:39:59 -07001668 if (skip + top < entryCount)
Ed Tanous002d39b2022-05-31 08:59:27 -07001669 {
Ed Tanous253f11b2024-05-16 09:38:31 -07001670 asyncResp->res
1671 .jsonValue["Members@odata.nextLink"] = boost::urls::format(
1672 "/redfish/v1/Systems/{}/LogServices/EventLog/Entries?$skip={}",
1673 BMCWEB_REDFISH_SYSTEM_URI_NAME, std::to_string(skip + top));
Ed Tanous002d39b2022-05-31 08:59:27 -07001674 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001675 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001676}
Chicago Duan336e96c2019-07-15 14:22:08 +08001677
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001678inline void requestRoutesJournalEventLogEntry(App& app)
1679{
1680 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07001681 app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001682 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001683 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001684 [&app](const crow::Request& req,
1685 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07001686 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001687 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001688 {
1689 return;
1690 }
Ed Tanous25b54db2024-04-17 15:40:31 -07001691 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08001692 {
1693 // Option currently returns no systems. TBD
1694 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1695 systemName);
1696 return;
1697 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001698
Ed Tanous253f11b2024-05-16 09:38:31 -07001699 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07001700 {
1701 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1702 systemName);
1703 return;
1704 }
1705
Ed Tanous002d39b2022-05-31 08:59:27 -07001706 const std::string& targetID = param;
1707
1708 // Go through the log files and check the unique ID for each
1709 // entry to find the target entry
1710 std::vector<std::filesystem::path> redfishLogFiles;
1711 getRedfishLogFiles(redfishLogFiles);
1712 std::string logEntry;
1713
1714 // Oldest logs are in the last file, so start there and loop
1715 // backwards
1716 for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend();
1717 it++)
1718 {
1719 std::ifstream logStream(*it);
1720 if (!logStream.is_open())
1721 {
1722 continue;
1723 }
1724
1725 // Reset the unique ID on the first entry
1726 bool firstEntry = true;
1727 while (std::getline(logStream, logEntry))
1728 {
1729 std::string idStr;
1730 if (!getUniqueEntryID(logEntry, idStr, firstEntry))
Ed Tanous45ca1b82022-03-25 13:07:27 -07001731 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001732 continue;
1733 }
Jason M. Billsefde4ec2022-06-24 08:59:52 -07001734 firstEntry = false;
Ed Tanous002d39b2022-05-31 08:59:27 -07001735
1736 if (idStr == targetID)
1737 {
Jason M. Billsde703c52022-06-23 14:19:04 -07001738 nlohmann::json::object_t bmcLogEntry;
Jason M. Billsac992cd2022-06-24 13:31:46 -07001739 LogParseError status =
1740 fillEventLogEntryJson(idStr, logEntry, bmcLogEntry);
1741 if (status != LogParseError::success)
Ed Tanous002d39b2022-05-31 08:59:27 -07001742 {
1743 messages::internalError(asyncResp->res);
1744 return;
1745 }
Jason M. Billsd405bb52022-06-24 10:52:05 -07001746 asyncResp->res.jsonValue.update(bmcLogEntry);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001747 return;
1748 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001749 }
1750 }
1751 // Requested ID was not found
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08001752 messages::resourceNotFound(asyncResp->res, "LogEntry", targetID);
Patrick Williams5a39f772023-10-20 11:20:21 -05001753 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001754}
1755
1756inline void requestRoutesDBusEventLogEntryCollection(App& app)
1757{
Ed Tanous22d268c2022-05-19 09:39:07 -07001758 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07001759 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07001760 .methods(boost::beast::http::verb::get)(
1761 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001762 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1763 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001764 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001765 {
1766 return;
1767 }
Ed Tanous25b54db2024-04-17 15:40:31 -07001768 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08001769 {
1770 // Option currently returns no systems. TBD
1771 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1772 systemName);
1773 return;
1774 }
Ed Tanous253f11b2024-05-16 09:38:31 -07001775 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07001776 {
1777 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1778 systemName);
1779 return;
1780 }
1781
Ed Tanous002d39b2022-05-31 08:59:27 -07001782 // Collections don't include the static data added by SubRoute
1783 // because it has a duplicate entry for members
1784 asyncResp->res.jsonValue["@odata.type"] =
1785 "#LogEntryCollection.LogEntryCollection";
1786 asyncResp->res.jsonValue["@odata.id"] =
Ed Tanous253f11b2024-05-16 09:38:31 -07001787 std::format("/redfish/v1/Systems/{}/LogServices/EventLog/Entries",
1788 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Ed Tanous002d39b2022-05-31 08:59:27 -07001789 asyncResp->res.jsonValue["Name"] = "System Event Log Entries";
1790 asyncResp->res.jsonValue["Description"] =
1791 "Collection of System Event Log Entries";
1792
1793 // DBus implementation of EventLog/Entries
1794 // Make call to Logging Service to find all log entry objects
George Liu5eb468d2023-06-20 17:03:24 +08001795 sdbusplus::message::object_path path("/xyz/openbmc_project/logging");
1796 dbus::utility::getManagedObjects(
1797 "xyz.openbmc_project.Logging", path,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001798 [asyncResp](const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -07001799 const dbus::utility::ManagedObjectType& resp) {
1800 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -07001801 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001802 // TODO Handle for specific error code
Ed Tanous62598e32023-07-17 17:06:25 -07001803 BMCWEB_LOG_ERROR(
1804 "getLogEntriesIfaceData resp_handler got error {}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -07001805 messages::internalError(asyncResp->res);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001806 return;
1807 }
Ed Tanous3544d2a2023-08-06 18:12:20 -07001808 nlohmann::json::array_t entriesArray;
Ed Tanous002d39b2022-05-31 08:59:27 -07001809 for (const auto& objectPath : resp)
1810 {
1811 const uint32_t* id = nullptr;
1812 const uint64_t* timestamp = nullptr;
1813 const uint64_t* updateTimestamp = nullptr;
1814 const std::string* severity = nullptr;
1815 const std::string* message = nullptr;
1816 const std::string* filePath = nullptr;
Vijay Lobo9c11a172021-10-07 16:53:16 -05001817 const std::string* resolution = nullptr;
Ed Tanous002d39b2022-05-31 08:59:27 -07001818 bool resolved = false;
Abhishek Patel9017faf2021-09-14 22:48:55 -05001819 const std::string* notify = nullptr;
1820
Ed Tanous002d39b2022-05-31 08:59:27 -07001821 for (const auto& interfaceMap : objectPath.second)
1822 {
1823 if (interfaceMap.first ==
1824 "xyz.openbmc_project.Logging.Entry")
Xiaochao Ma75710de2021-01-21 17:56:02 +08001825 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001826 for (const auto& propertyMap : interfaceMap.second)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001827 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001828 if (propertyMap.first == "Id")
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001829 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001830 id = std::get_if<uint32_t>(&propertyMap.second);
1831 }
1832 else if (propertyMap.first == "Timestamp")
1833 {
1834 timestamp =
1835 std::get_if<uint64_t>(&propertyMap.second);
1836 }
1837 else if (propertyMap.first == "UpdateTimestamp")
1838 {
1839 updateTimestamp =
1840 std::get_if<uint64_t>(&propertyMap.second);
1841 }
1842 else if (propertyMap.first == "Severity")
1843 {
1844 severity = std::get_if<std::string>(
1845 &propertyMap.second);
1846 }
Vijay Lobo9c11a172021-10-07 16:53:16 -05001847 else if (propertyMap.first == "Resolution")
1848 {
1849 resolution = std::get_if<std::string>(
1850 &propertyMap.second);
1851 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001852 else if (propertyMap.first == "Message")
1853 {
1854 message = std::get_if<std::string>(
1855 &propertyMap.second);
1856 }
1857 else if (propertyMap.first == "Resolved")
1858 {
1859 const bool* resolveptr =
1860 std::get_if<bool>(&propertyMap.second);
1861 if (resolveptr == nullptr)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001862 {
1863 messages::internalError(asyncResp->res);
1864 return;
1865 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001866 resolved = *resolveptr;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001867 }
Abhishek Patel9017faf2021-09-14 22:48:55 -05001868 else if (propertyMap.first ==
1869 "ServiceProviderNotify")
1870 {
1871 notify = std::get_if<std::string>(
1872 &propertyMap.second);
1873 if (notify == nullptr)
1874 {
1875 messages::internalError(asyncResp->res);
1876 return;
1877 }
1878 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001879 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001880 if (id == nullptr || message == nullptr ||
Ed Tanous002d39b2022-05-31 08:59:27 -07001881 severity == nullptr)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001882 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001883 messages::internalError(asyncResp->res);
1884 return;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001885 }
1886 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001887 else if (interfaceMap.first ==
1888 "xyz.openbmc_project.Common.FilePath")
1889 {
1890 for (const auto& propertyMap : interfaceMap.second)
1891 {
1892 if (propertyMap.first == "Path")
1893 {
1894 filePath = std::get_if<std::string>(
1895 &propertyMap.second);
1896 }
1897 }
1898 }
1899 }
1900 // Object path without the
1901 // xyz.openbmc_project.Logging.Entry interface, ignore
1902 // and continue.
1903 if (id == nullptr || message == nullptr ||
1904 severity == nullptr || timestamp == nullptr ||
1905 updateTimestamp == nullptr)
1906 {
1907 continue;
1908 }
Ed Tanous3544d2a2023-08-06 18:12:20 -07001909 nlohmann::json& thisEntry = entriesArray.emplace_back();
Vijay Lobo9c11a172021-10-07 16:53:16 -05001910 thisEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Ed Tanousef4c65b2023-04-24 15:28:50 -07001911 thisEntry["@odata.id"] = boost::urls::format(
Ed Tanous253f11b2024-05-16 09:38:31 -07001912 "/redfish/v1/Systems/{}/LogServices/EventLog/Entries/{}",
1913 BMCWEB_REDFISH_SYSTEM_URI_NAME, std::to_string(*id));
Ed Tanous002d39b2022-05-31 08:59:27 -07001914 thisEntry["Name"] = "System Event Log Entry";
1915 thisEntry["Id"] = std::to_string(*id);
1916 thisEntry["Message"] = *message;
1917 thisEntry["Resolved"] = resolved;
Vijay Lobo9c11a172021-10-07 16:53:16 -05001918 if ((resolution != nullptr) && (!(*resolution).empty()))
1919 {
1920 thisEntry["Resolution"] = *resolution;
1921 }
Abhishek Patel9017faf2021-09-14 22:48:55 -05001922 std::optional<bool> notifyAction =
1923 getProviderNotifyAction(*notify);
1924 if (notifyAction)
1925 {
1926 thisEntry["ServiceProviderNotified"] = *notifyAction;
1927 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001928 thisEntry["EntryType"] = "Event";
1929 thisEntry["Severity"] =
1930 translateSeverityDbusToRedfish(*severity);
1931 thisEntry["Created"] =
Ed Tanous2b829372022-08-03 14:22:34 -07001932 redfish::time_utils::getDateTimeUintMs(*timestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07001933 thisEntry["Modified"] =
Ed Tanous2b829372022-08-03 14:22:34 -07001934 redfish::time_utils::getDateTimeUintMs(*updateTimestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07001935 if (filePath != nullptr)
1936 {
1937 thisEntry["AdditionalDataURI"] =
Ed Tanous253f11b2024-05-16 09:38:31 -07001938 std::format(
1939 "/redfish/v1/Systems/{}/LogServices/EventLog/Entries/",
1940 BMCWEB_REDFISH_SYSTEM_URI_NAME) +
Ed Tanous002d39b2022-05-31 08:59:27 -07001941 std::to_string(*id) + "/attachment";
1942 }
1943 }
Ed Tanous3544d2a2023-08-06 18:12:20 -07001944 std::ranges::sort(entriesArray, [](const nlohmann::json& left,
1945 const nlohmann::json& right) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001946 return (left["Id"] <= right["Id"]);
Ed Tanous3544d2a2023-08-06 18:12:20 -07001947 });
Ed Tanous002d39b2022-05-31 08:59:27 -07001948 asyncResp->res.jsonValue["Members@odata.count"] =
1949 entriesArray.size();
Ed Tanous3544d2a2023-08-06 18:12:20 -07001950 asyncResp->res.jsonValue["Members"] = std::move(entriesArray);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001951 });
Patrick Williams5a39f772023-10-20 11:20:21 -05001952 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001953}
Xiaochao Ma75710de2021-01-21 17:56:02 +08001954
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001955inline void requestRoutesDBusEventLogEntry(App& app)
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001956{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001957 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07001958 app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001959 .privileges(redfish::privileges::getLogEntry)
Ed Tanous002d39b2022-05-31 08:59:27 -07001960 .methods(boost::beast::http::verb::get)(
1961 [&app](const crow::Request& req,
1962 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07001963 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001964 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001965 {
1966 return;
1967 }
Ed Tanous25b54db2024-04-17 15:40:31 -07001968 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08001969 {
1970 // Option currently returns no systems. TBD
1971 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1972 systemName);
1973 return;
1974 }
Ed Tanous253f11b2024-05-16 09:38:31 -07001975 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07001976 {
1977 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1978 systemName);
1979 return;
1980 }
1981
Ed Tanous002d39b2022-05-31 08:59:27 -07001982 std::string entryID = param;
1983 dbus::utility::escapePathForDbus(entryID);
1984
1985 // DBus implementation of EventLog/Entries
1986 // Make call to Logging Service to find all log entry objects
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001987 sdbusplus::asio::getAllProperties(
1988 *crow::connections::systemBus, "xyz.openbmc_project.Logging",
1989 "/xyz/openbmc_project/logging/entry/" + entryID, "",
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001990 [asyncResp, entryID](const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -07001991 const dbus::utility::DBusPropertiesMap& resp) {
1992 if (ec.value() == EBADR)
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001993 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001994 messages::resourceNotFound(asyncResp->res, "EventLogEntry",
1995 entryID);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001996 return;
1997 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001998 if (ec)
1999 {
Ed Tanous62598e32023-07-17 17:06:25 -07002000 BMCWEB_LOG_ERROR(
2001 "EventLogEntry (DBus) resp_handler got error {}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -07002002 messages::internalError(asyncResp->res);
2003 return;
2004 }
2005 const uint32_t* id = nullptr;
2006 const uint64_t* timestamp = nullptr;
2007 const uint64_t* updateTimestamp = nullptr;
2008 const std::string* severity = nullptr;
2009 const std::string* message = nullptr;
2010 const std::string* filePath = nullptr;
Vijay Lobo9c11a172021-10-07 16:53:16 -05002011 const std::string* resolution = nullptr;
Ed Tanous002d39b2022-05-31 08:59:27 -07002012 bool resolved = false;
Abhishek Patel9017faf2021-09-14 22:48:55 -05002013 const std::string* notify = nullptr;
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06002014
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02002015 const bool success = sdbusplus::unpackPropertiesNoThrow(
2016 dbus_utils::UnpackErrorPrinter(), resp, "Id", id, "Timestamp",
2017 timestamp, "UpdateTimestamp", updateTimestamp, "Severity",
Vijay Lobo9c11a172021-10-07 16:53:16 -05002018 severity, "Message", message, "Resolved", resolved,
Abhishek Patel9017faf2021-09-14 22:48:55 -05002019 "Resolution", resolution, "Path", filePath,
2020 "ServiceProviderNotify", notify);
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02002021
2022 if (!success)
Ed Tanous002d39b2022-05-31 08:59:27 -07002023 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02002024 messages::internalError(asyncResp->res);
2025 return;
Ed Tanous002d39b2022-05-31 08:59:27 -07002026 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02002027
Ed Tanous002d39b2022-05-31 08:59:27 -07002028 if (id == nullptr || message == nullptr || severity == nullptr ||
Abhishek Patel9017faf2021-09-14 22:48:55 -05002029 timestamp == nullptr || updateTimestamp == nullptr ||
2030 notify == nullptr)
Ed Tanous002d39b2022-05-31 08:59:27 -07002031 {
2032 messages::internalError(asyncResp->res);
2033 return;
2034 }
Abhishek Patel9017faf2021-09-14 22:48:55 -05002035
Ed Tanous002d39b2022-05-31 08:59:27 -07002036 asyncResp->res.jsonValue["@odata.type"] =
Vijay Lobo9c11a172021-10-07 16:53:16 -05002037 "#LogEntry.v1_9_0.LogEntry";
Ed Tanousef4c65b2023-04-24 15:28:50 -07002038 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
Ed Tanous253f11b2024-05-16 09:38:31 -07002039 "/redfish/v1/Systems/{}/LogServices/EventLog/Entries/{}",
2040 BMCWEB_REDFISH_SYSTEM_URI_NAME, std::to_string(*id));
Ed Tanous002d39b2022-05-31 08:59:27 -07002041 asyncResp->res.jsonValue["Name"] = "System Event Log Entry";
2042 asyncResp->res.jsonValue["Id"] = std::to_string(*id);
2043 asyncResp->res.jsonValue["Message"] = *message;
2044 asyncResp->res.jsonValue["Resolved"] = resolved;
Abhishek Patel9017faf2021-09-14 22:48:55 -05002045 std::optional<bool> notifyAction = getProviderNotifyAction(*notify);
2046 if (notifyAction)
2047 {
2048 asyncResp->res.jsonValue["ServiceProviderNotified"] =
2049 *notifyAction;
2050 }
Vijay Lobo9c11a172021-10-07 16:53:16 -05002051 if ((resolution != nullptr) && (!(*resolution).empty()))
2052 {
2053 asyncResp->res.jsonValue["Resolution"] = *resolution;
2054 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002055 asyncResp->res.jsonValue["EntryType"] = "Event";
2056 asyncResp->res.jsonValue["Severity"] =
2057 translateSeverityDbusToRedfish(*severity);
2058 asyncResp->res.jsonValue["Created"] =
Ed Tanous2b829372022-08-03 14:22:34 -07002059 redfish::time_utils::getDateTimeUintMs(*timestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07002060 asyncResp->res.jsonValue["Modified"] =
Ed Tanous2b829372022-08-03 14:22:34 -07002061 redfish::time_utils::getDateTimeUintMs(*updateTimestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07002062 if (filePath != nullptr)
2063 {
2064 asyncResp->res.jsonValue["AdditionalDataURI"] =
Ed Tanous253f11b2024-05-16 09:38:31 -07002065 std::format(
2066 "/redfish/v1/Systems/{}/LogServices/EventLog/Entries/",
2067 BMCWEB_REDFISH_SYSTEM_URI_NAME) +
Ed Tanous002d39b2022-05-31 08:59:27 -07002068 std::to_string(*id) + "/attachment";
2069 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07002070 });
Patrick Williams5a39f772023-10-20 11:20:21 -05002071 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002072
2073 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07002074 app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002075 .privileges(redfish::privileges::patchLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002076 .methods(boost::beast::http::verb::patch)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002077 [&app](const crow::Request& req,
2078 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07002079 const std::string& systemName, const std::string& entryId) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002080 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002081 {
2082 return;
2083 }
Ed Tanous25b54db2024-04-17 15:40:31 -07002084 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08002085 {
2086 // Option currently returns no systems. TBD
2087 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2088 systemName);
2089 return;
2090 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002091 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07002092 {
2093 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2094 systemName);
2095 return;
2096 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002097 std::optional<bool> resolved;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002098
Ed Tanous002d39b2022-05-31 08:59:27 -07002099 if (!json_util::readJsonPatch(req, asyncResp->res, "Resolved",
2100 resolved))
2101 {
2102 return;
2103 }
Ed Tanous62598e32023-07-17 17:06:25 -07002104 BMCWEB_LOG_DEBUG("Set Resolved");
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06002105
Asmitha Karunanithi3eb66652024-04-02 16:34:36 +00002106 setDbusProperty(asyncResp, "xyz.openbmc_project.Logging",
2107 "/xyz/openbmc_project/logging/entry/" + entryId,
2108 "xyz.openbmc_project.Logging.Entry", "Resolved",
2109 "Resolved", *resolved);
Patrick Williams5a39f772023-10-20 11:20:21 -05002110 });
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06002111
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002112 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07002113 app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002114 .privileges(redfish::privileges::deleteLogEntry)
2115
Ed Tanous002d39b2022-05-31 08:59:27 -07002116 .methods(boost::beast::http::verb::delete_)(
2117 [&app](const crow::Request& req,
2118 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07002119 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002120 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002121 {
2122 return;
2123 }
Ed Tanous25b54db2024-04-17 15:40:31 -07002124 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08002125 {
2126 // Option currently returns no systems. TBD
2127 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2128 systemName);
2129 return;
2130 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002131 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07002132 {
2133 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2134 systemName);
2135 return;
2136 }
Ed Tanous62598e32023-07-17 17:06:25 -07002137 BMCWEB_LOG_DEBUG("Do delete single event entries.");
Ed Tanous002d39b2022-05-31 08:59:27 -07002138
2139 std::string entryID = param;
2140
2141 dbus::utility::escapePathForDbus(entryID);
2142
2143 // Process response from Logging service.
Patrick Williams5a39f772023-10-20 11:20:21 -05002144 auto respHandler = [asyncResp,
2145 entryID](const boost::system::error_code& ec) {
Ed Tanous62598e32023-07-17 17:06:25 -07002146 BMCWEB_LOG_DEBUG("EventLogEntry (DBus) doDelete callback: Done");
Ed Tanous002d39b2022-05-31 08:59:27 -07002147 if (ec)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002148 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002149 if (ec.value() == EBADR)
Ed Tanous45ca1b82022-03-25 13:07:27 -07002150 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002151 messages::resourceNotFound(asyncResp->res, "LogEntry",
2152 entryID);
Ed Tanous45ca1b82022-03-25 13:07:27 -07002153 return;
2154 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002155 // TODO Handle for specific error code
Ed Tanous62598e32023-07-17 17:06:25 -07002156 BMCWEB_LOG_ERROR(
2157 "EventLogEntry (DBus) doDelete respHandler got error {}",
2158 ec);
Ed Tanous002d39b2022-05-31 08:59:27 -07002159 asyncResp->res.result(
2160 boost::beast::http::status::internal_server_error);
2161 return;
2162 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002163
Ed Tanous002d39b2022-05-31 08:59:27 -07002164 asyncResp->res.result(boost::beast::http::status::ok);
2165 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002166
Ed Tanous002d39b2022-05-31 08:59:27 -07002167 // Make call to Logging service to request Delete Log
2168 crow::connections::systemBus->async_method_call(
2169 respHandler, "xyz.openbmc_project.Logging",
2170 "/xyz/openbmc_project/logging/entry/" + entryID,
2171 "xyz.openbmc_project.Object.Delete", "Delete");
Patrick Williams5a39f772023-10-20 11:20:21 -05002172 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002173}
2174
Spencer Kub7028eb2021-10-26 15:27:35 +08002175constexpr const char* hostLoggerFolderPath = "/var/log/console";
2176
2177inline bool
2178 getHostLoggerFiles(const std::string& hostLoggerFilePath,
2179 std::vector<std::filesystem::path>& hostLoggerFiles)
2180{
2181 std::error_code ec;
2182 std::filesystem::directory_iterator logPath(hostLoggerFilePath, ec);
2183 if (ec)
2184 {
Carson Labradobf2dded2023-08-10 00:37:06 +00002185 BMCWEB_LOG_WARNING("{}", ec.message());
Spencer Kub7028eb2021-10-26 15:27:35 +08002186 return false;
2187 }
2188 for (const std::filesystem::directory_entry& it : logPath)
2189 {
2190 std::string filename = it.path().filename();
2191 // Prefix of each log files is "log". Find the file and save the
2192 // path
Ed Tanous11ba3972022-07-11 09:50:41 -07002193 if (filename.starts_with("log"))
Spencer Kub7028eb2021-10-26 15:27:35 +08002194 {
2195 hostLoggerFiles.emplace_back(it.path());
2196 }
2197 }
2198 // As the log files rotate, they are appended with a ".#" that is higher for
2199 // the older logs. Since we start from oldest logs, sort the name in
2200 // descending order.
2201 std::sort(hostLoggerFiles.rbegin(), hostLoggerFiles.rend(),
2202 AlphanumLess<std::string>());
2203
2204 return true;
2205}
2206
Ed Tanous02cad962022-06-30 16:50:15 -07002207inline bool getHostLoggerEntries(
2208 const std::vector<std::filesystem::path>& hostLoggerFiles, uint64_t skip,
2209 uint64_t top, std::vector<std::string>& logEntries, size_t& logCount)
Spencer Kub7028eb2021-10-26 15:27:35 +08002210{
2211 GzFileReader logFile;
2212
2213 // Go though all log files and expose host logs.
2214 for (const std::filesystem::path& it : hostLoggerFiles)
2215 {
2216 if (!logFile.gzGetLines(it.string(), skip, top, logEntries, logCount))
2217 {
Ed Tanous62598e32023-07-17 17:06:25 -07002218 BMCWEB_LOG_ERROR("fail to expose host logs");
Spencer Kub7028eb2021-10-26 15:27:35 +08002219 return false;
2220 }
2221 }
2222 // Get lastMessage from constructor by getter
2223 std::string lastMessage = logFile.getLastMessage();
2224 if (!lastMessage.empty())
2225 {
2226 logCount++;
2227 if (logCount > skip && logCount <= (skip + top))
2228 {
2229 logEntries.push_back(lastMessage);
2230 }
2231 }
2232 return true;
2233}
2234
Ed Tanous6f056f22024-04-07 13:35:51 -07002235inline void fillHostLoggerEntryJson(std::string_view logEntryID,
2236 std::string_view msg,
Jason M. Bills6d6574c2022-06-28 12:30:16 -07002237 nlohmann::json::object_t& logEntryJson)
Spencer Kub7028eb2021-10-26 15:27:35 +08002238{
2239 // Fill in the log entry with the gathered data.
Vijay Lobo9c11a172021-10-07 16:53:16 -05002240 logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Ed Tanousef4c65b2023-04-24 15:28:50 -07002241 logEntryJson["@odata.id"] = boost::urls::format(
Ed Tanous253f11b2024-05-16 09:38:31 -07002242 "/redfish/v1/Systems/{}/LogServices/HostLogger/Entries/{}",
2243 BMCWEB_REDFISH_SYSTEM_URI_NAME, logEntryID);
Jason M. Bills6d6574c2022-06-28 12:30:16 -07002244 logEntryJson["Name"] = "Host Logger Entry";
2245 logEntryJson["Id"] = logEntryID;
2246 logEntryJson["Message"] = msg;
2247 logEntryJson["EntryType"] = "Oem";
2248 logEntryJson["Severity"] = "OK";
2249 logEntryJson["OemRecordFormat"] = "Host Logger Entry";
Spencer Kub7028eb2021-10-26 15:27:35 +08002250}
2251
2252inline void requestRoutesSystemHostLogger(App& app)
2253{
Ed Tanous22d268c2022-05-19 09:39:07 -07002254 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/")
Spencer Kub7028eb2021-10-26 15:27:35 +08002255 .privileges(redfish::privileges::getLogService)
Ed Tanous14766872022-03-15 10:44:42 -07002256 .methods(boost::beast::http::verb::get)(
2257 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07002258 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2259 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002260 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002261 {
2262 return;
2263 }
Ed Tanous25b54db2024-04-17 15:40:31 -07002264 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08002265 {
2266 // Option currently returns no systems. TBD
2267 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2268 systemName);
2269 return;
2270 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002271 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07002272 {
2273 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2274 systemName);
2275 return;
2276 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002277 asyncResp->res.jsonValue["@odata.id"] =
Ed Tanous253f11b2024-05-16 09:38:31 -07002278 std::format("/redfish/v1/Systems/{}/LogServices/HostLogger",
2279 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Ed Tanous002d39b2022-05-31 08:59:27 -07002280 asyncResp->res.jsonValue["@odata.type"] =
Janet Adkinsb25644a2023-08-16 11:23:45 -05002281 "#LogService.v1_2_0.LogService";
Ed Tanous002d39b2022-05-31 08:59:27 -07002282 asyncResp->res.jsonValue["Name"] = "Host Logger Service";
2283 asyncResp->res.jsonValue["Description"] = "Host Logger Service";
2284 asyncResp->res.jsonValue["Id"] = "HostLogger";
2285 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
Ed Tanous253f11b2024-05-16 09:38:31 -07002286 std::format("/redfish/v1/Systems/{}/LogServices/HostLogger/Entries",
2287 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Patrick Williams5a39f772023-10-20 11:20:21 -05002288 });
Spencer Kub7028eb2021-10-26 15:27:35 +08002289}
2290
2291inline void requestRoutesSystemHostLoggerCollection(App& app)
2292{
2293 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07002294 "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/")
Spencer Kub7028eb2021-10-26 15:27:35 +08002295 .privileges(redfish::privileges::getLogEntry)
Ed Tanous002d39b2022-05-31 08:59:27 -07002296 .methods(boost::beast::http::verb::get)(
2297 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07002298 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2299 const std::string& systemName) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002300 query_param::QueryCapabilities capabilities = {
2301 .canDelegateTop = true,
2302 .canDelegateSkip = true,
2303 };
2304 query_param::Query delegatedQuery;
2305 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00002306 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07002307 {
2308 return;
2309 }
Ed Tanous25b54db2024-04-17 15:40:31 -07002310 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08002311 {
2312 // Option currently returns no systems. TBD
2313 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2314 systemName);
2315 return;
2316 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002317 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07002318 {
2319 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2320 systemName);
2321 return;
2322 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002323 asyncResp->res.jsonValue["@odata.id"] =
Ed Tanous253f11b2024-05-16 09:38:31 -07002324 std::format("/redfish/v1/Systems/{}/LogServices/HostLogger/Entries",
2325 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Ed Tanous002d39b2022-05-31 08:59:27 -07002326 asyncResp->res.jsonValue["@odata.type"] =
2327 "#LogEntryCollection.LogEntryCollection";
2328 asyncResp->res.jsonValue["Name"] = "HostLogger Entries";
2329 asyncResp->res.jsonValue["Description"] =
2330 "Collection of HostLogger Entries";
2331 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
2332 logEntryArray = nlohmann::json::array();
2333 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Spencer Kub7028eb2021-10-26 15:27:35 +08002334
Ed Tanous002d39b2022-05-31 08:59:27 -07002335 std::vector<std::filesystem::path> hostLoggerFiles;
2336 if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles))
2337 {
Carson Labradobf2dded2023-08-10 00:37:06 +00002338 BMCWEB_LOG_DEBUG("Failed to get host log file path");
Ed Tanous002d39b2022-05-31 08:59:27 -07002339 return;
2340 }
Ed Tanous3648c8b2022-07-25 13:39:59 -07002341 // If we weren't provided top and skip limits, use the defaults.
2342 size_t skip = delegatedQuery.skip.value_or(0);
Jiaqing Zhao5143f7a2022-07-22 09:33:33 +08002343 size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
Ed Tanous002d39b2022-05-31 08:59:27 -07002344 size_t logCount = 0;
2345 // This vector only store the entries we want to expose that
2346 // control by skip and top.
2347 std::vector<std::string> logEntries;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002348 if (!getHostLoggerEntries(hostLoggerFiles, skip, top, logEntries,
2349 logCount))
Ed Tanous002d39b2022-05-31 08:59:27 -07002350 {
2351 messages::internalError(asyncResp->res);
2352 return;
2353 }
2354 // If vector is empty, that means skip value larger than total
2355 // log count
2356 if (logEntries.empty())
2357 {
2358 asyncResp->res.jsonValue["Members@odata.count"] = logCount;
2359 return;
2360 }
2361 if (!logEntries.empty())
2362 {
2363 for (size_t i = 0; i < logEntries.size(); i++)
George Liu0fda0f12021-11-16 10:06:17 +08002364 {
Jason M. Bills6d6574c2022-06-28 12:30:16 -07002365 nlohmann::json::object_t hostLogEntry;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002366 fillHostLoggerEntryJson(std::to_string(skip + i), logEntries[i],
2367 hostLogEntry);
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002368 logEntryArray.emplace_back(std::move(hostLogEntry));
George Liu0fda0f12021-11-16 10:06:17 +08002369 }
2370
Ed Tanous002d39b2022-05-31 08:59:27 -07002371 asyncResp->res.jsonValue["Members@odata.count"] = logCount;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002372 if (skip + top < logCount)
George Liu0fda0f12021-11-16 10:06:17 +08002373 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002374 asyncResp->res.jsonValue["Members@odata.nextLink"] =
Ed Tanous253f11b2024-05-16 09:38:31 -07002375 std::format(
2376 "/redfish/v1/Systems/{}/LogServices/HostLogger/Entries?$skip=",
2377 BMCWEB_REDFISH_SYSTEM_URI_NAME) +
Ed Tanous3648c8b2022-07-25 13:39:59 -07002378 std::to_string(skip + top);
George Liu0fda0f12021-11-16 10:06:17 +08002379 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002380 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002381 });
Spencer Kub7028eb2021-10-26 15:27:35 +08002382}
2383
2384inline void requestRoutesSystemHostLoggerLogEntry(App& app)
2385{
2386 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07002387 app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/<str>/")
Spencer Kub7028eb2021-10-26 15:27:35 +08002388 .privileges(redfish::privileges::getLogEntry)
2389 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002390 [&app](const crow::Request& req,
2391 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07002392 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002393 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002394 {
2395 return;
2396 }
Ed Tanous25b54db2024-04-17 15:40:31 -07002397 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08002398 {
2399 // Option currently returns no systems. TBD
2400 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2401 systemName);
2402 return;
2403 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002404 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07002405 {
2406 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2407 systemName);
2408 return;
2409 }
Ed Tanous6f056f22024-04-07 13:35:51 -07002410 std::string_view targetID = param;
Spencer Kub7028eb2021-10-26 15:27:35 +08002411
Ed Tanous002d39b2022-05-31 08:59:27 -07002412 uint64_t idInt = 0;
Ed Tanousca45aa32022-01-07 09:28:45 -08002413
Ed Tanous6f056f22024-04-07 13:35:51 -07002414 auto [ptr, ec] = std::from_chars(targetID.begin(), targetID.end(),
Patrick Williams84396af2023-05-11 11:47:45 -05002415 idInt);
Ed Tanous6f056f22024-04-07 13:35:51 -07002416 if (ec != std::errc{} || ptr != targetID.end())
Ed Tanous002d39b2022-05-31 08:59:27 -07002417 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08002418 messages::resourceNotFound(asyncResp->res, "LogEntry", param);
Ed Tanous002d39b2022-05-31 08:59:27 -07002419 return;
2420 }
Spencer Kub7028eb2021-10-26 15:27:35 +08002421
Ed Tanous002d39b2022-05-31 08:59:27 -07002422 std::vector<std::filesystem::path> hostLoggerFiles;
2423 if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles))
2424 {
Carson Labradobf2dded2023-08-10 00:37:06 +00002425 BMCWEB_LOG_DEBUG("Failed to get host log file path");
Ed Tanous002d39b2022-05-31 08:59:27 -07002426 return;
2427 }
Spencer Kub7028eb2021-10-26 15:27:35 +08002428
Ed Tanous002d39b2022-05-31 08:59:27 -07002429 size_t logCount = 0;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002430 size_t top = 1;
Ed Tanous002d39b2022-05-31 08:59:27 -07002431 std::vector<std::string> logEntries;
2432 // We can get specific entry by skip and top. For example, if we
2433 // want to get nth entry, we can set skip = n-1 and top = 1 to
2434 // get that entry
2435 if (!getHostLoggerEntries(hostLoggerFiles, idInt, top, logEntries,
2436 logCount))
2437 {
2438 messages::internalError(asyncResp->res);
2439 return;
2440 }
Spencer Kub7028eb2021-10-26 15:27:35 +08002441
Ed Tanous002d39b2022-05-31 08:59:27 -07002442 if (!logEntries.empty())
2443 {
Jason M. Bills6d6574c2022-06-28 12:30:16 -07002444 nlohmann::json::object_t hostLogEntry;
2445 fillHostLoggerEntryJson(targetID, logEntries[0], hostLogEntry);
2446 asyncResp->res.jsonValue.update(hostLogEntry);
Ed Tanous002d39b2022-05-31 08:59:27 -07002447 return;
2448 }
Spencer Kub7028eb2021-10-26 15:27:35 +08002449
Ed Tanous002d39b2022-05-31 08:59:27 -07002450 // Requested ID was not found
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08002451 messages::resourceNotFound(asyncResp->res, "LogEntry", param);
Patrick Williams5a39f772023-10-20 11:20:21 -05002452 });
Spencer Kub7028eb2021-10-26 15:27:35 +08002453}
2454
Claire Weinandd72e872022-08-15 14:20:06 -07002455inline void handleBMCLogServicesCollectionGet(
Claire Weinanfdd26902022-03-01 14:18:25 -08002456 crow::App& app, const crow::Request& req,
Ed Tanous253f11b2024-05-16 09:38:31 -07002457 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2458 const std::string& managerId)
Claire Weinanfdd26902022-03-01 14:18:25 -08002459{
2460 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2461 {
2462 return;
2463 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002464
2465 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
2466 {
2467 messages::resourceNotFound(asyncResp->res, "Manager", managerId);
2468 return;
2469 }
2470
Claire Weinanfdd26902022-03-01 14:18:25 -08002471 // Collections don't include the static data added by SubRoute
2472 // because it has a duplicate entry for members
2473 asyncResp->res.jsonValue["@odata.type"] =
2474 "#LogServiceCollection.LogServiceCollection";
Ed Tanous253f11b2024-05-16 09:38:31 -07002475 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
2476 "/redfish/v1/Managers/{}/LogServices", BMCWEB_REDFISH_MANAGER_URI_NAME);
Claire Weinanfdd26902022-03-01 14:18:25 -08002477 asyncResp->res.jsonValue["Name"] = "Open BMC Log Services Collection";
2478 asyncResp->res.jsonValue["Description"] =
2479 "Collection of LogServices for this Manager";
2480 nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"];
2481 logServiceArray = nlohmann::json::array();
2482
Ed Tanous25b54db2024-04-17 15:40:31 -07002483 if constexpr (BMCWEB_REDFISH_BMC_JOURNAL)
2484 {
2485 nlohmann::json::object_t journal;
Ed Tanous253f11b2024-05-16 09:38:31 -07002486 journal["@odata.id"] =
2487 boost::urls::format("/redfish/v1/Managers/{}/LogServices/Journal",
2488 BMCWEB_REDFISH_MANAGER_URI_NAME);
Ed Tanous25b54db2024-04-17 15:40:31 -07002489 logServiceArray.emplace_back(std::move(journal));
2490 }
Claire Weinanfdd26902022-03-01 14:18:25 -08002491
2492 asyncResp->res.jsonValue["Members@odata.count"] = logServiceArray.size();
2493
Ed Tanous25b54db2024-04-17 15:40:31 -07002494 if constexpr (BMCWEB_REDFISH_DUMP_LOG)
2495 {
2496 constexpr std::array<std::string_view, 1> interfaces = {
2497 "xyz.openbmc_project.Collection.DeleteAll"};
2498 dbus::utility::getSubTreePaths(
2499 "/xyz/openbmc_project/dump", 0, interfaces,
2500 [asyncResp](const boost::system::error_code& ec,
2501 const dbus::utility::MapperGetSubTreePathsResponse&
2502 subTreePaths) {
2503 if (ec)
Claire Weinanfdd26902022-03-01 14:18:25 -08002504 {
Ed Tanous25b54db2024-04-17 15:40:31 -07002505 BMCWEB_LOG_ERROR(
2506 "handleBMCLogServicesCollectionGet respHandler got error {}",
2507 ec);
2508 // Assume that getting an error simply means there are no dump
2509 // LogServices. Return without adding any error response.
2510 return;
Claire Weinanfdd26902022-03-01 14:18:25 -08002511 }
Claire Weinanfdd26902022-03-01 14:18:25 -08002512
Ed Tanous25b54db2024-04-17 15:40:31 -07002513 nlohmann::json& logServiceArrayLocal =
2514 asyncResp->res.jsonValue["Members"];
2515
2516 for (const std::string& path : subTreePaths)
2517 {
2518 if (path == "/xyz/openbmc_project/dump/bmc")
2519 {
2520 nlohmann::json::object_t member;
Ed Tanous253f11b2024-05-16 09:38:31 -07002521 member["@odata.id"] = boost::urls::format(
2522 "/redfish/v1/Managers/{}/LogServices/Dump",
2523 BMCWEB_REDFISH_MANAGER_URI_NAME);
Ed Tanous25b54db2024-04-17 15:40:31 -07002524 logServiceArrayLocal.emplace_back(std::move(member));
2525 }
2526 else if (path == "/xyz/openbmc_project/dump/faultlog")
2527 {
2528 nlohmann::json::object_t member;
Ed Tanous253f11b2024-05-16 09:38:31 -07002529 member["@odata.id"] = boost::urls::format(
2530 "/redfish/v1/Managers/{}/LogServices/FaultLog",
2531 BMCWEB_REDFISH_MANAGER_URI_NAME);
Ed Tanous25b54db2024-04-17 15:40:31 -07002532 logServiceArrayLocal.emplace_back(std::move(member));
2533 }
2534 }
2535
2536 asyncResp->res.jsonValue["Members@odata.count"] =
2537 logServiceArrayLocal.size();
2538 });
2539 }
Claire Weinanfdd26902022-03-01 14:18:25 -08002540}
2541
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002542inline void requestRoutesBMCLogServiceCollection(App& app)
2543{
Ed Tanous253f11b2024-05-16 09:38:31 -07002544 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/LogServices/")
Gunnar Millsad89dcf2021-07-30 14:40:11 -05002545 .privileges(redfish::privileges::getLogServiceCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002546 .methods(boost::beast::http::verb::get)(
Claire Weinandd72e872022-08-15 14:20:06 -07002547 std::bind_front(handleBMCLogServicesCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002548}
Ed Tanous1da66f72018-07-27 16:13:37 -07002549
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002550inline void requestRoutesBMCJournalLogService(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07002551{
Ed Tanous253f11b2024-05-16 09:38:31 -07002552 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/LogServices/Journal/")
Ed Tanoused398212021-06-09 17:05:54 -07002553 .privileges(redfish::privileges::getLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002554 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002555 [&app](const crow::Request& req,
Ed Tanous253f11b2024-05-16 09:38:31 -07002556 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2557 const std::string& managerId) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002558 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002559 {
2560 return;
2561 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002562
2563 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
2564 {
2565 messages::resourceNotFound(asyncResp->res, "Manager", managerId);
2566 return;
2567 }
2568
Ed Tanous002d39b2022-05-31 08:59:27 -07002569 asyncResp->res.jsonValue["@odata.type"] =
Janet Adkinsb25644a2023-08-16 11:23:45 -05002570 "#LogService.v1_2_0.LogService";
Ed Tanous002d39b2022-05-31 08:59:27 -07002571 asyncResp->res.jsonValue["@odata.id"] =
Ed Tanous253f11b2024-05-16 09:38:31 -07002572 boost::urls::format("/redfish/v1/Managers/{}/LogServices/Journal",
2573 BMCWEB_REDFISH_MANAGER_URI_NAME);
Ed Tanous002d39b2022-05-31 08:59:27 -07002574 asyncResp->res.jsonValue["Name"] = "Open BMC Journal Log Service";
2575 asyncResp->res.jsonValue["Description"] = "BMC Journal Log Service";
Ed Tanoused34a4a2023-02-08 15:43:27 -08002576 asyncResp->res.jsonValue["Id"] = "Journal";
Ed Tanous002d39b2022-05-31 08:59:27 -07002577 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
Tejas Patil7c8c4052021-06-04 17:43:14 +05302578
Ed Tanous002d39b2022-05-31 08:59:27 -07002579 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07002580 redfish::time_utils::getDateTimeOffsetNow();
Ed Tanous002d39b2022-05-31 08:59:27 -07002581 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2582 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2583 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05302584
Ed Tanous253f11b2024-05-16 09:38:31 -07002585 asyncResp->res.jsonValue["Entries"]["@odata.id"] = boost::urls::format(
2586 "/redfish/v1/Managers/{}/LogServices/Journal/Entries",
2587 BMCWEB_REDFISH_MANAGER_URI_NAME);
Patrick Williams5a39f772023-10-20 11:20:21 -05002588 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002589}
Jason M. Billse1f26342018-07-18 12:12:00 -07002590
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002591static int
2592 fillBMCJournalLogEntryJson(const std::string& bmcJournalLogEntryID,
2593 sd_journal* journal,
2594 nlohmann::json::object_t& bmcJournalLogEntryJson)
Jason M. Billse1f26342018-07-18 12:12:00 -07002595{
2596 // Get the Log Entry contents
2597 int ret = 0;
Jason M. Billse1f26342018-07-18 12:12:00 -07002598
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08002599 std::string message;
2600 std::string_view syslogID;
2601 ret = getJournalMetadata(journal, "SYSLOG_IDENTIFIER", syslogID);
2602 if (ret < 0)
2603 {
Carson Labradobf2dded2023-08-10 00:37:06 +00002604 BMCWEB_LOG_DEBUG("Failed to read SYSLOG_IDENTIFIER field: {}",
Ed Tanous62598e32023-07-17 17:06:25 -07002605 strerror(-ret));
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08002606 }
2607 if (!syslogID.empty())
2608 {
2609 message += std::string(syslogID) + ": ";
2610 }
2611
Ed Tanous39e77502019-03-04 17:35:53 -08002612 std::string_view msg;
Jason M. Bills16428a12018-11-02 12:42:29 -07002613 ret = getJournalMetadata(journal, "MESSAGE", msg);
Jason M. Billse1f26342018-07-18 12:12:00 -07002614 if (ret < 0)
2615 {
Ed Tanous62598e32023-07-17 17:06:25 -07002616 BMCWEB_LOG_ERROR("Failed to read MESSAGE field: {}", strerror(-ret));
Jason M. Billse1f26342018-07-18 12:12:00 -07002617 return 1;
2618 }
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08002619 message += std::string(msg);
Jason M. Billse1f26342018-07-18 12:12:00 -07002620
2621 // Get the severity from the PRIORITY field
Ed Tanous271584a2019-07-09 16:24:22 -07002622 long int severity = 8; // Default to an invalid priority
Jason M. Bills16428a12018-11-02 12:42:29 -07002623 ret = getJournalMetadata(journal, "PRIORITY", 10, severity);
Jason M. Billse1f26342018-07-18 12:12:00 -07002624 if (ret < 0)
2625 {
Carson Labradobf2dded2023-08-10 00:37:06 +00002626 BMCWEB_LOG_DEBUG("Failed to read PRIORITY field: {}", strerror(-ret));
Jason M. Billse1f26342018-07-18 12:12:00 -07002627 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002628
2629 // Get the Created time from the timestamp
Jason M. Bills16428a12018-11-02 12:42:29 -07002630 std::string entryTimeStr;
2631 if (!getEntryTimestamp(journal, entryTimeStr))
Jason M. Billse1f26342018-07-18 12:12:00 -07002632 {
Jason M. Bills16428a12018-11-02 12:42:29 -07002633 return 1;
Jason M. Billse1f26342018-07-18 12:12:00 -07002634 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002635
2636 // Fill in the log entry with the gathered data
Vijay Lobo9c11a172021-10-07 16:53:16 -05002637 bmcJournalLogEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Ed Tanousef4c65b2023-04-24 15:28:50 -07002638 bmcJournalLogEntryJson["@odata.id"] = boost::urls::format(
Ed Tanous253f11b2024-05-16 09:38:31 -07002639 "/redfish/v1/Managers/{}/LogServices/Journal/Entries/{}",
2640 BMCWEB_REDFISH_MANAGER_URI_NAME, bmcJournalLogEntryID);
Jason M. Bills84afc482022-06-24 12:38:23 -07002641 bmcJournalLogEntryJson["Name"] = "BMC Journal Entry";
2642 bmcJournalLogEntryJson["Id"] = bmcJournalLogEntryID;
2643 bmcJournalLogEntryJson["Message"] = std::move(message);
2644 bmcJournalLogEntryJson["EntryType"] = "Oem";
Ed Tanousddf35642024-03-27 14:12:21 -07002645 log_entry::EventSeverity severityEnum = log_entry::EventSeverity::OK;
2646 if (severity <= 2)
2647 {
2648 severityEnum = log_entry::EventSeverity::Critical;
2649 }
2650 else if (severity <= 4)
2651 {
2652 severityEnum = log_entry::EventSeverity::Warning;
2653 }
2654
2655 bmcJournalLogEntryJson["Severity"] = severityEnum;
Jason M. Bills84afc482022-06-24 12:38:23 -07002656 bmcJournalLogEntryJson["OemRecordFormat"] = "BMC Journal Entry";
2657 bmcJournalLogEntryJson["Created"] = std::move(entryTimeStr);
Jason M. Billse1f26342018-07-18 12:12:00 -07002658 return 0;
2659}
2660
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002661inline void requestRoutesBMCJournalLogEntryCollection(App& app)
Jason M. Billse1f26342018-07-18 12:12:00 -07002662{
Ed Tanous253f11b2024-05-16 09:38:31 -07002663 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/LogServices/Journal/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07002664 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07002665 .methods(boost::beast::http::verb::get)(
2666 [&app](const crow::Request& req,
Ed Tanous253f11b2024-05-16 09:38:31 -07002667 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2668 const std::string& managerId) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002669 query_param::QueryCapabilities capabilities = {
2670 .canDelegateTop = true,
2671 .canDelegateSkip = true,
2672 };
2673 query_param::Query delegatedQuery;
2674 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00002675 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07002676 {
2677 return;
2678 }
Ed Tanous3648c8b2022-07-25 13:39:59 -07002679
Ed Tanous253f11b2024-05-16 09:38:31 -07002680 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
2681 {
2682 messages::resourceNotFound(asyncResp->res, "Manager", managerId);
2683 return;
2684 }
2685
Ed Tanous3648c8b2022-07-25 13:39:59 -07002686 size_t skip = delegatedQuery.skip.value_or(0);
Jiaqing Zhao5143f7a2022-07-22 09:33:33 +08002687 size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
Ed Tanous3648c8b2022-07-25 13:39:59 -07002688
Ed Tanous002d39b2022-05-31 08:59:27 -07002689 // Collections don't include the static data added by SubRoute
2690 // because it has a duplicate entry for members
2691 asyncResp->res.jsonValue["@odata.type"] =
2692 "#LogEntryCollection.LogEntryCollection";
Ed Tanous253f11b2024-05-16 09:38:31 -07002693 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
2694 "/redfish/v1/Managers/{}/LogServices/Journal/Entries",
2695 BMCWEB_REDFISH_MANAGER_URI_NAME);
Ed Tanous002d39b2022-05-31 08:59:27 -07002696 asyncResp->res.jsonValue["Name"] = "Open BMC Journal Entries";
2697 asyncResp->res.jsonValue["Description"] =
2698 "Collection of BMC Journal Entries";
2699 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
2700 logEntryArray = nlohmann::json::array();
Jason M. Billse1f26342018-07-18 12:12:00 -07002701
Ed Tanous002d39b2022-05-31 08:59:27 -07002702 // Go through the journal and use the timestamp to create a
2703 // unique ID for each entry
2704 sd_journal* journalTmp = nullptr;
2705 int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY);
2706 if (ret < 0)
2707 {
Ed Tanous62598e32023-07-17 17:06:25 -07002708 BMCWEB_LOG_ERROR("failed to open journal: {}", strerror(-ret));
Ed Tanous002d39b2022-05-31 08:59:27 -07002709 messages::internalError(asyncResp->res);
2710 return;
2711 }
2712 std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal(
2713 journalTmp, sd_journal_close);
2714 journalTmp = nullptr;
2715 uint64_t entryCount = 0;
2716 // Reset the unique ID on the first entry
2717 bool firstEntry = true;
2718 SD_JOURNAL_FOREACH(journal.get())
2719 {
2720 entryCount++;
2721 // Handle paging using skip (number of entries to skip from
2722 // the start) and top (number of entries to display)
Ed Tanous3648c8b2022-07-25 13:39:59 -07002723 if (entryCount <= skip || entryCount > skip + top)
George Liu0fda0f12021-11-16 10:06:17 +08002724 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002725 continue;
2726 }
2727
2728 std::string idStr;
2729 if (!getUniqueEntryID(journal.get(), idStr, firstEntry))
2730 {
2731 continue;
2732 }
Jason M. Billsefde4ec2022-06-24 08:59:52 -07002733 firstEntry = false;
Ed Tanous002d39b2022-05-31 08:59:27 -07002734
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002735 nlohmann::json::object_t bmcJournalLogEntry;
Ed Tanous002d39b2022-05-31 08:59:27 -07002736 if (fillBMCJournalLogEntryJson(idStr, journal.get(),
2737 bmcJournalLogEntry) != 0)
2738 {
George Liu0fda0f12021-11-16 10:06:17 +08002739 messages::internalError(asyncResp->res);
2740 return;
2741 }
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002742 logEntryArray.emplace_back(std::move(bmcJournalLogEntry));
Ed Tanous002d39b2022-05-31 08:59:27 -07002743 }
2744 asyncResp->res.jsonValue["Members@odata.count"] = entryCount;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002745 if (skip + top < entryCount)
Ed Tanous002d39b2022-05-31 08:59:27 -07002746 {
Ed Tanous253f11b2024-05-16 09:38:31 -07002747 asyncResp->res
2748 .jsonValue["Members@odata.nextLink"] = boost::urls::format(
2749 "/redfish/v1/Managers/{}/LogServices/Journal/Entries?$skip={}",
2750 BMCWEB_REDFISH_MANAGER_URI_NAME, std::to_string(skip + top));
Ed Tanous002d39b2022-05-31 08:59:27 -07002751 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002752 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002753}
Jason M. Billse1f26342018-07-18 12:12:00 -07002754
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002755inline void requestRoutesBMCJournalLogEntry(App& app)
Jason M. Billse1f26342018-07-18 12:12:00 -07002756{
Ed Tanous253f11b2024-05-16 09:38:31 -07002757 BMCWEB_ROUTE(
2758 app, "/redfish/v1/Managers/<str>/LogServices/Journal/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002759 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002760 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002761 [&app](const crow::Request& req,
2762 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous253f11b2024-05-16 09:38:31 -07002763 const std::string& managerId, const std::string& entryID) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002764 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002765 {
2766 return;
2767 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002768
2769 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
2770 {
2771 messages::resourceNotFound(asyncResp->res, "Manager", managerId);
2772 return;
2773 }
2774
Ed Tanous002d39b2022-05-31 08:59:27 -07002775 // Convert the unique ID back to a timestamp to find the entry
Myung Bae75e8e212023-11-30 12:53:46 -08002776 sd_id128_t bootID{};
Ed Tanous002d39b2022-05-31 08:59:27 -07002777 uint64_t ts = 0;
2778 uint64_t index = 0;
Myung Bae75e8e212023-11-30 12:53:46 -08002779 if (!getTimestampFromID(asyncResp, entryID, bootID, ts, index))
Ed Tanous002d39b2022-05-31 08:59:27 -07002780 {
2781 return;
2782 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002783
Ed Tanous002d39b2022-05-31 08:59:27 -07002784 sd_journal* journalTmp = nullptr;
2785 int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY);
2786 if (ret < 0)
2787 {
Ed Tanous62598e32023-07-17 17:06:25 -07002788 BMCWEB_LOG_ERROR("failed to open journal: {}", strerror(-ret));
Ed Tanous002d39b2022-05-31 08:59:27 -07002789 messages::internalError(asyncResp->res);
2790 return;
2791 }
2792 std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal(
2793 journalTmp, sd_journal_close);
2794 journalTmp = nullptr;
2795 // Go to the timestamp in the log and move to the entry at the
2796 // index tracking the unique ID
2797 std::string idStr;
2798 bool firstEntry = true;
Myung Bae75e8e212023-11-30 12:53:46 -08002799 ret = sd_journal_seek_monotonic_usec(journal.get(), bootID, ts);
Ed Tanous002d39b2022-05-31 08:59:27 -07002800 if (ret < 0)
2801 {
Ed Tanous62598e32023-07-17 17:06:25 -07002802 BMCWEB_LOG_ERROR("failed to seek to an entry in journal{}",
2803 strerror(-ret));
Ed Tanous002d39b2022-05-31 08:59:27 -07002804 messages::internalError(asyncResp->res);
2805 return;
2806 }
2807 for (uint64_t i = 0; i <= index; i++)
2808 {
2809 sd_journal_next(journal.get());
2810 if (!getUniqueEntryID(journal.get(), idStr, firstEntry))
2811 {
2812 messages::internalError(asyncResp->res);
2813 return;
2814 }
Jason M. Billsefde4ec2022-06-24 08:59:52 -07002815 firstEntry = false;
Ed Tanous002d39b2022-05-31 08:59:27 -07002816 }
2817 // Confirm that the entry ID matches what was requested
2818 if (idStr != entryID)
2819 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08002820 messages::resourceNotFound(asyncResp->res, "LogEntry", entryID);
Ed Tanous002d39b2022-05-31 08:59:27 -07002821 return;
2822 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002823
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002824 nlohmann::json::object_t bmcJournalLogEntry;
Ed Tanous002d39b2022-05-31 08:59:27 -07002825 if (fillBMCJournalLogEntryJson(entryID, journal.get(),
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002826 bmcJournalLogEntry) != 0)
Ed Tanous002d39b2022-05-31 08:59:27 -07002827 {
2828 messages::internalError(asyncResp->res);
2829 return;
2830 }
Jason M. Billsd405bb52022-06-24 10:52:05 -07002831 asyncResp->res.jsonValue.update(bmcJournalLogEntry);
Patrick Williams5a39f772023-10-20 11:20:21 -05002832 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002833}
2834
Claire Weinanfdd26902022-03-01 14:18:25 -08002835inline void
2836 getDumpServiceInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2837 const std::string& dumpType)
2838{
2839 std::string dumpPath;
2840 std::string overWritePolicy;
2841 bool collectDiagnosticDataSupported = false;
2842
2843 if (dumpType == "BMC")
2844 {
Ed Tanous253f11b2024-05-16 09:38:31 -07002845 dumpPath = std::format("/redfish/v1/Managers/{}/LogServices/Dump",
2846 BMCWEB_REDFISH_MANAGER_URI_NAME);
Claire Weinanfdd26902022-03-01 14:18:25 -08002847 overWritePolicy = "WrapsWhenFull";
2848 collectDiagnosticDataSupported = true;
2849 }
2850 else if (dumpType == "FaultLog")
2851 {
Ed Tanous253f11b2024-05-16 09:38:31 -07002852 dumpPath = std::format("/redfish/v1/Managers/{}/LogServices/FaultLog",
2853 BMCWEB_REDFISH_MANAGER_URI_NAME);
Claire Weinanfdd26902022-03-01 14:18:25 -08002854 overWritePolicy = "Unknown";
2855 collectDiagnosticDataSupported = false;
2856 }
2857 else if (dumpType == "System")
2858 {
Ed Tanous253f11b2024-05-16 09:38:31 -07002859 dumpPath = std::format("/redfish/v1/Systems/{}/LogServices/Dump",
2860 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Claire Weinanfdd26902022-03-01 14:18:25 -08002861 overWritePolicy = "WrapsWhenFull";
2862 collectDiagnosticDataSupported = true;
2863 }
2864 else
2865 {
Ed Tanous62598e32023-07-17 17:06:25 -07002866 BMCWEB_LOG_ERROR("getDumpServiceInfo() invalid dump type: {}",
2867 dumpType);
Claire Weinanfdd26902022-03-01 14:18:25 -08002868 messages::internalError(asyncResp->res);
2869 return;
2870 }
2871
2872 asyncResp->res.jsonValue["@odata.id"] = dumpPath;
2873 asyncResp->res.jsonValue["@odata.type"] = "#LogService.v1_2_0.LogService";
2874 asyncResp->res.jsonValue["Name"] = "Dump LogService";
2875 asyncResp->res.jsonValue["Description"] = dumpType + " Dump LogService";
2876 asyncResp->res.jsonValue["Id"] = std::filesystem::path(dumpPath).filename();
2877 asyncResp->res.jsonValue["OverWritePolicy"] = std::move(overWritePolicy);
2878
2879 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07002880 redfish::time_utils::getDateTimeOffsetNow();
Claire Weinanfdd26902022-03-01 14:18:25 -08002881 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2882 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2883 redfishDateTimeOffset.second;
2884
2885 asyncResp->res.jsonValue["Entries"]["@odata.id"] = dumpPath + "/Entries";
Claire Weinanfdd26902022-03-01 14:18:25 -08002886
2887 if (collectDiagnosticDataSupported)
2888 {
2889 asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"]
2890 ["target"] =
2891 dumpPath + "/Actions/LogService.CollectDiagnosticData";
2892 }
Claire Weinan0d946212022-07-13 19:40:19 -07002893
2894 constexpr std::array<std::string_view, 1> interfaces = {deleteAllInterface};
2895 dbus::utility::getSubTreePaths(
2896 "/xyz/openbmc_project/dump", 0, interfaces,
2897 [asyncResp, dumpType, dumpPath](
2898 const boost::system::error_code& ec,
2899 const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) {
2900 if (ec)
2901 {
Ed Tanous62598e32023-07-17 17:06:25 -07002902 BMCWEB_LOG_ERROR("getDumpServiceInfo respHandler got error {}", ec);
Claire Weinan0d946212022-07-13 19:40:19 -07002903 // Assume that getting an error simply means there are no dump
2904 // LogServices. Return without adding any error response.
2905 return;
2906 }
Ed Tanous18f8f602023-07-18 10:07:23 -07002907 std::string dbusDumpPath = getDumpPath(dumpType);
Claire Weinan0d946212022-07-13 19:40:19 -07002908 for (const std::string& path : subTreePaths)
2909 {
2910 if (path == dbusDumpPath)
2911 {
2912 asyncResp->res
2913 .jsonValue["Actions"]["#LogService.ClearLog"]["target"] =
2914 dumpPath + "/Actions/LogService.ClearLog";
2915 break;
2916 }
2917 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002918 });
Claire Weinanfdd26902022-03-01 14:18:25 -08002919}
2920
2921inline void handleLogServicesDumpServiceGet(
2922 crow::App& app, const std::string& dumpType, const crow::Request& req,
Ed Tanous253f11b2024-05-16 09:38:31 -07002923 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2924 const std::string& managerId)
Claire Weinanfdd26902022-03-01 14:18:25 -08002925{
2926 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2927 {
2928 return;
2929 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002930
2931 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
2932 {
2933 messages::resourceNotFound(asyncResp->res, "Manager", managerId);
2934 return;
2935 }
2936
Claire Weinanfdd26902022-03-01 14:18:25 -08002937 getDumpServiceInfo(asyncResp, dumpType);
2938}
2939
Ed Tanous22d268c2022-05-19 09:39:07 -07002940inline void handleLogServicesDumpServiceComputerSystemGet(
2941 crow::App& app, const crow::Request& req,
2942 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2943 const std::string& chassisId)
2944{
2945 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2946 {
2947 return;
2948 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002949 if (chassisId != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07002950 {
2951 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2952 return;
2953 }
2954 getDumpServiceInfo(asyncResp, "System");
2955}
2956
Claire Weinanfdd26902022-03-01 14:18:25 -08002957inline void handleLogServicesDumpEntriesCollectionGet(
2958 crow::App& app, const std::string& dumpType, const crow::Request& req,
Ed Tanous253f11b2024-05-16 09:38:31 -07002959 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2960 const std::string& managerId)
Claire Weinanfdd26902022-03-01 14:18:25 -08002961{
2962 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2963 {
2964 return;
2965 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002966
2967 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
2968 {
2969 messages::resourceNotFound(asyncResp->res, "Manager", managerId);
2970 return;
2971 }
Claire Weinanfdd26902022-03-01 14:18:25 -08002972 getDumpEntryCollection(asyncResp, dumpType);
2973}
2974
Ed Tanous22d268c2022-05-19 09:39:07 -07002975inline void handleLogServicesDumpEntriesCollectionComputerSystemGet(
2976 crow::App& app, const crow::Request& req,
2977 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2978 const std::string& chassisId)
2979{
2980 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2981 {
2982 return;
2983 }
Ed Tanous253f11b2024-05-16 09:38:31 -07002984 if (chassisId != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07002985 {
2986 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2987 return;
2988 }
2989 getDumpEntryCollection(asyncResp, "System");
2990}
2991
Claire Weinanfdd26902022-03-01 14:18:25 -08002992inline void handleLogServicesDumpEntryGet(
2993 crow::App& app, const std::string& dumpType, const crow::Request& req,
2994 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous253f11b2024-05-16 09:38:31 -07002995 const std::string& managerId, const std::string& dumpId)
Claire Weinanfdd26902022-03-01 14:18:25 -08002996{
2997 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2998 {
2999 return;
3000 }
Ed Tanous253f11b2024-05-16 09:38:31 -07003001 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
3002 {
3003 messages::resourceNotFound(asyncResp->res, "Manager", managerId);
3004 return;
3005 }
Claire Weinanfdd26902022-03-01 14:18:25 -08003006 getDumpEntryById(asyncResp, dumpId, dumpType);
3007}
Carson Labrado168d1b12023-03-27 17:04:46 +00003008
Ed Tanous22d268c2022-05-19 09:39:07 -07003009inline void handleLogServicesDumpEntryComputerSystemGet(
3010 crow::App& app, const crow::Request& req,
3011 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3012 const std::string& chassisId, const std::string& dumpId)
3013{
3014 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
3015 {
3016 return;
3017 }
Ed Tanous253f11b2024-05-16 09:38:31 -07003018 if (chassisId != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07003019 {
3020 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
3021 return;
3022 }
3023 getDumpEntryById(asyncResp, dumpId, "System");
3024}
Claire Weinanfdd26902022-03-01 14:18:25 -08003025
3026inline void handleLogServicesDumpEntryDelete(
3027 crow::App& app, const std::string& dumpType, const crow::Request& req,
3028 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous253f11b2024-05-16 09:38:31 -07003029 const std::string& managerId, const std::string& dumpId)
Claire Weinanfdd26902022-03-01 14:18:25 -08003030{
3031 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
3032 {
3033 return;
3034 }
Ed Tanous253f11b2024-05-16 09:38:31 -07003035
3036 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
3037 {
3038 messages::resourceNotFound(asyncResp->res, "Manager", managerId);
3039 return;
3040 }
Claire Weinanfdd26902022-03-01 14:18:25 -08003041 deleteDumpEntry(asyncResp, dumpId, dumpType);
3042}
3043
Ed Tanous22d268c2022-05-19 09:39:07 -07003044inline void handleLogServicesDumpEntryComputerSystemDelete(
3045 crow::App& app, const crow::Request& req,
3046 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3047 const std::string& chassisId, const std::string& dumpId)
3048{
3049 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
3050 {
3051 return;
3052 }
Ed Tanous253f11b2024-05-16 09:38:31 -07003053 if (chassisId != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07003054 {
3055 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
3056 return;
3057 }
3058 deleteDumpEntry(asyncResp, dumpId, "System");
3059}
3060
Carson Labrado168d1b12023-03-27 17:04:46 +00003061inline void handleLogServicesDumpEntryDownloadGet(
3062 crow::App& app, const std::string& dumpType, const crow::Request& req,
3063 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous253f11b2024-05-16 09:38:31 -07003064 const std::string& managerId, const std::string& dumpId)
Carson Labrado168d1b12023-03-27 17:04:46 +00003065{
3066 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
3067 {
3068 return;
3069 }
Ed Tanous253f11b2024-05-16 09:38:31 -07003070
3071 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
3072 {
3073 messages::resourceNotFound(asyncResp->res, "Manager", managerId);
3074 return;
3075 }
Carson Labrado168d1b12023-03-27 17:04:46 +00003076 downloadDumpEntry(asyncResp, dumpId, dumpType);
3077}
3078
3079inline void handleDBusEventLogEntryDownloadGet(
3080 crow::App& app, const std::string& dumpType, const crow::Request& req,
3081 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3082 const std::string& systemName, const std::string& entryID)
3083{
3084 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
3085 {
3086 return;
3087 }
3088 if (!http_helpers::isContentTypeAllowed(
3089 req.getHeaderValue("Accept"),
3090 http_helpers::ContentType::OctetStream, true))
3091 {
3092 asyncResp->res.result(boost::beast::http::status::bad_request);
3093 return;
3094 }
3095 downloadEventLogEntry(asyncResp, systemName, entryID, dumpType);
3096}
3097
Claire Weinanfdd26902022-03-01 14:18:25 -08003098inline void handleLogServicesDumpCollectDiagnosticDataPost(
3099 crow::App& app, const std::string& dumpType, const crow::Request& req,
Ed Tanous253f11b2024-05-16 09:38:31 -07003100 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3101 const std::string& managerId)
Claire Weinanfdd26902022-03-01 14:18:25 -08003102{
3103 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
3104 {
3105 return;
3106 }
Ed Tanous253f11b2024-05-16 09:38:31 -07003107 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
3108 {
3109 messages::resourceNotFound(asyncResp->res, "Manager", managerId);
3110 return;
3111 }
3112
Claire Weinanfdd26902022-03-01 14:18:25 -08003113 createDump(asyncResp, req, dumpType);
3114}
3115
Ed Tanous22d268c2022-05-19 09:39:07 -07003116inline void handleLogServicesDumpCollectDiagnosticDataComputerSystemPost(
3117 crow::App& app, const crow::Request& req,
3118 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003119 const std::string& systemName)
Ed Tanous22d268c2022-05-19 09:39:07 -07003120{
3121 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
3122 {
3123 return;
3124 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003125
Ed Tanous25b54db2024-04-17 15:40:31 -07003126 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous22d268c2022-05-19 09:39:07 -07003127 {
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003128 // Option currently returns no systems. TBD
3129 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3130 systemName);
3131 return;
3132 }
Ed Tanous253f11b2024-05-16 09:38:31 -07003133 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003134 {
3135 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3136 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003137 return;
3138 }
3139 createDump(asyncResp, req, "System");
3140}
3141
Claire Weinanfdd26902022-03-01 14:18:25 -08003142inline void handleLogServicesDumpClearLogPost(
3143 crow::App& app, const std::string& dumpType, const crow::Request& req,
Ed Tanous253f11b2024-05-16 09:38:31 -07003144 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3145 const std::string& managerId)
Claire Weinanfdd26902022-03-01 14:18:25 -08003146{
3147 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
3148 {
3149 return;
3150 }
Ed Tanous253f11b2024-05-16 09:38:31 -07003151
3152 if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
3153 {
3154 messages::resourceNotFound(asyncResp->res, "Manager", managerId);
3155 return;
3156 }
Claire Weinanfdd26902022-03-01 14:18:25 -08003157 clearDump(asyncResp, dumpType);
3158}
3159
Ed Tanous22d268c2022-05-19 09:39:07 -07003160inline void handleLogServicesDumpClearLogComputerSystemPost(
3161 crow::App& app, const crow::Request& req,
3162 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003163 const std::string& systemName)
Ed Tanous22d268c2022-05-19 09:39:07 -07003164{
3165 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
3166 {
3167 return;
3168 }
Ed Tanous25b54db2024-04-17 15:40:31 -07003169 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous22d268c2022-05-19 09:39:07 -07003170 {
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003171 // Option currently returns no systems. TBD
3172 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3173 systemName);
3174 return;
3175 }
Ed Tanous253f11b2024-05-16 09:38:31 -07003176 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003177 {
3178 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3179 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003180 return;
3181 }
3182 clearDump(asyncResp, "System");
3183}
3184
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003185inline void requestRoutesBMCDumpService(App& app)
3186{
Ed Tanous253f11b2024-05-16 09:38:31 -07003187 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/LogServices/Dump/")
Ed Tanoused398212021-06-09 17:05:54 -07003188 .privileges(redfish::privileges::getLogService)
Claire Weinanfdd26902022-03-01 14:18:25 -08003189 .methods(boost::beast::http::verb::get)(std::bind_front(
3190 handleLogServicesDumpServiceGet, std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003191}
3192
3193inline void requestRoutesBMCDumpEntryCollection(App& app)
3194{
Ed Tanous253f11b2024-05-16 09:38:31 -07003195 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/LogServices/Dump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07003196 .privileges(redfish::privileges::getLogEntryCollection)
Claire Weinanfdd26902022-03-01 14:18:25 -08003197 .methods(boost::beast::http::verb::get)(std::bind_front(
3198 handleLogServicesDumpEntriesCollectionGet, std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003199}
3200
3201inline void requestRoutesBMCDumpEntry(App& app)
3202{
3203 BMCWEB_ROUTE(app,
Ed Tanous253f11b2024-05-16 09:38:31 -07003204 "/redfish/v1/Managers/<str>/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003205 .privileges(redfish::privileges::getLogEntry)
Claire Weinanfdd26902022-03-01 14:18:25 -08003206 .methods(boost::beast::http::verb::get)(std::bind_front(
3207 handleLogServicesDumpEntryGet, std::ref(app), "BMC"));
3208
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003209 BMCWEB_ROUTE(app,
Ed Tanous253f11b2024-05-16 09:38:31 -07003210 "/redfish/v1/Managers/<str>/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003211 .privileges(redfish::privileges::deleteLogEntry)
Claire Weinanfdd26902022-03-01 14:18:25 -08003212 .methods(boost::beast::http::verb::delete_)(std::bind_front(
3213 handleLogServicesDumpEntryDelete, std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003214}
3215
Carson Labrado168d1b12023-03-27 17:04:46 +00003216inline void requestRoutesBMCDumpEntryDownload(App& app)
3217{
3218 BMCWEB_ROUTE(
3219 app,
Ed Tanous253f11b2024-05-16 09:38:31 -07003220 "/redfish/v1/Managers/<str>/LogServices/Dump/Entries/<str>/attachment/")
Carson Labrado168d1b12023-03-27 17:04:46 +00003221 .privileges(redfish::privileges::getLogEntry)
3222 .methods(boost::beast::http::verb::get)(std::bind_front(
3223 handleLogServicesDumpEntryDownloadGet, std::ref(app), "BMC"));
3224}
3225
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003226inline void requestRoutesBMCDumpCreate(App& app)
3227{
George Liu0fda0f12021-11-16 10:06:17 +08003228 BMCWEB_ROUTE(
3229 app,
Ed Tanous253f11b2024-05-16 09:38:31 -07003230 "/redfish/v1/Managers/<str>/LogServices/Dump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07003231 .privileges(redfish::privileges::postLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003232 .methods(boost::beast::http::verb::post)(
Claire Weinanfdd26902022-03-01 14:18:25 -08003233 std::bind_front(handleLogServicesDumpCollectDiagnosticDataPost,
3234 std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003235}
3236
3237inline void requestRoutesBMCDumpClear(App& app)
3238{
George Liu0fda0f12021-11-16 10:06:17 +08003239 BMCWEB_ROUTE(
3240 app,
Ed Tanous253f11b2024-05-16 09:38:31 -07003241 "/redfish/v1/Managers/<str>/LogServices/Dump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07003242 .privileges(redfish::privileges::postLogService)
Claire Weinanfdd26902022-03-01 14:18:25 -08003243 .methods(boost::beast::http::verb::post)(std::bind_front(
3244 handleLogServicesDumpClearLogPost, std::ref(app), "BMC"));
3245}
3246
Carson Labrado168d1b12023-03-27 17:04:46 +00003247inline void requestRoutesDBusEventLogEntryDownload(App& app)
3248{
3249 BMCWEB_ROUTE(
3250 app,
Ravi Teja9e9d99d2023-11-08 05:33:59 -06003251 "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/attachment/")
Carson Labrado168d1b12023-03-27 17:04:46 +00003252 .privileges(redfish::privileges::getLogEntry)
3253 .methods(boost::beast::http::verb::get)(std::bind_front(
3254 handleDBusEventLogEntryDownloadGet, std::ref(app), "System"));
3255}
3256
Claire Weinanfdd26902022-03-01 14:18:25 -08003257inline void requestRoutesFaultLogDumpService(App& app)
3258{
Ed Tanous253f11b2024-05-16 09:38:31 -07003259 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/LogServices/FaultLog/")
Claire Weinanfdd26902022-03-01 14:18:25 -08003260 .privileges(redfish::privileges::getLogService)
3261 .methods(boost::beast::http::verb::get)(std::bind_front(
3262 handleLogServicesDumpServiceGet, std::ref(app), "FaultLog"));
3263}
3264
3265inline void requestRoutesFaultLogDumpEntryCollection(App& app)
3266{
Ed Tanous253f11b2024-05-16 09:38:31 -07003267 BMCWEB_ROUTE(app,
3268 "/redfish/v1/Managers/<str>/LogServices/FaultLog/Entries/")
Claire Weinanfdd26902022-03-01 14:18:25 -08003269 .privileges(redfish::privileges::getLogEntryCollection)
3270 .methods(boost::beast::http::verb::get)(
3271 std::bind_front(handleLogServicesDumpEntriesCollectionGet,
3272 std::ref(app), "FaultLog"));
3273}
3274
3275inline void requestRoutesFaultLogDumpEntry(App& app)
3276{
Ed Tanous253f11b2024-05-16 09:38:31 -07003277 BMCWEB_ROUTE(
3278 app, "/redfish/v1/Managers/<str>/LogServices/FaultLog/Entries/<str>/")
Claire Weinanfdd26902022-03-01 14:18:25 -08003279 .privileges(redfish::privileges::getLogEntry)
3280 .methods(boost::beast::http::verb::get)(std::bind_front(
3281 handleLogServicesDumpEntryGet, std::ref(app), "FaultLog"));
3282
Ed Tanous253f11b2024-05-16 09:38:31 -07003283 BMCWEB_ROUTE(
3284 app, "/redfish/v1/Managers/<str>/LogServices/FaultLog/Entries/<str>/")
Claire Weinanfdd26902022-03-01 14:18:25 -08003285 .privileges(redfish::privileges::deleteLogEntry)
3286 .methods(boost::beast::http::verb::delete_)(std::bind_front(
3287 handleLogServicesDumpEntryDelete, std::ref(app), "FaultLog"));
3288}
3289
3290inline void requestRoutesFaultLogDumpClear(App& app)
3291{
3292 BMCWEB_ROUTE(
3293 app,
Ed Tanous253f11b2024-05-16 09:38:31 -07003294 "/redfish/v1/Managers/<str>/LogServices/FaultLog/Actions/LogService.ClearLog/")
Claire Weinanfdd26902022-03-01 14:18:25 -08003295 .privileges(redfish::privileges::postLogService)
3296 .methods(boost::beast::http::verb::post)(std::bind_front(
3297 handleLogServicesDumpClearLogPost, std::ref(app), "FaultLog"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003298}
3299
3300inline void requestRoutesSystemDumpService(App& app)
3301{
Ed Tanous22d268c2022-05-19 09:39:07 -07003302 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/")
Ed Tanoused398212021-06-09 17:05:54 -07003303 .privileges(redfish::privileges::getLogService)
Claire Weinan6ab9ad52022-08-12 18:20:17 -07003304 .methods(boost::beast::http::verb::get)(std::bind_front(
Ed Tanous22d268c2022-05-19 09:39:07 -07003305 handleLogServicesDumpServiceComputerSystemGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003306}
3307
3308inline void requestRoutesSystemDumpEntryCollection(App& app)
3309{
Ed Tanous22d268c2022-05-19 09:39:07 -07003310 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07003311 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous22d268c2022-05-19 09:39:07 -07003312 .methods(boost::beast::http::verb::get)(std::bind_front(
3313 handleLogServicesDumpEntriesCollectionComputerSystemGet,
3314 std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003315}
3316
3317inline void requestRoutesSystemDumpEntry(App& app)
3318{
3319 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003320 "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003321 .privileges(redfish::privileges::getLogEntry)
Claire Weinan6ab9ad52022-08-12 18:20:17 -07003322 .methods(boost::beast::http::verb::get)(std::bind_front(
Ed Tanous22d268c2022-05-19 09:39:07 -07003323 handleLogServicesDumpEntryComputerSystemGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003324
3325 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003326 "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003327 .privileges(redfish::privileges::deleteLogEntry)
Claire Weinan6ab9ad52022-08-12 18:20:17 -07003328 .methods(boost::beast::http::verb::delete_)(std::bind_front(
Ed Tanous22d268c2022-05-19 09:39:07 -07003329 handleLogServicesDumpEntryComputerSystemDelete, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003330}
3331
3332inline void requestRoutesSystemDumpCreate(App& app)
3333{
George Liu0fda0f12021-11-16 10:06:17 +08003334 BMCWEB_ROUTE(
3335 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003336 "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07003337 .privileges(redfish::privileges::postLogService)
Ed Tanous22d268c2022-05-19 09:39:07 -07003338 .methods(boost::beast::http::verb::post)(std::bind_front(
3339 handleLogServicesDumpCollectDiagnosticDataComputerSystemPost,
3340 std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003341}
3342
3343inline void requestRoutesSystemDumpClear(App& app)
3344{
George Liu0fda0f12021-11-16 10:06:17 +08003345 BMCWEB_ROUTE(
3346 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003347 "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07003348 .privileges(redfish::privileges::postLogService)
Claire Weinan6ab9ad52022-08-12 18:20:17 -07003349 .methods(boost::beast::http::verb::post)(std::bind_front(
Ed Tanous22d268c2022-05-19 09:39:07 -07003350 handleLogServicesDumpClearLogComputerSystemPost, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003351}
3352
3353inline void requestRoutesCrashdumpService(App& app)
3354{
3355 // Note: Deviated from redfish privilege registry for GET & HEAD
3356 // method for security reasons.
3357 /**
3358 * Functions triggers appropriate requests on DBus
3359 */
Ed Tanous22d268c2022-05-19 09:39:07 -07003360 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/")
Ed Tanoused398212021-06-09 17:05:54 -07003361 // This is incorrect, should be:
3362 //.privileges(redfish::privileges::getLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07003363 .privileges({{"ConfigureManager"}})
Ed Tanous002d39b2022-05-31 08:59:27 -07003364 .methods(boost::beast::http::verb::get)(
3365 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003366 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3367 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003368 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003369 {
3370 return;
3371 }
Ed Tanous25b54db2024-04-17 15:40:31 -07003372 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003373 {
3374 // Option currently returns no systems. TBD
3375 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3376 systemName);
3377 return;
3378 }
Ed Tanous253f11b2024-05-16 09:38:31 -07003379 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07003380 {
3381 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3382 systemName);
3383 return;
3384 }
3385
Ed Tanous002d39b2022-05-31 08:59:27 -07003386 // Copy over the static data to include the entries added by
3387 // SubRoute
3388 asyncResp->res.jsonValue["@odata.id"] =
Ed Tanous253f11b2024-05-16 09:38:31 -07003389 std::format("/redfish/v1/Systems/{}/LogServices/Crashdump",
3390 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Ed Tanous002d39b2022-05-31 08:59:27 -07003391 asyncResp->res.jsonValue["@odata.type"] =
3392 "#LogService.v1_2_0.LogService";
3393 asyncResp->res.jsonValue["Name"] = "Open BMC Oem Crashdump Service";
3394 asyncResp->res.jsonValue["Description"] = "Oem Crashdump Service";
V-Sanjana15b89722023-05-11 16:27:03 +05303395 asyncResp->res.jsonValue["Id"] = "Crashdump";
Ed Tanous002d39b2022-05-31 08:59:27 -07003396 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
3397 asyncResp->res.jsonValue["MaxNumberOfRecords"] = 3;
Tejas Patil7c8c4052021-06-04 17:43:14 +05303398
Ed Tanous002d39b2022-05-31 08:59:27 -07003399 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07003400 redfish::time_utils::getDateTimeOffsetNow();
Ed Tanous002d39b2022-05-31 08:59:27 -07003401 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
3402 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
3403 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05303404
Ed Tanous002d39b2022-05-31 08:59:27 -07003405 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
Ed Tanous253f11b2024-05-16 09:38:31 -07003406 std::format("/redfish/v1/Systems/{}/LogServices/Crashdump/Entries",
3407 BMCWEB_REDFISH_SYSTEM_URI_NAME);
3408 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]
3409 ["target"] = std::format(
3410 "/redfish/v1/Systems/{}/LogServices/Crashdump/Actions/LogService.ClearLog",
3411 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Ed Tanous002d39b2022-05-31 08:59:27 -07003412 asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"]
Ed Tanous253f11b2024-05-16 09:38:31 -07003413 ["target"] = std::format(
3414 "/redfish/v1/Systems/{}/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData",
3415 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Patrick Williams5a39f772023-10-20 11:20:21 -05003416 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003417}
3418
3419void inline requestRoutesCrashdumpClear(App& app)
3420{
George Liu0fda0f12021-11-16 10:06:17 +08003421 BMCWEB_ROUTE(
3422 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003423 "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07003424 // This is incorrect, should be:
3425 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07003426 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003427 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003428 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003429 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3430 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003431 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003432 {
3433 return;
3434 }
Ed Tanous25b54db2024-04-17 15:40:31 -07003435 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003436 {
3437 // Option currently returns no systems. TBD
3438 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3439 systemName);
3440 return;
3441 }
Ed Tanous253f11b2024-05-16 09:38:31 -07003442 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07003443 {
3444 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3445 systemName);
3446 return;
3447 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003448 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08003449 [asyncResp](const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -07003450 const std::string&) {
3451 if (ec)
3452 {
3453 messages::internalError(asyncResp->res);
3454 return;
3455 }
3456 messages::success(asyncResp->res);
Patrick Williams5a39f772023-10-20 11:20:21 -05003457 },
Ed Tanous002d39b2022-05-31 08:59:27 -07003458 crashdumpObject, crashdumpPath, deleteAllInterface, "DeleteAll");
Patrick Williams5a39f772023-10-20 11:20:21 -05003459 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003460}
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07003461
zhanghch058d1b46d2021-04-01 11:18:24 +08003462static void
3463 logCrashdumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3464 const std::string& logID, nlohmann::json& logEntryJson)
Jason M. Billse855dd22019-10-08 11:37:48 -07003465{
Johnathan Mantey043a0532020-03-10 17:15:28 -07003466 auto getStoredLogCallback =
Ed Tanousb9d36b42022-02-26 21:42:46 -08003467 [asyncResp, logID,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08003468 &logEntryJson](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08003469 const dbus::utility::DBusPropertiesMap& params) {
Ed Tanous002d39b2022-05-31 08:59:27 -07003470 if (ec)
3471 {
Ed Tanous62598e32023-07-17 17:06:25 -07003472 BMCWEB_LOG_DEBUG("failed to get log ec: {}", ec.message());
Ed Tanous002d39b2022-05-31 08:59:27 -07003473 if (ec.value() ==
3474 boost::system::linux_error::bad_request_descriptor)
Jason M. Bills1ddcf012019-11-26 14:59:21 -08003475 {
Ed Tanous002d39b2022-05-31 08:59:27 -07003476 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Jason M. Bills2b20ef62022-01-06 15:48:07 -08003477 }
3478 else
3479 {
Ed Tanous002d39b2022-05-31 08:59:27 -07003480 messages::internalError(asyncResp->res);
Jason M. Bills2b20ef62022-01-06 15:48:07 -08003481 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003482 return;
3483 }
3484
3485 std::string timestamp{};
3486 std::string filename{};
3487 std::string logfile{};
3488 parseCrashdumpParameters(params, filename, timestamp, logfile);
3489
3490 if (filename.empty() || timestamp.empty())
3491 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08003492 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Ed Tanous002d39b2022-05-31 08:59:27 -07003493 return;
3494 }
3495
3496 std::string crashdumpURI =
Ed Tanous253f11b2024-05-16 09:38:31 -07003497 std::format("/redfish/v1/Systems/{}/LogServices/Crashdump/Entries/",
3498 BMCWEB_REDFISH_SYSTEM_URI_NAME) +
Ed Tanous002d39b2022-05-31 08:59:27 -07003499 logID + "/" + filename;
Jason M. Bills84afc482022-06-24 12:38:23 -07003500 nlohmann::json::object_t logEntry;
Vijay Lobo9c11a172021-10-07 16:53:16 -05003501 logEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Ed Tanousef4c65b2023-04-24 15:28:50 -07003502 logEntry["@odata.id"] = boost::urls::format(
Ed Tanous253f11b2024-05-16 09:38:31 -07003503 "/redfish/v1/Systems/{}/LogServices/Crashdump/Entries/{}",
3504 BMCWEB_REDFISH_SYSTEM_URI_NAME, logID);
Jason M. Bills84afc482022-06-24 12:38:23 -07003505 logEntry["Name"] = "CPU Crashdump";
3506 logEntry["Id"] = logID;
3507 logEntry["EntryType"] = "Oem";
3508 logEntry["AdditionalDataURI"] = std::move(crashdumpURI);
3509 logEntry["DiagnosticDataType"] = "OEM";
3510 logEntry["OEMDiagnosticDataType"] = "PECICrashdump";
3511 logEntry["Created"] = std::move(timestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07003512
3513 // If logEntryJson references an array of LogEntry resources
3514 // ('Members' list), then push this as a new entry, otherwise set it
3515 // directly
3516 if (logEntryJson.is_array())
3517 {
3518 logEntryJson.push_back(logEntry);
3519 asyncResp->res.jsonValue["Members@odata.count"] =
3520 logEntryJson.size();
3521 }
3522 else
3523 {
Jason M. Billsd405bb52022-06-24 10:52:05 -07003524 logEntryJson.update(logEntry);
Ed Tanous002d39b2022-05-31 08:59:27 -07003525 }
3526 };
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02003527 sdbusplus::asio::getAllProperties(
3528 *crow::connections::systemBus, crashdumpObject,
3529 crashdumpPath + std::string("/") + logID, crashdumpInterface,
3530 std::move(getStoredLogCallback));
Jason M. Billse855dd22019-10-08 11:37:48 -07003531}
3532
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003533inline void requestRoutesCrashdumpEntryCollection(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07003534{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003535 // Note: Deviated from redfish privilege registry for GET & HEAD
3536 // method for security reasons.
Ed Tanous1da66f72018-07-27 16:13:37 -07003537 /**
3538 * Functions triggers appropriate requests on DBus
3539 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003540 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003541 "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07003542 // This is incorrect, should be.
3543 //.privileges(redfish::privileges::postLogEntryCollection)
Ed Tanous432a8902021-06-14 15:28:56 -07003544 .privileges({{"ConfigureComponents"}})
Ed Tanous002d39b2022-05-31 08:59:27 -07003545 .methods(boost::beast::http::verb::get)(
3546 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003547 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3548 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003549 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003550 {
3551 return;
3552 }
Ed Tanous25b54db2024-04-17 15:40:31 -07003553 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003554 {
3555 // Option currently returns no systems. TBD
3556 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3557 systemName);
3558 return;
3559 }
Ed Tanous253f11b2024-05-16 09:38:31 -07003560 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07003561 {
3562 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3563 systemName);
3564 return;
3565 }
3566
George Liu7a1dbc42022-12-07 16:03:22 +08003567 constexpr std::array<std::string_view, 1> interfaces = {
3568 crashdumpInterface};
3569 dbus::utility::getSubTreePaths(
3570 "/", 0, interfaces,
3571 [asyncResp](const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -07003572 const std::vector<std::string>& resp) {
3573 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -07003574 {
Ed Tanous002d39b2022-05-31 08:59:27 -07003575 if (ec.value() !=
3576 boost::system::errc::no_such_file_or_directory)
3577 {
Ed Tanous62598e32023-07-17 17:06:25 -07003578 BMCWEB_LOG_DEBUG("failed to get entries ec: {}",
3579 ec.message());
Ed Tanous002d39b2022-05-31 08:59:27 -07003580 messages::internalError(asyncResp->res);
3581 return;
3582 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07003583 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003584 asyncResp->res.jsonValue["@odata.type"] =
3585 "#LogEntryCollection.LogEntryCollection";
Ed Tanous253f11b2024-05-16 09:38:31 -07003586 asyncResp->res.jsonValue["@odata.id"] = std::format(
3587 "/redfish/v1/Systems/{}/LogServices/Crashdump/Entries",
3588 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Ed Tanous002d39b2022-05-31 08:59:27 -07003589 asyncResp->res.jsonValue["Name"] = "Open BMC Crashdump Entries";
3590 asyncResp->res.jsonValue["Description"] =
3591 "Collection of Crashdump Entries";
3592 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
3593 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Jason M. Bills2b20ef62022-01-06 15:48:07 -08003594
Ed Tanous002d39b2022-05-31 08:59:27 -07003595 for (const std::string& path : resp)
3596 {
3597 const sdbusplus::message::object_path objPath(path);
3598 // Get the log ID
3599 std::string logID = objPath.filename();
3600 if (logID.empty())
3601 {
3602 continue;
3603 }
3604 // Add the log entry to the array
3605 logCrashdumpEntry(asyncResp, logID,
3606 asyncResp->res.jsonValue["Members"]);
3607 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003608 });
Patrick Williams5a39f772023-10-20 11:20:21 -05003609 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003610}
Ed Tanous1da66f72018-07-27 16:13:37 -07003611
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003612inline void requestRoutesCrashdumpEntry(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07003613{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003614 // Note: Deviated from redfish privilege registry for GET & HEAD
3615 // method for security reasons.
Ed Tanous1da66f72018-07-27 16:13:37 -07003616
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003617 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07003618 app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003619 // this is incorrect, should be
3620 // .privileges(redfish::privileges::getLogEntry)
Ed Tanous432a8902021-06-14 15:28:56 -07003621 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003622 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003623 [&app](const crow::Request& req,
3624 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07003625 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003626 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003627 {
3628 return;
3629 }
Ed Tanous25b54db2024-04-17 15:40:31 -07003630 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003631 {
3632 // Option currently returns no systems. TBD
3633 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3634 systemName);
3635 return;
3636 }
Ed Tanous253f11b2024-05-16 09:38:31 -07003637 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07003638 {
3639 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3640 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003641 return;
3642 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003643 const std::string& logID = param;
3644 logCrashdumpEntry(asyncResp, logID, asyncResp->res.jsonValue);
Patrick Williams5a39f772023-10-20 11:20:21 -05003645 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003646}
Ed Tanous1da66f72018-07-27 16:13:37 -07003647
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003648inline void requestRoutesCrashdumpFile(App& app)
3649{
3650 // Note: Deviated from redfish privilege registry for GET & HEAD
3651 // method for security reasons.
3652 BMCWEB_ROUTE(
3653 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003654 "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003655 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003656 .methods(boost::beast::http::verb::get)(
Nan Zhoua4ce1142022-08-02 18:45:25 +00003657 [](const crow::Request& req,
3658 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07003659 const std::string& systemName, const std::string& logID,
3660 const std::string& fileName) {
Shounak Mitra2a9beee2022-07-20 18:41:30 +00003661 // Do not call getRedfishRoute here since the crashdump file is not a
3662 // Redfish resource.
Ed Tanous22d268c2022-05-19 09:39:07 -07003663
Ed Tanous25b54db2024-04-17 15:40:31 -07003664 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003665 {
3666 // Option currently returns no systems. TBD
3667 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3668 systemName);
3669 return;
3670 }
Ed Tanous253f11b2024-05-16 09:38:31 -07003671 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07003672 {
3673 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3674 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003675 return;
3676 }
3677
Ed Tanous002d39b2022-05-31 08:59:27 -07003678 auto getStoredLogCallback =
Ed Tanous39662a32023-02-06 15:09:46 -08003679 [asyncResp, logID, fileName, url(boost::urls::url(req.url()))](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08003680 const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -07003681 const std::vector<
3682 std::pair<std::string, dbus::utility::DbusVariantType>>&
3683 resp) {
3684 if (ec)
3685 {
Ed Tanous62598e32023-07-17 17:06:25 -07003686 BMCWEB_LOG_DEBUG("failed to get log ec: {}", ec.message());
Ed Tanous002d39b2022-05-31 08:59:27 -07003687 messages::internalError(asyncResp->res);
3688 return;
3689 }
Jason M. Bills8e6c0992021-03-11 16:26:53 -08003690
Ed Tanous002d39b2022-05-31 08:59:27 -07003691 std::string dbusFilename{};
3692 std::string dbusTimestamp{};
3693 std::string dbusFilepath{};
Jason M. Bills8e6c0992021-03-11 16:26:53 -08003694
Ed Tanous002d39b2022-05-31 08:59:27 -07003695 parseCrashdumpParameters(resp, dbusFilename, dbusTimestamp,
3696 dbusFilepath);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003697
Ed Tanous002d39b2022-05-31 08:59:27 -07003698 if (dbusFilename.empty() || dbusTimestamp.empty() ||
3699 dbusFilepath.empty())
3700 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08003701 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Ed Tanous002d39b2022-05-31 08:59:27 -07003702 return;
3703 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003704
Ed Tanous002d39b2022-05-31 08:59:27 -07003705 // Verify the file name parameter is correct
3706 if (fileName != dbusFilename)
3707 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08003708 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Ed Tanous002d39b2022-05-31 08:59:27 -07003709 return;
3710 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003711
Ed Tanous27b0cf92023-08-07 12:02:40 -07003712 if (!asyncResp->res.openFile(dbusFilepath))
Ed Tanous002d39b2022-05-31 08:59:27 -07003713 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08003714 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Ed Tanous002d39b2022-05-31 08:59:27 -07003715 return;
3716 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003717
Ed Tanous002d39b2022-05-31 08:59:27 -07003718 // Configure this to be a file download when accessed
3719 // from a browser
Ed Tanousd9f6c622022-03-17 09:12:17 -07003720 asyncResp->res.addHeader(
3721 boost::beast::http::field::content_disposition, "attachment");
Ed Tanous002d39b2022-05-31 08:59:27 -07003722 };
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02003723 sdbusplus::asio::getAllProperties(
3724 *crow::connections::systemBus, crashdumpObject,
3725 crashdumpPath + std::string("/") + logID, crashdumpInterface,
3726 std::move(getStoredLogCallback));
Patrick Williams5a39f772023-10-20 11:20:21 -05003727 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003728}
3729
Jason M. Billsc5a4c822022-01-06 15:51:23 -08003730enum class OEMDiagnosticType
3731{
3732 onDemand,
3733 telemetry,
3734 invalid,
3735};
3736
Ed Tanous26ccae32023-02-16 10:28:44 -08003737inline OEMDiagnosticType getOEMDiagnosticType(std::string_view oemDiagStr)
Jason M. Billsc5a4c822022-01-06 15:51:23 -08003738{
3739 if (oemDiagStr == "OnDemand")
3740 {
3741 return OEMDiagnosticType::onDemand;
3742 }
3743 if (oemDiagStr == "Telemetry")
3744 {
3745 return OEMDiagnosticType::telemetry;
3746 }
3747
3748 return OEMDiagnosticType::invalid;
3749}
3750
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003751inline void requestRoutesCrashdumpCollect(App& app)
3752{
3753 // Note: Deviated from redfish privilege registry for GET & HEAD
3754 // method for security reasons.
George Liu0fda0f12021-11-16 10:06:17 +08003755 BMCWEB_ROUTE(
3756 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003757 "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07003758 // The below is incorrect; Should be ConfigureManager
3759 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07003760 .privileges({{"ConfigureComponents"}})
Ed Tanous002d39b2022-05-31 08:59:27 -07003761 .methods(boost::beast::http::verb::post)(
3762 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003763 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3764 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003765 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003766 {
3767 return;
3768 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003769
Ed Tanous25b54db2024-04-17 15:40:31 -07003770 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003771 {
3772 // Option currently returns no systems. TBD
3773 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3774 systemName);
3775 return;
3776 }
Ed Tanous253f11b2024-05-16 09:38:31 -07003777 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07003778 {
3779 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3780 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003781 return;
3782 }
3783
Ed Tanous002d39b2022-05-31 08:59:27 -07003784 std::string diagnosticDataType;
3785 std::string oemDiagnosticDataType;
3786 if (!redfish::json_util::readJsonAction(
3787 req, asyncResp->res, "DiagnosticDataType", diagnosticDataType,
3788 "OEMDiagnosticDataType", oemDiagnosticDataType))
3789 {
3790 return;
3791 }
3792
3793 if (diagnosticDataType != "OEM")
3794 {
Ed Tanous62598e32023-07-17 17:06:25 -07003795 BMCWEB_LOG_ERROR(
3796 "Only OEM DiagnosticDataType supported for Crashdump");
Ed Tanous002d39b2022-05-31 08:59:27 -07003797 messages::actionParameterValueFormatError(
3798 asyncResp->res, diagnosticDataType, "DiagnosticDataType",
3799 "CollectDiagnosticData");
3800 return;
3801 }
3802
3803 OEMDiagnosticType oemDiagType =
3804 getOEMDiagnosticType(oemDiagnosticDataType);
3805
3806 std::string iface;
3807 std::string method;
3808 std::string taskMatchStr;
3809 if (oemDiagType == OEMDiagnosticType::onDemand)
3810 {
3811 iface = crashdumpOnDemandInterface;
3812 method = "GenerateOnDemandLog";
3813 taskMatchStr = "type='signal',"
3814 "interface='org.freedesktop.DBus.Properties',"
3815 "member='PropertiesChanged',"
3816 "arg0namespace='com.intel.crashdump'";
3817 }
3818 else if (oemDiagType == OEMDiagnosticType::telemetry)
3819 {
3820 iface = crashdumpTelemetryInterface;
3821 method = "GenerateTelemetryLog";
3822 taskMatchStr = "type='signal',"
3823 "interface='org.freedesktop.DBus.Properties',"
3824 "member='PropertiesChanged',"
3825 "arg0namespace='com.intel.crashdump'";
3826 }
3827 else
3828 {
Ed Tanous62598e32023-07-17 17:06:25 -07003829 BMCWEB_LOG_ERROR("Unsupported OEMDiagnosticDataType: {}",
3830 oemDiagnosticDataType);
Ed Tanous002d39b2022-05-31 08:59:27 -07003831 messages::actionParameterValueFormatError(
3832 asyncResp->res, oemDiagnosticDataType, "OEMDiagnosticDataType",
3833 "CollectDiagnosticData");
3834 return;
3835 }
3836
3837 auto collectCrashdumpCallback =
3838 [asyncResp, payload(task::Payload(req)),
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08003839 taskMatchStr](const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -07003840 const std::string&) mutable {
3841 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -07003842 {
Ed Tanous002d39b2022-05-31 08:59:27 -07003843 if (ec.value() == boost::system::errc::operation_not_supported)
3844 {
3845 messages::resourceInStandby(asyncResp->res);
3846 }
3847 else if (ec.value() ==
3848 boost::system::errc::device_or_resource_busy)
3849 {
3850 messages::serviceTemporarilyUnavailable(asyncResp->res,
3851 "60");
3852 }
3853 else
3854 {
3855 messages::internalError(asyncResp->res);
3856 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07003857 return;
3858 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003859 std::shared_ptr<task::TaskData> task = task::TaskData::createTask(
Ed Tanous8b242752023-06-27 17:17:13 -07003860 [](const boost::system::error_code& ec2, sdbusplus::message_t&,
Ed Tanous002d39b2022-05-31 08:59:27 -07003861 const std::shared_ptr<task::TaskData>& taskData) {
Ed Tanous8b242752023-06-27 17:17:13 -07003862 if (!ec2)
Ed Tanous002d39b2022-05-31 08:59:27 -07003863 {
3864 taskData->messages.emplace_back(messages::taskCompletedOK(
3865 std::to_string(taskData->index)));
3866 taskData->state = "Completed";
3867 }
3868 return task::completed;
Patrick Williams5a39f772023-10-20 11:20:21 -05003869 },
Ed Tanous002d39b2022-05-31 08:59:27 -07003870 taskMatchStr);
Ed Tanous1da66f72018-07-27 16:13:37 -07003871
Ed Tanous002d39b2022-05-31 08:59:27 -07003872 task->startTimer(std::chrono::minutes(5));
3873 task->populateResp(asyncResp->res);
3874 task->payload.emplace(std::move(payload));
3875 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003876
Ed Tanous002d39b2022-05-31 08:59:27 -07003877 crow::connections::systemBus->async_method_call(
3878 std::move(collectCrashdumpCallback), crashdumpObject, crashdumpPath,
3879 iface, method);
Patrick Williams5a39f772023-10-20 11:20:21 -05003880 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003881}
Kenny L. Ku6eda7682020-06-19 09:48:36 -07003882
Andrew Geisslercb92c032018-08-17 07:56:14 -07003883/**
3884 * DBusLogServiceActionsClear class supports POST method for ClearLog action.
3885 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003886inline void requestRoutesDBusLogServiceActionsClear(App& app)
Andrew Geisslercb92c032018-08-17 07:56:14 -07003887{
Andrew Geisslercb92c032018-08-17 07:56:14 -07003888 /**
3889 * Function handles POST method request.
3890 * The Clear Log actions does not require any parameter.The action deletes
3891 * all entries found in the Entries collection for this Log Service.
3892 */
Andrew Geisslercb92c032018-08-17 07:56:14 -07003893
George Liu0fda0f12021-11-16 10:06:17 +08003894 BMCWEB_ROUTE(
3895 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003896 "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07003897 .privileges(redfish::privileges::postLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003898 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003899 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003900 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3901 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003902 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003903 {
3904 return;
3905 }
Ed Tanous25b54db2024-04-17 15:40:31 -07003906 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003907 {
3908 // Option currently returns no systems. TBD
3909 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3910 systemName);
3911 return;
3912 }
Ed Tanous253f11b2024-05-16 09:38:31 -07003913 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07003914 {
3915 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3916 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003917 return;
3918 }
Ed Tanous62598e32023-07-17 17:06:25 -07003919 BMCWEB_LOG_DEBUG("Do delete all entries.");
Andrew Geisslercb92c032018-08-17 07:56:14 -07003920
Ed Tanous002d39b2022-05-31 08:59:27 -07003921 // Process response from Logging service.
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08003922 auto respHandler = [asyncResp](const boost::system::error_code& ec) {
Ed Tanous62598e32023-07-17 17:06:25 -07003923 BMCWEB_LOG_DEBUG("doClearLog resp_handler callback: Done");
Ed Tanous002d39b2022-05-31 08:59:27 -07003924 if (ec)
3925 {
3926 // TODO Handle for specific error code
Ed Tanous62598e32023-07-17 17:06:25 -07003927 BMCWEB_LOG_ERROR("doClearLog resp_handler got error {}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -07003928 asyncResp->res.result(
3929 boost::beast::http::status::internal_server_error);
3930 return;
3931 }
Andrew Geisslercb92c032018-08-17 07:56:14 -07003932
Ed Tanous002d39b2022-05-31 08:59:27 -07003933 asyncResp->res.result(boost::beast::http::status::no_content);
3934 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003935
Ed Tanous002d39b2022-05-31 08:59:27 -07003936 // Make call to Logging service to request Clear Log
3937 crow::connections::systemBus->async_method_call(
3938 respHandler, "xyz.openbmc_project.Logging",
3939 "/xyz/openbmc_project/logging",
3940 "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
Patrick Williams5a39f772023-10-20 11:20:21 -05003941 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003942}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003943
3944/****************************************************
3945 * Redfish PostCode interfaces
3946 * using DBUS interface: getPostCodesTS
3947 ******************************************************/
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003948inline void requestRoutesPostCodesLogService(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003949{
Ed Tanous22d268c2022-05-19 09:39:07 -07003950 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/")
Ed Tanoused398212021-06-09 17:05:54 -07003951 .privileges(redfish::privileges::getLogService)
Ed Tanous002d39b2022-05-31 08:59:27 -07003952 .methods(boost::beast::http::verb::get)(
3953 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003954 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3955 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003956 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003957 {
3958 return;
3959 }
Ed Tanous25b54db2024-04-17 15:40:31 -07003960 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003961 {
3962 // Option currently returns no systems. TBD
3963 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3964 systemName);
3965 return;
3966 }
Ed Tanous253f11b2024-05-16 09:38:31 -07003967 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07003968 {
3969 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3970 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003971 return;
3972 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003973 asyncResp->res.jsonValue["@odata.id"] =
Ed Tanous253f11b2024-05-16 09:38:31 -07003974 std::format("/redfish/v1/Systems/{}/LogServices/PostCodes",
3975 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Ed Tanous002d39b2022-05-31 08:59:27 -07003976 asyncResp->res.jsonValue["@odata.type"] =
Janet Adkinsb25644a2023-08-16 11:23:45 -05003977 "#LogService.v1_2_0.LogService";
Ed Tanous002d39b2022-05-31 08:59:27 -07003978 asyncResp->res.jsonValue["Name"] = "POST Code Log Service";
3979 asyncResp->res.jsonValue["Description"] = "POST Code Log Service";
Ed Tanoused34a4a2023-02-08 15:43:27 -08003980 asyncResp->res.jsonValue["Id"] = "PostCodes";
Ed Tanous002d39b2022-05-31 08:59:27 -07003981 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
3982 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
Ed Tanous253f11b2024-05-16 09:38:31 -07003983 std::format("/redfish/v1/Systems/{}/LogServices/PostCodes/Entries",
3984 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Tejas Patil7c8c4052021-06-04 17:43:14 +05303985
Ed Tanous002d39b2022-05-31 08:59:27 -07003986 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07003987 redfish::time_utils::getDateTimeOffsetNow();
Ed Tanous002d39b2022-05-31 08:59:27 -07003988 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
3989 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
3990 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05303991
Ed Tanous002d39b2022-05-31 08:59:27 -07003992 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = {
3993 {"target",
Ed Tanous253f11b2024-05-16 09:38:31 -07003994 std::format(
3995 "/redfish/v1/Systems/{}/LogServices/PostCodes/Actions/LogService.ClearLog",
3996 BMCWEB_REDFISH_SYSTEM_URI_NAME)}};
Patrick Williams5a39f772023-10-20 11:20:21 -05003997 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003998}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003999
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004000inline void requestRoutesPostCodesClear(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08004001{
George Liu0fda0f12021-11-16 10:06:17 +08004002 BMCWEB_ROUTE(
4003 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07004004 "/redfish/v1/Systems/<str>/LogServices/PostCodes/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07004005 // The following privilege is incorrect; It should be ConfigureManager
4006 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07004007 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004008 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07004009 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07004010 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
4011 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00004012 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07004013 {
4014 return;
4015 }
Ed Tanous25b54db2024-04-17 15:40:31 -07004016 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08004017 {
4018 // Option currently returns no systems. TBD
4019 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
4020 systemName);
4021 return;
4022 }
Ed Tanous253f11b2024-05-16 09:38:31 -07004023 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07004024 {
4025 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
4026 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07004027 return;
4028 }
Ed Tanous62598e32023-07-17 17:06:25 -07004029 BMCWEB_LOG_DEBUG("Do delete all postcodes entries.");
ZhikuiRena3316fc2020-01-29 14:58:08 -08004030
Ed Tanous002d39b2022-05-31 08:59:27 -07004031 // Make call to post-code service to request clear all
4032 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08004033 [asyncResp](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -07004034 if (ec)
4035 {
4036 // TODO Handle for specific error code
Ed Tanous62598e32023-07-17 17:06:25 -07004037 BMCWEB_LOG_ERROR("doClearPostCodes resp_handler got error {}",
4038 ec);
Ed Tanous002d39b2022-05-31 08:59:27 -07004039 asyncResp->res.result(
4040 boost::beast::http::status::internal_server_error);
4041 messages::internalError(asyncResp->res);
4042 return;
4043 }
Tony Lee18fc70c2023-08-24 16:15:54 +08004044 messages::success(asyncResp->res);
Patrick Williams5a39f772023-10-20 11:20:21 -05004045 },
Ed Tanous002d39b2022-05-31 08:59:27 -07004046 "xyz.openbmc_project.State.Boot.PostCode0",
4047 "/xyz/openbmc_project/State/Boot/PostCode0",
4048 "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
Patrick Williams5a39f772023-10-20 11:20:21 -05004049 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004050}
ZhikuiRena3316fc2020-01-29 14:58:08 -08004051
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004052/**
4053 * @brief Parse post code ID and get the current value and index value
4054 * eg: postCodeID=B1-2, currentValue=1, index=2
4055 *
4056 * @param[in] postCodeID Post Code ID
4057 * @param[out] currentValue Current value
4058 * @param[out] index Index value
4059 *
4060 * @return bool true if the parsing is successful, false the parsing fails
4061 */
Ed Tanous6f056f22024-04-07 13:35:51 -07004062inline bool parsePostCode(std::string_view postCodeID, uint64_t& currentValue,
Ed Tanousdf254f22024-04-01 13:25:46 -07004063 uint16_t& index)
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004064{
4065 std::vector<std::string> split;
Ed Tanous50ebd4a2023-01-19 19:03:17 -08004066 bmcweb::split(split, postCodeID, '-');
Ed Tanous6f056f22024-04-07 13:35:51 -07004067 if (split.size() != 2)
4068 {
4069 return false;
4070 }
4071 std::string_view postCodeNumber = split[0];
4072 if (postCodeNumber.size() < 2)
4073 {
4074 return false;
4075 }
4076 if (postCodeNumber[0] != 'B')
4077 {
4078 return false;
4079 }
4080 postCodeNumber.remove_prefix(1);
4081 auto [ptrIndex, ecIndex] = std::from_chars(postCodeNumber.begin(),
4082 postCodeNumber.end(), index);
4083 if (ptrIndex != postCodeNumber.end() || ecIndex != std::errc())
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004084 {
4085 return false;
4086 }
4087
Ed Tanous6f056f22024-04-07 13:35:51 -07004088 std::string_view postCodeIndex = split[1];
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004089
Ed Tanous6f056f22024-04-07 13:35:51 -07004090 auto [ptrValue, ecValue] = std::from_chars(
4091 postCodeIndex.begin(), postCodeIndex.end(), currentValue);
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004092
Ed Tanous6f056f22024-04-07 13:35:51 -07004093 return ptrValue == postCodeIndex.end() && ecValue == std::errc();
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004094}
4095
4096static bool fillPostCodeEntry(
Ed Tanousac106bf2023-06-07 09:24:59 -07004097 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05304098 const boost::container::flat_map<
4099 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& postcode,
ZhikuiRena3316fc2020-01-29 14:58:08 -08004100 const uint16_t bootIndex, const uint64_t codeIndex = 0,
4101 const uint64_t skip = 0, const uint64_t top = 0)
4102{
4103 // Get the Message from the MessageRegistry
Ed Tanousfffb8c12022-02-07 23:53:03 -08004104 const registries::Message* message =
4105 registries::getMessage("OpenBMC.0.2.BIOSPOSTCode");
Ed Tanousdc8cfa62024-04-07 13:37:25 -07004106 if (message == nullptr)
4107 {
4108 BMCWEB_LOG_ERROR("Couldn't find known message?");
4109 return false;
4110 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08004111 uint64_t currentCodeIndex = 0;
ZhikuiRena3316fc2020-01-29 14:58:08 -08004112 uint64_t firstCodeTimeUs = 0;
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05304113 for (const std::pair<uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
4114 code : postcode)
ZhikuiRena3316fc2020-01-29 14:58:08 -08004115 {
4116 currentCodeIndex++;
4117 std::string postcodeEntryID =
4118 "B" + std::to_string(bootIndex) + "-" +
4119 std::to_string(currentCodeIndex); // 1 based index in EntryID string
4120
4121 uint64_t usecSinceEpoch = code.first;
4122 uint64_t usTimeOffset = 0;
4123
4124 if (1 == currentCodeIndex)
4125 { // already incremented
4126 firstCodeTimeUs = code.first;
4127 }
4128 else
4129 {
4130 usTimeOffset = code.first - firstCodeTimeUs;
4131 }
4132
4133 // skip if no specific codeIndex is specified and currentCodeIndex does
4134 // not fall between top and skip
4135 if ((codeIndex == 0) &&
4136 (currentCodeIndex <= skip || currentCodeIndex > top))
4137 {
4138 continue;
4139 }
4140
Gunnar Mills4e0453b2020-07-08 14:00:30 -05004141 // skip if a specific codeIndex is specified and does not match the
ZhikuiRena3316fc2020-01-29 14:58:08 -08004142 // currentIndex
4143 if ((codeIndex > 0) && (currentCodeIndex != codeIndex))
4144 {
4145 // This is done for simplicity. 1st entry is needed to calculate
4146 // time offset. To improve efficiency, one can get to the entry
4147 // directly (possibly with flatmap's nth method)
4148 continue;
4149 }
4150
4151 // currentCodeIndex is within top and skip or equal to specified code
4152 // index
4153
4154 // Get the Created time from the timestamp
4155 std::string entryTimeStr;
Konstantin Aladyshev2a025612023-02-15 11:52:58 +03004156 entryTimeStr = redfish::time_utils::getDateTimeUintUs(usecSinceEpoch);
ZhikuiRena3316fc2020-01-29 14:58:08 -08004157
4158 // assemble messageArgs: BootIndex, TimeOffset(100us), PostCode(hex)
4159 std::ostringstream hexCode;
4160 hexCode << "0x" << std::setfill('0') << std::setw(2) << std::hex
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05304161 << std::get<0>(code.second);
ZhikuiRena3316fc2020-01-29 14:58:08 -08004162 std::ostringstream timeOffsetStr;
4163 // Set Fixed -Point Notation
4164 timeOffsetStr << std::fixed;
4165 // Set precision to 4 digits
4166 timeOffsetStr << std::setprecision(4);
4167 // Add double to stream
4168 timeOffsetStr << static_cast<double>(usTimeOffset) / 1000 / 1000;
ZhikuiRena3316fc2020-01-29 14:58:08 -08004169
Ed Tanous1e6deaf2022-02-17 11:32:37 -08004170 std::string bootIndexStr = std::to_string(bootIndex);
4171 std::string timeOffsetString = timeOffsetStr.str();
4172 std::string hexCodeStr = hexCode.str();
4173
4174 std::array<std::string_view, 3> messageArgs = {
4175 bootIndexStr, timeOffsetString, hexCodeStr};
4176
4177 std::string msg =
4178 redfish::registries::fillMessageArgs(messageArgs, message->message);
4179 if (msg.empty())
ZhikuiRena3316fc2020-01-29 14:58:08 -08004180 {
Ed Tanous1e6deaf2022-02-17 11:32:37 -08004181 messages::internalError(asyncResp->res);
4182 return false;
ZhikuiRena3316fc2020-01-29 14:58:08 -08004183 }
4184
Tim Leed4342a92020-04-27 11:47:58 +08004185 // Get Severity template from message registry
4186 std::string severity;
4187 if (message != nullptr)
4188 {
Ed Tanous5f2b84e2022-02-08 00:41:53 -08004189 severity = message->messageSeverity;
Tim Leed4342a92020-04-27 11:47:58 +08004190 }
4191
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004192 // Format entry
4193 nlohmann::json::object_t bmcLogEntry;
Vijay Lobo9c11a172021-10-07 16:53:16 -05004194 bmcLogEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Ed Tanousef4c65b2023-04-24 15:28:50 -07004195 bmcLogEntry["@odata.id"] = boost::urls::format(
Ed Tanous253f11b2024-05-16 09:38:31 -07004196 "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries/{}",
4197 BMCWEB_REDFISH_SYSTEM_URI_NAME, postcodeEntryID);
Jason M. Bills84afc482022-06-24 12:38:23 -07004198 bmcLogEntry["Name"] = "POST Code Log Entry";
4199 bmcLogEntry["Id"] = postcodeEntryID;
4200 bmcLogEntry["Message"] = std::move(msg);
4201 bmcLogEntry["MessageId"] = "OpenBMC.0.2.BIOSPOSTCode";
Ed Tanous1e6deaf2022-02-17 11:32:37 -08004202 bmcLogEntry["MessageArgs"] = messageArgs;
Jason M. Bills84afc482022-06-24 12:38:23 -07004203 bmcLogEntry["EntryType"] = "Event";
4204 bmcLogEntry["Severity"] = std::move(severity);
4205 bmcLogEntry["Created"] = entryTimeStr;
George Liu647b3cd2021-07-05 12:43:56 +08004206 if (!std::get<std::vector<uint8_t>>(code.second).empty())
4207 {
4208 bmcLogEntry["AdditionalDataURI"] =
Ed Tanous253f11b2024-05-16 09:38:31 -07004209 std::format(
4210 "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries/",
4211 BMCWEB_REDFISH_SYSTEM_URI_NAME) +
George Liu647b3cd2021-07-05 12:43:56 +08004212 postcodeEntryID + "/attachment";
4213 }
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004214
4215 // codeIndex is only specified when querying single entry, return only
4216 // that entry in this case
4217 if (codeIndex != 0)
4218 {
Ed Tanousac106bf2023-06-07 09:24:59 -07004219 asyncResp->res.jsonValue.update(bmcLogEntry);
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004220 return true;
4221 }
4222
Ed Tanousac106bf2023-06-07 09:24:59 -07004223 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
Patrick Williamsb2ba3072023-05-12 10:27:39 -05004224 logEntryArray.emplace_back(std::move(bmcLogEntry));
ZhikuiRena3316fc2020-01-29 14:58:08 -08004225 }
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004226
4227 // Return value is always false when querying multiple entries
4228 return false;
ZhikuiRena3316fc2020-01-29 14:58:08 -08004229}
4230
Ed Tanousac106bf2023-06-07 09:24:59 -07004231static void
4232 getPostCodeForEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
4233 const std::string& entryId)
ZhikuiRena3316fc2020-01-29 14:58:08 -08004234{
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004235 uint16_t bootIndex = 0;
4236 uint64_t codeIndex = 0;
4237 if (!parsePostCode(entryId, codeIndex, bootIndex))
4238 {
4239 // Requested ID was not found
Ed Tanousac106bf2023-06-07 09:24:59 -07004240 messages::resourceNotFound(asyncResp->res, "LogEntry", entryId);
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004241 return;
4242 }
4243
4244 if (bootIndex == 0 || codeIndex == 0)
4245 {
4246 // 0 is an invalid index
Ed Tanousac106bf2023-06-07 09:24:59 -07004247 messages::resourceNotFound(asyncResp->res, "LogEntry", entryId);
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004248 return;
4249 }
4250
ZhikuiRena3316fc2020-01-29 14:58:08 -08004251 crow::connections::systemBus->async_method_call(
Ed Tanousac106bf2023-06-07 09:24:59 -07004252 [asyncResp, entryId, bootIndex,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08004253 codeIndex](const boost::system::error_code& ec,
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05304254 const boost::container::flat_map<
4255 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
4256 postcode) {
Ed Tanous002d39b2022-05-31 08:59:27 -07004257 if (ec)
4258 {
Ed Tanous62598e32023-07-17 17:06:25 -07004259 BMCWEB_LOG_DEBUG("DBUS POST CODE PostCode response error");
Ed Tanousac106bf2023-06-07 09:24:59 -07004260 messages::internalError(asyncResp->res);
Ed Tanous002d39b2022-05-31 08:59:27 -07004261 return;
4262 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08004263
Ed Tanous002d39b2022-05-31 08:59:27 -07004264 if (postcode.empty())
4265 {
Ed Tanousac106bf2023-06-07 09:24:59 -07004266 messages::resourceNotFound(asyncResp->res, "LogEntry", entryId);
Ed Tanous002d39b2022-05-31 08:59:27 -07004267 return;
4268 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08004269
Ed Tanousac106bf2023-06-07 09:24:59 -07004270 if (!fillPostCodeEntry(asyncResp, postcode, bootIndex, codeIndex))
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004271 {
Ed Tanousac106bf2023-06-07 09:24:59 -07004272 messages::resourceNotFound(asyncResp->res, "LogEntry", entryId);
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004273 return;
4274 }
Patrick Williams5a39f772023-10-20 11:20:21 -05004275 },
Jonathan Doman15124762021-01-07 17:54:17 -08004276 "xyz.openbmc_project.State.Boot.PostCode0",
4277 "/xyz/openbmc_project/State/Boot/PostCode0",
ZhikuiRena3316fc2020-01-29 14:58:08 -08004278 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
4279 bootIndex);
4280}
4281
Ed Tanousac106bf2023-06-07 09:24:59 -07004282static void
4283 getPostCodeForBoot(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
4284 const uint16_t bootIndex, const uint16_t bootCount,
4285 const uint64_t entryCount, size_t skip, size_t top)
ZhikuiRena3316fc2020-01-29 14:58:08 -08004286{
4287 crow::connections::systemBus->async_method_call(
Ed Tanousac106bf2023-06-07 09:24:59 -07004288 [asyncResp, bootIndex, bootCount, entryCount, skip,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08004289 top](const boost::system::error_code& ec,
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05304290 const boost::container::flat_map<
4291 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
4292 postcode) {
Ed Tanous002d39b2022-05-31 08:59:27 -07004293 if (ec)
4294 {
Ed Tanous62598e32023-07-17 17:06:25 -07004295 BMCWEB_LOG_DEBUG("DBUS POST CODE PostCode response error");
Ed Tanousac106bf2023-06-07 09:24:59 -07004296 messages::internalError(asyncResp->res);
Ed Tanous002d39b2022-05-31 08:59:27 -07004297 return;
4298 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08004299
Ed Tanous002d39b2022-05-31 08:59:27 -07004300 uint64_t endCount = entryCount;
4301 if (!postcode.empty())
4302 {
4303 endCount = entryCount + postcode.size();
Ed Tanous3648c8b2022-07-25 13:39:59 -07004304 if (skip < endCount && (top + skip) > entryCount)
ZhikuiRena3316fc2020-01-29 14:58:08 -08004305 {
Patrick Williams89492a12023-05-10 07:51:34 -05004306 uint64_t thisBootSkip = std::max(static_cast<uint64_t>(skip),
4307 entryCount) -
4308 entryCount;
Ed Tanous002d39b2022-05-31 08:59:27 -07004309 uint64_t thisBootTop =
Ed Tanous3648c8b2022-07-25 13:39:59 -07004310 std::min(static_cast<uint64_t>(top + skip), endCount) -
4311 entryCount;
Ed Tanous002d39b2022-05-31 08:59:27 -07004312
Ed Tanousac106bf2023-06-07 09:24:59 -07004313 fillPostCodeEntry(asyncResp, postcode, bootIndex, 0,
4314 thisBootSkip, thisBootTop);
ZhikuiRena3316fc2020-01-29 14:58:08 -08004315 }
Ed Tanousac106bf2023-06-07 09:24:59 -07004316 asyncResp->res.jsonValue["Members@odata.count"] = endCount;
Ed Tanous002d39b2022-05-31 08:59:27 -07004317 }
4318
4319 // continue to previous bootIndex
4320 if (bootIndex < bootCount)
4321 {
Ed Tanousac106bf2023-06-07 09:24:59 -07004322 getPostCodeForBoot(asyncResp, static_cast<uint16_t>(bootIndex + 1),
Ed Tanous002d39b2022-05-31 08:59:27 -07004323 bootCount, endCount, skip, top);
4324 }
Jiaqing Zhao81584ab2022-07-28 00:33:45 +08004325 else if (skip + top < endCount)
Ed Tanous002d39b2022-05-31 08:59:27 -07004326 {
Ed Tanousac106bf2023-06-07 09:24:59 -07004327 asyncResp->res.jsonValue["Members@odata.nextLink"] =
Ed Tanous253f11b2024-05-16 09:38:31 -07004328 std::format(
4329 "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries?$skip=",
4330 BMCWEB_REDFISH_SYSTEM_URI_NAME) +
Ed Tanous002d39b2022-05-31 08:59:27 -07004331 std::to_string(skip + top);
4332 }
Patrick Williams5a39f772023-10-20 11:20:21 -05004333 },
Jonathan Doman15124762021-01-07 17:54:17 -08004334 "xyz.openbmc_project.State.Boot.PostCode0",
4335 "/xyz/openbmc_project/State/Boot/PostCode0",
ZhikuiRena3316fc2020-01-29 14:58:08 -08004336 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
4337 bootIndex);
4338}
4339
zhanghch058d1b46d2021-04-01 11:18:24 +08004340static void
Ed Tanousac106bf2023-06-07 09:24:59 -07004341 getCurrentBootNumber(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous3648c8b2022-07-25 13:39:59 -07004342 size_t skip, size_t top)
ZhikuiRena3316fc2020-01-29 14:58:08 -08004343{
4344 uint64_t entryCount = 0;
Jonathan Doman1e1e5982021-06-11 09:36:17 -07004345 sdbusplus::asio::getProperty<uint16_t>(
4346 *crow::connections::systemBus,
4347 "xyz.openbmc_project.State.Boot.PostCode0",
4348 "/xyz/openbmc_project/State/Boot/PostCode0",
4349 "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount",
Ed Tanousac106bf2023-06-07 09:24:59 -07004350 [asyncResp, entryCount, skip, top](const boost::system::error_code& ec,
4351 const uint16_t bootCount) {
Ed Tanous002d39b2022-05-31 08:59:27 -07004352 if (ec)
4353 {
Ed Tanous62598e32023-07-17 17:06:25 -07004354 BMCWEB_LOG_DEBUG("DBUS response error {}", ec);
Ed Tanousac106bf2023-06-07 09:24:59 -07004355 messages::internalError(asyncResp->res);
Ed Tanous002d39b2022-05-31 08:59:27 -07004356 return;
4357 }
Ed Tanousac106bf2023-06-07 09:24:59 -07004358 getPostCodeForBoot(asyncResp, 1, bootCount, entryCount, skip, top);
Patrick Williams5a39f772023-10-20 11:20:21 -05004359 });
ZhikuiRena3316fc2020-01-29 14:58:08 -08004360}
4361
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004362inline void requestRoutesPostCodesEntryCollection(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08004363{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004364 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07004365 "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07004366 .privileges(redfish::privileges::getLogEntryCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004367 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07004368 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07004369 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
4370 const std::string& systemName) {
Ed Tanous002d39b2022-05-31 08:59:27 -07004371 query_param::QueryCapabilities capabilities = {
4372 .canDelegateTop = true,
4373 .canDelegateSkip = true,
4374 };
4375 query_param::Query delegatedQuery;
4376 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00004377 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07004378 {
4379 return;
4380 }
Ed Tanous25b54db2024-04-17 15:40:31 -07004381 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08004382 {
4383 // Option currently returns no systems. TBD
4384 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
4385 systemName);
4386 return;
4387 }
Ed Tanous22d268c2022-05-19 09:39:07 -07004388
Ed Tanous253f11b2024-05-16 09:38:31 -07004389 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07004390 {
4391 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
4392 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07004393 return;
4394 }
Ed Tanous002d39b2022-05-31 08:59:27 -07004395 asyncResp->res.jsonValue["@odata.type"] =
4396 "#LogEntryCollection.LogEntryCollection";
4397 asyncResp->res.jsonValue["@odata.id"] =
Ed Tanous253f11b2024-05-16 09:38:31 -07004398 std::format("/redfish/v1/Systems/{}/LogServices/PostCodes/Entries",
4399 BMCWEB_REDFISH_SYSTEM_URI_NAME);
Ed Tanous002d39b2022-05-31 08:59:27 -07004400 asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries";
4401 asyncResp->res.jsonValue["Description"] =
4402 "Collection of POST Code Log Entries";
4403 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
4404 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Ed Tanous3648c8b2022-07-25 13:39:59 -07004405 size_t skip = delegatedQuery.skip.value_or(0);
Jiaqing Zhao5143f7a2022-07-22 09:33:33 +08004406 size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
Ed Tanous3648c8b2022-07-25 13:39:59 -07004407 getCurrentBootNumber(asyncResp, skip, top);
Patrick Williams5a39f772023-10-20 11:20:21 -05004408 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004409}
ZhikuiRena3316fc2020-01-29 14:58:08 -08004410
George Liu647b3cd2021-07-05 12:43:56 +08004411inline void requestRoutesPostCodesEntryAdditionalData(App& app)
4412{
George Liu0fda0f12021-11-16 10:06:17 +08004413 BMCWEB_ROUTE(
4414 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07004415 "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/attachment/")
George Liu647b3cd2021-07-05 12:43:56 +08004416 .privileges(redfish::privileges::getLogEntry)
4417 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07004418 [&app](const crow::Request& req,
4419 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07004420 const std::string& systemName,
Ed Tanous45ca1b82022-03-25 13:07:27 -07004421 const std::string& postCodeID) {
Carson Labrado3ba00072022-06-06 19:40:56 +00004422 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07004423 {
4424 return;
4425 }
Matt Spinler72e21372023-04-19 12:53:33 -05004426 if (!http_helpers::isContentTypeAllowed(
Ed Tanous99351cd2022-08-07 16:42:51 -07004427 req.getHeaderValue("Accept"),
Ed Tanous4a0e1a02022-09-21 15:28:04 -07004428 http_helpers::ContentType::OctetStream, true))
Ed Tanous002d39b2022-05-31 08:59:27 -07004429 {
4430 asyncResp->res.result(boost::beast::http::status::bad_request);
4431 return;
4432 }
Ed Tanous25b54db2024-04-17 15:40:31 -07004433 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08004434 {
4435 // Option currently returns no systems. TBD
4436 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
4437 systemName);
4438 return;
4439 }
Ed Tanous253f11b2024-05-16 09:38:31 -07004440 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07004441 {
4442 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
4443 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07004444 return;
4445 }
George Liu647b3cd2021-07-05 12:43:56 +08004446
Ed Tanous002d39b2022-05-31 08:59:27 -07004447 uint64_t currentValue = 0;
4448 uint16_t index = 0;
4449 if (!parsePostCode(postCodeID, currentValue, index))
4450 {
4451 messages::resourceNotFound(asyncResp->res, "LogEntry", postCodeID);
4452 return;
4453 }
George Liu647b3cd2021-07-05 12:43:56 +08004454
Ed Tanous002d39b2022-05-31 08:59:27 -07004455 crow::connections::systemBus->async_method_call(
4456 [asyncResp, postCodeID, currentValue](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08004457 const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -07004458 const std::vector<std::tuple<uint64_t, std::vector<uint8_t>>>&
4459 postcodes) {
4460 if (ec.value() == EBADR)
4461 {
4462 messages::resourceNotFound(asyncResp->res, "LogEntry",
4463 postCodeID);
4464 return;
4465 }
4466 if (ec)
4467 {
Ed Tanous62598e32023-07-17 17:06:25 -07004468 BMCWEB_LOG_DEBUG("DBUS response error {}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -07004469 messages::internalError(asyncResp->res);
4470 return;
4471 }
George Liu647b3cd2021-07-05 12:43:56 +08004472
Ed Tanous002d39b2022-05-31 08:59:27 -07004473 size_t value = static_cast<size_t>(currentValue) - 1;
4474 if (value == std::string::npos || postcodes.size() < currentValue)
4475 {
Ed Tanous62598e32023-07-17 17:06:25 -07004476 BMCWEB_LOG_WARNING("Wrong currentValue value");
Ed Tanous002d39b2022-05-31 08:59:27 -07004477 messages::resourceNotFound(asyncResp->res, "LogEntry",
4478 postCodeID);
4479 return;
4480 }
George Liu647b3cd2021-07-05 12:43:56 +08004481
Ed Tanous002d39b2022-05-31 08:59:27 -07004482 const auto& [tID, c] = postcodes[value];
4483 if (c.empty())
4484 {
Ed Tanous62598e32023-07-17 17:06:25 -07004485 BMCWEB_LOG_WARNING("No found post code data");
Ed Tanous002d39b2022-05-31 08:59:27 -07004486 messages::resourceNotFound(asyncResp->res, "LogEntry",
4487 postCodeID);
4488 return;
4489 }
4490 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
4491 const char* d = reinterpret_cast<const char*>(c.data());
4492 std::string_view strData(d, c.size());
George Liu647b3cd2021-07-05 12:43:56 +08004493
Ed Tanousd9f6c622022-03-17 09:12:17 -07004494 asyncResp->res.addHeader(boost::beast::http::field::content_type,
Ed Tanous002d39b2022-05-31 08:59:27 -07004495 "application/octet-stream");
Ed Tanousd9f6c622022-03-17 09:12:17 -07004496 asyncResp->res.addHeader(
4497 boost::beast::http::field::content_transfer_encoding, "Base64");
Ed Tanous27b0cf92023-08-07 12:02:40 -07004498 asyncResp->res.write(crow::utility::base64encode(strData));
Patrick Williams5a39f772023-10-20 11:20:21 -05004499 },
Ed Tanous002d39b2022-05-31 08:59:27 -07004500 "xyz.openbmc_project.State.Boot.PostCode0",
4501 "/xyz/openbmc_project/State/Boot/PostCode0",
4502 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodes", index);
Patrick Williams5a39f772023-10-20 11:20:21 -05004503 });
George Liu647b3cd2021-07-05 12:43:56 +08004504}
4505
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004506inline void requestRoutesPostCodesEntry(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08004507{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004508 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07004509 app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07004510 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004511 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07004512 [&app](const crow::Request& req,
4513 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07004514 const std::string& systemName, const std::string& targetID) {
Carson Labrado3ba00072022-06-06 19:40:56 +00004515 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07004516 {
4517 return;
4518 }
Ed Tanous25b54db2024-04-17 15:40:31 -07004519 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08004520 {
4521 // Option currently returns no systems. TBD
4522 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
4523 systemName);
4524 return;
4525 }
Ed Tanous253f11b2024-05-16 09:38:31 -07004526 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
Ed Tanous22d268c2022-05-19 09:39:07 -07004527 {
4528 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
4529 systemName);
4530 return;
4531 }
4532
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004533 getPostCodeForEntry(asyncResp, targetID);
Patrick Williams5a39f772023-10-20 11:20:21 -05004534 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004535}
ZhikuiRena3316fc2020-01-29 14:58:08 -08004536
Ed Tanous1da66f72018-07-27 16:13:37 -07004537} // namespace redfish