blob: 1453a4b11f11c695dd8dc7b921daa480592c46b3 [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 {
485 entriesPath = "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/";
486 }
487 else if (dumpType == "FaultLog")
488 {
489 entriesPath = "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/";
490 }
491 else if (dumpType == "System")
492 {
493 entriesPath = "/redfish/v1/Systems/system/LogServices/Dump/Entries/";
494 }
495 else
496 {
Ed Tanous62598e32023-07-17 17:06:25 -0700497 BMCWEB_LOG_ERROR("getDumpEntriesPath() invalid dump type: {}",
498 dumpType);
Claire Weinanfdd26902022-03-01 14:18:25 -0800499 }
500
501 // Returns empty string on error
502 return entriesPath;
503}
504
zhanghch058d1b46d2021-04-01 11:18:24 +0800505inline void
506 getDumpEntryCollection(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
507 const std::string& dumpType)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500508{
Claire Weinanfdd26902022-03-01 14:18:25 -0800509 std::string entriesPath = getDumpEntriesPath(dumpType);
510 if (entriesPath.empty())
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500511 {
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500512 messages::internalError(asyncResp->res);
513 return;
514 }
515
George Liu5eb468d2023-06-20 17:03:24 +0800516 sdbusplus::message::object_path path("/xyz/openbmc_project/dump");
517 dbus::utility::getManagedObjects(
518 "xyz.openbmc_project.Dump.Manager", path,
Claire Weinanfdd26902022-03-01 14:18:25 -0800519 [asyncResp, entriesPath,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800520 dumpType](const boost::system::error_code& ec,
George Liu5eb468d2023-06-20 17:03:24 +0800521 const dbus::utility::ManagedObjectType& objects) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700522 if (ec)
523 {
Ed Tanous62598e32023-07-17 17:06:25 -0700524 BMCWEB_LOG_ERROR("DumpEntry resp_handler got error {}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -0700525 messages::internalError(asyncResp->res);
526 return;
527 }
528
Claire Weinanfdd26902022-03-01 14:18:25 -0800529 // Remove ending slash
530 std::string odataIdStr = entriesPath;
531 if (!odataIdStr.empty())
532 {
533 odataIdStr.pop_back();
534 }
535
536 asyncResp->res.jsonValue["@odata.type"] =
537 "#LogEntryCollection.LogEntryCollection";
538 asyncResp->res.jsonValue["@odata.id"] = std::move(odataIdStr);
539 asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entries";
Patrick Williams89492a12023-05-10 07:51:34 -0500540 asyncResp->res.jsonValue["Description"] = "Collection of " + dumpType +
541 " Dump Entries";
Claire Weinanfdd26902022-03-01 14:18:25 -0800542
Ed Tanous3544d2a2023-08-06 18:12:20 -0700543 nlohmann::json::array_t entriesArray;
Ed Tanous18f8f602023-07-18 10:07:23 -0700544 std::string dumpEntryPath = getDumpPath(dumpType) + "/entry/";
Ed Tanous002d39b2022-05-31 08:59:27 -0700545
George Liu5eb468d2023-06-20 17:03:24 +0800546 dbus::utility::ManagedObjectType resp(objects);
Ed Tanous3544d2a2023-08-06 18:12:20 -0700547 std::ranges::sort(resp, [](const auto& l, const auto& r) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700548 return AlphanumLess<std::string>()(l.first.filename(),
549 r.first.filename());
550 });
551
552 for (auto& object : resp)
553 {
554 if (object.first.str.find(dumpEntryPath) == std::string::npos)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500555 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700556 continue;
557 }
Claire Weinanc6fecda2022-07-15 10:43:25 -0700558 uint64_t timestampUs = 0;
Ed Tanous002d39b2022-05-31 08:59:27 -0700559 uint64_t size = 0;
560 std::string dumpStatus;
Asmitha Karunanithi68dd0752022-11-15 11:33:46 -0600561 std::string originatorId;
562 log_entry::OriginatorTypes originatorType =
563 log_entry::OriginatorTypes::Internal;
Jason M. Bills433b68b2022-06-28 12:24:26 -0700564 nlohmann::json::object_t thisEntry;
Ed Tanous002d39b2022-05-31 08:59:27 -0700565
566 std::string entryID = object.first.filename();
567 if (entryID.empty())
568 {
569 continue;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500570 }
571
Claire Weinanc6fecda2022-07-15 10:43:25 -0700572 parseDumpEntryFromDbusObject(object, dumpStatus, size, timestampUs,
Asmitha Karunanithi68dd0752022-11-15 11:33:46 -0600573 originatorId, originatorType,
Claire Weinanaefe3782022-07-15 19:17:19 -0700574 asyncResp);
Ed Tanous002d39b2022-05-31 08:59:27 -0700575
576 if (dumpStatus !=
577 "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" &&
578 !dumpStatus.empty())
579 {
580 // Dump status is not Complete, no need to enumerate
581 continue;
582 }
583
Asmitha Karunanithi68dd0752022-11-15 11:33:46 -0600584 thisEntry["@odata.type"] = "#LogEntry.v1_11_0.LogEntry";
Claire Weinanfdd26902022-03-01 14:18:25 -0800585 thisEntry["@odata.id"] = entriesPath + entryID;
Ed Tanous002d39b2022-05-31 08:59:27 -0700586 thisEntry["Id"] = entryID;
587 thisEntry["EntryType"] = "Event";
Ed Tanous002d39b2022-05-31 08:59:27 -0700588 thisEntry["Name"] = dumpType + " Dump Entry";
Claire Weinanbbd80db2022-10-26 16:55:52 -0700589 thisEntry["Created"] =
590 redfish::time_utils::getDateTimeUintUs(timestampUs);
Ed Tanous002d39b2022-05-31 08:59:27 -0700591
Asmitha Karunanithi68dd0752022-11-15 11:33:46 -0600592 if (!originatorId.empty())
593 {
594 thisEntry["Originator"] = originatorId;
595 thisEntry["OriginatorType"] = originatorType;
596 }
597
Ed Tanous002d39b2022-05-31 08:59:27 -0700598 if (dumpType == "BMC")
599 {
600 thisEntry["DiagnosticDataType"] = "Manager";
Patrick Williams89492a12023-05-10 07:51:34 -0500601 thisEntry["AdditionalDataURI"] = entriesPath + entryID +
602 "/attachment";
Claire Weinanfdd26902022-03-01 14:18:25 -0800603 thisEntry["AdditionalDataSizeBytes"] = size;
Ed Tanous002d39b2022-05-31 08:59:27 -0700604 }
605 else if (dumpType == "System")
606 {
607 thisEntry["DiagnosticDataType"] = "OEM";
608 thisEntry["OEMDiagnosticDataType"] = "System";
Patrick Williams89492a12023-05-10 07:51:34 -0500609 thisEntry["AdditionalDataURI"] = entriesPath + entryID +
610 "/attachment";
Claire Weinanfdd26902022-03-01 14:18:25 -0800611 thisEntry["AdditionalDataSizeBytes"] = size;
Ed Tanous002d39b2022-05-31 08:59:27 -0700612 }
Patrick Williamsb2ba3072023-05-12 10:27:39 -0500613 entriesArray.emplace_back(std::move(thisEntry));
Ed Tanous002d39b2022-05-31 08:59:27 -0700614 }
615 asyncResp->res.jsonValue["Members@odata.count"] = entriesArray.size();
Ed Tanous3544d2a2023-08-06 18:12:20 -0700616 asyncResp->res.jsonValue["Members"] = std::move(entriesArray);
Patrick Williams5a39f772023-10-20 11:20:21 -0500617 });
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500618}
619
zhanghch058d1b46d2021-04-01 11:18:24 +0800620inline void
Claire Weinanc7a6d662022-06-13 16:36:39 -0700621 getDumpEntryById(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
zhanghch058d1b46d2021-04-01 11:18:24 +0800622 const std::string& entryID, const std::string& dumpType)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500623{
Claire Weinanfdd26902022-03-01 14:18:25 -0800624 std::string entriesPath = getDumpEntriesPath(dumpType);
625 if (entriesPath.empty())
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500626 {
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500627 messages::internalError(asyncResp->res);
628 return;
629 }
630
George Liu5eb468d2023-06-20 17:03:24 +0800631 sdbusplus::message::object_path path("/xyz/openbmc_project/dump");
632 dbus::utility::getManagedObjects(
633 "xyz.openbmc_project.Dump.Manager", path,
Claire Weinanfdd26902022-03-01 14:18:25 -0800634 [asyncResp, entryID, dumpType,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800635 entriesPath](const boost::system::error_code& ec,
Ed Tanous02cad962022-06-30 16:50:15 -0700636 const dbus::utility::ManagedObjectType& resp) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700637 if (ec)
638 {
Ed Tanous62598e32023-07-17 17:06:25 -0700639 BMCWEB_LOG_ERROR("DumpEntry resp_handler got error {}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -0700640 messages::internalError(asyncResp->res);
641 return;
642 }
643
644 bool foundDumpEntry = false;
Ed Tanous18f8f602023-07-18 10:07:23 -0700645 std::string dumpEntryPath = getDumpPath(dumpType) + "/entry/";
Ed Tanous002d39b2022-05-31 08:59:27 -0700646
647 for (const auto& objectPath : resp)
648 {
649 if (objectPath.first.str != dumpEntryPath + entryID)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500650 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700651 continue;
652 }
653
654 foundDumpEntry = true;
Claire Weinanc6fecda2022-07-15 10:43:25 -0700655 uint64_t timestampUs = 0;
Ed Tanous002d39b2022-05-31 08:59:27 -0700656 uint64_t size = 0;
657 std::string dumpStatus;
Asmitha Karunanithi68dd0752022-11-15 11:33:46 -0600658 std::string originatorId;
659 log_entry::OriginatorTypes originatorType =
660 log_entry::OriginatorTypes::Internal;
Ed Tanous002d39b2022-05-31 08:59:27 -0700661
Claire Weinanaefe3782022-07-15 19:17:19 -0700662 parseDumpEntryFromDbusObject(objectPath, dumpStatus, size,
Asmitha Karunanithi68dd0752022-11-15 11:33:46 -0600663 timestampUs, originatorId,
664 originatorType, asyncResp);
Ed Tanous002d39b2022-05-31 08:59:27 -0700665
666 if (dumpStatus !=
667 "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" &&
668 !dumpStatus.empty())
669 {
670 // Dump status is not Complete
671 // return not found until status is changed to Completed
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200672 messages::resourceNotFound(asyncResp->res, dumpType + " dump",
673 entryID);
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500674 return;
675 }
676
Ed Tanous002d39b2022-05-31 08:59:27 -0700677 asyncResp->res.jsonValue["@odata.type"] =
Asmitha Karunanithi68dd0752022-11-15 11:33:46 -0600678 "#LogEntry.v1_11_0.LogEntry";
Claire Weinanfdd26902022-03-01 14:18:25 -0800679 asyncResp->res.jsonValue["@odata.id"] = entriesPath + entryID;
Ed Tanous002d39b2022-05-31 08:59:27 -0700680 asyncResp->res.jsonValue["Id"] = entryID;
681 asyncResp->res.jsonValue["EntryType"] = "Event";
Ed Tanous002d39b2022-05-31 08:59:27 -0700682 asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entry";
Claire Weinanbbd80db2022-10-26 16:55:52 -0700683 asyncResp->res.jsonValue["Created"] =
684 redfish::time_utils::getDateTimeUintUs(timestampUs);
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500685
Asmitha Karunanithi68dd0752022-11-15 11:33:46 -0600686 if (!originatorId.empty())
687 {
688 asyncResp->res.jsonValue["Originator"] = originatorId;
689 asyncResp->res.jsonValue["OriginatorType"] = originatorType;
690 }
691
Ed Tanous002d39b2022-05-31 08:59:27 -0700692 if (dumpType == "BMC")
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500693 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700694 asyncResp->res.jsonValue["DiagnosticDataType"] = "Manager";
695 asyncResp->res.jsonValue["AdditionalDataURI"] =
Claire Weinanfdd26902022-03-01 14:18:25 -0800696 entriesPath + entryID + "/attachment";
697 asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500698 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700699 else if (dumpType == "System")
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500700 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700701 asyncResp->res.jsonValue["DiagnosticDataType"] = "OEM";
702 asyncResp->res.jsonValue["OEMDiagnosticDataType"] = "System";
703 asyncResp->res.jsonValue["AdditionalDataURI"] =
Claire Weinanfdd26902022-03-01 14:18:25 -0800704 entriesPath + entryID + "/attachment";
705 asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size;
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500706 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700707 }
708 if (!foundDumpEntry)
709 {
Ed Tanous62598e32023-07-17 17:06:25 -0700710 BMCWEB_LOG_WARNING("Can't find Dump Entry {}", entryID);
Myung Baeb90d14f2023-05-31 14:40:39 -0500711 messages::resourceNotFound(asyncResp->res, dumpType + " dump",
712 entryID);
Ed Tanous002d39b2022-05-31 08:59:27 -0700713 return;
714 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500715 });
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500716}
717
zhanghch058d1b46d2021-04-01 11:18:24 +0800718inline void deleteDumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Stanley Chu98782562020-11-04 16:10:24 +0800719 const std::string& entryID,
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500720 const std::string& dumpType)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500721{
Patrick Williams5a39f772023-10-20 11:20:21 -0500722 auto respHandler = [asyncResp,
723 entryID](const boost::system::error_code& ec) {
Ed Tanous62598e32023-07-17 17:06:25 -0700724 BMCWEB_LOG_DEBUG("Dump Entry doDelete callback: Done");
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500725 if (ec)
726 {
George Liu3de8d8b2021-03-22 17:49:39 +0800727 if (ec.value() == EBADR)
728 {
729 messages::resourceNotFound(asyncResp->res, "LogEntry", entryID);
730 return;
731 }
Ed Tanous62598e32023-07-17 17:06:25 -0700732 BMCWEB_LOG_ERROR(
733 "Dump (DBus) doDelete respHandler got error {} entryID={}", ec,
734 entryID);
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500735 messages::internalError(asyncResp->res);
736 return;
737 }
738 };
Ed Tanous18f8f602023-07-18 10:07:23 -0700739
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500740 crow::connections::systemBus->async_method_call(
741 respHandler, "xyz.openbmc_project.Dump.Manager",
Ed Tanous18f8f602023-07-18 10:07:23 -0700742 std::format("{}/entry/{}", getDumpPath(dumpType), entryID),
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500743 "xyz.openbmc_project.Object.Delete", "Delete");
744}
Abhilash Rajub5f288d2023-11-08 22:32:44 -0600745inline bool checkSizeLimit(int fd, crow::Response& res)
746{
747 long long int size = lseek(fd, 0, SEEK_END);
748 if (size <= 0)
749 {
750 BMCWEB_LOG_ERROR("Failed to get size of file, lseek() returned {}",
751 size);
752 messages::internalError(res);
753 return false;
754 }
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500755
Abhilash Rajub5f288d2023-11-08 22:32:44 -0600756 // Arbitrary max size of 20MB to accommodate BMC dumps
757 constexpr long long int maxFileSize = 20LL * 1024LL * 1024LL;
758 if (size > maxFileSize)
759 {
760 BMCWEB_LOG_ERROR("File size {} exceeds maximum allowed size of {}",
761 size, maxFileSize);
762 messages::internalError(res);
763 return false;
764 }
765 off_t rc = lseek(fd, 0, SEEK_SET);
766 if (rc < 0)
767 {
768 BMCWEB_LOG_ERROR("Failed to reset file offset to 0");
769 messages::internalError(res);
770 return false;
771 }
772 return true;
773}
Carson Labrado168d1b12023-03-27 17:04:46 +0000774inline void
775 downloadEntryCallback(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
776 const std::string& entryID,
777 const std::string& downloadEntryType,
778 const boost::system::error_code& ec,
779 const sdbusplus::message::unix_fd& unixfd)
780{
781 if (ec.value() == EBADR)
782 {
783 messages::resourceNotFound(asyncResp->res, "EntryAttachment", entryID);
784 return;
785 }
786 if (ec)
787 {
788 BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
789 messages::internalError(asyncResp->res);
790 return;
791 }
792
793 // Make sure we know how to process the retrieved entry attachment
794 if ((downloadEntryType != "BMC") && (downloadEntryType != "System"))
795 {
796 BMCWEB_LOG_ERROR("downloadEntryCallback() invalid entry type: {}",
797 downloadEntryType);
798 messages::internalError(asyncResp->res);
799 }
800
801 int fd = -1;
802 fd = dup(unixfd);
803 if (fd < 0)
804 {
805 BMCWEB_LOG_ERROR("Failed to open file");
806 messages::internalError(asyncResp->res);
807 return;
808 }
Abhilash Rajub5f288d2023-11-08 22:32:44 -0600809 if (!checkSizeLimit(fd, asyncResp->res))
Carson Labrado168d1b12023-03-27 17:04:46 +0000810 {
Carson Labrado168d1b12023-03-27 17:04:46 +0000811 close(fd);
812 return;
813 }
Carson Labrado168d1b12023-03-27 17:04:46 +0000814 if (downloadEntryType == "System")
815 {
Abhilash Rajub5f288d2023-11-08 22:32:44 -0600816 if (!asyncResp->res.openFd(fd, bmcweb::EncodingType::Base64))
817 {
818 messages::internalError(asyncResp->res);
819 close(fd);
820 return;
821 }
Carson Labrado168d1b12023-03-27 17:04:46 +0000822 asyncResp->res.addHeader(
823 boost::beast::http::field::content_transfer_encoding, "Base64");
Abhilash Rajub5f288d2023-11-08 22:32:44 -0600824 return;
Carson Labrado168d1b12023-03-27 17:04:46 +0000825 }
Abhilash Rajub5f288d2023-11-08 22:32:44 -0600826 if (!asyncResp->res.openFd(fd))
Ed Tanous27b0cf92023-08-07 12:02:40 -0700827 {
Abhilash Rajub5f288d2023-11-08 22:32:44 -0600828 messages::internalError(asyncResp->res);
829 close(fd);
830 return;
Ed Tanous27b0cf92023-08-07 12:02:40 -0700831 }
Carson Labrado168d1b12023-03-27 17:04:46 +0000832 asyncResp->res.addHeader(boost::beast::http::field::content_type,
833 "application/octet-stream");
834}
835
836inline void
837 downloadDumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
838 const std::string& entryID, const std::string& dumpType)
839{
840 if (dumpType != "BMC")
841 {
842 BMCWEB_LOG_WARNING("Can't find Dump Entry {}", entryID);
843 messages::resourceNotFound(asyncResp->res, dumpType + " dump", entryID);
844 return;
845 }
846
Ed Tanous18f8f602023-07-18 10:07:23 -0700847 std::string dumpEntryPath = std::format("{}/entry/{}",
848 getDumpPath(dumpType), entryID);
Carson Labrado168d1b12023-03-27 17:04:46 +0000849
850 auto downloadDumpEntryHandler =
851 [asyncResp, entryID,
852 dumpType](const boost::system::error_code& ec,
853 const sdbusplus::message::unix_fd& unixfd) {
854 downloadEntryCallback(asyncResp, entryID, dumpType, ec, unixfd);
855 };
856
857 crow::connections::systemBus->async_method_call(
858 std::move(downloadDumpEntryHandler), "xyz.openbmc_project.Dump.Manager",
859 dumpEntryPath, "xyz.openbmc_project.Dump.Entry", "GetFileHandle");
860}
861
862inline void
863 downloadEventLogEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
864 const std::string& systemName,
865 const std::string& entryID,
866 const std::string& dumpType)
867{
Ed Tanous25b54db2024-04-17 15:40:31 -0700868 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Carson Labrado168d1b12023-03-27 17:04:46 +0000869 {
870 // Option currently returns no systems. TBD
871 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
872 systemName);
873 return;
874 }
875 if (systemName != "system")
876 {
877 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
878 systemName);
879 return;
880 }
881
882 std::string entryPath =
883 sdbusplus::message::object_path("/xyz/openbmc_project/logging/entry") /
884 entryID;
885
886 auto downloadEventLogEntryHandler =
887 [asyncResp, entryID,
888 dumpType](const boost::system::error_code& ec,
889 const sdbusplus::message::unix_fd& unixfd) {
890 downloadEntryCallback(asyncResp, entryID, dumpType, ec, unixfd);
891 };
892
893 crow::connections::systemBus->async_method_call(
894 std::move(downloadEventLogEntryHandler), "xyz.openbmc_project.Logging",
895 entryPath, "xyz.openbmc_project.Logging.Entry", "GetEntry");
896}
897
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600898inline DumpCreationProgress
899 mapDbusStatusToDumpProgress(const std::string& status)
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500900{
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600901 if (status ==
902 "xyz.openbmc_project.Common.Progress.OperationStatus.Failed" ||
903 status == "xyz.openbmc_project.Common.Progress.OperationStatus.Aborted")
904 {
905 return DumpCreationProgress::DUMP_CREATE_FAILED;
906 }
907 if (status ==
908 "xyz.openbmc_project.Common.Progress.OperationStatus.Completed")
909 {
910 return DumpCreationProgress::DUMP_CREATE_SUCCESS;
911 }
912 return DumpCreationProgress::DUMP_CREATE_INPROGRESS;
913}
914
915inline DumpCreationProgress
916 getDumpCompletionStatus(const dbus::utility::DBusPropertiesMap& values)
917{
918 for (const auto& [key, val] : values)
919 {
920 if (key == "Status")
Ed Tanous002d39b2022-05-31 08:59:27 -0700921 {
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600922 const std::string* value = std::get_if<std::string>(&val);
923 if (value == nullptr)
924 {
Ed Tanous62598e32023-07-17 17:06:25 -0700925 BMCWEB_LOG_ERROR("Status property value is null");
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600926 return DumpCreationProgress::DUMP_CREATE_FAILED;
927 }
928 return mapDbusStatusToDumpProgress(*value);
929 }
930 }
931 return DumpCreationProgress::DUMP_CREATE_INPROGRESS;
932}
933
934inline std::string getDumpEntryPath(const std::string& dumpPath)
935{
936 if (dumpPath == "/xyz/openbmc_project/dump/bmc/entry")
937 {
938 return "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/";
939 }
940 if (dumpPath == "/xyz/openbmc_project/dump/system/entry")
941 {
942 return "/redfish/v1/Systems/system/LogServices/Dump/Entries/";
943 }
944 return "";
945}
946
947inline void createDumpTaskCallback(
948 task::Payload&& payload,
949 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
950 const sdbusplus::message::object_path& createdObjPath)
951{
952 const std::string dumpPath = createdObjPath.parent_path().str;
953 const std::string dumpId = createdObjPath.filename();
954
955 std::string dumpEntryPath = getDumpEntryPath(dumpPath);
956
957 if (dumpEntryPath.empty())
958 {
Ed Tanous62598e32023-07-17 17:06:25 -0700959 BMCWEB_LOG_ERROR("Invalid dump type received");
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600960 messages::internalError(asyncResp->res);
961 return;
962 }
963
964 crow::connections::systemBus->async_method_call(
Ed Tanous8cb2c022024-03-27 16:31:46 -0700965 [asyncResp, payload = std::move(payload), createdObjPath,
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600966 dumpEntryPath{std::move(dumpEntryPath)},
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800967 dumpId](const boost::system::error_code& ec,
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600968 const std::string& introspectXml) {
969 if (ec)
970 {
Ed Tanous62598e32023-07-17 17:06:25 -0700971 BMCWEB_LOG_ERROR("Introspect call failed with error: {}",
972 ec.message());
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600973 messages::internalError(asyncResp->res);
974 return;
Ed Tanous002d39b2022-05-31 08:59:27 -0700975 }
976
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600977 // Check if the created dump object has implemented Progress
978 // interface to track dump completion. If yes, fetch the "Status"
979 // property of the interface, modify the task state accordingly.
980 // Else, return task completed.
981 tinyxml2::XMLDocument doc;
Ed Tanous002d39b2022-05-31 08:59:27 -0700982
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600983 doc.Parse(introspectXml.data(), introspectXml.size());
984 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
985 if (pRoot == nullptr)
Ed Tanous002d39b2022-05-31 08:59:27 -0700986 {
Ed Tanous62598e32023-07-17 17:06:25 -0700987 BMCWEB_LOG_ERROR("XML document failed to parse");
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600988 messages::internalError(asyncResp->res);
989 return;
990 }
991 tinyxml2::XMLElement* interfaceNode =
992 pRoot->FirstChildElement("interface");
993
994 bool isProgressIntfPresent = false;
995 while (interfaceNode != nullptr)
996 {
997 const char* thisInterfaceName = interfaceNode->Attribute("name");
998 if (thisInterfaceName != nullptr)
999 {
1000 if (thisInterfaceName ==
1001 std::string_view("xyz.openbmc_project.Common.Progress"))
1002 {
1003 interfaceNode =
1004 interfaceNode->NextSiblingElement("interface");
1005 continue;
1006 }
1007 isProgressIntfPresent = true;
1008 break;
1009 }
1010 interfaceNode = interfaceNode->NextSiblingElement("interface");
1011 }
1012
1013 std::shared_ptr<task::TaskData> task = task::TaskData::createTask(
1014 [createdObjPath, dumpEntryPath, dumpId, isProgressIntfPresent](
Ed Tanous8b242752023-06-27 17:17:13 -07001015 const boost::system::error_code& ec2, sdbusplus::message_t& msg,
Asmitha Karunanithi8e317782020-12-10 03:35:05 -06001016 const std::shared_ptr<task::TaskData>& taskData) {
Ed Tanous8b242752023-06-27 17:17:13 -07001017 if (ec2)
Asmitha Karunanithi8e317782020-12-10 03:35:05 -06001018 {
Ed Tanous62598e32023-07-17 17:06:25 -07001019 BMCWEB_LOG_ERROR("{}: Error in creating dump",
1020 createdObjPath.str);
Asmitha Karunanithi8e317782020-12-10 03:35:05 -06001021 taskData->messages.emplace_back(messages::internalError());
1022 taskData->state = "Cancelled";
1023 return task::completed;
1024 }
1025
1026 if (isProgressIntfPresent)
1027 {
1028 dbus::utility::DBusPropertiesMap values;
1029 std::string prop;
1030 msg.read(prop, values);
1031
1032 DumpCreationProgress dumpStatus =
1033 getDumpCompletionStatus(values);
1034 if (dumpStatus == DumpCreationProgress::DUMP_CREATE_FAILED)
1035 {
Ed Tanous62598e32023-07-17 17:06:25 -07001036 BMCWEB_LOG_ERROR("{}: Error in creating dump",
1037 createdObjPath.str);
Asmitha Karunanithi8e317782020-12-10 03:35:05 -06001038 taskData->state = "Cancelled";
1039 return task::completed;
1040 }
1041
1042 if (dumpStatus == DumpCreationProgress::DUMP_CREATE_INPROGRESS)
1043 {
Ed Tanous62598e32023-07-17 17:06:25 -07001044 BMCWEB_LOG_DEBUG("{}: Dump creation task is in progress",
1045 createdObjPath.str);
Asmitha Karunanithi8e317782020-12-10 03:35:05 -06001046 return !task::completed;
1047 }
1048 }
1049
Ed Tanous002d39b2022-05-31 08:59:27 -07001050 nlohmann::json retMessage = messages::success();
1051 taskData->messages.emplace_back(retMessage);
1052
Ed Tanousc51a58e2023-03-27 14:43:19 -07001053 boost::urls::url url = boost::urls::format(
1054 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/{}", dumpId);
1055
1056 std::string headerLoc = "Location: ";
1057 headerLoc += url.buffer();
1058
Ed Tanous002d39b2022-05-31 08:59:27 -07001059 taskData->payload->httpHeaders.emplace_back(std::move(headerLoc));
1060
Ed Tanous62598e32023-07-17 17:06:25 -07001061 BMCWEB_LOG_DEBUG("{}: Dump creation task completed",
1062 createdObjPath.str);
Ed Tanous002d39b2022-05-31 08:59:27 -07001063 taskData->state = "Completed";
1064 return task::completed;
Patrick Williams5a39f772023-10-20 11:20:21 -05001065 },
Asmitha Karunanithi8e317782020-12-10 03:35:05 -06001066 "type='signal',interface='org.freedesktop.DBus.Properties',"
1067 "member='PropertiesChanged',path='" +
1068 createdObjPath.str + "'");
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001069
Asmitha Karunanithi8e317782020-12-10 03:35:05 -06001070 // The task timer is set to max time limit within which the
1071 // requested dump will be collected.
1072 task->startTimer(std::chrono::minutes(6));
1073 task->populateResp(asyncResp->res);
1074 task->payload.emplace(payload);
Patrick Williams5a39f772023-10-20 11:20:21 -05001075 },
Asmitha Karunanithi8e317782020-12-10 03:35:05 -06001076 "xyz.openbmc_project.Dump.Manager", createdObjPath,
1077 "org.freedesktop.DBus.Introspectable", "Introspect");
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001078}
1079
zhanghch058d1b46d2021-04-01 11:18:24 +08001080inline void createDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1081 const crow::Request& req, const std::string& dumpType)
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001082{
Claire Weinanfdd26902022-03-01 14:18:25 -08001083 std::string dumpPath = getDumpEntriesPath(dumpType);
1084 if (dumpPath.empty())
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001085 {
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001086 messages::internalError(asyncResp->res);
1087 return;
1088 }
1089
1090 std::optional<std::string> diagnosticDataType;
1091 std::optional<std::string> oemDiagnosticDataType;
1092
Willy Tu15ed6782021-12-14 11:03:16 -08001093 if (!redfish::json_util::readJsonAction(
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001094 req, asyncResp->res, "DiagnosticDataType", diagnosticDataType,
1095 "OEMDiagnosticDataType", oemDiagnosticDataType))
1096 {
1097 return;
1098 }
1099
1100 if (dumpType == "System")
1101 {
1102 if (!oemDiagnosticDataType || !diagnosticDataType)
1103 {
Ed Tanous62598e32023-07-17 17:06:25 -07001104 BMCWEB_LOG_ERROR(
1105 "CreateDump action parameter 'DiagnosticDataType'/'OEMDiagnosticDataType' value not found!");
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001106 messages::actionParameterMissing(
1107 asyncResp->res, "CollectDiagnosticData",
1108 "DiagnosticDataType & OEMDiagnosticDataType");
1109 return;
1110 }
Ed Tanous3174e4d2020-10-07 11:41:22 -07001111 if ((*oemDiagnosticDataType != "System") ||
1112 (*diagnosticDataType != "OEM"))
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001113 {
Ed Tanous62598e32023-07-17 17:06:25 -07001114 BMCWEB_LOG_ERROR("Wrong parameter values passed");
Ed Tanousace85d62021-10-26 12:45:59 -07001115 messages::internalError(asyncResp->res);
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001116 return;
1117 }
Asmitha Karunanithi59075712021-10-22 01:17:41 -05001118 dumpPath = "/redfish/v1/Systems/system/LogServices/Dump/";
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001119 }
1120 else if (dumpType == "BMC")
1121 {
1122 if (!diagnosticDataType)
1123 {
Ed Tanous62598e32023-07-17 17:06:25 -07001124 BMCWEB_LOG_ERROR(
1125 "CreateDump action parameter 'DiagnosticDataType' not found!");
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001126 messages::actionParameterMissing(
1127 asyncResp->res, "CollectDiagnosticData", "DiagnosticDataType");
1128 return;
1129 }
Ed Tanous3174e4d2020-10-07 11:41:22 -07001130 if (*diagnosticDataType != "Manager")
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001131 {
Ed Tanous62598e32023-07-17 17:06:25 -07001132 BMCWEB_LOG_ERROR(
1133 "Wrong parameter value passed for 'DiagnosticDataType'");
Ed Tanousace85d62021-10-26 12:45:59 -07001134 messages::internalError(asyncResp->res);
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001135 return;
1136 }
Asmitha Karunanithi59075712021-10-22 01:17:41 -05001137 dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump/";
1138 }
1139 else
1140 {
Ed Tanous62598e32023-07-17 17:06:25 -07001141 BMCWEB_LOG_ERROR("CreateDump failed. Unknown dump type");
Asmitha Karunanithi59075712021-10-22 01:17:41 -05001142 messages::internalError(asyncResp->res);
1143 return;
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001144 }
1145
Asmitha Karunanithi8e317782020-12-10 03:35:05 -06001146 std::vector<std::pair<std::string, std::variant<std::string, uint64_t>>>
1147 createDumpParamVec;
1148
Carson Labradof574a8e2023-03-22 02:26:00 +00001149 if (req.session != nullptr)
1150 {
1151 createDumpParamVec.emplace_back(
1152 "xyz.openbmc_project.Dump.Create.CreateParameters.OriginatorId",
1153 req.session->clientIp);
1154 createDumpParamVec.emplace_back(
1155 "xyz.openbmc_project.Dump.Create.CreateParameters.OriginatorType",
1156 "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.Client");
1157 }
Asmitha Karunanithi68dd0752022-11-15 11:33:46 -06001158
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001159 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001160 [asyncResp, payload(task::Payload(req)),
1161 dumpPath](const boost::system::error_code& ec,
1162 const sdbusplus::message_t& msg,
1163 const sdbusplus::message::object_path& objPath) mutable {
Ed Tanous002d39b2022-05-31 08:59:27 -07001164 if (ec)
1165 {
Ed Tanous62598e32023-07-17 17:06:25 -07001166 BMCWEB_LOG_ERROR("CreateDump resp_handler got error {}", ec);
Asmitha Karunanithi59075712021-10-22 01:17:41 -05001167 const sd_bus_error* dbusError = msg.get_error();
1168 if (dbusError == nullptr)
1169 {
1170 messages::internalError(asyncResp->res);
1171 return;
1172 }
1173
Ed Tanous62598e32023-07-17 17:06:25 -07001174 BMCWEB_LOG_ERROR("CreateDump DBus error: {} and error msg: {}",
1175 dbusError->name, dbusError->message);
Asmitha Karunanithi59075712021-10-22 01:17:41 -05001176 if (std::string_view(
1177 "xyz.openbmc_project.Common.Error.NotAllowed") ==
1178 dbusError->name)
1179 {
1180 messages::resourceInStandby(asyncResp->res);
1181 return;
1182 }
1183 if (std::string_view(
1184 "xyz.openbmc_project.Dump.Create.Error.Disabled") ==
1185 dbusError->name)
1186 {
1187 messages::serviceDisabled(asyncResp->res, dumpPath);
1188 return;
1189 }
1190 if (std::string_view(
1191 "xyz.openbmc_project.Common.Error.Unavailable") ==
1192 dbusError->name)
1193 {
1194 messages::resourceInUse(asyncResp->res);
1195 return;
1196 }
1197 // Other Dbus errors such as:
1198 // xyz.openbmc_project.Common.Error.InvalidArgument &
1199 // org.freedesktop.DBus.Error.InvalidArgs are all related to
1200 // the dbus call that is made here in the bmcweb
1201 // implementation and has nothing to do with the client's
1202 // input in the request. Hence, returning internal error
1203 // back to the client.
Ed Tanous002d39b2022-05-31 08:59:27 -07001204 messages::internalError(asyncResp->res);
1205 return;
1206 }
Ed Tanous62598e32023-07-17 17:06:25 -07001207 BMCWEB_LOG_DEBUG("Dump Created. Path: {}", objPath.str);
Asmitha Karunanithi8e317782020-12-10 03:35:05 -06001208 createDumpTaskCallback(std::move(payload), asyncResp, objPath);
Patrick Williams5a39f772023-10-20 11:20:21 -05001209 },
Ed Tanous18f8f602023-07-18 10:07:23 -07001210 "xyz.openbmc_project.Dump.Manager", getDumpPath(dumpType),
Asmitha Karunanithi8e317782020-12-10 03:35:05 -06001211 "xyz.openbmc_project.Dump.Create", "CreateDump", createDumpParamVec);
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001212}
1213
zhanghch058d1b46d2021-04-01 11:18:24 +08001214inline void clearDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1215 const std::string& dumpType)
Asmitha Karunanithi80319af2020-05-07 05:30:21 -05001216{
Claire Weinan0d946212022-07-13 19:40:19 -07001217 crow::connections::systemBus->async_method_call(
1218 [asyncResp](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001219 if (ec)
1220 {
Ed Tanous62598e32023-07-17 17:06:25 -07001221 BMCWEB_LOG_ERROR("clearDump resp_handler got error {}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -07001222 messages::internalError(asyncResp->res);
1223 return;
1224 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001225 },
Ed Tanous18f8f602023-07-18 10:07:23 -07001226 "xyz.openbmc_project.Dump.Manager", getDumpPath(dumpType),
Claire Weinan0d946212022-07-13 19:40:19 -07001227 "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
Asmitha Karunanithi80319af2020-05-07 05:30:21 -05001228}
1229
Ed Tanousdf254f22024-04-01 13:25:46 -07001230inline void
Ed Tanousb9d36b42022-02-26 21:42:46 -08001231 parseCrashdumpParameters(const dbus::utility::DBusPropertiesMap& params,
1232 std::string& filename, std::string& timestamp,
1233 std::string& logfile)
Johnathan Mantey043a0532020-03-10 17:15:28 -07001234{
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001235 const std::string* filenamePtr = nullptr;
1236 const std::string* timestampPtr = nullptr;
1237 const std::string* logfilePtr = nullptr;
1238
1239 const bool success = sdbusplus::unpackPropertiesNoThrow(
1240 dbus_utils::UnpackErrorPrinter(), params, "Timestamp", timestampPtr,
1241 "Filename", filenamePtr, "Log", logfilePtr);
1242
1243 if (!success)
Johnathan Mantey043a0532020-03-10 17:15:28 -07001244 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001245 return;
1246 }
1247
1248 if (filenamePtr != nullptr)
1249 {
1250 filename = *filenamePtr;
1251 }
1252
1253 if (timestampPtr != nullptr)
1254 {
1255 timestamp = *timestampPtr;
1256 }
1257
1258 if (logfilePtr != nullptr)
1259 {
1260 logfile = *logfilePtr;
Johnathan Mantey043a0532020-03-10 17:15:28 -07001261 }
1262}
1263
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001264inline void requestRoutesSystemLogServiceCollection(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07001265{
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001266 /**
1267 * Functions triggers appropriate requests on DBus
1268 */
Ed Tanous22d268c2022-05-19 09:39:07 -07001269 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/")
Ed Tanoused398212021-06-09 17:05:54 -07001270 .privileges(redfish::privileges::getLogServiceCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07001271 .methods(boost::beast::http::verb::get)(
1272 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001273 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1274 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001275 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001276 {
1277 return;
1278 }
Ed Tanous25b54db2024-04-17 15:40:31 -07001279 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08001280 {
1281 // Option currently returns no systems. TBD
1282 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1283 systemName);
1284 return;
1285 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001286 if (systemName != "system")
1287 {
1288 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1289 systemName);
1290 return;
1291 }
1292
Ed Tanous002d39b2022-05-31 08:59:27 -07001293 // Collections don't include the static data added by SubRoute
1294 // because it has a duplicate entry for members
1295 asyncResp->res.jsonValue["@odata.type"] =
1296 "#LogServiceCollection.LogServiceCollection";
1297 asyncResp->res.jsonValue["@odata.id"] =
1298 "/redfish/v1/Systems/system/LogServices";
1299 asyncResp->res.jsonValue["Name"] = "System Log Services Collection";
1300 asyncResp->res.jsonValue["Description"] =
1301 "Collection of LogServices for this Computer System";
1302 nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"];
1303 logServiceArray = nlohmann::json::array();
1304 nlohmann::json::object_t eventLog;
1305 eventLog["@odata.id"] =
1306 "/redfish/v1/Systems/system/LogServices/EventLog";
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001307 logServiceArray.emplace_back(std::move(eventLog));
Ed Tanous25b54db2024-04-17 15:40:31 -07001308 if constexpr (BMCWEB_REDFISH_DUMP_LOG)
1309 {
1310 nlohmann::json::object_t dumpLog;
1311 dumpLog["@odata.id"] =
1312 "/redfish/v1/Systems/system/LogServices/Dump";
1313 logServiceArray.emplace_back(std::move(dumpLog));
1314 }
raviteja-bc9bb6862020-02-03 11:53:32 -06001315
Ed Tanous25b54db2024-04-17 15:40:31 -07001316 if constexpr (BMCWEB_REDFISH_DUMP_LOG)
1317 {
1318 nlohmann::json::object_t crashdump;
1319 crashdump["@odata.id"] =
1320 "/redfish/v1/Systems/system/LogServices/Crashdump";
1321 logServiceArray.emplace_back(std::move(crashdump));
1322 }
Spencer Kub7028eb2021-10-26 15:27:35 +08001323
Ed Tanous25b54db2024-04-17 15:40:31 -07001324 if constexpr (BMCWEB_REDFISH_HOST_LOGGER)
1325 {
1326 nlohmann::json::object_t hostlogger;
1327 hostlogger["@odata.id"] =
1328 "/redfish/v1/Systems/system/LogServices/HostLogger";
1329 logServiceArray.emplace_back(std::move(hostlogger));
1330 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001331 asyncResp->res.jsonValue["Members@odata.count"] =
1332 logServiceArray.size();
ZhikuiRena3316fc2020-01-29 14:58:08 -08001333
George Liu7a1dbc42022-12-07 16:03:22 +08001334 constexpr std::array<std::string_view, 1> interfaces = {
1335 "xyz.openbmc_project.State.Boot.PostCode"};
1336 dbus::utility::getSubTreePaths(
1337 "/", 0, interfaces,
1338 [asyncResp](const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -07001339 const dbus::utility::MapperGetSubTreePathsResponse&
1340 subtreePath) {
1341 if (ec)
1342 {
Ed Tanous62598e32023-07-17 17:06:25 -07001343 BMCWEB_LOG_ERROR("{}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -07001344 return;
1345 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07001346
Ed Tanous002d39b2022-05-31 08:59:27 -07001347 for (const auto& pathStr : subtreePath)
1348 {
1349 if (pathStr.find("PostCode") != std::string::npos)
1350 {
1351 nlohmann::json& logServiceArrayLocal =
1352 asyncResp->res.jsonValue["Members"];
Ed Tanous613dabe2022-07-09 11:17:36 -07001353 nlohmann::json::object_t member;
1354 member["@odata.id"] =
1355 "/redfish/v1/Systems/system/LogServices/PostCodes";
1356
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001357 logServiceArrayLocal.emplace_back(std::move(member));
Ed Tanous613dabe2022-07-09 11:17:36 -07001358
Ed Tanous002d39b2022-05-31 08:59:27 -07001359 asyncResp->res.jsonValue["Members@odata.count"] =
1360 logServiceArrayLocal.size();
1361 return;
1362 }
1363 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07001364 });
Patrick Williams5a39f772023-10-20 11:20:21 -05001365 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001366}
1367
1368inline void requestRoutesEventLogService(App& app)
1369{
Ed Tanous22d268c2022-05-19 09:39:07 -07001370 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/")
Ed Tanoused398212021-06-09 17:05:54 -07001371 .privileges(redfish::privileges::getLogService)
Ed Tanous002d39b2022-05-31 08:59:27 -07001372 .methods(boost::beast::http::verb::get)(
1373 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001374 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1375 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001376 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001377 {
1378 return;
1379 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001380 if (systemName != "system")
1381 {
1382 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1383 systemName);
1384 return;
1385 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001386 asyncResp->res.jsonValue["@odata.id"] =
1387 "/redfish/v1/Systems/system/LogServices/EventLog";
1388 asyncResp->res.jsonValue["@odata.type"] =
Janet Adkinsb25644a2023-08-16 11:23:45 -05001389 "#LogService.v1_2_0.LogService";
Ed Tanous002d39b2022-05-31 08:59:27 -07001390 asyncResp->res.jsonValue["Name"] = "Event Log Service";
1391 asyncResp->res.jsonValue["Description"] = "System Event Log Service";
1392 asyncResp->res.jsonValue["Id"] = "EventLog";
1393 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
Tejas Patil7c8c4052021-06-04 17:43:14 +05301394
Ed Tanous002d39b2022-05-31 08:59:27 -07001395 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07001396 redfish::time_utils::getDateTimeOffsetNow();
Tejas Patil7c8c4052021-06-04 17:43:14 +05301397
Ed Tanous002d39b2022-05-31 08:59:27 -07001398 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
1399 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
1400 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05301401
Ed Tanous002d39b2022-05-31 08:59:27 -07001402 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
1403 "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
1404 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = {
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001405
Ed Tanous002d39b2022-05-31 08:59:27 -07001406 {"target",
1407 "/redfish/v1/Systems/system/LogServices/EventLog/Actions/LogService.ClearLog"}};
Patrick Williams5a39f772023-10-20 11:20:21 -05001408 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001409}
1410
1411inline void requestRoutesJournalEventLogClear(App& app)
1412{
Jason M. Bills4978b632022-02-22 14:17:43 -08001413 BMCWEB_ROUTE(
1414 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07001415 "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/")
Ed Tanous432a8902021-06-14 15:28:56 -07001416 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001417 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001418 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001419 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1420 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001421 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001422 {
1423 return;
1424 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001425 if (systemName != "system")
1426 {
1427 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1428 systemName);
1429 return;
1430 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001431 // Clear the EventLog by deleting the log files
1432 std::vector<std::filesystem::path> redfishLogFiles;
1433 if (getRedfishLogFiles(redfishLogFiles))
1434 {
1435 for (const std::filesystem::path& file : redfishLogFiles)
1436 {
1437 std::error_code ec;
1438 std::filesystem::remove(file, ec);
1439 }
1440 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001441
Ed Tanous002d39b2022-05-31 08:59:27 -07001442 // Reload rsyslog so it knows to start new log files
1443 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001444 [asyncResp](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001445 if (ec)
1446 {
Ed Tanous62598e32023-07-17 17:06:25 -07001447 BMCWEB_LOG_ERROR("Failed to reload rsyslog: {}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -07001448 messages::internalError(asyncResp->res);
1449 return;
1450 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001451
Ed Tanous002d39b2022-05-31 08:59:27 -07001452 messages::success(asyncResp->res);
Patrick Williams5a39f772023-10-20 11:20:21 -05001453 },
Ed Tanous002d39b2022-05-31 08:59:27 -07001454 "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
1455 "org.freedesktop.systemd1.Manager", "ReloadUnit", "rsyslog.service",
1456 "replace");
Patrick Williams5a39f772023-10-20 11:20:21 -05001457 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001458}
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001459
Jason M. Billsac992cd2022-06-24 13:31:46 -07001460enum class LogParseError
1461{
1462 success,
1463 parseFailed,
1464 messageIdNotInRegistry,
1465};
1466
1467static LogParseError
1468 fillEventLogEntryJson(const std::string& logEntryID,
1469 const std::string& logEntry,
1470 nlohmann::json::object_t& logEntryJson)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001471{
Jason M. Bills95820182019-04-22 16:25:34 -07001472 // The redfish log format is "<Timestamp> <MessageId>,<MessageArgs>"
Jason M. Billscd225da2019-05-08 15:31:57 -07001473 // First get the Timestamp
Ed Tanousf23b7292020-10-15 09:41:17 -07001474 size_t space = logEntry.find_first_of(' ');
Jason M. Billscd225da2019-05-08 15:31:57 -07001475 if (space == std::string::npos)
Jason M. Bills95820182019-04-22 16:25:34 -07001476 {
Jason M. Billsac992cd2022-06-24 13:31:46 -07001477 return LogParseError::parseFailed;
Jason M. Bills95820182019-04-22 16:25:34 -07001478 }
Jason M. Billscd225da2019-05-08 15:31:57 -07001479 std::string timestamp = logEntry.substr(0, space);
1480 // Then get the log contents
Ed Tanousf23b7292020-10-15 09:41:17 -07001481 size_t entryStart = logEntry.find_first_not_of(' ', space);
Jason M. Billscd225da2019-05-08 15:31:57 -07001482 if (entryStart == std::string::npos)
1483 {
Jason M. Billsac992cd2022-06-24 13:31:46 -07001484 return LogParseError::parseFailed;
Jason M. Billscd225da2019-05-08 15:31:57 -07001485 }
1486 std::string_view entry(logEntry);
1487 entry.remove_prefix(entryStart);
1488 // Use split to separate the entry into its fields
1489 std::vector<std::string> logEntryFields;
Ed Tanous50ebd4a2023-01-19 19:03:17 -08001490 bmcweb::split(logEntryFields, entry, ',');
Jason M. Billscd225da2019-05-08 15:31:57 -07001491 // We need at least a MessageId to be valid
Ed Tanous1e6deaf2022-02-17 11:32:37 -08001492 auto logEntryIter = logEntryFields.begin();
1493 if (logEntryIter == logEntryFields.end())
Jason M. Billscd225da2019-05-08 15:31:57 -07001494 {
Jason M. Billsac992cd2022-06-24 13:31:46 -07001495 return LogParseError::parseFailed;
Jason M. Billscd225da2019-05-08 15:31:57 -07001496 }
Ed Tanous1e6deaf2022-02-17 11:32:37 -08001497 std::string& messageID = *logEntryIter;
Jason M. Bills4851d452019-03-28 11:27:48 -07001498 // Get the Message from the MessageRegistry
Ed Tanousfffb8c12022-02-07 23:53:03 -08001499 const registries::Message* message = registries::getMessage(messageID);
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001500
Ed Tanous1e6deaf2022-02-17 11:32:37 -08001501 logEntryIter++;
Sui Chen54417b02022-03-24 14:59:52 -07001502 if (message == nullptr)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001503 {
Ed Tanous62598e32023-07-17 17:06:25 -07001504 BMCWEB_LOG_WARNING("Log entry not found in registry: {}", logEntry);
Jason M. Billsac992cd2022-06-24 13:31:46 -07001505 return LogParseError::messageIdNotInRegistry;
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001506 }
1507
Ed Tanous1e6deaf2022-02-17 11:32:37 -08001508 std::vector<std::string_view> messageArgs(logEntryIter,
1509 logEntryFields.end());
Ed Tanousc05bba42023-06-28 08:33:29 -07001510 messageArgs.resize(message->numberOfArgs);
1511
Ed Tanous1e6deaf2022-02-17 11:32:37 -08001512 std::string msg = redfish::registries::fillMessageArgs(messageArgs,
1513 message->message);
1514 if (msg.empty())
Jason M. Bills4851d452019-03-28 11:27:48 -07001515 {
Ed Tanous1e6deaf2022-02-17 11:32:37 -08001516 return LogParseError::parseFailed;
Jason M. Bills4851d452019-03-28 11:27:48 -07001517 }
1518
Jason M. Bills95820182019-04-22 16:25:34 -07001519 // Get the Created time from the timestamp. The log timestamp is in RFC3339
1520 // format which matches the Redfish format except for the fractional seconds
1521 // between the '.' and the '+', so just remove them.
Ed Tanousf23b7292020-10-15 09:41:17 -07001522 std::size_t dot = timestamp.find_first_of('.');
1523 std::size_t plus = timestamp.find_first_of('+');
Jason M. Bills95820182019-04-22 16:25:34 -07001524 if (dot != std::string::npos && plus != std::string::npos)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001525 {
Jason M. Bills95820182019-04-22 16:25:34 -07001526 timestamp.erase(dot, plus - dot);
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001527 }
1528
1529 // Fill in the log entry with the gathered data
Vijay Lobo9c11a172021-10-07 16:53:16 -05001530 logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Ed Tanousef4c65b2023-04-24 15:28:50 -07001531 logEntryJson["@odata.id"] = boost::urls::format(
1532 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/{}",
1533 logEntryID);
Jason M. Bills84afc482022-06-24 12:38:23 -07001534 logEntryJson["Name"] = "System Event Log Entry";
1535 logEntryJson["Id"] = logEntryID;
1536 logEntryJson["Message"] = std::move(msg);
1537 logEntryJson["MessageId"] = std::move(messageID);
1538 logEntryJson["MessageArgs"] = messageArgs;
1539 logEntryJson["EntryType"] = "Event";
1540 logEntryJson["Severity"] = message->messageSeverity;
1541 logEntryJson["Created"] = std::move(timestamp);
Jason M. Billsac992cd2022-06-24 13:31:46 -07001542 return LogParseError::success;
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001543}
1544
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001545inline void requestRoutesJournalEventLogEntryCollection(App& app)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001546{
Ed Tanous22d268c2022-05-19 09:39:07 -07001547 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/")
Gunnar Mills8b6a35f2021-07-30 14:52:53 -05001548 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07001549 .methods(boost::beast::http::verb::get)(
1550 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001551 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1552 const std::string& systemName) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001553 query_param::QueryCapabilities capabilities = {
1554 .canDelegateTop = true,
1555 .canDelegateSkip = true,
1556 };
1557 query_param::Query delegatedQuery;
1558 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00001559 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07001560 {
1561 return;
1562 }
Ed Tanous25b54db2024-04-17 15:40:31 -07001563 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08001564 {
1565 // Option currently returns no systems. TBD
1566 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1567 systemName);
1568 return;
1569 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001570 if (systemName != "system")
1571 {
1572 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1573 systemName);
1574 return;
1575 }
1576
Jiaqing Zhao5143f7a2022-07-22 09:33:33 +08001577 size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
Ed Tanous3648c8b2022-07-25 13:39:59 -07001578 size_t skip = delegatedQuery.skip.value_or(0);
1579
Ed Tanous002d39b2022-05-31 08:59:27 -07001580 // Collections don't include the static data added by SubRoute
1581 // because it has a duplicate entry for members
1582 asyncResp->res.jsonValue["@odata.type"] =
1583 "#LogEntryCollection.LogEntryCollection";
1584 asyncResp->res.jsonValue["@odata.id"] =
1585 "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
1586 asyncResp->res.jsonValue["Name"] = "System Event Log Entries";
1587 asyncResp->res.jsonValue["Description"] =
1588 "Collection of System Event Log Entries";
1589
1590 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
1591 logEntryArray = nlohmann::json::array();
1592 // Go through the log files and create a unique ID for each
1593 // entry
1594 std::vector<std::filesystem::path> redfishLogFiles;
1595 getRedfishLogFiles(redfishLogFiles);
1596 uint64_t entryCount = 0;
1597 std::string logEntry;
1598
1599 // Oldest logs are in the last file, so start there and loop
1600 // backwards
1601 for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend();
1602 it++)
1603 {
1604 std::ifstream logStream(*it);
1605 if (!logStream.is_open())
Jason M. Bills4978b632022-02-22 14:17:43 -08001606 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001607 continue;
Jason M. Bills4978b632022-02-22 14:17:43 -08001608 }
Jason M. Bills897967d2019-07-29 17:05:30 -07001609
Ed Tanous002d39b2022-05-31 08:59:27 -07001610 // Reset the unique ID on the first entry
1611 bool firstEntry = true;
1612 while (std::getline(logStream, logEntry))
Jason M. Bills4978b632022-02-22 14:17:43 -08001613 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001614 std::string idStr;
1615 if (!getUniqueEntryID(logEntry, idStr, firstEntry))
Jason M. Bills4978b632022-02-22 14:17:43 -08001616 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001617 continue;
1618 }
Jason M. Billsefde4ec2022-06-24 08:59:52 -07001619 firstEntry = false;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001620
Jason M. Billsde703c52022-06-23 14:19:04 -07001621 nlohmann::json::object_t bmcLogEntry;
Patrick Williams89492a12023-05-10 07:51:34 -05001622 LogParseError status = fillEventLogEntryJson(idStr, logEntry,
1623 bmcLogEntry);
Jason M. Billsac992cd2022-06-24 13:31:46 -07001624 if (status == LogParseError::messageIdNotInRegistry)
1625 {
1626 continue;
1627 }
1628 if (status != LogParseError::success)
Ed Tanous002d39b2022-05-31 08:59:27 -07001629 {
1630 messages::internalError(asyncResp->res);
1631 return;
Andrew Geisslercb92c032018-08-17 07:56:14 -07001632 }
Jason M. Billsde703c52022-06-23 14:19:04 -07001633
Jason M. Billsde703c52022-06-23 14:19:04 -07001634 entryCount++;
1635 // Handle paging using skip (number of entries to skip from the
1636 // start) and top (number of entries to display)
Ed Tanous3648c8b2022-07-25 13:39:59 -07001637 if (entryCount <= skip || entryCount > skip + top)
Jason M. Billsde703c52022-06-23 14:19:04 -07001638 {
1639 continue;
1640 }
1641
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001642 logEntryArray.emplace_back(std::move(bmcLogEntry));
Jason M. Bills4978b632022-02-22 14:17:43 -08001643 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001644 }
1645 asyncResp->res.jsonValue["Members@odata.count"] = entryCount;
Ed Tanous3648c8b2022-07-25 13:39:59 -07001646 if (skip + top < entryCount)
Ed Tanous002d39b2022-05-31 08:59:27 -07001647 {
1648 asyncResp->res.jsonValue["Members@odata.nextLink"] =
1649 "/redfish/v1/Systems/system/LogServices/EventLog/Entries?$skip=" +
Ed Tanous3648c8b2022-07-25 13:39:59 -07001650 std::to_string(skip + top);
Ed Tanous002d39b2022-05-31 08:59:27 -07001651 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001652 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001653}
Chicago Duan336e96c2019-07-15 14:22:08 +08001654
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001655inline void requestRoutesJournalEventLogEntry(App& app)
1656{
1657 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07001658 app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001659 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001660 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001661 [&app](const crow::Request& req,
1662 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07001663 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001664 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001665 {
1666 return;
1667 }
Ed Tanous25b54db2024-04-17 15:40:31 -07001668 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08001669 {
1670 // Option currently returns no systems. TBD
1671 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1672 systemName);
1673 return;
1674 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001675
1676 if (systemName != "system")
1677 {
1678 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1679 systemName);
1680 return;
1681 }
1682
Ed Tanous002d39b2022-05-31 08:59:27 -07001683 const std::string& targetID = param;
1684
1685 // Go through the log files and check the unique ID for each
1686 // entry to find the target entry
1687 std::vector<std::filesystem::path> redfishLogFiles;
1688 getRedfishLogFiles(redfishLogFiles);
1689 std::string logEntry;
1690
1691 // Oldest logs are in the last file, so start there and loop
1692 // backwards
1693 for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend();
1694 it++)
1695 {
1696 std::ifstream logStream(*it);
1697 if (!logStream.is_open())
1698 {
1699 continue;
1700 }
1701
1702 // Reset the unique ID on the first entry
1703 bool firstEntry = true;
1704 while (std::getline(logStream, logEntry))
1705 {
1706 std::string idStr;
1707 if (!getUniqueEntryID(logEntry, idStr, firstEntry))
Ed Tanous45ca1b82022-03-25 13:07:27 -07001708 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001709 continue;
1710 }
Jason M. Billsefde4ec2022-06-24 08:59:52 -07001711 firstEntry = false;
Ed Tanous002d39b2022-05-31 08:59:27 -07001712
1713 if (idStr == targetID)
1714 {
Jason M. Billsde703c52022-06-23 14:19:04 -07001715 nlohmann::json::object_t bmcLogEntry;
Jason M. Billsac992cd2022-06-24 13:31:46 -07001716 LogParseError status =
1717 fillEventLogEntryJson(idStr, logEntry, bmcLogEntry);
1718 if (status != LogParseError::success)
Ed Tanous002d39b2022-05-31 08:59:27 -07001719 {
1720 messages::internalError(asyncResp->res);
1721 return;
1722 }
Jason M. Billsd405bb52022-06-24 10:52:05 -07001723 asyncResp->res.jsonValue.update(bmcLogEntry);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001724 return;
1725 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001726 }
1727 }
1728 // Requested ID was not found
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08001729 messages::resourceNotFound(asyncResp->res, "LogEntry", targetID);
Patrick Williams5a39f772023-10-20 11:20:21 -05001730 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001731}
1732
1733inline void requestRoutesDBusEventLogEntryCollection(App& app)
1734{
Ed Tanous22d268c2022-05-19 09:39:07 -07001735 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07001736 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07001737 .methods(boost::beast::http::verb::get)(
1738 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001739 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1740 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001741 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001742 {
1743 return;
1744 }
Ed Tanous25b54db2024-04-17 15:40:31 -07001745 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08001746 {
1747 // Option currently returns no systems. TBD
1748 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1749 systemName);
1750 return;
1751 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001752 if (systemName != "system")
1753 {
1754 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1755 systemName);
1756 return;
1757 }
1758
Ed Tanous002d39b2022-05-31 08:59:27 -07001759 // Collections don't include the static data added by SubRoute
1760 // because it has a duplicate entry for members
1761 asyncResp->res.jsonValue["@odata.type"] =
1762 "#LogEntryCollection.LogEntryCollection";
1763 asyncResp->res.jsonValue["@odata.id"] =
1764 "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
1765 asyncResp->res.jsonValue["Name"] = "System Event Log Entries";
1766 asyncResp->res.jsonValue["Description"] =
1767 "Collection of System Event Log Entries";
1768
1769 // DBus implementation of EventLog/Entries
1770 // Make call to Logging Service to find all log entry objects
George Liu5eb468d2023-06-20 17:03:24 +08001771 sdbusplus::message::object_path path("/xyz/openbmc_project/logging");
1772 dbus::utility::getManagedObjects(
1773 "xyz.openbmc_project.Logging", path,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001774 [asyncResp](const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -07001775 const dbus::utility::ManagedObjectType& resp) {
1776 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -07001777 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001778 // TODO Handle for specific error code
Ed Tanous62598e32023-07-17 17:06:25 -07001779 BMCWEB_LOG_ERROR(
1780 "getLogEntriesIfaceData resp_handler got error {}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -07001781 messages::internalError(asyncResp->res);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001782 return;
1783 }
Ed Tanous3544d2a2023-08-06 18:12:20 -07001784 nlohmann::json::array_t entriesArray;
Ed Tanous002d39b2022-05-31 08:59:27 -07001785 for (const auto& objectPath : resp)
1786 {
1787 const uint32_t* id = nullptr;
1788 const uint64_t* timestamp = nullptr;
1789 const uint64_t* updateTimestamp = nullptr;
1790 const std::string* severity = nullptr;
1791 const std::string* message = nullptr;
1792 const std::string* filePath = nullptr;
Vijay Lobo9c11a172021-10-07 16:53:16 -05001793 const std::string* resolution = nullptr;
Ed Tanous002d39b2022-05-31 08:59:27 -07001794 bool resolved = false;
Abhishek Patel9017faf2021-09-14 22:48:55 -05001795 const std::string* notify = nullptr;
1796
Ed Tanous002d39b2022-05-31 08:59:27 -07001797 for (const auto& interfaceMap : objectPath.second)
1798 {
1799 if (interfaceMap.first ==
1800 "xyz.openbmc_project.Logging.Entry")
Xiaochao Ma75710de2021-01-21 17:56:02 +08001801 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001802 for (const auto& propertyMap : interfaceMap.second)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001803 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001804 if (propertyMap.first == "Id")
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001805 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001806 id = std::get_if<uint32_t>(&propertyMap.second);
1807 }
1808 else if (propertyMap.first == "Timestamp")
1809 {
1810 timestamp =
1811 std::get_if<uint64_t>(&propertyMap.second);
1812 }
1813 else if (propertyMap.first == "UpdateTimestamp")
1814 {
1815 updateTimestamp =
1816 std::get_if<uint64_t>(&propertyMap.second);
1817 }
1818 else if (propertyMap.first == "Severity")
1819 {
1820 severity = std::get_if<std::string>(
1821 &propertyMap.second);
1822 }
Vijay Lobo9c11a172021-10-07 16:53:16 -05001823 else if (propertyMap.first == "Resolution")
1824 {
1825 resolution = std::get_if<std::string>(
1826 &propertyMap.second);
1827 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001828 else if (propertyMap.first == "Message")
1829 {
1830 message = std::get_if<std::string>(
1831 &propertyMap.second);
1832 }
1833 else if (propertyMap.first == "Resolved")
1834 {
1835 const bool* resolveptr =
1836 std::get_if<bool>(&propertyMap.second);
1837 if (resolveptr == nullptr)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001838 {
1839 messages::internalError(asyncResp->res);
1840 return;
1841 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001842 resolved = *resolveptr;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001843 }
Abhishek Patel9017faf2021-09-14 22:48:55 -05001844 else if (propertyMap.first ==
1845 "ServiceProviderNotify")
1846 {
1847 notify = std::get_if<std::string>(
1848 &propertyMap.second);
1849 if (notify == nullptr)
1850 {
1851 messages::internalError(asyncResp->res);
1852 return;
1853 }
1854 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001855 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001856 if (id == nullptr || message == nullptr ||
Ed Tanous002d39b2022-05-31 08:59:27 -07001857 severity == nullptr)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001858 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001859 messages::internalError(asyncResp->res);
1860 return;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001861 }
1862 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001863 else if (interfaceMap.first ==
1864 "xyz.openbmc_project.Common.FilePath")
1865 {
1866 for (const auto& propertyMap : interfaceMap.second)
1867 {
1868 if (propertyMap.first == "Path")
1869 {
1870 filePath = std::get_if<std::string>(
1871 &propertyMap.second);
1872 }
1873 }
1874 }
1875 }
1876 // Object path without the
1877 // xyz.openbmc_project.Logging.Entry interface, ignore
1878 // and continue.
1879 if (id == nullptr || message == nullptr ||
1880 severity == nullptr || timestamp == nullptr ||
1881 updateTimestamp == nullptr)
1882 {
1883 continue;
1884 }
Ed Tanous3544d2a2023-08-06 18:12:20 -07001885 nlohmann::json& thisEntry = entriesArray.emplace_back();
Vijay Lobo9c11a172021-10-07 16:53:16 -05001886 thisEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Ed Tanousef4c65b2023-04-24 15:28:50 -07001887 thisEntry["@odata.id"] = boost::urls::format(
1888 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/{}",
1889 std::to_string(*id));
Ed Tanous002d39b2022-05-31 08:59:27 -07001890 thisEntry["Name"] = "System Event Log Entry";
1891 thisEntry["Id"] = std::to_string(*id);
1892 thisEntry["Message"] = *message;
1893 thisEntry["Resolved"] = resolved;
Vijay Lobo9c11a172021-10-07 16:53:16 -05001894 if ((resolution != nullptr) && (!(*resolution).empty()))
1895 {
1896 thisEntry["Resolution"] = *resolution;
1897 }
Abhishek Patel9017faf2021-09-14 22:48:55 -05001898 std::optional<bool> notifyAction =
1899 getProviderNotifyAction(*notify);
1900 if (notifyAction)
1901 {
1902 thisEntry["ServiceProviderNotified"] = *notifyAction;
1903 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001904 thisEntry["EntryType"] = "Event";
1905 thisEntry["Severity"] =
1906 translateSeverityDbusToRedfish(*severity);
1907 thisEntry["Created"] =
Ed Tanous2b829372022-08-03 14:22:34 -07001908 redfish::time_utils::getDateTimeUintMs(*timestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07001909 thisEntry["Modified"] =
Ed Tanous2b829372022-08-03 14:22:34 -07001910 redfish::time_utils::getDateTimeUintMs(*updateTimestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07001911 if (filePath != nullptr)
1912 {
1913 thisEntry["AdditionalDataURI"] =
1914 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
1915 std::to_string(*id) + "/attachment";
1916 }
1917 }
Ed Tanous3544d2a2023-08-06 18:12:20 -07001918 std::ranges::sort(entriesArray, [](const nlohmann::json& left,
1919 const nlohmann::json& right) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001920 return (left["Id"] <= right["Id"]);
Ed Tanous3544d2a2023-08-06 18:12:20 -07001921 });
Ed Tanous002d39b2022-05-31 08:59:27 -07001922 asyncResp->res.jsonValue["Members@odata.count"] =
1923 entriesArray.size();
Ed Tanous3544d2a2023-08-06 18:12:20 -07001924 asyncResp->res.jsonValue["Members"] = std::move(entriesArray);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001925 });
Patrick Williams5a39f772023-10-20 11:20:21 -05001926 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001927}
Xiaochao Ma75710de2021-01-21 17:56:02 +08001928
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001929inline void requestRoutesDBusEventLogEntry(App& app)
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001930{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001931 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07001932 app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001933 .privileges(redfish::privileges::getLogEntry)
Ed Tanous002d39b2022-05-31 08:59:27 -07001934 .methods(boost::beast::http::verb::get)(
1935 [&app](const crow::Request& req,
1936 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07001937 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001938 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001939 {
1940 return;
1941 }
Ed Tanous25b54db2024-04-17 15:40:31 -07001942 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08001943 {
1944 // Option currently returns no systems. TBD
1945 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1946 systemName);
1947 return;
1948 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001949 if (systemName != "system")
1950 {
1951 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1952 systemName);
1953 return;
1954 }
1955
Ed Tanous002d39b2022-05-31 08:59:27 -07001956 std::string entryID = param;
1957 dbus::utility::escapePathForDbus(entryID);
1958
1959 // DBus implementation of EventLog/Entries
1960 // Make call to Logging Service to find all log entry objects
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001961 sdbusplus::asio::getAllProperties(
1962 *crow::connections::systemBus, "xyz.openbmc_project.Logging",
1963 "/xyz/openbmc_project/logging/entry/" + entryID, "",
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001964 [asyncResp, entryID](const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -07001965 const dbus::utility::DBusPropertiesMap& resp) {
1966 if (ec.value() == EBADR)
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001967 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001968 messages::resourceNotFound(asyncResp->res, "EventLogEntry",
1969 entryID);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001970 return;
1971 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001972 if (ec)
1973 {
Ed Tanous62598e32023-07-17 17:06:25 -07001974 BMCWEB_LOG_ERROR(
1975 "EventLogEntry (DBus) resp_handler got error {}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -07001976 messages::internalError(asyncResp->res);
1977 return;
1978 }
1979 const uint32_t* id = nullptr;
1980 const uint64_t* timestamp = nullptr;
1981 const uint64_t* updateTimestamp = nullptr;
1982 const std::string* severity = nullptr;
1983 const std::string* message = nullptr;
1984 const std::string* filePath = nullptr;
Vijay Lobo9c11a172021-10-07 16:53:16 -05001985 const std::string* resolution = nullptr;
Ed Tanous002d39b2022-05-31 08:59:27 -07001986 bool resolved = false;
Abhishek Patel9017faf2021-09-14 22:48:55 -05001987 const std::string* notify = nullptr;
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001988
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001989 const bool success = sdbusplus::unpackPropertiesNoThrow(
1990 dbus_utils::UnpackErrorPrinter(), resp, "Id", id, "Timestamp",
1991 timestamp, "UpdateTimestamp", updateTimestamp, "Severity",
Vijay Lobo9c11a172021-10-07 16:53:16 -05001992 severity, "Message", message, "Resolved", resolved,
Abhishek Patel9017faf2021-09-14 22:48:55 -05001993 "Resolution", resolution, "Path", filePath,
1994 "ServiceProviderNotify", notify);
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001995
1996 if (!success)
Ed Tanous002d39b2022-05-31 08:59:27 -07001997 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001998 messages::internalError(asyncResp->res);
1999 return;
Ed Tanous002d39b2022-05-31 08:59:27 -07002000 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02002001
Ed Tanous002d39b2022-05-31 08:59:27 -07002002 if (id == nullptr || message == nullptr || severity == nullptr ||
Abhishek Patel9017faf2021-09-14 22:48:55 -05002003 timestamp == nullptr || updateTimestamp == nullptr ||
2004 notify == nullptr)
Ed Tanous002d39b2022-05-31 08:59:27 -07002005 {
2006 messages::internalError(asyncResp->res);
2007 return;
2008 }
Abhishek Patel9017faf2021-09-14 22:48:55 -05002009
Ed Tanous002d39b2022-05-31 08:59:27 -07002010 asyncResp->res.jsonValue["@odata.type"] =
Vijay Lobo9c11a172021-10-07 16:53:16 -05002011 "#LogEntry.v1_9_0.LogEntry";
Ed Tanousef4c65b2023-04-24 15:28:50 -07002012 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
2013 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/{}",
2014 std::to_string(*id));
Ed Tanous002d39b2022-05-31 08:59:27 -07002015 asyncResp->res.jsonValue["Name"] = "System Event Log Entry";
2016 asyncResp->res.jsonValue["Id"] = std::to_string(*id);
2017 asyncResp->res.jsonValue["Message"] = *message;
2018 asyncResp->res.jsonValue["Resolved"] = resolved;
Abhishek Patel9017faf2021-09-14 22:48:55 -05002019 std::optional<bool> notifyAction = getProviderNotifyAction(*notify);
2020 if (notifyAction)
2021 {
2022 asyncResp->res.jsonValue["ServiceProviderNotified"] =
2023 *notifyAction;
2024 }
Vijay Lobo9c11a172021-10-07 16:53:16 -05002025 if ((resolution != nullptr) && (!(*resolution).empty()))
2026 {
2027 asyncResp->res.jsonValue["Resolution"] = *resolution;
2028 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002029 asyncResp->res.jsonValue["EntryType"] = "Event";
2030 asyncResp->res.jsonValue["Severity"] =
2031 translateSeverityDbusToRedfish(*severity);
2032 asyncResp->res.jsonValue["Created"] =
Ed Tanous2b829372022-08-03 14:22:34 -07002033 redfish::time_utils::getDateTimeUintMs(*timestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07002034 asyncResp->res.jsonValue["Modified"] =
Ed Tanous2b829372022-08-03 14:22:34 -07002035 redfish::time_utils::getDateTimeUintMs(*updateTimestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07002036 if (filePath != nullptr)
2037 {
2038 asyncResp->res.jsonValue["AdditionalDataURI"] =
2039 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
2040 std::to_string(*id) + "/attachment";
2041 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07002042 });
Patrick Williams5a39f772023-10-20 11:20:21 -05002043 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002044
2045 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07002046 app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002047 .privileges(redfish::privileges::patchLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002048 .methods(boost::beast::http::verb::patch)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002049 [&app](const crow::Request& req,
2050 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07002051 const std::string& systemName, const std::string& entryId) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002052 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002053 {
2054 return;
2055 }
Ed Tanous25b54db2024-04-17 15:40:31 -07002056 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08002057 {
2058 // Option currently returns no systems. TBD
2059 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2060 systemName);
2061 return;
2062 }
Ed Tanous22d268c2022-05-19 09:39:07 -07002063 if (systemName != "system")
2064 {
2065 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2066 systemName);
2067 return;
2068 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002069 std::optional<bool> resolved;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002070
Ed Tanous002d39b2022-05-31 08:59:27 -07002071 if (!json_util::readJsonPatch(req, asyncResp->res, "Resolved",
2072 resolved))
2073 {
2074 return;
2075 }
Ed Tanous62598e32023-07-17 17:06:25 -07002076 BMCWEB_LOG_DEBUG("Set Resolved");
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06002077
Asmitha Karunanithi3eb66652024-04-02 16:34:36 +00002078 setDbusProperty(asyncResp, "xyz.openbmc_project.Logging",
2079 "/xyz/openbmc_project/logging/entry/" + entryId,
2080 "xyz.openbmc_project.Logging.Entry", "Resolved",
2081 "Resolved", *resolved);
Patrick Williams5a39f772023-10-20 11:20:21 -05002082 });
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06002083
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002084 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07002085 app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002086 .privileges(redfish::privileges::deleteLogEntry)
2087
Ed Tanous002d39b2022-05-31 08:59:27 -07002088 .methods(boost::beast::http::verb::delete_)(
2089 [&app](const crow::Request& req,
2090 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07002091 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002092 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002093 {
2094 return;
2095 }
Ed Tanous25b54db2024-04-17 15:40:31 -07002096 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08002097 {
2098 // Option currently returns no systems. TBD
2099 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2100 systemName);
2101 return;
2102 }
Ed Tanous22d268c2022-05-19 09:39:07 -07002103 if (systemName != "system")
2104 {
2105 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2106 systemName);
2107 return;
2108 }
Ed Tanous62598e32023-07-17 17:06:25 -07002109 BMCWEB_LOG_DEBUG("Do delete single event entries.");
Ed Tanous002d39b2022-05-31 08:59:27 -07002110
2111 std::string entryID = param;
2112
2113 dbus::utility::escapePathForDbus(entryID);
2114
2115 // Process response from Logging service.
Patrick Williams5a39f772023-10-20 11:20:21 -05002116 auto respHandler = [asyncResp,
2117 entryID](const boost::system::error_code& ec) {
Ed Tanous62598e32023-07-17 17:06:25 -07002118 BMCWEB_LOG_DEBUG("EventLogEntry (DBus) doDelete callback: Done");
Ed Tanous002d39b2022-05-31 08:59:27 -07002119 if (ec)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002120 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002121 if (ec.value() == EBADR)
Ed Tanous45ca1b82022-03-25 13:07:27 -07002122 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002123 messages::resourceNotFound(asyncResp->res, "LogEntry",
2124 entryID);
Ed Tanous45ca1b82022-03-25 13:07:27 -07002125 return;
2126 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002127 // TODO Handle for specific error code
Ed Tanous62598e32023-07-17 17:06:25 -07002128 BMCWEB_LOG_ERROR(
2129 "EventLogEntry (DBus) doDelete respHandler got error {}",
2130 ec);
Ed Tanous002d39b2022-05-31 08:59:27 -07002131 asyncResp->res.result(
2132 boost::beast::http::status::internal_server_error);
2133 return;
2134 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002135
Ed Tanous002d39b2022-05-31 08:59:27 -07002136 asyncResp->res.result(boost::beast::http::status::ok);
2137 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002138
Ed Tanous002d39b2022-05-31 08:59:27 -07002139 // Make call to Logging service to request Delete Log
2140 crow::connections::systemBus->async_method_call(
2141 respHandler, "xyz.openbmc_project.Logging",
2142 "/xyz/openbmc_project/logging/entry/" + entryID,
2143 "xyz.openbmc_project.Object.Delete", "Delete");
Patrick Williams5a39f772023-10-20 11:20:21 -05002144 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002145}
2146
Spencer Kub7028eb2021-10-26 15:27:35 +08002147constexpr const char* hostLoggerFolderPath = "/var/log/console";
2148
2149inline bool
2150 getHostLoggerFiles(const std::string& hostLoggerFilePath,
2151 std::vector<std::filesystem::path>& hostLoggerFiles)
2152{
2153 std::error_code ec;
2154 std::filesystem::directory_iterator logPath(hostLoggerFilePath, ec);
2155 if (ec)
2156 {
Carson Labradobf2dded2023-08-10 00:37:06 +00002157 BMCWEB_LOG_WARNING("{}", ec.message());
Spencer Kub7028eb2021-10-26 15:27:35 +08002158 return false;
2159 }
2160 for (const std::filesystem::directory_entry& it : logPath)
2161 {
2162 std::string filename = it.path().filename();
2163 // Prefix of each log files is "log". Find the file and save the
2164 // path
Ed Tanous11ba3972022-07-11 09:50:41 -07002165 if (filename.starts_with("log"))
Spencer Kub7028eb2021-10-26 15:27:35 +08002166 {
2167 hostLoggerFiles.emplace_back(it.path());
2168 }
2169 }
2170 // As the log files rotate, they are appended with a ".#" that is higher for
2171 // the older logs. Since we start from oldest logs, sort the name in
2172 // descending order.
2173 std::sort(hostLoggerFiles.rbegin(), hostLoggerFiles.rend(),
2174 AlphanumLess<std::string>());
2175
2176 return true;
2177}
2178
Ed Tanous02cad962022-06-30 16:50:15 -07002179inline bool getHostLoggerEntries(
2180 const std::vector<std::filesystem::path>& hostLoggerFiles, uint64_t skip,
2181 uint64_t top, std::vector<std::string>& logEntries, size_t& logCount)
Spencer Kub7028eb2021-10-26 15:27:35 +08002182{
2183 GzFileReader logFile;
2184
2185 // Go though all log files and expose host logs.
2186 for (const std::filesystem::path& it : hostLoggerFiles)
2187 {
2188 if (!logFile.gzGetLines(it.string(), skip, top, logEntries, logCount))
2189 {
Ed Tanous62598e32023-07-17 17:06:25 -07002190 BMCWEB_LOG_ERROR("fail to expose host logs");
Spencer Kub7028eb2021-10-26 15:27:35 +08002191 return false;
2192 }
2193 }
2194 // Get lastMessage from constructor by getter
2195 std::string lastMessage = logFile.getLastMessage();
2196 if (!lastMessage.empty())
2197 {
2198 logCount++;
2199 if (logCount > skip && logCount <= (skip + top))
2200 {
2201 logEntries.push_back(lastMessage);
2202 }
2203 }
2204 return true;
2205}
2206
Ed Tanous6f056f22024-04-07 13:35:51 -07002207inline void fillHostLoggerEntryJson(std::string_view logEntryID,
2208 std::string_view msg,
Jason M. Bills6d6574c2022-06-28 12:30:16 -07002209 nlohmann::json::object_t& logEntryJson)
Spencer Kub7028eb2021-10-26 15:27:35 +08002210{
2211 // Fill in the log entry with the gathered data.
Vijay Lobo9c11a172021-10-07 16:53:16 -05002212 logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Ed Tanousef4c65b2023-04-24 15:28:50 -07002213 logEntryJson["@odata.id"] = boost::urls::format(
2214 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries/{}",
2215 logEntryID);
Jason M. Bills6d6574c2022-06-28 12:30:16 -07002216 logEntryJson["Name"] = "Host Logger Entry";
2217 logEntryJson["Id"] = logEntryID;
2218 logEntryJson["Message"] = msg;
2219 logEntryJson["EntryType"] = "Oem";
2220 logEntryJson["Severity"] = "OK";
2221 logEntryJson["OemRecordFormat"] = "Host Logger Entry";
Spencer Kub7028eb2021-10-26 15:27:35 +08002222}
2223
2224inline void requestRoutesSystemHostLogger(App& app)
2225{
Ed Tanous22d268c2022-05-19 09:39:07 -07002226 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/")
Spencer Kub7028eb2021-10-26 15:27:35 +08002227 .privileges(redfish::privileges::getLogService)
Ed Tanous14766872022-03-15 10:44:42 -07002228 .methods(boost::beast::http::verb::get)(
2229 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07002230 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2231 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002232 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002233 {
2234 return;
2235 }
Ed Tanous25b54db2024-04-17 15:40:31 -07002236 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08002237 {
2238 // Option currently returns no systems. TBD
2239 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2240 systemName);
2241 return;
2242 }
Ed Tanous22d268c2022-05-19 09:39:07 -07002243 if (systemName != "system")
2244 {
2245 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2246 systemName);
2247 return;
2248 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002249 asyncResp->res.jsonValue["@odata.id"] =
2250 "/redfish/v1/Systems/system/LogServices/HostLogger";
2251 asyncResp->res.jsonValue["@odata.type"] =
Janet Adkinsb25644a2023-08-16 11:23:45 -05002252 "#LogService.v1_2_0.LogService";
Ed Tanous002d39b2022-05-31 08:59:27 -07002253 asyncResp->res.jsonValue["Name"] = "Host Logger Service";
2254 asyncResp->res.jsonValue["Description"] = "Host Logger Service";
2255 asyncResp->res.jsonValue["Id"] = "HostLogger";
2256 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
2257 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries";
Patrick Williams5a39f772023-10-20 11:20:21 -05002258 });
Spencer Kub7028eb2021-10-26 15:27:35 +08002259}
2260
2261inline void requestRoutesSystemHostLoggerCollection(App& app)
2262{
2263 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07002264 "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/")
Spencer Kub7028eb2021-10-26 15:27:35 +08002265 .privileges(redfish::privileges::getLogEntry)
Ed Tanous002d39b2022-05-31 08:59:27 -07002266 .methods(boost::beast::http::verb::get)(
2267 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07002268 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2269 const std::string& systemName) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002270 query_param::QueryCapabilities capabilities = {
2271 .canDelegateTop = true,
2272 .canDelegateSkip = true,
2273 };
2274 query_param::Query delegatedQuery;
2275 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00002276 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07002277 {
2278 return;
2279 }
Ed Tanous25b54db2024-04-17 15:40:31 -07002280 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08002281 {
2282 // Option currently returns no systems. TBD
2283 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2284 systemName);
2285 return;
2286 }
Ed Tanous22d268c2022-05-19 09:39:07 -07002287 if (systemName != "system")
2288 {
2289 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2290 systemName);
2291 return;
2292 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002293 asyncResp->res.jsonValue["@odata.id"] =
2294 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries";
2295 asyncResp->res.jsonValue["@odata.type"] =
2296 "#LogEntryCollection.LogEntryCollection";
2297 asyncResp->res.jsonValue["Name"] = "HostLogger Entries";
2298 asyncResp->res.jsonValue["Description"] =
2299 "Collection of HostLogger Entries";
2300 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
2301 logEntryArray = nlohmann::json::array();
2302 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Spencer Kub7028eb2021-10-26 15:27:35 +08002303
Ed Tanous002d39b2022-05-31 08:59:27 -07002304 std::vector<std::filesystem::path> hostLoggerFiles;
2305 if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles))
2306 {
Carson Labradobf2dded2023-08-10 00:37:06 +00002307 BMCWEB_LOG_DEBUG("Failed to get host log file path");
Ed Tanous002d39b2022-05-31 08:59:27 -07002308 return;
2309 }
Ed Tanous3648c8b2022-07-25 13:39:59 -07002310 // If we weren't provided top and skip limits, use the defaults.
2311 size_t skip = delegatedQuery.skip.value_or(0);
Jiaqing Zhao5143f7a2022-07-22 09:33:33 +08002312 size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
Ed Tanous002d39b2022-05-31 08:59:27 -07002313 size_t logCount = 0;
2314 // This vector only store the entries we want to expose that
2315 // control by skip and top.
2316 std::vector<std::string> logEntries;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002317 if (!getHostLoggerEntries(hostLoggerFiles, skip, top, logEntries,
2318 logCount))
Ed Tanous002d39b2022-05-31 08:59:27 -07002319 {
2320 messages::internalError(asyncResp->res);
2321 return;
2322 }
2323 // If vector is empty, that means skip value larger than total
2324 // log count
2325 if (logEntries.empty())
2326 {
2327 asyncResp->res.jsonValue["Members@odata.count"] = logCount;
2328 return;
2329 }
2330 if (!logEntries.empty())
2331 {
2332 for (size_t i = 0; i < logEntries.size(); i++)
George Liu0fda0f12021-11-16 10:06:17 +08002333 {
Jason M. Bills6d6574c2022-06-28 12:30:16 -07002334 nlohmann::json::object_t hostLogEntry;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002335 fillHostLoggerEntryJson(std::to_string(skip + i), logEntries[i],
2336 hostLogEntry);
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002337 logEntryArray.emplace_back(std::move(hostLogEntry));
George Liu0fda0f12021-11-16 10:06:17 +08002338 }
2339
Ed Tanous002d39b2022-05-31 08:59:27 -07002340 asyncResp->res.jsonValue["Members@odata.count"] = logCount;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002341 if (skip + top < logCount)
George Liu0fda0f12021-11-16 10:06:17 +08002342 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002343 asyncResp->res.jsonValue["Members@odata.nextLink"] =
2344 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries?$skip=" +
Ed Tanous3648c8b2022-07-25 13:39:59 -07002345 std::to_string(skip + top);
George Liu0fda0f12021-11-16 10:06:17 +08002346 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002347 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002348 });
Spencer Kub7028eb2021-10-26 15:27:35 +08002349}
2350
2351inline void requestRoutesSystemHostLoggerLogEntry(App& app)
2352{
2353 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07002354 app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/<str>/")
Spencer Kub7028eb2021-10-26 15:27:35 +08002355 .privileges(redfish::privileges::getLogEntry)
2356 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002357 [&app](const crow::Request& req,
2358 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07002359 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002360 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002361 {
2362 return;
2363 }
Ed Tanous25b54db2024-04-17 15:40:31 -07002364 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08002365 {
2366 // Option currently returns no systems. TBD
2367 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2368 systemName);
2369 return;
2370 }
Ed Tanous22d268c2022-05-19 09:39:07 -07002371 if (systemName != "system")
2372 {
2373 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2374 systemName);
2375 return;
2376 }
Ed Tanous6f056f22024-04-07 13:35:51 -07002377 std::string_view targetID = param;
Spencer Kub7028eb2021-10-26 15:27:35 +08002378
Ed Tanous002d39b2022-05-31 08:59:27 -07002379 uint64_t idInt = 0;
Ed Tanousca45aa32022-01-07 09:28:45 -08002380
Ed Tanous6f056f22024-04-07 13:35:51 -07002381 auto [ptr, ec] = std::from_chars(targetID.begin(), targetID.end(),
Patrick Williams84396af2023-05-11 11:47:45 -05002382 idInt);
Ed Tanous6f056f22024-04-07 13:35:51 -07002383 if (ec != std::errc{} || ptr != targetID.end())
Ed Tanous002d39b2022-05-31 08:59:27 -07002384 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08002385 messages::resourceNotFound(asyncResp->res, "LogEntry", param);
Ed Tanous002d39b2022-05-31 08:59:27 -07002386 return;
2387 }
Spencer Kub7028eb2021-10-26 15:27:35 +08002388
Ed Tanous002d39b2022-05-31 08:59:27 -07002389 std::vector<std::filesystem::path> hostLoggerFiles;
2390 if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles))
2391 {
Carson Labradobf2dded2023-08-10 00:37:06 +00002392 BMCWEB_LOG_DEBUG("Failed to get host log file path");
Ed Tanous002d39b2022-05-31 08:59:27 -07002393 return;
2394 }
Spencer Kub7028eb2021-10-26 15:27:35 +08002395
Ed Tanous002d39b2022-05-31 08:59:27 -07002396 size_t logCount = 0;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002397 size_t top = 1;
Ed Tanous002d39b2022-05-31 08:59:27 -07002398 std::vector<std::string> logEntries;
2399 // We can get specific entry by skip and top. For example, if we
2400 // want to get nth entry, we can set skip = n-1 and top = 1 to
2401 // get that entry
2402 if (!getHostLoggerEntries(hostLoggerFiles, idInt, top, logEntries,
2403 logCount))
2404 {
2405 messages::internalError(asyncResp->res);
2406 return;
2407 }
Spencer Kub7028eb2021-10-26 15:27:35 +08002408
Ed Tanous002d39b2022-05-31 08:59:27 -07002409 if (!logEntries.empty())
2410 {
Jason M. Bills6d6574c2022-06-28 12:30:16 -07002411 nlohmann::json::object_t hostLogEntry;
2412 fillHostLoggerEntryJson(targetID, logEntries[0], hostLogEntry);
2413 asyncResp->res.jsonValue.update(hostLogEntry);
Ed Tanous002d39b2022-05-31 08:59:27 -07002414 return;
2415 }
Spencer Kub7028eb2021-10-26 15:27:35 +08002416
Ed Tanous002d39b2022-05-31 08:59:27 -07002417 // Requested ID was not found
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08002418 messages::resourceNotFound(asyncResp->res, "LogEntry", param);
Patrick Williams5a39f772023-10-20 11:20:21 -05002419 });
Spencer Kub7028eb2021-10-26 15:27:35 +08002420}
2421
Claire Weinandd72e872022-08-15 14:20:06 -07002422inline void handleBMCLogServicesCollectionGet(
Claire Weinanfdd26902022-03-01 14:18:25 -08002423 crow::App& app, const crow::Request& req,
2424 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2425{
2426 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2427 {
2428 return;
2429 }
2430 // Collections don't include the static data added by SubRoute
2431 // because it has a duplicate entry for members
2432 asyncResp->res.jsonValue["@odata.type"] =
2433 "#LogServiceCollection.LogServiceCollection";
2434 asyncResp->res.jsonValue["@odata.id"] =
2435 "/redfish/v1/Managers/bmc/LogServices";
2436 asyncResp->res.jsonValue["Name"] = "Open BMC Log Services Collection";
2437 asyncResp->res.jsonValue["Description"] =
2438 "Collection of LogServices for this Manager";
2439 nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"];
2440 logServiceArray = nlohmann::json::array();
2441
Ed Tanous25b54db2024-04-17 15:40:31 -07002442 if constexpr (BMCWEB_REDFISH_BMC_JOURNAL)
2443 {
2444 nlohmann::json::object_t journal;
2445 journal["@odata.id"] = "/redfish/v1/Managers/bmc/LogServices/Journal";
2446 logServiceArray.emplace_back(std::move(journal));
2447 }
Claire Weinanfdd26902022-03-01 14:18:25 -08002448
2449 asyncResp->res.jsonValue["Members@odata.count"] = logServiceArray.size();
2450
Ed Tanous25b54db2024-04-17 15:40:31 -07002451 if constexpr (BMCWEB_REDFISH_DUMP_LOG)
2452 {
2453 constexpr std::array<std::string_view, 1> interfaces = {
2454 "xyz.openbmc_project.Collection.DeleteAll"};
2455 dbus::utility::getSubTreePaths(
2456 "/xyz/openbmc_project/dump", 0, interfaces,
2457 [asyncResp](const boost::system::error_code& ec,
2458 const dbus::utility::MapperGetSubTreePathsResponse&
2459 subTreePaths) {
2460 if (ec)
Claire Weinanfdd26902022-03-01 14:18:25 -08002461 {
Ed Tanous25b54db2024-04-17 15:40:31 -07002462 BMCWEB_LOG_ERROR(
2463 "handleBMCLogServicesCollectionGet respHandler got error {}",
2464 ec);
2465 // Assume that getting an error simply means there are no dump
2466 // LogServices. Return without adding any error response.
2467 return;
Claire Weinanfdd26902022-03-01 14:18:25 -08002468 }
Claire Weinanfdd26902022-03-01 14:18:25 -08002469
Ed Tanous25b54db2024-04-17 15:40:31 -07002470 nlohmann::json& logServiceArrayLocal =
2471 asyncResp->res.jsonValue["Members"];
2472
2473 for (const std::string& path : subTreePaths)
2474 {
2475 if (path == "/xyz/openbmc_project/dump/bmc")
2476 {
2477 nlohmann::json::object_t member;
2478 member["@odata.id"] =
2479 "/redfish/v1/Managers/bmc/LogServices/Dump";
2480 logServiceArrayLocal.emplace_back(std::move(member));
2481 }
2482 else if (path == "/xyz/openbmc_project/dump/faultlog")
2483 {
2484 nlohmann::json::object_t member;
2485 member["@odata.id"] =
2486 "/redfish/v1/Managers/bmc/LogServices/FaultLog";
2487 logServiceArrayLocal.emplace_back(std::move(member));
2488 }
2489 }
2490
2491 asyncResp->res.jsonValue["Members@odata.count"] =
2492 logServiceArrayLocal.size();
2493 });
2494 }
Claire Weinanfdd26902022-03-01 14:18:25 -08002495}
2496
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002497inline void requestRoutesBMCLogServiceCollection(App& app)
2498{
2499 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/")
Gunnar Millsad89dcf2021-07-30 14:40:11 -05002500 .privileges(redfish::privileges::getLogServiceCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002501 .methods(boost::beast::http::verb::get)(
Claire Weinandd72e872022-08-15 14:20:06 -07002502 std::bind_front(handleBMCLogServicesCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002503}
Ed Tanous1da66f72018-07-27 16:13:37 -07002504
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002505inline void requestRoutesBMCJournalLogService(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07002506{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002507 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/")
Ed Tanoused398212021-06-09 17:05:54 -07002508 .privileges(redfish::privileges::getLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002509 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002510 [&app](const crow::Request& req,
2511 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002512 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002513 {
2514 return;
2515 }
2516 asyncResp->res.jsonValue["@odata.type"] =
Janet Adkinsb25644a2023-08-16 11:23:45 -05002517 "#LogService.v1_2_0.LogService";
Ed Tanous002d39b2022-05-31 08:59:27 -07002518 asyncResp->res.jsonValue["@odata.id"] =
2519 "/redfish/v1/Managers/bmc/LogServices/Journal";
2520 asyncResp->res.jsonValue["Name"] = "Open BMC Journal Log Service";
2521 asyncResp->res.jsonValue["Description"] = "BMC Journal Log Service";
Ed Tanoused34a4a2023-02-08 15:43:27 -08002522 asyncResp->res.jsonValue["Id"] = "Journal";
Ed Tanous002d39b2022-05-31 08:59:27 -07002523 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
Tejas Patil7c8c4052021-06-04 17:43:14 +05302524
Ed Tanous002d39b2022-05-31 08:59:27 -07002525 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07002526 redfish::time_utils::getDateTimeOffsetNow();
Ed Tanous002d39b2022-05-31 08:59:27 -07002527 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2528 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2529 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05302530
Ed Tanous002d39b2022-05-31 08:59:27 -07002531 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
2532 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries";
Patrick Williams5a39f772023-10-20 11:20:21 -05002533 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002534}
Jason M. Billse1f26342018-07-18 12:12:00 -07002535
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002536static int
2537 fillBMCJournalLogEntryJson(const std::string& bmcJournalLogEntryID,
2538 sd_journal* journal,
2539 nlohmann::json::object_t& bmcJournalLogEntryJson)
Jason M. Billse1f26342018-07-18 12:12:00 -07002540{
2541 // Get the Log Entry contents
2542 int ret = 0;
Jason M. Billse1f26342018-07-18 12:12:00 -07002543
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08002544 std::string message;
2545 std::string_view syslogID;
2546 ret = getJournalMetadata(journal, "SYSLOG_IDENTIFIER", syslogID);
2547 if (ret < 0)
2548 {
Carson Labradobf2dded2023-08-10 00:37:06 +00002549 BMCWEB_LOG_DEBUG("Failed to read SYSLOG_IDENTIFIER field: {}",
Ed Tanous62598e32023-07-17 17:06:25 -07002550 strerror(-ret));
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08002551 }
2552 if (!syslogID.empty())
2553 {
2554 message += std::string(syslogID) + ": ";
2555 }
2556
Ed Tanous39e77502019-03-04 17:35:53 -08002557 std::string_view msg;
Jason M. Bills16428a12018-11-02 12:42:29 -07002558 ret = getJournalMetadata(journal, "MESSAGE", msg);
Jason M. Billse1f26342018-07-18 12:12:00 -07002559 if (ret < 0)
2560 {
Ed Tanous62598e32023-07-17 17:06:25 -07002561 BMCWEB_LOG_ERROR("Failed to read MESSAGE field: {}", strerror(-ret));
Jason M. Billse1f26342018-07-18 12:12:00 -07002562 return 1;
2563 }
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08002564 message += std::string(msg);
Jason M. Billse1f26342018-07-18 12:12:00 -07002565
2566 // Get the severity from the PRIORITY field
Ed Tanous271584a2019-07-09 16:24:22 -07002567 long int severity = 8; // Default to an invalid priority
Jason M. Bills16428a12018-11-02 12:42:29 -07002568 ret = getJournalMetadata(journal, "PRIORITY", 10, severity);
Jason M. Billse1f26342018-07-18 12:12:00 -07002569 if (ret < 0)
2570 {
Carson Labradobf2dded2023-08-10 00:37:06 +00002571 BMCWEB_LOG_DEBUG("Failed to read PRIORITY field: {}", strerror(-ret));
Jason M. Billse1f26342018-07-18 12:12:00 -07002572 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002573
2574 // Get the Created time from the timestamp
Jason M. Bills16428a12018-11-02 12:42:29 -07002575 std::string entryTimeStr;
2576 if (!getEntryTimestamp(journal, entryTimeStr))
Jason M. Billse1f26342018-07-18 12:12:00 -07002577 {
Jason M. Bills16428a12018-11-02 12:42:29 -07002578 return 1;
Jason M. Billse1f26342018-07-18 12:12:00 -07002579 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002580
2581 // Fill in the log entry with the gathered data
Vijay Lobo9c11a172021-10-07 16:53:16 -05002582 bmcJournalLogEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Ed Tanousef4c65b2023-04-24 15:28:50 -07002583 bmcJournalLogEntryJson["@odata.id"] = boost::urls::format(
2584 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/{}",
Willy Tueddfc432022-09-26 16:46:38 +00002585 bmcJournalLogEntryID);
Jason M. Bills84afc482022-06-24 12:38:23 -07002586 bmcJournalLogEntryJson["Name"] = "BMC Journal Entry";
2587 bmcJournalLogEntryJson["Id"] = bmcJournalLogEntryID;
2588 bmcJournalLogEntryJson["Message"] = std::move(message);
2589 bmcJournalLogEntryJson["EntryType"] = "Oem";
Ed Tanousddf35642024-03-27 14:12:21 -07002590 log_entry::EventSeverity severityEnum = log_entry::EventSeverity::OK;
2591 if (severity <= 2)
2592 {
2593 severityEnum = log_entry::EventSeverity::Critical;
2594 }
2595 else if (severity <= 4)
2596 {
2597 severityEnum = log_entry::EventSeverity::Warning;
2598 }
2599
2600 bmcJournalLogEntryJson["Severity"] = severityEnum;
Jason M. Bills84afc482022-06-24 12:38:23 -07002601 bmcJournalLogEntryJson["OemRecordFormat"] = "BMC Journal Entry";
2602 bmcJournalLogEntryJson["Created"] = std::move(entryTimeStr);
Jason M. Billse1f26342018-07-18 12:12:00 -07002603 return 0;
2604}
2605
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002606inline void requestRoutesBMCJournalLogEntryCollection(App& app)
Jason M. Billse1f26342018-07-18 12:12:00 -07002607{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002608 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07002609 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07002610 .methods(boost::beast::http::verb::get)(
2611 [&app](const crow::Request& req,
2612 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2613 query_param::QueryCapabilities capabilities = {
2614 .canDelegateTop = true,
2615 .canDelegateSkip = true,
2616 };
2617 query_param::Query delegatedQuery;
2618 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00002619 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07002620 {
2621 return;
2622 }
Ed Tanous3648c8b2022-07-25 13:39:59 -07002623
2624 size_t skip = delegatedQuery.skip.value_or(0);
Jiaqing Zhao5143f7a2022-07-22 09:33:33 +08002625 size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
Ed Tanous3648c8b2022-07-25 13:39:59 -07002626
Ed Tanous002d39b2022-05-31 08:59:27 -07002627 // Collections don't include the static data added by SubRoute
2628 // because it has a duplicate entry for members
2629 asyncResp->res.jsonValue["@odata.type"] =
2630 "#LogEntryCollection.LogEntryCollection";
2631 asyncResp->res.jsonValue["@odata.id"] =
2632 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries";
2633 asyncResp->res.jsonValue["Name"] = "Open BMC Journal Entries";
2634 asyncResp->res.jsonValue["Description"] =
2635 "Collection of BMC Journal Entries";
2636 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
2637 logEntryArray = nlohmann::json::array();
Jason M. Billse1f26342018-07-18 12:12:00 -07002638
Ed Tanous002d39b2022-05-31 08:59:27 -07002639 // Go through the journal and use the timestamp to create a
2640 // unique ID for each entry
2641 sd_journal* journalTmp = nullptr;
2642 int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY);
2643 if (ret < 0)
2644 {
Ed Tanous62598e32023-07-17 17:06:25 -07002645 BMCWEB_LOG_ERROR("failed to open journal: {}", strerror(-ret));
Ed Tanous002d39b2022-05-31 08:59:27 -07002646 messages::internalError(asyncResp->res);
2647 return;
2648 }
2649 std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal(
2650 journalTmp, sd_journal_close);
2651 journalTmp = nullptr;
2652 uint64_t entryCount = 0;
2653 // Reset the unique ID on the first entry
2654 bool firstEntry = true;
2655 SD_JOURNAL_FOREACH(journal.get())
2656 {
2657 entryCount++;
2658 // Handle paging using skip (number of entries to skip from
2659 // the start) and top (number of entries to display)
Ed Tanous3648c8b2022-07-25 13:39:59 -07002660 if (entryCount <= skip || entryCount > skip + top)
George Liu0fda0f12021-11-16 10:06:17 +08002661 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002662 continue;
2663 }
2664
2665 std::string idStr;
2666 if (!getUniqueEntryID(journal.get(), idStr, firstEntry))
2667 {
2668 continue;
2669 }
Jason M. Billsefde4ec2022-06-24 08:59:52 -07002670 firstEntry = false;
Ed Tanous002d39b2022-05-31 08:59:27 -07002671
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002672 nlohmann::json::object_t bmcJournalLogEntry;
Ed Tanous002d39b2022-05-31 08:59:27 -07002673 if (fillBMCJournalLogEntryJson(idStr, journal.get(),
2674 bmcJournalLogEntry) != 0)
2675 {
George Liu0fda0f12021-11-16 10:06:17 +08002676 messages::internalError(asyncResp->res);
2677 return;
2678 }
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002679 logEntryArray.emplace_back(std::move(bmcJournalLogEntry));
Ed Tanous002d39b2022-05-31 08:59:27 -07002680 }
2681 asyncResp->res.jsonValue["Members@odata.count"] = entryCount;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002682 if (skip + top < entryCount)
Ed Tanous002d39b2022-05-31 08:59:27 -07002683 {
2684 asyncResp->res.jsonValue["Members@odata.nextLink"] =
2685 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries?$skip=" +
Ed Tanous3648c8b2022-07-25 13:39:59 -07002686 std::to_string(skip + top);
Ed Tanous002d39b2022-05-31 08:59:27 -07002687 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002688 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002689}
Jason M. Billse1f26342018-07-18 12:12:00 -07002690
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002691inline void requestRoutesBMCJournalLogEntry(App& app)
Jason M. Billse1f26342018-07-18 12:12:00 -07002692{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002693 BMCWEB_ROUTE(app,
2694 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002695 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002696 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002697 [&app](const crow::Request& req,
2698 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2699 const std::string& entryID) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002700 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002701 {
2702 return;
2703 }
2704 // Convert the unique ID back to a timestamp to find the entry
Myung Bae75e8e212023-11-30 12:53:46 -08002705 sd_id128_t bootID{};
Ed Tanous002d39b2022-05-31 08:59:27 -07002706 uint64_t ts = 0;
2707 uint64_t index = 0;
Myung Bae75e8e212023-11-30 12:53:46 -08002708 if (!getTimestampFromID(asyncResp, entryID, bootID, ts, index))
Ed Tanous002d39b2022-05-31 08:59:27 -07002709 {
2710 return;
2711 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002712
Ed Tanous002d39b2022-05-31 08:59:27 -07002713 sd_journal* journalTmp = nullptr;
2714 int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY);
2715 if (ret < 0)
2716 {
Ed Tanous62598e32023-07-17 17:06:25 -07002717 BMCWEB_LOG_ERROR("failed to open journal: {}", strerror(-ret));
Ed Tanous002d39b2022-05-31 08:59:27 -07002718 messages::internalError(asyncResp->res);
2719 return;
2720 }
2721 std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal(
2722 journalTmp, sd_journal_close);
2723 journalTmp = nullptr;
2724 // Go to the timestamp in the log and move to the entry at the
2725 // index tracking the unique ID
2726 std::string idStr;
2727 bool firstEntry = true;
Myung Bae75e8e212023-11-30 12:53:46 -08002728 ret = sd_journal_seek_monotonic_usec(journal.get(), bootID, ts);
Ed Tanous002d39b2022-05-31 08:59:27 -07002729 if (ret < 0)
2730 {
Ed Tanous62598e32023-07-17 17:06:25 -07002731 BMCWEB_LOG_ERROR("failed to seek to an entry in journal{}",
2732 strerror(-ret));
Ed Tanous002d39b2022-05-31 08:59:27 -07002733 messages::internalError(asyncResp->res);
2734 return;
2735 }
2736 for (uint64_t i = 0; i <= index; i++)
2737 {
2738 sd_journal_next(journal.get());
2739 if (!getUniqueEntryID(journal.get(), idStr, firstEntry))
2740 {
2741 messages::internalError(asyncResp->res);
2742 return;
2743 }
Jason M. Billsefde4ec2022-06-24 08:59:52 -07002744 firstEntry = false;
Ed Tanous002d39b2022-05-31 08:59:27 -07002745 }
2746 // Confirm that the entry ID matches what was requested
2747 if (idStr != entryID)
2748 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08002749 messages::resourceNotFound(asyncResp->res, "LogEntry", entryID);
Ed Tanous002d39b2022-05-31 08:59:27 -07002750 return;
2751 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002752
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002753 nlohmann::json::object_t bmcJournalLogEntry;
Ed Tanous002d39b2022-05-31 08:59:27 -07002754 if (fillBMCJournalLogEntryJson(entryID, journal.get(),
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002755 bmcJournalLogEntry) != 0)
Ed Tanous002d39b2022-05-31 08:59:27 -07002756 {
2757 messages::internalError(asyncResp->res);
2758 return;
2759 }
Jason M. Billsd405bb52022-06-24 10:52:05 -07002760 asyncResp->res.jsonValue.update(bmcJournalLogEntry);
Patrick Williams5a39f772023-10-20 11:20:21 -05002761 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002762}
2763
Claire Weinanfdd26902022-03-01 14:18:25 -08002764inline void
2765 getDumpServiceInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2766 const std::string& dumpType)
2767{
2768 std::string dumpPath;
2769 std::string overWritePolicy;
2770 bool collectDiagnosticDataSupported = false;
2771
2772 if (dumpType == "BMC")
2773 {
2774 dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump";
2775 overWritePolicy = "WrapsWhenFull";
2776 collectDiagnosticDataSupported = true;
2777 }
2778 else if (dumpType == "FaultLog")
2779 {
2780 dumpPath = "/redfish/v1/Managers/bmc/LogServices/FaultLog";
2781 overWritePolicy = "Unknown";
2782 collectDiagnosticDataSupported = false;
2783 }
2784 else if (dumpType == "System")
2785 {
2786 dumpPath = "/redfish/v1/Systems/system/LogServices/Dump";
2787 overWritePolicy = "WrapsWhenFull";
2788 collectDiagnosticDataSupported = true;
2789 }
2790 else
2791 {
Ed Tanous62598e32023-07-17 17:06:25 -07002792 BMCWEB_LOG_ERROR("getDumpServiceInfo() invalid dump type: {}",
2793 dumpType);
Claire Weinanfdd26902022-03-01 14:18:25 -08002794 messages::internalError(asyncResp->res);
2795 return;
2796 }
2797
2798 asyncResp->res.jsonValue["@odata.id"] = dumpPath;
2799 asyncResp->res.jsonValue["@odata.type"] = "#LogService.v1_2_0.LogService";
2800 asyncResp->res.jsonValue["Name"] = "Dump LogService";
2801 asyncResp->res.jsonValue["Description"] = dumpType + " Dump LogService";
2802 asyncResp->res.jsonValue["Id"] = std::filesystem::path(dumpPath).filename();
2803 asyncResp->res.jsonValue["OverWritePolicy"] = std::move(overWritePolicy);
2804
2805 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07002806 redfish::time_utils::getDateTimeOffsetNow();
Claire Weinanfdd26902022-03-01 14:18:25 -08002807 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2808 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2809 redfishDateTimeOffset.second;
2810
2811 asyncResp->res.jsonValue["Entries"]["@odata.id"] = dumpPath + "/Entries";
Claire Weinanfdd26902022-03-01 14:18:25 -08002812
2813 if (collectDiagnosticDataSupported)
2814 {
2815 asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"]
2816 ["target"] =
2817 dumpPath + "/Actions/LogService.CollectDiagnosticData";
2818 }
Claire Weinan0d946212022-07-13 19:40:19 -07002819
2820 constexpr std::array<std::string_view, 1> interfaces = {deleteAllInterface};
2821 dbus::utility::getSubTreePaths(
2822 "/xyz/openbmc_project/dump", 0, interfaces,
2823 [asyncResp, dumpType, dumpPath](
2824 const boost::system::error_code& ec,
2825 const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) {
2826 if (ec)
2827 {
Ed Tanous62598e32023-07-17 17:06:25 -07002828 BMCWEB_LOG_ERROR("getDumpServiceInfo respHandler got error {}", ec);
Claire Weinan0d946212022-07-13 19:40:19 -07002829 // Assume that getting an error simply means there are no dump
2830 // LogServices. Return without adding any error response.
2831 return;
2832 }
Ed Tanous18f8f602023-07-18 10:07:23 -07002833 std::string dbusDumpPath = getDumpPath(dumpType);
Claire Weinan0d946212022-07-13 19:40:19 -07002834 for (const std::string& path : subTreePaths)
2835 {
2836 if (path == dbusDumpPath)
2837 {
2838 asyncResp->res
2839 .jsonValue["Actions"]["#LogService.ClearLog"]["target"] =
2840 dumpPath + "/Actions/LogService.ClearLog";
2841 break;
2842 }
2843 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002844 });
Claire Weinanfdd26902022-03-01 14:18:25 -08002845}
2846
2847inline void handleLogServicesDumpServiceGet(
2848 crow::App& app, const std::string& dumpType, const crow::Request& req,
2849 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2850{
2851 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2852 {
2853 return;
2854 }
2855 getDumpServiceInfo(asyncResp, dumpType);
2856}
2857
Ed Tanous22d268c2022-05-19 09:39:07 -07002858inline void handleLogServicesDumpServiceComputerSystemGet(
2859 crow::App& app, const crow::Request& req,
2860 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2861 const std::string& chassisId)
2862{
2863 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2864 {
2865 return;
2866 }
2867 if (chassisId != "system")
2868 {
2869 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2870 return;
2871 }
2872 getDumpServiceInfo(asyncResp, "System");
2873}
2874
Claire Weinanfdd26902022-03-01 14:18:25 -08002875inline void handleLogServicesDumpEntriesCollectionGet(
2876 crow::App& app, const std::string& dumpType, const crow::Request& req,
2877 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2878{
2879 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2880 {
2881 return;
2882 }
2883 getDumpEntryCollection(asyncResp, dumpType);
2884}
2885
Ed Tanous22d268c2022-05-19 09:39:07 -07002886inline void handleLogServicesDumpEntriesCollectionComputerSystemGet(
2887 crow::App& app, const crow::Request& req,
2888 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2889 const std::string& chassisId)
2890{
2891 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2892 {
2893 return;
2894 }
2895 if (chassisId != "system")
2896 {
2897 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2898 return;
2899 }
2900 getDumpEntryCollection(asyncResp, "System");
2901}
2902
Claire Weinanfdd26902022-03-01 14:18:25 -08002903inline void handleLogServicesDumpEntryGet(
2904 crow::App& app, const std::string& dumpType, const crow::Request& req,
2905 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2906 const std::string& dumpId)
2907{
2908 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2909 {
2910 return;
2911 }
2912 getDumpEntryById(asyncResp, dumpId, dumpType);
2913}
Carson Labrado168d1b12023-03-27 17:04:46 +00002914
Ed Tanous22d268c2022-05-19 09:39:07 -07002915inline void handleLogServicesDumpEntryComputerSystemGet(
2916 crow::App& app, const crow::Request& req,
2917 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2918 const std::string& chassisId, const std::string& dumpId)
2919{
2920 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2921 {
2922 return;
2923 }
2924 if (chassisId != "system")
2925 {
2926 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2927 return;
2928 }
2929 getDumpEntryById(asyncResp, dumpId, "System");
2930}
Claire Weinanfdd26902022-03-01 14:18:25 -08002931
2932inline void handleLogServicesDumpEntryDelete(
2933 crow::App& app, const std::string& dumpType, const crow::Request& req,
2934 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2935 const std::string& dumpId)
2936{
2937 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2938 {
2939 return;
2940 }
2941 deleteDumpEntry(asyncResp, dumpId, dumpType);
2942}
2943
Ed Tanous22d268c2022-05-19 09:39:07 -07002944inline void handleLogServicesDumpEntryComputerSystemDelete(
2945 crow::App& app, const crow::Request& req,
2946 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2947 const std::string& chassisId, const std::string& dumpId)
2948{
2949 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2950 {
2951 return;
2952 }
2953 if (chassisId != "system")
2954 {
2955 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2956 return;
2957 }
2958 deleteDumpEntry(asyncResp, dumpId, "System");
2959}
2960
Carson Labrado168d1b12023-03-27 17:04:46 +00002961inline void handleLogServicesDumpEntryDownloadGet(
2962 crow::App& app, const std::string& dumpType, const crow::Request& req,
2963 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2964 const std::string& dumpId)
2965{
2966 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2967 {
2968 return;
2969 }
2970 downloadDumpEntry(asyncResp, dumpId, dumpType);
2971}
2972
2973inline void handleDBusEventLogEntryDownloadGet(
2974 crow::App& app, const std::string& dumpType, const crow::Request& req,
2975 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2976 const std::string& systemName, const std::string& entryID)
2977{
2978 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2979 {
2980 return;
2981 }
2982 if (!http_helpers::isContentTypeAllowed(
2983 req.getHeaderValue("Accept"),
2984 http_helpers::ContentType::OctetStream, true))
2985 {
2986 asyncResp->res.result(boost::beast::http::status::bad_request);
2987 return;
2988 }
2989 downloadEventLogEntry(asyncResp, systemName, entryID, dumpType);
2990}
2991
Claire Weinanfdd26902022-03-01 14:18:25 -08002992inline void handleLogServicesDumpCollectDiagnosticDataPost(
2993 crow::App& app, const std::string& dumpType, const crow::Request& req,
2994 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2995{
2996 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2997 {
2998 return;
2999 }
3000 createDump(asyncResp, req, dumpType);
3001}
3002
Ed Tanous22d268c2022-05-19 09:39:07 -07003003inline void handleLogServicesDumpCollectDiagnosticDataComputerSystemPost(
3004 crow::App& app, const crow::Request& req,
3005 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003006 const std::string& systemName)
Ed Tanous22d268c2022-05-19 09:39:07 -07003007{
3008 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
3009 {
3010 return;
3011 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003012
Ed Tanous25b54db2024-04-17 15:40:31 -07003013 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous22d268c2022-05-19 09:39:07 -07003014 {
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003015 // Option currently returns no systems. TBD
3016 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3017 systemName);
3018 return;
3019 }
3020 if (systemName != "system")
3021 {
3022 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3023 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003024 return;
3025 }
3026 createDump(asyncResp, req, "System");
3027}
3028
Claire Weinanfdd26902022-03-01 14:18:25 -08003029inline void handleLogServicesDumpClearLogPost(
3030 crow::App& app, const std::string& dumpType, const crow::Request& req,
3031 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
3032{
3033 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
3034 {
3035 return;
3036 }
3037 clearDump(asyncResp, dumpType);
3038}
3039
Ed Tanous22d268c2022-05-19 09:39:07 -07003040inline void handleLogServicesDumpClearLogComputerSystemPost(
3041 crow::App& app, const crow::Request& req,
3042 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003043 const std::string& systemName)
Ed Tanous22d268c2022-05-19 09:39:07 -07003044{
3045 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
3046 {
3047 return;
3048 }
Ed Tanous25b54db2024-04-17 15:40:31 -07003049 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous22d268c2022-05-19 09:39:07 -07003050 {
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003051 // Option currently returns no systems. TBD
3052 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3053 systemName);
3054 return;
3055 }
3056 if (systemName != "system")
3057 {
3058 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3059 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003060 return;
3061 }
3062 clearDump(asyncResp, "System");
3063}
3064
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003065inline void requestRoutesBMCDumpService(App& app)
3066{
3067 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/")
Ed Tanoused398212021-06-09 17:05:54 -07003068 .privileges(redfish::privileges::getLogService)
Claire Weinanfdd26902022-03-01 14:18:25 -08003069 .methods(boost::beast::http::verb::get)(std::bind_front(
3070 handleLogServicesDumpServiceGet, std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003071}
3072
3073inline void requestRoutesBMCDumpEntryCollection(App& app)
3074{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003075 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07003076 .privileges(redfish::privileges::getLogEntryCollection)
Claire Weinanfdd26902022-03-01 14:18:25 -08003077 .methods(boost::beast::http::verb::get)(std::bind_front(
3078 handleLogServicesDumpEntriesCollectionGet, std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003079}
3080
3081inline void requestRoutesBMCDumpEntry(App& app)
3082{
3083 BMCWEB_ROUTE(app,
3084 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003085 .privileges(redfish::privileges::getLogEntry)
Claire Weinanfdd26902022-03-01 14:18:25 -08003086 .methods(boost::beast::http::verb::get)(std::bind_front(
3087 handleLogServicesDumpEntryGet, std::ref(app), "BMC"));
3088
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003089 BMCWEB_ROUTE(app,
3090 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003091 .privileges(redfish::privileges::deleteLogEntry)
Claire Weinanfdd26902022-03-01 14:18:25 -08003092 .methods(boost::beast::http::verb::delete_)(std::bind_front(
3093 handleLogServicesDumpEntryDelete, std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003094}
3095
Carson Labrado168d1b12023-03-27 17:04:46 +00003096inline void requestRoutesBMCDumpEntryDownload(App& app)
3097{
3098 BMCWEB_ROUTE(
3099 app,
Ravi Teja9e9d99d2023-11-08 05:33:59 -06003100 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/attachment/")
Carson Labrado168d1b12023-03-27 17:04:46 +00003101 .privileges(redfish::privileges::getLogEntry)
3102 .methods(boost::beast::http::verb::get)(std::bind_front(
3103 handleLogServicesDumpEntryDownloadGet, std::ref(app), "BMC"));
3104}
3105
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003106inline void requestRoutesBMCDumpCreate(App& app)
3107{
George Liu0fda0f12021-11-16 10:06:17 +08003108 BMCWEB_ROUTE(
3109 app,
3110 "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07003111 .privileges(redfish::privileges::postLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003112 .methods(boost::beast::http::verb::post)(
Claire Weinanfdd26902022-03-01 14:18:25 -08003113 std::bind_front(handleLogServicesDumpCollectDiagnosticDataPost,
3114 std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003115}
3116
3117inline void requestRoutesBMCDumpClear(App& app)
3118{
George Liu0fda0f12021-11-16 10:06:17 +08003119 BMCWEB_ROUTE(
3120 app,
3121 "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07003122 .privileges(redfish::privileges::postLogService)
Claire Weinanfdd26902022-03-01 14:18:25 -08003123 .methods(boost::beast::http::verb::post)(std::bind_front(
3124 handleLogServicesDumpClearLogPost, std::ref(app), "BMC"));
3125}
3126
Carson Labrado168d1b12023-03-27 17:04:46 +00003127inline void requestRoutesDBusEventLogEntryDownload(App& app)
3128{
3129 BMCWEB_ROUTE(
3130 app,
Ravi Teja9e9d99d2023-11-08 05:33:59 -06003131 "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/attachment/")
Carson Labrado168d1b12023-03-27 17:04:46 +00003132 .privileges(redfish::privileges::getLogEntry)
3133 .methods(boost::beast::http::verb::get)(std::bind_front(
3134 handleDBusEventLogEntryDownloadGet, std::ref(app), "System"));
3135}
3136
Claire Weinanfdd26902022-03-01 14:18:25 -08003137inline void requestRoutesFaultLogDumpService(App& app)
3138{
3139 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/FaultLog/")
3140 .privileges(redfish::privileges::getLogService)
3141 .methods(boost::beast::http::verb::get)(std::bind_front(
3142 handleLogServicesDumpServiceGet, std::ref(app), "FaultLog"));
3143}
3144
3145inline void requestRoutesFaultLogDumpEntryCollection(App& app)
3146{
3147 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/")
3148 .privileges(redfish::privileges::getLogEntryCollection)
3149 .methods(boost::beast::http::verb::get)(
3150 std::bind_front(handleLogServicesDumpEntriesCollectionGet,
3151 std::ref(app), "FaultLog"));
3152}
3153
3154inline void requestRoutesFaultLogDumpEntry(App& app)
3155{
3156 BMCWEB_ROUTE(app,
3157 "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/<str>/")
3158 .privileges(redfish::privileges::getLogEntry)
3159 .methods(boost::beast::http::verb::get)(std::bind_front(
3160 handleLogServicesDumpEntryGet, std::ref(app), "FaultLog"));
3161
3162 BMCWEB_ROUTE(app,
3163 "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/<str>/")
3164 .privileges(redfish::privileges::deleteLogEntry)
3165 .methods(boost::beast::http::verb::delete_)(std::bind_front(
3166 handleLogServicesDumpEntryDelete, std::ref(app), "FaultLog"));
3167}
3168
3169inline void requestRoutesFaultLogDumpClear(App& app)
3170{
3171 BMCWEB_ROUTE(
3172 app,
3173 "/redfish/v1/Managers/bmc/LogServices/FaultLog/Actions/LogService.ClearLog/")
3174 .privileges(redfish::privileges::postLogService)
3175 .methods(boost::beast::http::verb::post)(std::bind_front(
3176 handleLogServicesDumpClearLogPost, std::ref(app), "FaultLog"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003177}
3178
3179inline void requestRoutesSystemDumpService(App& app)
3180{
Ed Tanous22d268c2022-05-19 09:39:07 -07003181 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/")
Ed Tanoused398212021-06-09 17:05:54 -07003182 .privileges(redfish::privileges::getLogService)
Claire Weinan6ab9ad52022-08-12 18:20:17 -07003183 .methods(boost::beast::http::verb::get)(std::bind_front(
Ed Tanous22d268c2022-05-19 09:39:07 -07003184 handleLogServicesDumpServiceComputerSystemGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003185}
3186
3187inline void requestRoutesSystemDumpEntryCollection(App& app)
3188{
Ed Tanous22d268c2022-05-19 09:39:07 -07003189 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07003190 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous22d268c2022-05-19 09:39:07 -07003191 .methods(boost::beast::http::verb::get)(std::bind_front(
3192 handleLogServicesDumpEntriesCollectionComputerSystemGet,
3193 std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003194}
3195
3196inline void requestRoutesSystemDumpEntry(App& app)
3197{
3198 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003199 "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003200 .privileges(redfish::privileges::getLogEntry)
Claire Weinan6ab9ad52022-08-12 18:20:17 -07003201 .methods(boost::beast::http::verb::get)(std::bind_front(
Ed Tanous22d268c2022-05-19 09:39:07 -07003202 handleLogServicesDumpEntryComputerSystemGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003203
3204 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003205 "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003206 .privileges(redfish::privileges::deleteLogEntry)
Claire Weinan6ab9ad52022-08-12 18:20:17 -07003207 .methods(boost::beast::http::verb::delete_)(std::bind_front(
Ed Tanous22d268c2022-05-19 09:39:07 -07003208 handleLogServicesDumpEntryComputerSystemDelete, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003209}
3210
3211inline void requestRoutesSystemDumpCreate(App& app)
3212{
George Liu0fda0f12021-11-16 10:06:17 +08003213 BMCWEB_ROUTE(
3214 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003215 "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07003216 .privileges(redfish::privileges::postLogService)
Ed Tanous22d268c2022-05-19 09:39:07 -07003217 .methods(boost::beast::http::verb::post)(std::bind_front(
3218 handleLogServicesDumpCollectDiagnosticDataComputerSystemPost,
3219 std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003220}
3221
3222inline void requestRoutesSystemDumpClear(App& app)
3223{
George Liu0fda0f12021-11-16 10:06:17 +08003224 BMCWEB_ROUTE(
3225 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003226 "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07003227 .privileges(redfish::privileges::postLogService)
Claire Weinan6ab9ad52022-08-12 18:20:17 -07003228 .methods(boost::beast::http::verb::post)(std::bind_front(
Ed Tanous22d268c2022-05-19 09:39:07 -07003229 handleLogServicesDumpClearLogComputerSystemPost, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003230}
3231
3232inline void requestRoutesCrashdumpService(App& app)
3233{
3234 // Note: Deviated from redfish privilege registry for GET & HEAD
3235 // method for security reasons.
3236 /**
3237 * Functions triggers appropriate requests on DBus
3238 */
Ed Tanous22d268c2022-05-19 09:39:07 -07003239 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/")
Ed Tanoused398212021-06-09 17:05:54 -07003240 // This is incorrect, should be:
3241 //.privileges(redfish::privileges::getLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07003242 .privileges({{"ConfigureManager"}})
Ed Tanous002d39b2022-05-31 08:59:27 -07003243 .methods(boost::beast::http::verb::get)(
3244 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003245 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3246 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003247 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003248 {
3249 return;
3250 }
Ed Tanous25b54db2024-04-17 15:40:31 -07003251 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003252 {
3253 // Option currently returns no systems. TBD
3254 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3255 systemName);
3256 return;
3257 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003258 if (systemName != "system")
3259 {
3260 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3261 systemName);
3262 return;
3263 }
3264
Ed Tanous002d39b2022-05-31 08:59:27 -07003265 // Copy over the static data to include the entries added by
3266 // SubRoute
3267 asyncResp->res.jsonValue["@odata.id"] =
3268 "/redfish/v1/Systems/system/LogServices/Crashdump";
3269 asyncResp->res.jsonValue["@odata.type"] =
3270 "#LogService.v1_2_0.LogService";
3271 asyncResp->res.jsonValue["Name"] = "Open BMC Oem Crashdump Service";
3272 asyncResp->res.jsonValue["Description"] = "Oem Crashdump Service";
V-Sanjana15b89722023-05-11 16:27:03 +05303273 asyncResp->res.jsonValue["Id"] = "Crashdump";
Ed Tanous002d39b2022-05-31 08:59:27 -07003274 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
3275 asyncResp->res.jsonValue["MaxNumberOfRecords"] = 3;
Tejas Patil7c8c4052021-06-04 17:43:14 +05303276
Ed Tanous002d39b2022-05-31 08:59:27 -07003277 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07003278 redfish::time_utils::getDateTimeOffsetNow();
Ed Tanous002d39b2022-05-31 08:59:27 -07003279 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
3280 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
3281 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05303282
Ed Tanous002d39b2022-05-31 08:59:27 -07003283 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
Ed Tanousef4c65b2023-04-24 15:28:50 -07003284 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries";
Ed Tanous002d39b2022-05-31 08:59:27 -07003285 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"] =
3286 "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.ClearLog";
3287 asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"]
3288 ["target"] =
3289 "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData";
Patrick Williams5a39f772023-10-20 11:20:21 -05003290 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003291}
3292
3293void inline requestRoutesCrashdumpClear(App& app)
3294{
George Liu0fda0f12021-11-16 10:06:17 +08003295 BMCWEB_ROUTE(
3296 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003297 "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07003298 // This is incorrect, should be:
3299 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07003300 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003301 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003302 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003303 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3304 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003305 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003306 {
3307 return;
3308 }
Ed Tanous25b54db2024-04-17 15:40:31 -07003309 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003310 {
3311 // Option currently returns no systems. TBD
3312 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3313 systemName);
3314 return;
3315 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003316 if (systemName != "system")
3317 {
3318 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3319 systemName);
3320 return;
3321 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003322 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08003323 [asyncResp](const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -07003324 const std::string&) {
3325 if (ec)
3326 {
3327 messages::internalError(asyncResp->res);
3328 return;
3329 }
3330 messages::success(asyncResp->res);
Patrick Williams5a39f772023-10-20 11:20:21 -05003331 },
Ed Tanous002d39b2022-05-31 08:59:27 -07003332 crashdumpObject, crashdumpPath, deleteAllInterface, "DeleteAll");
Patrick Williams5a39f772023-10-20 11:20:21 -05003333 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003334}
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07003335
zhanghch058d1b46d2021-04-01 11:18:24 +08003336static void
3337 logCrashdumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3338 const std::string& logID, nlohmann::json& logEntryJson)
Jason M. Billse855dd22019-10-08 11:37:48 -07003339{
Johnathan Mantey043a0532020-03-10 17:15:28 -07003340 auto getStoredLogCallback =
Ed Tanousb9d36b42022-02-26 21:42:46 -08003341 [asyncResp, logID,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08003342 &logEntryJson](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08003343 const dbus::utility::DBusPropertiesMap& params) {
Ed Tanous002d39b2022-05-31 08:59:27 -07003344 if (ec)
3345 {
Ed Tanous62598e32023-07-17 17:06:25 -07003346 BMCWEB_LOG_DEBUG("failed to get log ec: {}", ec.message());
Ed Tanous002d39b2022-05-31 08:59:27 -07003347 if (ec.value() ==
3348 boost::system::linux_error::bad_request_descriptor)
Jason M. Bills1ddcf012019-11-26 14:59:21 -08003349 {
Ed Tanous002d39b2022-05-31 08:59:27 -07003350 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Jason M. Bills2b20ef62022-01-06 15:48:07 -08003351 }
3352 else
3353 {
Ed Tanous002d39b2022-05-31 08:59:27 -07003354 messages::internalError(asyncResp->res);
Jason M. Bills2b20ef62022-01-06 15:48:07 -08003355 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003356 return;
3357 }
3358
3359 std::string timestamp{};
3360 std::string filename{};
3361 std::string logfile{};
3362 parseCrashdumpParameters(params, filename, timestamp, logfile);
3363
3364 if (filename.empty() || timestamp.empty())
3365 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08003366 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Ed Tanous002d39b2022-05-31 08:59:27 -07003367 return;
3368 }
3369
3370 std::string crashdumpURI =
3371 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" +
3372 logID + "/" + filename;
Jason M. Bills84afc482022-06-24 12:38:23 -07003373 nlohmann::json::object_t logEntry;
Vijay Lobo9c11a172021-10-07 16:53:16 -05003374 logEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Ed Tanousef4c65b2023-04-24 15:28:50 -07003375 logEntry["@odata.id"] = boost::urls::format(
3376 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/{}",
3377 logID);
Jason M. Bills84afc482022-06-24 12:38:23 -07003378 logEntry["Name"] = "CPU Crashdump";
3379 logEntry["Id"] = logID;
3380 logEntry["EntryType"] = "Oem";
3381 logEntry["AdditionalDataURI"] = std::move(crashdumpURI);
3382 logEntry["DiagnosticDataType"] = "OEM";
3383 logEntry["OEMDiagnosticDataType"] = "PECICrashdump";
3384 logEntry["Created"] = std::move(timestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07003385
3386 // If logEntryJson references an array of LogEntry resources
3387 // ('Members' list), then push this as a new entry, otherwise set it
3388 // directly
3389 if (logEntryJson.is_array())
3390 {
3391 logEntryJson.push_back(logEntry);
3392 asyncResp->res.jsonValue["Members@odata.count"] =
3393 logEntryJson.size();
3394 }
3395 else
3396 {
Jason M. Billsd405bb52022-06-24 10:52:05 -07003397 logEntryJson.update(logEntry);
Ed Tanous002d39b2022-05-31 08:59:27 -07003398 }
3399 };
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02003400 sdbusplus::asio::getAllProperties(
3401 *crow::connections::systemBus, crashdumpObject,
3402 crashdumpPath + std::string("/") + logID, crashdumpInterface,
3403 std::move(getStoredLogCallback));
Jason M. Billse855dd22019-10-08 11:37:48 -07003404}
3405
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003406inline void requestRoutesCrashdumpEntryCollection(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07003407{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003408 // Note: Deviated from redfish privilege registry for GET & HEAD
3409 // method for security reasons.
Ed Tanous1da66f72018-07-27 16:13:37 -07003410 /**
3411 * Functions triggers appropriate requests on DBus
3412 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003413 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003414 "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07003415 // This is incorrect, should be.
3416 //.privileges(redfish::privileges::postLogEntryCollection)
Ed Tanous432a8902021-06-14 15:28:56 -07003417 .privileges({{"ConfigureComponents"}})
Ed Tanous002d39b2022-05-31 08:59:27 -07003418 .methods(boost::beast::http::verb::get)(
3419 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003420 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3421 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003422 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003423 {
3424 return;
3425 }
Ed Tanous25b54db2024-04-17 15:40:31 -07003426 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003427 {
3428 // Option currently returns no systems. TBD
3429 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3430 systemName);
3431 return;
3432 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003433 if (systemName != "system")
3434 {
3435 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3436 systemName);
3437 return;
3438 }
3439
George Liu7a1dbc42022-12-07 16:03:22 +08003440 constexpr std::array<std::string_view, 1> interfaces = {
3441 crashdumpInterface};
3442 dbus::utility::getSubTreePaths(
3443 "/", 0, interfaces,
3444 [asyncResp](const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -07003445 const std::vector<std::string>& resp) {
3446 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -07003447 {
Ed Tanous002d39b2022-05-31 08:59:27 -07003448 if (ec.value() !=
3449 boost::system::errc::no_such_file_or_directory)
3450 {
Ed Tanous62598e32023-07-17 17:06:25 -07003451 BMCWEB_LOG_DEBUG("failed to get entries ec: {}",
3452 ec.message());
Ed Tanous002d39b2022-05-31 08:59:27 -07003453 messages::internalError(asyncResp->res);
3454 return;
3455 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07003456 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003457 asyncResp->res.jsonValue["@odata.type"] =
3458 "#LogEntryCollection.LogEntryCollection";
3459 asyncResp->res.jsonValue["@odata.id"] =
3460 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries";
3461 asyncResp->res.jsonValue["Name"] = "Open BMC Crashdump Entries";
3462 asyncResp->res.jsonValue["Description"] =
3463 "Collection of Crashdump Entries";
3464 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
3465 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Jason M. Bills2b20ef62022-01-06 15:48:07 -08003466
Ed Tanous002d39b2022-05-31 08:59:27 -07003467 for (const std::string& path : resp)
3468 {
3469 const sdbusplus::message::object_path objPath(path);
3470 // Get the log ID
3471 std::string logID = objPath.filename();
3472 if (logID.empty())
3473 {
3474 continue;
3475 }
3476 // Add the log entry to the array
3477 logCrashdumpEntry(asyncResp, logID,
3478 asyncResp->res.jsonValue["Members"]);
3479 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003480 });
Patrick Williams5a39f772023-10-20 11:20:21 -05003481 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003482}
Ed Tanous1da66f72018-07-27 16:13:37 -07003483
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003484inline void requestRoutesCrashdumpEntry(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07003485{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003486 // Note: Deviated from redfish privilege registry for GET & HEAD
3487 // method for security reasons.
Ed Tanous1da66f72018-07-27 16:13:37 -07003488
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003489 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07003490 app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003491 // this is incorrect, should be
3492 // .privileges(redfish::privileges::getLogEntry)
Ed Tanous432a8902021-06-14 15:28:56 -07003493 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003494 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003495 [&app](const crow::Request& req,
3496 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07003497 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003498 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003499 {
3500 return;
3501 }
Ed Tanous25b54db2024-04-17 15:40:31 -07003502 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003503 {
3504 // Option currently returns no systems. TBD
3505 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3506 systemName);
3507 return;
3508 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003509 if (systemName != "system")
3510 {
3511 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3512 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003513 return;
3514 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003515 const std::string& logID = param;
3516 logCrashdumpEntry(asyncResp, logID, asyncResp->res.jsonValue);
Patrick Williams5a39f772023-10-20 11:20:21 -05003517 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003518}
Ed Tanous1da66f72018-07-27 16:13:37 -07003519
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003520inline void requestRoutesCrashdumpFile(App& app)
3521{
3522 // Note: Deviated from redfish privilege registry for GET & HEAD
3523 // method for security reasons.
3524 BMCWEB_ROUTE(
3525 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003526 "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003527 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003528 .methods(boost::beast::http::verb::get)(
Nan Zhoua4ce1142022-08-02 18:45:25 +00003529 [](const crow::Request& req,
3530 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07003531 const std::string& systemName, const std::string& logID,
3532 const std::string& fileName) {
Shounak Mitra2a9beee2022-07-20 18:41:30 +00003533 // Do not call getRedfishRoute here since the crashdump file is not a
3534 // Redfish resource.
Ed Tanous22d268c2022-05-19 09:39:07 -07003535
Ed Tanous25b54db2024-04-17 15:40:31 -07003536 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003537 {
3538 // Option currently returns no systems. TBD
3539 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3540 systemName);
3541 return;
3542 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003543 if (systemName != "system")
3544 {
3545 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3546 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003547 return;
3548 }
3549
Ed Tanous002d39b2022-05-31 08:59:27 -07003550 auto getStoredLogCallback =
Ed Tanous39662a32023-02-06 15:09:46 -08003551 [asyncResp, logID, fileName, url(boost::urls::url(req.url()))](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08003552 const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -07003553 const std::vector<
3554 std::pair<std::string, dbus::utility::DbusVariantType>>&
3555 resp) {
3556 if (ec)
3557 {
Ed Tanous62598e32023-07-17 17:06:25 -07003558 BMCWEB_LOG_DEBUG("failed to get log ec: {}", ec.message());
Ed Tanous002d39b2022-05-31 08:59:27 -07003559 messages::internalError(asyncResp->res);
3560 return;
3561 }
Jason M. Bills8e6c0992021-03-11 16:26:53 -08003562
Ed Tanous002d39b2022-05-31 08:59:27 -07003563 std::string dbusFilename{};
3564 std::string dbusTimestamp{};
3565 std::string dbusFilepath{};
Jason M. Bills8e6c0992021-03-11 16:26:53 -08003566
Ed Tanous002d39b2022-05-31 08:59:27 -07003567 parseCrashdumpParameters(resp, dbusFilename, dbusTimestamp,
3568 dbusFilepath);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003569
Ed Tanous002d39b2022-05-31 08:59:27 -07003570 if (dbusFilename.empty() || dbusTimestamp.empty() ||
3571 dbusFilepath.empty())
3572 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08003573 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Ed Tanous002d39b2022-05-31 08:59:27 -07003574 return;
3575 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003576
Ed Tanous002d39b2022-05-31 08:59:27 -07003577 // Verify the file name parameter is correct
3578 if (fileName != dbusFilename)
3579 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08003580 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Ed Tanous002d39b2022-05-31 08:59:27 -07003581 return;
3582 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003583
Ed Tanous27b0cf92023-08-07 12:02:40 -07003584 if (!asyncResp->res.openFile(dbusFilepath))
Ed Tanous002d39b2022-05-31 08:59:27 -07003585 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08003586 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Ed Tanous002d39b2022-05-31 08:59:27 -07003587 return;
3588 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003589
Ed Tanous002d39b2022-05-31 08:59:27 -07003590 // Configure this to be a file download when accessed
3591 // from a browser
Ed Tanousd9f6c622022-03-17 09:12:17 -07003592 asyncResp->res.addHeader(
3593 boost::beast::http::field::content_disposition, "attachment");
Ed Tanous002d39b2022-05-31 08:59:27 -07003594 };
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02003595 sdbusplus::asio::getAllProperties(
3596 *crow::connections::systemBus, crashdumpObject,
3597 crashdumpPath + std::string("/") + logID, crashdumpInterface,
3598 std::move(getStoredLogCallback));
Patrick Williams5a39f772023-10-20 11:20:21 -05003599 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003600}
3601
Jason M. Billsc5a4c822022-01-06 15:51:23 -08003602enum class OEMDiagnosticType
3603{
3604 onDemand,
3605 telemetry,
3606 invalid,
3607};
3608
Ed Tanous26ccae32023-02-16 10:28:44 -08003609inline OEMDiagnosticType getOEMDiagnosticType(std::string_view oemDiagStr)
Jason M. Billsc5a4c822022-01-06 15:51:23 -08003610{
3611 if (oemDiagStr == "OnDemand")
3612 {
3613 return OEMDiagnosticType::onDemand;
3614 }
3615 if (oemDiagStr == "Telemetry")
3616 {
3617 return OEMDiagnosticType::telemetry;
3618 }
3619
3620 return OEMDiagnosticType::invalid;
3621}
3622
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003623inline void requestRoutesCrashdumpCollect(App& app)
3624{
3625 // Note: Deviated from redfish privilege registry for GET & HEAD
3626 // method for security reasons.
George Liu0fda0f12021-11-16 10:06:17 +08003627 BMCWEB_ROUTE(
3628 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003629 "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07003630 // The below is incorrect; Should be ConfigureManager
3631 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07003632 .privileges({{"ConfigureComponents"}})
Ed Tanous002d39b2022-05-31 08:59:27 -07003633 .methods(boost::beast::http::verb::post)(
3634 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003635 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3636 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003637 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003638 {
3639 return;
3640 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003641
Ed Tanous25b54db2024-04-17 15:40:31 -07003642 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003643 {
3644 // Option currently returns no systems. TBD
3645 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3646 systemName);
3647 return;
3648 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003649 if (systemName != "system")
3650 {
3651 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3652 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003653 return;
3654 }
3655
Ed Tanous002d39b2022-05-31 08:59:27 -07003656 std::string diagnosticDataType;
3657 std::string oemDiagnosticDataType;
3658 if (!redfish::json_util::readJsonAction(
3659 req, asyncResp->res, "DiagnosticDataType", diagnosticDataType,
3660 "OEMDiagnosticDataType", oemDiagnosticDataType))
3661 {
3662 return;
3663 }
3664
3665 if (diagnosticDataType != "OEM")
3666 {
Ed Tanous62598e32023-07-17 17:06:25 -07003667 BMCWEB_LOG_ERROR(
3668 "Only OEM DiagnosticDataType supported for Crashdump");
Ed Tanous002d39b2022-05-31 08:59:27 -07003669 messages::actionParameterValueFormatError(
3670 asyncResp->res, diagnosticDataType, "DiagnosticDataType",
3671 "CollectDiagnosticData");
3672 return;
3673 }
3674
3675 OEMDiagnosticType oemDiagType =
3676 getOEMDiagnosticType(oemDiagnosticDataType);
3677
3678 std::string iface;
3679 std::string method;
3680 std::string taskMatchStr;
3681 if (oemDiagType == OEMDiagnosticType::onDemand)
3682 {
3683 iface = crashdumpOnDemandInterface;
3684 method = "GenerateOnDemandLog";
3685 taskMatchStr = "type='signal',"
3686 "interface='org.freedesktop.DBus.Properties',"
3687 "member='PropertiesChanged',"
3688 "arg0namespace='com.intel.crashdump'";
3689 }
3690 else if (oemDiagType == OEMDiagnosticType::telemetry)
3691 {
3692 iface = crashdumpTelemetryInterface;
3693 method = "GenerateTelemetryLog";
3694 taskMatchStr = "type='signal',"
3695 "interface='org.freedesktop.DBus.Properties',"
3696 "member='PropertiesChanged',"
3697 "arg0namespace='com.intel.crashdump'";
3698 }
3699 else
3700 {
Ed Tanous62598e32023-07-17 17:06:25 -07003701 BMCWEB_LOG_ERROR("Unsupported OEMDiagnosticDataType: {}",
3702 oemDiagnosticDataType);
Ed Tanous002d39b2022-05-31 08:59:27 -07003703 messages::actionParameterValueFormatError(
3704 asyncResp->res, oemDiagnosticDataType, "OEMDiagnosticDataType",
3705 "CollectDiagnosticData");
3706 return;
3707 }
3708
3709 auto collectCrashdumpCallback =
3710 [asyncResp, payload(task::Payload(req)),
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08003711 taskMatchStr](const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -07003712 const std::string&) mutable {
3713 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -07003714 {
Ed Tanous002d39b2022-05-31 08:59:27 -07003715 if (ec.value() == boost::system::errc::operation_not_supported)
3716 {
3717 messages::resourceInStandby(asyncResp->res);
3718 }
3719 else if (ec.value() ==
3720 boost::system::errc::device_or_resource_busy)
3721 {
3722 messages::serviceTemporarilyUnavailable(asyncResp->res,
3723 "60");
3724 }
3725 else
3726 {
3727 messages::internalError(asyncResp->res);
3728 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07003729 return;
3730 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003731 std::shared_ptr<task::TaskData> task = task::TaskData::createTask(
Ed Tanous8b242752023-06-27 17:17:13 -07003732 [](const boost::system::error_code& ec2, sdbusplus::message_t&,
Ed Tanous002d39b2022-05-31 08:59:27 -07003733 const std::shared_ptr<task::TaskData>& taskData) {
Ed Tanous8b242752023-06-27 17:17:13 -07003734 if (!ec2)
Ed Tanous002d39b2022-05-31 08:59:27 -07003735 {
3736 taskData->messages.emplace_back(messages::taskCompletedOK(
3737 std::to_string(taskData->index)));
3738 taskData->state = "Completed";
3739 }
3740 return task::completed;
Patrick Williams5a39f772023-10-20 11:20:21 -05003741 },
Ed Tanous002d39b2022-05-31 08:59:27 -07003742 taskMatchStr);
Ed Tanous1da66f72018-07-27 16:13:37 -07003743
Ed Tanous002d39b2022-05-31 08:59:27 -07003744 task->startTimer(std::chrono::minutes(5));
3745 task->populateResp(asyncResp->res);
3746 task->payload.emplace(std::move(payload));
3747 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003748
Ed Tanous002d39b2022-05-31 08:59:27 -07003749 crow::connections::systemBus->async_method_call(
3750 std::move(collectCrashdumpCallback), crashdumpObject, crashdumpPath,
3751 iface, method);
Patrick Williams5a39f772023-10-20 11:20:21 -05003752 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003753}
Kenny L. Ku6eda7682020-06-19 09:48:36 -07003754
Andrew Geisslercb92c032018-08-17 07:56:14 -07003755/**
3756 * DBusLogServiceActionsClear class supports POST method for ClearLog action.
3757 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003758inline void requestRoutesDBusLogServiceActionsClear(App& app)
Andrew Geisslercb92c032018-08-17 07:56:14 -07003759{
Andrew Geisslercb92c032018-08-17 07:56:14 -07003760 /**
3761 * Function handles POST method request.
3762 * The Clear Log actions does not require any parameter.The action deletes
3763 * all entries found in the Entries collection for this Log Service.
3764 */
Andrew Geisslercb92c032018-08-17 07:56:14 -07003765
George Liu0fda0f12021-11-16 10:06:17 +08003766 BMCWEB_ROUTE(
3767 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003768 "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07003769 .privileges(redfish::privileges::postLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003770 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003771 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003772 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3773 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003774 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003775 {
3776 return;
3777 }
Ed Tanous25b54db2024-04-17 15:40:31 -07003778 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003779 {
3780 // Option currently returns no systems. TBD
3781 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3782 systemName);
3783 return;
3784 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003785 if (systemName != "system")
3786 {
3787 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3788 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003789 return;
3790 }
Ed Tanous62598e32023-07-17 17:06:25 -07003791 BMCWEB_LOG_DEBUG("Do delete all entries.");
Andrew Geisslercb92c032018-08-17 07:56:14 -07003792
Ed Tanous002d39b2022-05-31 08:59:27 -07003793 // Process response from Logging service.
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08003794 auto respHandler = [asyncResp](const boost::system::error_code& ec) {
Ed Tanous62598e32023-07-17 17:06:25 -07003795 BMCWEB_LOG_DEBUG("doClearLog resp_handler callback: Done");
Ed Tanous002d39b2022-05-31 08:59:27 -07003796 if (ec)
3797 {
3798 // TODO Handle for specific error code
Ed Tanous62598e32023-07-17 17:06:25 -07003799 BMCWEB_LOG_ERROR("doClearLog resp_handler got error {}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -07003800 asyncResp->res.result(
3801 boost::beast::http::status::internal_server_error);
3802 return;
3803 }
Andrew Geisslercb92c032018-08-17 07:56:14 -07003804
Ed Tanous002d39b2022-05-31 08:59:27 -07003805 asyncResp->res.result(boost::beast::http::status::no_content);
3806 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003807
Ed Tanous002d39b2022-05-31 08:59:27 -07003808 // Make call to Logging service to request Clear Log
3809 crow::connections::systemBus->async_method_call(
3810 respHandler, "xyz.openbmc_project.Logging",
3811 "/xyz/openbmc_project/logging",
3812 "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
Patrick Williams5a39f772023-10-20 11:20:21 -05003813 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003814}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003815
3816/****************************************************
3817 * Redfish PostCode interfaces
3818 * using DBUS interface: getPostCodesTS
3819 ******************************************************/
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003820inline void requestRoutesPostCodesLogService(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003821{
Ed Tanous22d268c2022-05-19 09:39:07 -07003822 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/")
Ed Tanoused398212021-06-09 17:05:54 -07003823 .privileges(redfish::privileges::getLogService)
Ed Tanous002d39b2022-05-31 08:59:27 -07003824 .methods(boost::beast::http::verb::get)(
3825 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003826 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3827 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003828 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003829 {
3830 return;
3831 }
Ed Tanous25b54db2024-04-17 15:40:31 -07003832 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003833 {
3834 // Option currently returns no systems. TBD
3835 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3836 systemName);
3837 return;
3838 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003839 if (systemName != "system")
3840 {
3841 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3842 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003843 return;
3844 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003845 asyncResp->res.jsonValue["@odata.id"] =
3846 "/redfish/v1/Systems/system/LogServices/PostCodes";
3847 asyncResp->res.jsonValue["@odata.type"] =
Janet Adkinsb25644a2023-08-16 11:23:45 -05003848 "#LogService.v1_2_0.LogService";
Ed Tanous002d39b2022-05-31 08:59:27 -07003849 asyncResp->res.jsonValue["Name"] = "POST Code Log Service";
3850 asyncResp->res.jsonValue["Description"] = "POST Code Log Service";
Ed Tanoused34a4a2023-02-08 15:43:27 -08003851 asyncResp->res.jsonValue["Id"] = "PostCodes";
Ed Tanous002d39b2022-05-31 08:59:27 -07003852 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
3853 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
3854 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries";
Tejas Patil7c8c4052021-06-04 17:43:14 +05303855
Ed Tanous002d39b2022-05-31 08:59:27 -07003856 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07003857 redfish::time_utils::getDateTimeOffsetNow();
Ed Tanous002d39b2022-05-31 08:59:27 -07003858 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
3859 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
3860 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05303861
Ed Tanous002d39b2022-05-31 08:59:27 -07003862 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = {
3863 {"target",
3864 "/redfish/v1/Systems/system/LogServices/PostCodes/Actions/LogService.ClearLog"}};
Patrick Williams5a39f772023-10-20 11:20:21 -05003865 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003866}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003867
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003868inline void requestRoutesPostCodesClear(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003869{
George Liu0fda0f12021-11-16 10:06:17 +08003870 BMCWEB_ROUTE(
3871 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003872 "/redfish/v1/Systems/<str>/LogServices/PostCodes/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07003873 // The following privilege is incorrect; It should be ConfigureManager
3874 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07003875 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003876 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003877 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003878 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3879 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003880 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003881 {
3882 return;
3883 }
Ed Tanous25b54db2024-04-17 15:40:31 -07003884 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003885 {
3886 // Option currently returns no systems. TBD
3887 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3888 systemName);
3889 return;
3890 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003891 if (systemName != "system")
3892 {
3893 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3894 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003895 return;
3896 }
Ed Tanous62598e32023-07-17 17:06:25 -07003897 BMCWEB_LOG_DEBUG("Do delete all postcodes entries.");
ZhikuiRena3316fc2020-01-29 14:58:08 -08003898
Ed Tanous002d39b2022-05-31 08:59:27 -07003899 // Make call to post-code service to request clear all
3900 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08003901 [asyncResp](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -07003902 if (ec)
3903 {
3904 // TODO Handle for specific error code
Ed Tanous62598e32023-07-17 17:06:25 -07003905 BMCWEB_LOG_ERROR("doClearPostCodes resp_handler got error {}",
3906 ec);
Ed Tanous002d39b2022-05-31 08:59:27 -07003907 asyncResp->res.result(
3908 boost::beast::http::status::internal_server_error);
3909 messages::internalError(asyncResp->res);
3910 return;
3911 }
Tony Lee18fc70c2023-08-24 16:15:54 +08003912 messages::success(asyncResp->res);
Patrick Williams5a39f772023-10-20 11:20:21 -05003913 },
Ed Tanous002d39b2022-05-31 08:59:27 -07003914 "xyz.openbmc_project.State.Boot.PostCode0",
3915 "/xyz/openbmc_project/State/Boot/PostCode0",
3916 "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
Patrick Williams5a39f772023-10-20 11:20:21 -05003917 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003918}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003919
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08003920/**
3921 * @brief Parse post code ID and get the current value and index value
3922 * eg: postCodeID=B1-2, currentValue=1, index=2
3923 *
3924 * @param[in] postCodeID Post Code ID
3925 * @param[out] currentValue Current value
3926 * @param[out] index Index value
3927 *
3928 * @return bool true if the parsing is successful, false the parsing fails
3929 */
Ed Tanous6f056f22024-04-07 13:35:51 -07003930inline bool parsePostCode(std::string_view postCodeID, uint64_t& currentValue,
Ed Tanousdf254f22024-04-01 13:25:46 -07003931 uint16_t& index)
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08003932{
3933 std::vector<std::string> split;
Ed Tanous50ebd4a2023-01-19 19:03:17 -08003934 bmcweb::split(split, postCodeID, '-');
Ed Tanous6f056f22024-04-07 13:35:51 -07003935 if (split.size() != 2)
3936 {
3937 return false;
3938 }
3939 std::string_view postCodeNumber = split[0];
3940 if (postCodeNumber.size() < 2)
3941 {
3942 return false;
3943 }
3944 if (postCodeNumber[0] != 'B')
3945 {
3946 return false;
3947 }
3948 postCodeNumber.remove_prefix(1);
3949 auto [ptrIndex, ecIndex] = std::from_chars(postCodeNumber.begin(),
3950 postCodeNumber.end(), index);
3951 if (ptrIndex != postCodeNumber.end() || ecIndex != std::errc())
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08003952 {
3953 return false;
3954 }
3955
Ed Tanous6f056f22024-04-07 13:35:51 -07003956 std::string_view postCodeIndex = split[1];
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08003957
Ed Tanous6f056f22024-04-07 13:35:51 -07003958 auto [ptrValue, ecValue] = std::from_chars(
3959 postCodeIndex.begin(), postCodeIndex.end(), currentValue);
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08003960
Ed Tanous6f056f22024-04-07 13:35:51 -07003961 return ptrValue == postCodeIndex.end() && ecValue == std::errc();
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08003962}
3963
3964static bool fillPostCodeEntry(
Ed Tanousac106bf2023-06-07 09:24:59 -07003965 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303966 const boost::container::flat_map<
3967 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& postcode,
ZhikuiRena3316fc2020-01-29 14:58:08 -08003968 const uint16_t bootIndex, const uint64_t codeIndex = 0,
3969 const uint64_t skip = 0, const uint64_t top = 0)
3970{
3971 // Get the Message from the MessageRegistry
Ed Tanousfffb8c12022-02-07 23:53:03 -08003972 const registries::Message* message =
3973 registries::getMessage("OpenBMC.0.2.BIOSPOSTCode");
Ed Tanousdc8cfa62024-04-07 13:37:25 -07003974 if (message == nullptr)
3975 {
3976 BMCWEB_LOG_ERROR("Couldn't find known message?");
3977 return false;
3978 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003979 uint64_t currentCodeIndex = 0;
ZhikuiRena3316fc2020-01-29 14:58:08 -08003980 uint64_t firstCodeTimeUs = 0;
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303981 for (const std::pair<uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
3982 code : postcode)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003983 {
3984 currentCodeIndex++;
3985 std::string postcodeEntryID =
3986 "B" + std::to_string(bootIndex) + "-" +
3987 std::to_string(currentCodeIndex); // 1 based index in EntryID string
3988
3989 uint64_t usecSinceEpoch = code.first;
3990 uint64_t usTimeOffset = 0;
3991
3992 if (1 == currentCodeIndex)
3993 { // already incremented
3994 firstCodeTimeUs = code.first;
3995 }
3996 else
3997 {
3998 usTimeOffset = code.first - firstCodeTimeUs;
3999 }
4000
4001 // skip if no specific codeIndex is specified and currentCodeIndex does
4002 // not fall between top and skip
4003 if ((codeIndex == 0) &&
4004 (currentCodeIndex <= skip || currentCodeIndex > top))
4005 {
4006 continue;
4007 }
4008
Gunnar Mills4e0453b2020-07-08 14:00:30 -05004009 // skip if a specific codeIndex is specified and does not match the
ZhikuiRena3316fc2020-01-29 14:58:08 -08004010 // currentIndex
4011 if ((codeIndex > 0) && (currentCodeIndex != codeIndex))
4012 {
4013 // This is done for simplicity. 1st entry is needed to calculate
4014 // time offset. To improve efficiency, one can get to the entry
4015 // directly (possibly with flatmap's nth method)
4016 continue;
4017 }
4018
4019 // currentCodeIndex is within top and skip or equal to specified code
4020 // index
4021
4022 // Get the Created time from the timestamp
4023 std::string entryTimeStr;
Konstantin Aladyshev2a025612023-02-15 11:52:58 +03004024 entryTimeStr = redfish::time_utils::getDateTimeUintUs(usecSinceEpoch);
ZhikuiRena3316fc2020-01-29 14:58:08 -08004025
4026 // assemble messageArgs: BootIndex, TimeOffset(100us), PostCode(hex)
4027 std::ostringstream hexCode;
4028 hexCode << "0x" << std::setfill('0') << std::setw(2) << std::hex
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05304029 << std::get<0>(code.second);
ZhikuiRena3316fc2020-01-29 14:58:08 -08004030 std::ostringstream timeOffsetStr;
4031 // Set Fixed -Point Notation
4032 timeOffsetStr << std::fixed;
4033 // Set precision to 4 digits
4034 timeOffsetStr << std::setprecision(4);
4035 // Add double to stream
4036 timeOffsetStr << static_cast<double>(usTimeOffset) / 1000 / 1000;
ZhikuiRena3316fc2020-01-29 14:58:08 -08004037
Ed Tanous1e6deaf2022-02-17 11:32:37 -08004038 std::string bootIndexStr = std::to_string(bootIndex);
4039 std::string timeOffsetString = timeOffsetStr.str();
4040 std::string hexCodeStr = hexCode.str();
4041
4042 std::array<std::string_view, 3> messageArgs = {
4043 bootIndexStr, timeOffsetString, hexCodeStr};
4044
4045 std::string msg =
4046 redfish::registries::fillMessageArgs(messageArgs, message->message);
4047 if (msg.empty())
ZhikuiRena3316fc2020-01-29 14:58:08 -08004048 {
Ed Tanous1e6deaf2022-02-17 11:32:37 -08004049 messages::internalError(asyncResp->res);
4050 return false;
ZhikuiRena3316fc2020-01-29 14:58:08 -08004051 }
4052
Tim Leed4342a92020-04-27 11:47:58 +08004053 // Get Severity template from message registry
4054 std::string severity;
4055 if (message != nullptr)
4056 {
Ed Tanous5f2b84e2022-02-08 00:41:53 -08004057 severity = message->messageSeverity;
Tim Leed4342a92020-04-27 11:47:58 +08004058 }
4059
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004060 // Format entry
4061 nlohmann::json::object_t bmcLogEntry;
Vijay Lobo9c11a172021-10-07 16:53:16 -05004062 bmcLogEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Ed Tanousef4c65b2023-04-24 15:28:50 -07004063 bmcLogEntry["@odata.id"] = boost::urls::format(
4064 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/{}",
4065 postcodeEntryID);
Jason M. Bills84afc482022-06-24 12:38:23 -07004066 bmcLogEntry["Name"] = "POST Code Log Entry";
4067 bmcLogEntry["Id"] = postcodeEntryID;
4068 bmcLogEntry["Message"] = std::move(msg);
4069 bmcLogEntry["MessageId"] = "OpenBMC.0.2.BIOSPOSTCode";
Ed Tanous1e6deaf2022-02-17 11:32:37 -08004070 bmcLogEntry["MessageArgs"] = messageArgs;
Jason M. Bills84afc482022-06-24 12:38:23 -07004071 bmcLogEntry["EntryType"] = "Event";
4072 bmcLogEntry["Severity"] = std::move(severity);
4073 bmcLogEntry["Created"] = entryTimeStr;
George Liu647b3cd2021-07-05 12:43:56 +08004074 if (!std::get<std::vector<uint8_t>>(code.second).empty())
4075 {
4076 bmcLogEntry["AdditionalDataURI"] =
4077 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/" +
4078 postcodeEntryID + "/attachment";
4079 }
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004080
4081 // codeIndex is only specified when querying single entry, return only
4082 // that entry in this case
4083 if (codeIndex != 0)
4084 {
Ed Tanousac106bf2023-06-07 09:24:59 -07004085 asyncResp->res.jsonValue.update(bmcLogEntry);
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004086 return true;
4087 }
4088
Ed Tanousac106bf2023-06-07 09:24:59 -07004089 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
Patrick Williamsb2ba3072023-05-12 10:27:39 -05004090 logEntryArray.emplace_back(std::move(bmcLogEntry));
ZhikuiRena3316fc2020-01-29 14:58:08 -08004091 }
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004092
4093 // Return value is always false when querying multiple entries
4094 return false;
ZhikuiRena3316fc2020-01-29 14:58:08 -08004095}
4096
Ed Tanousac106bf2023-06-07 09:24:59 -07004097static void
4098 getPostCodeForEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
4099 const std::string& entryId)
ZhikuiRena3316fc2020-01-29 14:58:08 -08004100{
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004101 uint16_t bootIndex = 0;
4102 uint64_t codeIndex = 0;
4103 if (!parsePostCode(entryId, codeIndex, bootIndex))
4104 {
4105 // Requested ID was not found
Ed Tanousac106bf2023-06-07 09:24:59 -07004106 messages::resourceNotFound(asyncResp->res, "LogEntry", entryId);
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004107 return;
4108 }
4109
4110 if (bootIndex == 0 || codeIndex == 0)
4111 {
4112 // 0 is an invalid index
Ed Tanousac106bf2023-06-07 09:24:59 -07004113 messages::resourceNotFound(asyncResp->res, "LogEntry", entryId);
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004114 return;
4115 }
4116
ZhikuiRena3316fc2020-01-29 14:58:08 -08004117 crow::connections::systemBus->async_method_call(
Ed Tanousac106bf2023-06-07 09:24:59 -07004118 [asyncResp, entryId, bootIndex,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08004119 codeIndex](const boost::system::error_code& ec,
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05304120 const boost::container::flat_map<
4121 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
4122 postcode) {
Ed Tanous002d39b2022-05-31 08:59:27 -07004123 if (ec)
4124 {
Ed Tanous62598e32023-07-17 17:06:25 -07004125 BMCWEB_LOG_DEBUG("DBUS POST CODE PostCode response error");
Ed Tanousac106bf2023-06-07 09:24:59 -07004126 messages::internalError(asyncResp->res);
Ed Tanous002d39b2022-05-31 08:59:27 -07004127 return;
4128 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08004129
Ed Tanous002d39b2022-05-31 08:59:27 -07004130 if (postcode.empty())
4131 {
Ed Tanousac106bf2023-06-07 09:24:59 -07004132 messages::resourceNotFound(asyncResp->res, "LogEntry", entryId);
Ed Tanous002d39b2022-05-31 08:59:27 -07004133 return;
4134 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08004135
Ed Tanousac106bf2023-06-07 09:24:59 -07004136 if (!fillPostCodeEntry(asyncResp, postcode, bootIndex, codeIndex))
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004137 {
Ed Tanousac106bf2023-06-07 09:24:59 -07004138 messages::resourceNotFound(asyncResp->res, "LogEntry", entryId);
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004139 return;
4140 }
Patrick Williams5a39f772023-10-20 11:20:21 -05004141 },
Jonathan Doman15124762021-01-07 17:54:17 -08004142 "xyz.openbmc_project.State.Boot.PostCode0",
4143 "/xyz/openbmc_project/State/Boot/PostCode0",
ZhikuiRena3316fc2020-01-29 14:58:08 -08004144 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
4145 bootIndex);
4146}
4147
Ed Tanousac106bf2023-06-07 09:24:59 -07004148static void
4149 getPostCodeForBoot(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
4150 const uint16_t bootIndex, const uint16_t bootCount,
4151 const uint64_t entryCount, size_t skip, size_t top)
ZhikuiRena3316fc2020-01-29 14:58:08 -08004152{
4153 crow::connections::systemBus->async_method_call(
Ed Tanousac106bf2023-06-07 09:24:59 -07004154 [asyncResp, bootIndex, bootCount, entryCount, skip,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08004155 top](const boost::system::error_code& ec,
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05304156 const boost::container::flat_map<
4157 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
4158 postcode) {
Ed Tanous002d39b2022-05-31 08:59:27 -07004159 if (ec)
4160 {
Ed Tanous62598e32023-07-17 17:06:25 -07004161 BMCWEB_LOG_DEBUG("DBUS POST CODE PostCode response error");
Ed Tanousac106bf2023-06-07 09:24:59 -07004162 messages::internalError(asyncResp->res);
Ed Tanous002d39b2022-05-31 08:59:27 -07004163 return;
4164 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08004165
Ed Tanous002d39b2022-05-31 08:59:27 -07004166 uint64_t endCount = entryCount;
4167 if (!postcode.empty())
4168 {
4169 endCount = entryCount + postcode.size();
Ed Tanous3648c8b2022-07-25 13:39:59 -07004170 if (skip < endCount && (top + skip) > entryCount)
ZhikuiRena3316fc2020-01-29 14:58:08 -08004171 {
Patrick Williams89492a12023-05-10 07:51:34 -05004172 uint64_t thisBootSkip = std::max(static_cast<uint64_t>(skip),
4173 entryCount) -
4174 entryCount;
Ed Tanous002d39b2022-05-31 08:59:27 -07004175 uint64_t thisBootTop =
Ed Tanous3648c8b2022-07-25 13:39:59 -07004176 std::min(static_cast<uint64_t>(top + skip), endCount) -
4177 entryCount;
Ed Tanous002d39b2022-05-31 08:59:27 -07004178
Ed Tanousac106bf2023-06-07 09:24:59 -07004179 fillPostCodeEntry(asyncResp, postcode, bootIndex, 0,
4180 thisBootSkip, thisBootTop);
ZhikuiRena3316fc2020-01-29 14:58:08 -08004181 }
Ed Tanousac106bf2023-06-07 09:24:59 -07004182 asyncResp->res.jsonValue["Members@odata.count"] = endCount;
Ed Tanous002d39b2022-05-31 08:59:27 -07004183 }
4184
4185 // continue to previous bootIndex
4186 if (bootIndex < bootCount)
4187 {
Ed Tanousac106bf2023-06-07 09:24:59 -07004188 getPostCodeForBoot(asyncResp, static_cast<uint16_t>(bootIndex + 1),
Ed Tanous002d39b2022-05-31 08:59:27 -07004189 bootCount, endCount, skip, top);
4190 }
Jiaqing Zhao81584ab2022-07-28 00:33:45 +08004191 else if (skip + top < endCount)
Ed Tanous002d39b2022-05-31 08:59:27 -07004192 {
Ed Tanousac106bf2023-06-07 09:24:59 -07004193 asyncResp->res.jsonValue["Members@odata.nextLink"] =
Ed Tanous002d39b2022-05-31 08:59:27 -07004194 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries?$skip=" +
4195 std::to_string(skip + top);
4196 }
Patrick Williams5a39f772023-10-20 11:20:21 -05004197 },
Jonathan Doman15124762021-01-07 17:54:17 -08004198 "xyz.openbmc_project.State.Boot.PostCode0",
4199 "/xyz/openbmc_project/State/Boot/PostCode0",
ZhikuiRena3316fc2020-01-29 14:58:08 -08004200 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
4201 bootIndex);
4202}
4203
zhanghch058d1b46d2021-04-01 11:18:24 +08004204static void
Ed Tanousac106bf2023-06-07 09:24:59 -07004205 getCurrentBootNumber(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous3648c8b2022-07-25 13:39:59 -07004206 size_t skip, size_t top)
ZhikuiRena3316fc2020-01-29 14:58:08 -08004207{
4208 uint64_t entryCount = 0;
Jonathan Doman1e1e5982021-06-11 09:36:17 -07004209 sdbusplus::asio::getProperty<uint16_t>(
4210 *crow::connections::systemBus,
4211 "xyz.openbmc_project.State.Boot.PostCode0",
4212 "/xyz/openbmc_project/State/Boot/PostCode0",
4213 "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount",
Ed Tanousac106bf2023-06-07 09:24:59 -07004214 [asyncResp, entryCount, skip, top](const boost::system::error_code& ec,
4215 const uint16_t bootCount) {
Ed Tanous002d39b2022-05-31 08:59:27 -07004216 if (ec)
4217 {
Ed Tanous62598e32023-07-17 17:06:25 -07004218 BMCWEB_LOG_DEBUG("DBUS response error {}", ec);
Ed Tanousac106bf2023-06-07 09:24:59 -07004219 messages::internalError(asyncResp->res);
Ed Tanous002d39b2022-05-31 08:59:27 -07004220 return;
4221 }
Ed Tanousac106bf2023-06-07 09:24:59 -07004222 getPostCodeForBoot(asyncResp, 1, bootCount, entryCount, skip, top);
Patrick Williams5a39f772023-10-20 11:20:21 -05004223 });
ZhikuiRena3316fc2020-01-29 14:58:08 -08004224}
4225
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004226inline void requestRoutesPostCodesEntryCollection(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08004227{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004228 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07004229 "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07004230 .privileges(redfish::privileges::getLogEntryCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004231 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07004232 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07004233 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
4234 const std::string& systemName) {
Ed Tanous002d39b2022-05-31 08:59:27 -07004235 query_param::QueryCapabilities capabilities = {
4236 .canDelegateTop = true,
4237 .canDelegateSkip = true,
4238 };
4239 query_param::Query delegatedQuery;
4240 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00004241 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07004242 {
4243 return;
4244 }
Ed Tanous25b54db2024-04-17 15:40:31 -07004245 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08004246 {
4247 // Option currently returns no systems. TBD
4248 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
4249 systemName);
4250 return;
4251 }
Ed Tanous22d268c2022-05-19 09:39:07 -07004252
4253 if (systemName != "system")
4254 {
4255 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
4256 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07004257 return;
4258 }
Ed Tanous002d39b2022-05-31 08:59:27 -07004259 asyncResp->res.jsonValue["@odata.type"] =
4260 "#LogEntryCollection.LogEntryCollection";
4261 asyncResp->res.jsonValue["@odata.id"] =
4262 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries";
4263 asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries";
4264 asyncResp->res.jsonValue["Description"] =
4265 "Collection of POST Code Log Entries";
4266 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
4267 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Ed Tanous3648c8b2022-07-25 13:39:59 -07004268 size_t skip = delegatedQuery.skip.value_or(0);
Jiaqing Zhao5143f7a2022-07-22 09:33:33 +08004269 size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
Ed Tanous3648c8b2022-07-25 13:39:59 -07004270 getCurrentBootNumber(asyncResp, skip, top);
Patrick Williams5a39f772023-10-20 11:20:21 -05004271 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004272}
ZhikuiRena3316fc2020-01-29 14:58:08 -08004273
George Liu647b3cd2021-07-05 12:43:56 +08004274inline void requestRoutesPostCodesEntryAdditionalData(App& app)
4275{
George Liu0fda0f12021-11-16 10:06:17 +08004276 BMCWEB_ROUTE(
4277 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07004278 "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/attachment/")
George Liu647b3cd2021-07-05 12:43:56 +08004279 .privileges(redfish::privileges::getLogEntry)
4280 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07004281 [&app](const crow::Request& req,
4282 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07004283 const std::string& systemName,
Ed Tanous45ca1b82022-03-25 13:07:27 -07004284 const std::string& postCodeID) {
Carson Labrado3ba00072022-06-06 19:40:56 +00004285 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07004286 {
4287 return;
4288 }
Matt Spinler72e21372023-04-19 12:53:33 -05004289 if (!http_helpers::isContentTypeAllowed(
Ed Tanous99351cd2022-08-07 16:42:51 -07004290 req.getHeaderValue("Accept"),
Ed Tanous4a0e1a02022-09-21 15:28:04 -07004291 http_helpers::ContentType::OctetStream, true))
Ed Tanous002d39b2022-05-31 08:59:27 -07004292 {
4293 asyncResp->res.result(boost::beast::http::status::bad_request);
4294 return;
4295 }
Ed Tanous25b54db2024-04-17 15:40:31 -07004296 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08004297 {
4298 // Option currently returns no systems. TBD
4299 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
4300 systemName);
4301 return;
4302 }
Ed Tanous22d268c2022-05-19 09:39:07 -07004303 if (systemName != "system")
4304 {
4305 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
4306 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07004307 return;
4308 }
George Liu647b3cd2021-07-05 12:43:56 +08004309
Ed Tanous002d39b2022-05-31 08:59:27 -07004310 uint64_t currentValue = 0;
4311 uint16_t index = 0;
4312 if (!parsePostCode(postCodeID, currentValue, index))
4313 {
4314 messages::resourceNotFound(asyncResp->res, "LogEntry", postCodeID);
4315 return;
4316 }
George Liu647b3cd2021-07-05 12:43:56 +08004317
Ed Tanous002d39b2022-05-31 08:59:27 -07004318 crow::connections::systemBus->async_method_call(
4319 [asyncResp, postCodeID, currentValue](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08004320 const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -07004321 const std::vector<std::tuple<uint64_t, std::vector<uint8_t>>>&
4322 postcodes) {
4323 if (ec.value() == EBADR)
4324 {
4325 messages::resourceNotFound(asyncResp->res, "LogEntry",
4326 postCodeID);
4327 return;
4328 }
4329 if (ec)
4330 {
Ed Tanous62598e32023-07-17 17:06:25 -07004331 BMCWEB_LOG_DEBUG("DBUS response error {}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -07004332 messages::internalError(asyncResp->res);
4333 return;
4334 }
George Liu647b3cd2021-07-05 12:43:56 +08004335
Ed Tanous002d39b2022-05-31 08:59:27 -07004336 size_t value = static_cast<size_t>(currentValue) - 1;
4337 if (value == std::string::npos || postcodes.size() < currentValue)
4338 {
Ed Tanous62598e32023-07-17 17:06:25 -07004339 BMCWEB_LOG_WARNING("Wrong currentValue value");
Ed Tanous002d39b2022-05-31 08:59:27 -07004340 messages::resourceNotFound(asyncResp->res, "LogEntry",
4341 postCodeID);
4342 return;
4343 }
George Liu647b3cd2021-07-05 12:43:56 +08004344
Ed Tanous002d39b2022-05-31 08:59:27 -07004345 const auto& [tID, c] = postcodes[value];
4346 if (c.empty())
4347 {
Ed Tanous62598e32023-07-17 17:06:25 -07004348 BMCWEB_LOG_WARNING("No found post code data");
Ed Tanous002d39b2022-05-31 08:59:27 -07004349 messages::resourceNotFound(asyncResp->res, "LogEntry",
4350 postCodeID);
4351 return;
4352 }
4353 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
4354 const char* d = reinterpret_cast<const char*>(c.data());
4355 std::string_view strData(d, c.size());
George Liu647b3cd2021-07-05 12:43:56 +08004356
Ed Tanousd9f6c622022-03-17 09:12:17 -07004357 asyncResp->res.addHeader(boost::beast::http::field::content_type,
Ed Tanous002d39b2022-05-31 08:59:27 -07004358 "application/octet-stream");
Ed Tanousd9f6c622022-03-17 09:12:17 -07004359 asyncResp->res.addHeader(
4360 boost::beast::http::field::content_transfer_encoding, "Base64");
Ed Tanous27b0cf92023-08-07 12:02:40 -07004361 asyncResp->res.write(crow::utility::base64encode(strData));
Patrick Williams5a39f772023-10-20 11:20:21 -05004362 },
Ed Tanous002d39b2022-05-31 08:59:27 -07004363 "xyz.openbmc_project.State.Boot.PostCode0",
4364 "/xyz/openbmc_project/State/Boot/PostCode0",
4365 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodes", index);
Patrick Williams5a39f772023-10-20 11:20:21 -05004366 });
George Liu647b3cd2021-07-05 12:43:56 +08004367}
4368
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004369inline void requestRoutesPostCodesEntry(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08004370{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004371 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07004372 app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07004373 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004374 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07004375 [&app](const crow::Request& req,
4376 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07004377 const std::string& systemName, const std::string& targetID) {
Carson Labrado3ba00072022-06-06 19:40:56 +00004378 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07004379 {
4380 return;
4381 }
Ed Tanous25b54db2024-04-17 15:40:31 -07004382 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
Ed Tanous7f3e84a2022-12-28 16:22:54 -08004383 {
4384 // Option currently returns no systems. TBD
4385 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
4386 systemName);
4387 return;
4388 }
Ed Tanous22d268c2022-05-19 09:39:07 -07004389 if (systemName != "system")
4390 {
4391 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
4392 systemName);
4393 return;
4394 }
4395
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004396 getPostCodeForEntry(asyncResp, targetID);
Patrick Williams5a39f772023-10-20 11:20:21 -05004397 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004398}
ZhikuiRena3316fc2020-01-29 14:58:08 -08004399
Ed Tanous1da66f72018-07-27 16:13:37 -07004400} // namespace redfish